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