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