Standardize License information
[openafs.git] / src / bucoord / main.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afs/param.h>
11 #include <afs/stds.h>
12 #include <sys/types.h>
13 #include <stdio.h>
14 #ifdef  AFS_AIX32_ENV
15 #include <signal.h>
16 #endif
17 #ifdef AFS_NT40_ENV
18 #include <winsock2.h>
19 #else
20 #include <sys/socket.h>
21 #include <netinet/in.h>
22 #include <netdb.h>
23 #endif
24 #include <errno.h>
25 #include <afs/cmd.h>
26 #include <rx/rx.h>
27 #include <rx/rx_globals.h>
28 #include <lwp.h>
29 #include <afs/bubasics.h>
30 #include <fcntl.h>
31 #include <afs/afsutil.h>
32 #include <afs/auth.h>
33 #include <afs/cellconfig.h>
34 #include <afs/keys.h>
35 #include <ubik.h>
36 #include <afs/cmd.h>
37 #include <rx/rxkad.h>
38 #include <afs/volser.h>     /*VLDB_MAXSERVERS*/
39 #include <afs/com_err.h>
40 #include <lock.h>
41 #include <afs/budb.h>
42
43 #include "bc.h"     /*Backup Coordinator structs and defs*/
44
45
46 int  localauth, interact;
47 char tcell[64];
48
49 extern int BC_ExecuteRequest();
50 extern int bc_AddDumpCmd();
51 extern int bc_AddHostCmd();
52 extern int bc_AddVolEntryCmd();
53 extern int bc_AddVolSetCmd();
54 /* extern int bc_CheckDumpStatCmd(); */
55 extern int bc_DeleteDumpCmd();
56 extern int bc_DeleteHostCmd();
57 extern int bc_DeleteVolEntryCmd();
58 extern int bc_DeleteVolSetCmd();
59 extern int bc_DiskRestoreCmd();
60 extern int bc_VolsetRestoreCmd();
61 extern int bc_DumpCmd();
62 extern int bc_GetTapeStatusCmd();
63 extern int bc_JobsCmd();
64 extern int bc_KillCmd();
65 extern int bc_LabelTapeCmd();
66 extern int bc_ListDumpScheduleCmd();
67 extern int bc_ListHostsCmd();
68 extern int bc_ListVolSetCmd();
69 extern int bc_QuitCmd();
70 extern int bc_ReadLabelCmd();
71 extern int bc_ScanDumpsCmd();
72 extern int bc_SetExpCmd();
73 extern int bc_VolRestoreCmd();
74 extern int bc_dblookupCmd();
75 extern int bc_dbVerifyCmd();
76 extern int bc_deleteDumpCmd();
77 extern int bc_dumpInfoCmd();
78 extern int bc_restoreDbCmd();
79 extern int bc_saveDbCmd();
80
81 extern PrintError();
82
83 /*
84  * Global configuration information for the Backup Coordinator.
85  */
86 struct bc_config *bc_globalConfig;              /*Ptr to global BC configuration info*/
87
88 extern struct rx_securityClass *rxnull_NewServerSecurityObject();
89
90 struct ubik_client *cstruct;            /* Ptr to Ubik client structure*/
91 struct ktc_token   ttoken;              /* The token */
92
93 static const char *DefaultConfDir;  /*Default backup config directory*/
94 static int bcInit = 0;                  /* backupInit called yet ? */
95 char *whoami = "backup";
96
97 /* dummy routine for the audit work.  It should do nothing since audits */
98 /* occur at the server level and bos is not a server. */
99 osi_audit() {return 0;}
100
101 /*
102  * Initialize all the error tables that may be used by com_err
103  * in this module.
104  */
105 void InitErrTabs()
106 {
107     initialize_acfg_error_table();
108     initialize_ka_error_table();
109     initialize_rxk_error_table();
110     initialize_cmd_error_table();
111     initialize_vl_error_table();
112     initialize_butm_error_table();
113     initialize_vols_error_table();
114     initialize_butc_error_table();
115     initialize_butx_error_table();
116     initialize_budb_error_table();
117     initialize_bucd_error_table();
118     initialize_ktc_error_table();
119 }
120
121 /* 
122  * got to account for the errors which are volume related but 
123  * not dealt with by standard errno and com_err stuff.
124  */
125 void bc_HandleMisc(code)
126 afs_int32 code;
127 {
128     if(((code <= VMOVED) && (code >= VSALVAGE)) || (code < 0)){
129         switch(code){
130             case -1     :   fprintf(STDERR,"Possible communication failure\n");
131                 break;
132             case VSALVAGE: fprintf(STDERR,"Volume needs salvage\n");
133                 break;
134             case VNOVNODE:  fprintf(STDERR,"Bad vnode number quoted\n");
135                 break;
136             case VNOVOL:    fprintf(STDERR,"Volume not attached, does not exist, or not on line\n");
137                 break;
138             case VVOLEXISTS:fprintf(STDERR,"Volume already exists\n");
139                 break;
140             case VNOSERVICE:fprintf(STDERR,"Volume is not in service\n");
141                 break;
142             case VOFFLINE:  fprintf(STDERR,"Volume is off line\n");
143                 break;
144             case VONLINE:   fprintf(STDERR,"Volume is already on line\n");
145                 break;
146             case VDISKFULL: fprintf(STDERR,"Partition is full\n");
147                 break;
148             case VOVERQUOTA:fprintf(STDERR,"Volume max quota exceeded\n");
149                 break;
150             case VBUSY: fprintf(STDERR,"Volume temporarily unavailable\n");
151                 break;
152             case VMOVED:fprintf(STDERR,"Volume has moved to another server\n");
153                 break;
154             default:
155               break;
156           }
157     }
158     return;
159 }
160
161 /* Return true if line is all whitespace */
162 static LineIsBlank(aline)
163     register char *aline;
164
165     register int tc;
166
167     while (tc = *aline++)
168         if ( (tc != ' ') && (tc != '\t') && (tc != '\n') ) return(0);
169
170     return(1);
171
172
173
174 /* bc_InitTextConfig
175  *      initialize configuration information that is stored as text blocks
176  */
177
178 afs_int32
179 bc_InitTextConfig()
180 {
181     udbClientTextP ctPtr;
182     int i;
183     afs_int32 code = 0;
184
185     extern struct bc_config *bc_globalConfig;
186
187     mkdir(DefaultConfDir, 777);                 /* temporary */
188
189     /* initialize the client text structures */
190     ctPtr = &bc_globalConfig->configText[0];
191
192     for ( i = 0; i < TB_NUM; i++ )
193     {
194         bzero(ctPtr, sizeof(*ctPtr));
195         ctPtr->textType = i;
196         ctPtr->textVersion = -1;
197         ctPtr++;
198     }
199         
200     return(0);
201 }
202
203 /*----------------------------------------------------------------------------
204  * backupInit
205  *
206  * Description:
207  *      Routine that is called when the backup coordinator is invoked, responsible for
208  *      basic initialization and some command line parsing.
209  *
210  * Returns:
211  *      Zero (but may exit the entire program on error!)
212  *
213  * Environment:
214  *      Nothing interesting.
215  *
216  * Side Effects:
217  *      Initializes this program.
218  *----------------------------------------------------------------------------
219  */
220
221 static int backupInit()
222 {
223     register afs_int32 code;
224     static int initd = 0;               /* ever called? */
225     PROCESS watcherPid;
226     PROCESS pid;                        /* LWP process ID*/
227
228     extern statusWatcher();
229
230     /* Initialization */
231     initialize_cmd_error_table();
232
233     /* don't run more than once */
234     if (initd) 
235     {
236         com_err(whoami,0,"Backup already initialized.");
237         return 0;
238     }
239     initd = 1;
240
241     code = bc_InitConfig(DefaultConfDir);
242     if (code)
243     {
244         com_err(whoami, code, "Can't initialize from config files in directory '%s'",
245                 DefaultConfDir);
246         return(code);
247     }
248
249     /*
250      * Set up Rx.
251      */
252     code = LWP_InitializeProcessSupport(LWP_NORMAL_PRIORITY, &pid);
253     if (code) 
254     {
255         com_err(whoami, code,"; Can't initialize LWP");
256         return(code);
257     }
258
259     code = rx_Init(htons(0)); 
260     if (code)
261     {
262         com_err(whoami, code, "; Can't initialize Rx");
263         return(code);
264     }
265
266     rx_SetRxDeadTime(60);
267
268     /* VLDB initialization */
269     vldbClientInit(0, localauth, tcell, &cstruct, &ttoken);
270     if (code) return(code);
271
272     /* Backup database initialization */
273     code = udbClientInit(0, localauth, tcell);
274     if (code) return(code);
275
276     /* setup status monitoring thread */
277     initStatus();
278     code = LWP_CreateProcess(statusWatcher, 20480, LWP_NORMAL_PRIORITY, 2,
279                              "statusWatcher", &watcherPid);
280     if ( code )
281     {
282         com_err(whoami, code, "; Can't create status monitor task");
283         return(code);
284     }
285
286     return(0);
287 }
288
289 /*----------------------------------------------------------------------------
290  * MyBeforeProc
291  *
292  * Description:
293  *      Make sure we mark down when we need to exit the Backup Coordinator.
294  *      Specifically, we don't want to continue when our help and apropos
295  *      routines are called from the command line.
296  *
297  * Arguments:
298  *      as : Ptr to the command syntax descriptor.
299  *
300  * Returns:
301  *      0.
302  *
303  * Environment:
304  *      This routine is called right before each of the Backup Coordinator
305  *      opcode routines are invoked.
306  *
307  *----------------------------------------------------------------------------
308  */
309
310 static int MyBeforeProc(as)
311     register struct cmd_syndesc *as;
312 {
313     char *rock;
314     afs_int32 code;
315
316     /* Handling the command line opcode */
317     if (!bcInit)
318     {
319         localauth = ((as && as->parms[14].items) ? 1 : 0);
320         if (as && as->parms[15].items) strcpy(tcell, as->parms[15].items->data);
321         else tcell[0]  = '\0';
322
323         code = backupInit();
324         if (code)
325         {
326             com_err(whoami,code,"; Can't initialize backup");
327             exit(1);
328         }
329
330         /* Get initial information from the database */
331         code = bc_InitTextConfig();
332         if (code)
333         {
334             com_err(whoami, code, "; Can't obtain configuration text from backup database");
335             exit(1);
336         }
337     }
338     bcInit = 1;
339
340     return 0;
341 }
342
343
344 #define MAXV    100
345
346 #include "AFS_component_version_number.c"
347
348 #define MAXRECURSION 20
349 extern int  dontExecute;                      /* declared in commands.c */
350 extern char *loadFile;                        /* declared in commands.c */
351 char lineBuffer[1024];                        /* Line typed in by user or read from load file */
352
353 /* 
354  * This will dispatch a command.  It holds a recursive loop for the
355  * "dump -file" option. This option reads backup commands from a file.
356  *
357  * Cannot put this code on other side of cmd_Dispatch call (in
358  * commands.c) because when make a dispatch call when in a dispatch
359  * call, environment is mucked up.
360  * 
361  * To avoid multiple processes stepping on each other in the dispatch code,
362  * put a lock around it so only 1 process gets in at a time.
363  */
364
365 struct Lock dispatchLock;                                   /* lock on the Dispatch call */
366 #define lock_Dispatch()     ObtainWriteLock(&dispatchLock)
367 #define unlock_Dispatch()   ReleaseWriteLock(&dispatchLock)
368
369 afs_int32 doDispatch(targc, targv, dispatchCount)
370   char **targv[MAXV];
371   afs_int32 targc; 
372   afs_int32 dispatchCount;                /* to prevent infinite recursion */
373 {
374   char **sargv[MAXV];
375   afs_int32 sargc; 
376   afs_int32 code, c;
377   FILE *fd;
378   int  i;
379   int  lineNumber;
380   int  noExecute;                    /* local capy of global variable */
381   char *internalLoadFile;
382
383   lock_Dispatch();
384
385   loadFile = (char *) 0;
386   code = cmd_Dispatch(targc, targv);
387   internalLoadFile = loadFile;
388
389   unlock_Dispatch();
390
391   if (internalLoadFile)                                            /* Load a file in */
392   {
393       if (dispatchCount > MAXRECURSION)                            /* Beware recursive loops. */
394       {
395           com_err(whoami,0,"Potential recursion: will not load file %s", internalLoadFile);
396           code = -1;
397           goto done;
398       }
399
400       fd = fopen(internalLoadFile, "r");                           /* Open the load file */
401       if (!fd)
402       {
403           com_err(whoami,errno,"; Cannot open file %s", internalLoadFile);
404           code = -1;
405           goto done;
406       }
407
408       noExecute = dontExecute;
409       if (noExecute)
410           printf("Would have executed the following commands:\n");
411       
412       lineNumber = 0;
413       while ( fgets(lineBuffer, sizeof(lineBuffer)-1, fd) )        /* Get commands from file */
414       {
415           lineNumber++;
416           
417           i = strlen(lineBuffer) - 1;
418           if (lineBuffer[i] == '\n')            /* Drop return at end of line */
419               lineBuffer[i] = '\0';
420
421           if (noExecute)
422               printf("        %s\n", lineBuffer);                      /* echo */
423           else 
424               printf("------> %s\n", lineBuffer);                      /* echo */
425
426           if ( !LineIsBlank(lineBuffer) &&                         /* Skip if blank line */
427               (lineBuffer[0] != '#')    &&                         /*      or comment    */
428               (!noExecute) )                                       /*      or no execute */
429           {
430               c = cmd_ParseLine(lineBuffer, sargv, &sargc, MAXV);
431               if (c)
432               {
433                   com_err(whoami, c, "; Can't parse line");
434               }
435               else
436               {
437                   doDispatch(sargc, sargv, dispatchCount+1);  /* Recursive - ignore error */
438                   cmd_FreeArgv(sargv);                        /* Free up arguments */
439               }
440           }
441       }
442
443       fclose(fd);
444   }
445
446 done:
447   if (internalLoadFile) free(internalLoadFile);
448   return(code);
449 }
450
451 int bc_interactCmd(as, arock)
452     struct cmd_syndesc *as;
453     char *arock;
454 {
455     interact = 1;
456 }
457
458 static void add_std_args(ts)
459    register struct cmd_syndesc *ts;
460 {
461     cmd_Seek(ts, 14);
462     cmd_AddParm(ts, "-localauth", CMD_FLAG, CMD_OPTIONAL, "local authentication");
463     cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");
464 }
465
466
467 main(argc, argv)
468     int    argc;
469     char **argv;
470 { /*main*/
471     char **targv[MAXV];                     /*Ptr to parsed argv stuff*/
472     afs_int32 targc;                        /*Num parsed arguments*/
473     afs_int32 code;                                 /*Return code*/
474     char *tp;                               /*Result of gets()*/
475     register struct cmd_syndesc *ts;        /*Ptr to parsed command line*/
476     int i;
477
478
479 #ifdef  AFS_AIX32_ENV
480     /*
481      * The following signal action for AIX is necessary so that in case of a 
482      * crash (i.e. core is generated) we can include the user's data section 
483      * in the core dump. Unfortunately, by default, only a partial core is
484      * generated which, in many cases, isn't too useful.
485      */
486     struct sigaction nsa;
487     
488     sigemptyset(&nsa.sa_mask);
489     nsa.sa_handler = SIG_DFL;
490     nsa.sa_flags = SA_FULLDUMP;
491     sigaction(SIGSEGV, &nsa, NULL);
492 #endif
493     Lock_Init(&dispatchLock);
494     InitErrTabs();      /* init all the error tables which may be used */
495
496     /* setup the default backup dir */
497     DefaultConfDir = AFSDIR_SERVER_BACKUP_DIRPATH;
498     /* Get early warning if the command is interacive mode or not */
499     interact = ( ((argc < 2) || (argv[1][0] == '-')) ? 1 : 0 );
500
501     cmd_SetBeforeProc(MyBeforeProc, (char *)0);
502
503     ts = cmd_CreateSyntax("dump", bc_DumpCmd, 0, "start dump");
504     cmd_AddParm(ts, "-volumeset", CMD_SINGLE, CMD_OPTIONAL, "volume set name");
505     cmd_AddParm(ts, "-dump", CMD_SINGLE, CMD_OPTIONAL, "dump level name");
506     cmd_AddParm(ts, "-portoffset", CMD_SINGLE, CMD_OPTIONAL, "TC port offset");
507     cmd_AddParm(ts, "-at", CMD_LIST, CMD_OPTIONAL, "Date/time to start dump");
508     cmd_AddParm(ts, "-append", CMD_FLAG, CMD_OPTIONAL, "append to existing dump set");
509     cmd_AddParm(ts, "-n", CMD_FLAG, CMD_OPTIONAL, "don't really execute it");
510     cmd_AddParm(ts, "-file", CMD_SINGLE, CMD_OPTIONAL, "load file");
511     if (!interact) add_std_args(ts);
512
513     ts = cmd_CreateSyntax("volrestore", bc_VolRestoreCmd, 0, "restore volume");
514     cmd_AddParm(ts, "-server",    CMD_SINGLE, CMD_REQUIRED, "destination machine");
515     cmd_AddParm(ts, "-partition", CMD_SINGLE, CMD_REQUIRED, "destination partition");
516     cmd_AddParm(ts, "-volume", CMD_LIST, CMD_REQUIRED, "volume(s) to restore");
517     cmd_AddParm(ts, "-extension", CMD_SINGLE, CMD_OPTIONAL, "new volume name extension");
518     cmd_AddParm(ts, "-date", CMD_LIST, CMD_OPTIONAL, "date from which to restore");
519     cmd_AddParm(ts, "-portoffset", CMD_LIST, CMD_OPTIONAL, "TC port offsets");
520     cmd_AddParm(ts, "-n", CMD_FLAG, CMD_OPTIONAL, "don't really execute it");
521     if (!interact) add_std_args(ts);
522     
523     ts = cmd_CreateSyntax("diskrestore", bc_DiskRestoreCmd, 0, "restore partition");
524     cmd_AddParm(ts, "-server",       CMD_SINGLE, CMD_REQUIRED, "machine to restore");
525     cmd_AddParm(ts, "-partition",    CMD_SINGLE, CMD_REQUIRED, "partition to restore");
526     cmd_AddParm(ts, "-portoffset",   CMD_LIST,   CMD_OPTIONAL, "TC port offset");
527     cmd_Seek(ts, 8);
528     cmd_AddParm(ts, "-newserver",    CMD_SINGLE, CMD_OPTIONAL, "destination machine");
529     cmd_AddParm(ts, "-newpartition", CMD_SINGLE, CMD_OPTIONAL, "destination partition");
530     cmd_AddParm(ts, "-extension", CMD_SINGLE, CMD_OPTIONAL, "new volume name extension");
531     cmd_AddParm(ts, "-n", CMD_FLAG, CMD_OPTIONAL, "don't really execute it");
532     if (!interact) add_std_args(ts);
533
534     ts = cmd_CreateSyntax("quit", bc_QuitCmd, 0, "leave the program");
535
536     ts = cmd_CreateSyntax("volsetrestore", bc_VolsetRestoreCmd, 0, "restore a set of volumes");
537     cmd_AddParm(ts, "-name", CMD_SINGLE, CMD_OPTIONAL, "volume set name");
538     cmd_AddParm(ts, "-file", CMD_SINGLE, CMD_OPTIONAL, "file name");
539     cmd_AddParm(ts, "-portoffset", CMD_LIST, CMD_OPTIONAL, "TC port offset");
540     cmd_AddParm(ts, "-extension", CMD_SINGLE, CMD_OPTIONAL, "new volume name extension");
541     cmd_AddParm(ts, "-n", CMD_FLAG, CMD_OPTIONAL, "don't really execute it");
542     if (!interact) add_std_args(ts);
543
544     ts = cmd_CreateSyntax("addhost", bc_AddHostCmd, 0, "add host to config");
545     cmd_AddParm(ts, "-tapehost", CMD_SINGLE, CMD_REQUIRED, "tape machine name");
546     cmd_AddParm(ts, "-portoffset", CMD_SINGLE, CMD_OPTIONAL, "TC port offset");
547     if (!interact) add_std_args(ts);
548
549     ts = cmd_CreateSyntax("delhost", bc_DeleteHostCmd, 0, "delete host to config");
550     cmd_AddParm(ts, "-tapehost", CMD_SINGLE, CMD_REQUIRED, "tape machine name");
551     cmd_AddParm(ts, "-portoffset", CMD_SINGLE, CMD_OPTIONAL, "TC port offset");
552     if (!interact) add_std_args(ts);
553
554     ts = cmd_CreateSyntax("listhosts", bc_ListHostsCmd, 0, "list config hosts");
555     if (!interact) add_std_args(ts);
556
557     ts = cmd_CreateSyntax("jobs", bc_JobsCmd, 0, "list running jobs");
558
559     ts = cmd_CreateSyntax("kill", bc_KillCmd, 0, "kill running job");
560     cmd_AddParm(ts, "-id", CMD_SINGLE, CMD_REQUIRED, "job ID or dump set name");
561
562     ts = cmd_CreateSyntax("listvolsets", bc_ListVolSetCmd, 0, "list volume sets");
563     cmd_AddParm(ts, "-name", CMD_SINGLE, CMD_OPTIONAL, "volume set name");
564     if (!interact) add_std_args(ts);
565
566     ts = cmd_CreateSyntax("listdumps", bc_ListDumpScheduleCmd, 0, "list dump schedules");
567     if (!interact) add_std_args(ts);
568
569     ts = cmd_CreateSyntax("addvolset", bc_AddVolSetCmd, 0, "create a new volume set");
570     cmd_AddParm(ts, "-name", CMD_SINGLE, CMD_REQUIRED, "volume set name");
571     cmd_AddParm(ts, "-temporary", CMD_FLAG, CMD_OPTIONAL, "temporary volume set");
572     if (!interact) add_std_args(ts);
573
574     ts = cmd_CreateSyntax("status", bc_GetTapeStatusCmd, 0, 
575                           "get tape coordinator status");
576     cmd_AddParm(ts, "-portoffset", CMD_SINGLE, CMD_OPTIONAL, "TC port offset");
577     if (!interact) add_std_args(ts);
578
579     ts = cmd_CreateSyntax("delvolset", bc_DeleteVolSetCmd, 0, "delete a volume set");
580     cmd_AddParm(ts, "-name", CMD_LIST, CMD_REQUIRED, "volume set name");
581     if (!interact) add_std_args(ts);
582
583     ts = cmd_CreateSyntax("addvolentry", bc_AddVolEntryCmd, 0, "add a new volume entry");
584     cmd_AddParm(ts, "-name", CMD_SINGLE, CMD_REQUIRED, "volume set name");
585     cmd_AddParm(ts, "-server", CMD_SINGLE, CMD_REQUIRED, "machine name");
586     cmd_AddParm(ts, "-partition", CMD_SINGLE, CMD_REQUIRED, "partition name");
587     cmd_AddParm(ts, "-volumes", CMD_SINGLE, CMD_REQUIRED, "volume name (regular expression)");
588     if (!interact) add_std_args(ts);
589
590     ts = cmd_CreateSyntax("delvolentry", bc_DeleteVolEntryCmd, 0, "delete a volume set sub-entry");
591     cmd_AddParm(ts, "-name", CMD_SINGLE, CMD_REQUIRED, "volume set name");
592     cmd_AddParm(ts, "-entry", CMD_SINGLE, CMD_REQUIRED, "volume set index");
593     if (!interact) add_std_args(ts);
594
595     ts = cmd_CreateSyntax("adddump", bc_AddDumpCmd, 0, "add dump schedule");
596     cmd_AddParm(ts, "-dump", CMD_LIST, CMD_REQUIRED, "dump level name");
597     cmd_AddParm(ts, "-expires", CMD_LIST, CMD_OPTIONAL, "expiration date");
598     if (!interact) add_std_args(ts);
599
600     ts = cmd_CreateSyntax("deldump", bc_DeleteDumpCmd, 0, "delete dump schedule");
601     cmd_AddParm(ts, "-dump", CMD_SINGLE, CMD_REQUIRED, "dump level name");
602     if (!interact) add_std_args(ts);
603
604     ts = cmd_CreateSyntax("labeltape", bc_LabelTapeCmd, 0, "label a tape");
605     cmd_AddParm(ts, "-name", CMD_SINGLE, CMD_OPTIONAL, "AFS tape name, defaults to NULL");
606     cmd_AddParm(ts, "-size", CMD_SINGLE, CMD_OPTIONAL, 
607                 "tape size in Kbytes, defaults to size in tapeconfig");
608     cmd_AddParm(ts, "-portoffset", CMD_SINGLE, CMD_OPTIONAL, "TC port offset");
609     cmd_AddParm(ts, "-pname", CMD_SINGLE, CMD_OPTIONAL, "permanent tape name");
610     if (!interact) add_std_args(ts);
611
612     ts = cmd_CreateSyntax("readlabel", bc_ReadLabelCmd, 0, "read the label on tape");
613     cmd_AddParm(ts, "-portoffset", CMD_SINGLE, CMD_OPTIONAL, "TC port offset");
614     if (!interact) add_std_args(ts);
615
616     ts = cmd_CreateSyntax("scantape", bc_ScanDumpsCmd, 0, "dump information recovery from tape");
617     cmd_AddParm(ts, "-dbadd", CMD_FLAG, CMD_OPTIONAL, "add information to the database");
618     cmd_AddParm(ts, "-portoffset", CMD_SINGLE, CMD_OPTIONAL, "TC port offset");
619     if (!interact) add_std_args(ts);
620
621     ts = cmd_CreateSyntax("volinfo", bc_dblookupCmd, 0, "query the backup database");
622     cmd_AddParm(ts, "-volume", CMD_SINGLE, CMD_REQUIRED, "volume name");
623     if (!interact) add_std_args(ts);
624
625     ts = cmd_CreateSyntax("setexp", bc_SetExpCmd, 0, "set/clear dump expiration dates");
626     cmd_AddParm(ts, "-dump", CMD_LIST, CMD_REQUIRED, "dump level name");
627     cmd_AddParm(ts, "-expires", CMD_LIST, CMD_OPTIONAL, "expiration date");
628     if (!interact) add_std_args(ts);
629
630     ts = cmd_CreateSyntax("savedb", bc_saveDbCmd, 0, "save backup database");
631     cmd_AddParm(ts, "-portoffset", CMD_SINGLE, CMD_OPTIONAL, "TC port offset");
632     cmd_AddParm(ts, "-archive",    CMD_LIST,   CMD_OPTIONAL, "date time");
633     if (!interact) add_std_args(ts);
634
635     ts = cmd_CreateSyntax("restoredb", bc_restoreDbCmd, 0, "restore backup database");
636     cmd_AddParm(ts, "-portoffset", CMD_SINGLE, CMD_OPTIONAL, "TC port offset");
637     if (!interact) add_std_args(ts);
638
639     ts = cmd_CreateSyntax("dumpinfo", bc_dumpInfoCmd, 0, 
640                           "provide information about a dump in the database");
641     cmd_AddParm(ts, "-ndumps", CMD_SINGLE, CMD_OPTIONAL, "no. of dumps");
642     cmd_AddParm(ts, "-id", CMD_SINGLE, CMD_OPTIONAL, "dump id");
643     cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, "detailed description");
644     if (!interact) add_std_args(ts);
645
646     ts = cmd_CreateSyntax("dbverify", bc_dbVerifyCmd, 0, "check ubik database integrity");
647     cmd_AddParm(ts, "-detail", CMD_FLAG, CMD_OPTIONAL, "additional details");
648     if (!interact) add_std_args(ts);
649
650    ts = cmd_CreateSyntax("deletedump", bc_deleteDumpCmd, 0, "delete dumps from the database");
651     cmd_AddParm(ts, "-dumpid", CMD_LIST,   CMD_OPTIONAL, "dump id");
652     cmd_AddParm(ts, "-from",   CMD_LIST,   CMD_OPTIONAL, "date time");
653     cmd_AddParm(ts, "-to",     CMD_LIST,   CMD_OPTIONAL, "date time");
654     cmd_AddParm(ts, "-port",   CMD_SINGLE, CMD_OPTIONAL, "TC port offset");
655     cmd_AddParm(ts, "-groupid", CMD_SINGLE, CMD_OPTIONAL, "group ID");
656     cmd_AddParm(ts, "-dbonly", CMD_FLAG, CMD_OPTIONAL,
657                     "delete the dump from the backup database only");
658     cmd_AddParm(ts, "-force",   CMD_FLAG, CMD_OPTIONAL,
659                     "always delete from backup database");
660     cmd_AddParm(ts, "-noexecute", CMD_FLAG, CMD_OPTIONAL, "Just list the dumps");
661     
662     if (!interact) add_std_args(ts);
663
664     ts = cmd_CreateSyntax("interactive", bc_interactCmd, 0, "enter interactive mode");
665     add_std_args(ts);
666
667     /*
668      * Now execute the command.
669      */
670
671     targc = 0;             targv[targc++] = argv[0];
672     if (interact)          targv[targc++] = "interactive";
673     for (i=1; i<argc; i++) targv[targc++] = argv[i];
674
675     code = doDispatch(targc, targv, 1);
676
677     if (!interact || !bcInit)           /* Non-interactive mode */
678     {
679         if (code) exit(-1);
680         if (bcInit) code = bc_WaitForNoJobs();    /* wait for any jobs to finish */
681         exit(code);                               /* and exit */
682     }
683
684     /* Iterate on command lines, interpreting user commands (interactive mode) */
685     while(1) 
686     {
687         printf("backup> ");
688         fflush(stdout);
689
690         
691         while (LWP_GetLine(lineBuffer, sizeof(lineBuffer)) == 0)
692           printf("%s: Command line too long\n", whoami); /* line too long */
693         
694         if ( !LineIsBlank(lineBuffer) ) 
695         {
696             code = cmd_ParseLine(lineBuffer, targv, &targc, MAXV);
697             if (code)
698                 com_err(whoami,code,"; Can't parse line: '%s'", 
699                         error_message(code));
700             else 
701             {
702                 doDispatch(targc, targv, 1);
703                 cmd_FreeArgv(targv);
704             }
705         }
706     }
707 } /*main*/