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