2 * Copyright 2000, International Business Machines Corporation and others.
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
10 #include <afsconfig.h>
11 #include <afs/param.h>
19 #include <rx/rx_globals.h>
21 #include <afs/bubasics.h>
22 #include <afs/afsutil.h>
24 #include <afs/cellconfig.h>
29 #include <afs/afsint.h>
30 #include <afs/volser.h> /*VLDB_MAXSERVERS */
31 #include <afs/com_err.h>
34 #include <afs/kautils.h>
35 #include <afs/vlserver.h>
38 #include <afs/tcdata.h>
40 #include "bc.h" /*Backup Coordinator structs and defs */
41 #include "bucoord_internal.h"
42 #include "bucoord_prototypes.h"
44 int localauth, interact;
48 * Global configuration information for the Backup Coordinator.
50 struct bc_config *bc_globalConfig; /*Ptr to global BC configuration info */
52 struct ubik_client *cstruct; /* Ptr to Ubik client structure */
53 time_t tokenExpires; /* The token's expiration time */
55 static const char *DefaultConfDir; /*Default backup config directory */
56 static int bcInit = 0; /* backupInit called yet ? */
57 char *whoami = "backup";
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. */
68 * Initialize all the error tables that may be used by com_err
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();
89 * got to account for the errors which are volume related but
90 * not dealt with by standard errno and com_err stuff.
93 bc_HandleMisc(afs_int32 code)
95 if (((code <= VMOVED) && (code >= VSALVAGE)) || (code < 0)) {
98 fprintf(STDERR, "Possible communication failure\n");
101 fprintf(STDERR, "Volume needs salvage\n");
104 fprintf(STDERR, "Bad vnode number quoted\n");
108 "Volume not attached, does not exist, or not on line\n");
111 fprintf(STDERR, "Volume already exists\n");
114 fprintf(STDERR, "Volume is not in service\n");
117 fprintf(STDERR, "Volume is off line\n");
120 fprintf(STDERR, "Volume is already on line\n");
123 fprintf(STDERR, "Partition is full\n");
126 fprintf(STDERR, "Volume max quota exceeded\n");
129 fprintf(STDERR, "Volume temporarily unavailable\n");
132 fprintf(STDERR, "Volume has moved to another server\n");
141 /* Return true if line is all whitespace */
143 LineIsBlank(char *aline)
147 while ((tc = *aline++))
148 if ((tc != ' ') && (tc != '\t') && (tc != '\n'))
156 * initialize configuration information that is stored as text blocks
160 bc_InitTextConfig(void)
162 udbClientTextP ctPtr;
165 extern struct bc_config *bc_globalConfig;
167 mkdir(DefaultConfDir, 777); /* temporary */
169 /* initialize the client text structures */
170 ctPtr = &bc_globalConfig->configText[0];
172 for (i = 0; i < TB_NUM; i++) {
173 memset(ctPtr, 0, sizeof(*ctPtr));
175 ctPtr->textVersion = -1;
182 /*----------------------------------------------------------------------------
186 * Routine that is called when the backup coordinator is invoked, responsible for
187 * basic initialization and some command line parsing.
190 * Zero (but may exit the entire program on error!)
193 * Nothing interesting.
196 * Initializes this program.
197 *----------------------------------------------------------------------------
204 static int initd = 0; /* ever called? */
206 PROCESS pid; /* LWP process ID */
209 initialize_CMD_error_table();
211 /* don't run more than once */
213 afs_com_err(whoami, 0, "Backup already initialized.");
218 code = bc_InitConfig((char *)DefaultConfDir);
220 afs_com_err(whoami, code,
221 "Can't initialize from config files in directory '%s'",
229 code = LWP_InitializeProcessSupport(LWP_NORMAL_PRIORITY, &pid);
231 afs_com_err(whoami, code, "; Can't initialize LWP");
235 code = rx_Init(htons(0));
237 afs_com_err(whoami, code, "; Can't initialize Rx");
241 rx_SetRxDeadTime(60);
243 /* VLDB initialization */
244 code = vldbClientInit(0, localauth, tcell, &cstruct, &tokenExpires);
248 /* Backup database initialization */
249 code = udbClientInit(0, localauth, tcell);
253 /* setup status monitoring thread */
256 LWP_CreateProcess(statusWatcher, 20480, LWP_NORMAL_PRIORITY,
257 (void *)2, "statusWatcher", &watcherPid);
259 afs_com_err(whoami, code, "; Can't create status monitor task");
266 /*----------------------------------------------------------------------------
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.
275 * as : Ptr to the command syntax descriptor.
281 * This routine is called right before each of the Backup Coordinator
282 * opcode routines are invoked.
284 *----------------------------------------------------------------------------
288 MyBeforeProc(struct cmd_syndesc *as, void *arock)
292 /* Handling the command line opcode */
294 localauth = ((as && as->parms[14].items) ? 1 : 0);
295 if (as && as->parms[15].items)
296 strcpy(tcell, as->parms[15].items->data);
302 afs_com_err(whoami, code, "; Can't initialize backup");
306 /* Get initial information from the database */
307 code = bc_InitTextConfig();
309 afs_com_err(whoami, code,
310 "; Can't obtain configuration text from backup database");
322 #include "AFS_component_version_number.c"
324 #define MAXRECURSION 20
325 extern int dontExecute; /* declared in commands.c */
326 extern char *loadFile; /* declared in commands.c */
327 char lineBuffer[1024]; /* Line typed in by user or read from load file */
330 * This will dispatch a command. It holds a recursive loop for the
331 * "dump -file" option. This option reads backup commands from a file.
333 * Cannot put this code on other side of cmd_Dispatch call (in
334 * commands.c) because when make a dispatch call when in a dispatch
335 * call, environment is mucked up.
337 * To avoid multiple processes stepping on each other in the dispatch code,
338 * put a lock around it so only 1 process gets in at a time.
341 struct Lock dispatchLock; /* lock on the Dispatch call */
342 #define lock_Dispatch() ObtainWriteLock(&dispatchLock)
343 #define unlock_Dispatch() ReleaseWriteLock(&dispatchLock)
346 doDispatch(afs_int32 targc,
348 afs_int32 dispatchCount) /* to prevent infinite recursion */
356 int noExecute; /* local capy of global variable */
357 char *internalLoadFile;
362 code = cmd_Dispatch(targc, targv);
363 internalLoadFile = loadFile;
367 if (internalLoadFile) { /* Load a file in */
368 if (dispatchCount > MAXRECURSION) { /* Beware recursive loops. */
369 afs_com_err(whoami, 0, "Potential recursion: will not load file %s",
375 fd = fopen(internalLoadFile, "r"); /* Open the load file */
377 afs_com_err(whoami, errno, "; Cannot open file %s", internalLoadFile);
382 noExecute = dontExecute;
384 printf("Would have executed the following commands:\n");
387 while (fgets(lineBuffer, sizeof(lineBuffer) - 1, fd)) { /* Get commands from file */
390 i = strlen(lineBuffer) - 1;
391 if (lineBuffer[i] == '\n') /* Drop return at end of line */
392 lineBuffer[i] = '\0';
395 printf(" %s\n", lineBuffer); /* echo */
397 printf("------> %s\n", lineBuffer); /* echo */
399 if (!LineIsBlank(lineBuffer) && /* Skip if blank line */
400 (lineBuffer[0] != '#') && /* or comment */
401 (!noExecute)) { /* or no execute */
402 c = cmd_ParseLine(lineBuffer, sargv, &sargc, MAXV);
404 afs_com_err(whoami, c, "; Can't parse line");
406 doDispatch(sargc, sargv, dispatchCount + 1); /* Recursive - ignore error */
407 cmd_FreeArgv(sargv); /* Free up arguments */
416 if (internalLoadFile)
417 free(internalLoadFile);
422 bc_interactCmd(struct cmd_syndesc *as, void *arock)
429 add_std_args(struct cmd_syndesc *ts)
432 cmd_AddParm(ts, "-localauth", CMD_FLAG, CMD_OPTIONAL,
433 "local authentication");
434 cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");
438 main(int argc, char **argv)
440 char *targv[MAXV]; /*Ptr to parsed argv stuff */
441 afs_int32 targc; /*Num parsed arguments */
442 afs_int32 code; /*Return code */
443 struct cmd_syndesc *ts; /*Ptr to parsed command line */
449 * The following signal action for AIX is necessary so that in case of a
450 * crash (i.e. core is generated) we can include the user's data section
451 * in the core dump. Unfortunately, by default, only a partial core is
452 * generated which, in many cases, isn't too useful.
454 struct sigaction nsa;
456 sigemptyset(&nsa.sa_mask);
457 nsa.sa_handler = SIG_DFL;
458 nsa.sa_flags = SA_FULLDUMP;
459 sigaction(SIGSEGV, &nsa, NULL);
461 Lock_Init(&dispatchLock);
462 InitErrTabs(); /* init all the error tables which may be used */
464 /* setup the default backup dir */
465 DefaultConfDir = AFSDIR_SERVER_BACKUP_DIRPATH;
466 /* Get early warning if the command is interacive mode or not */
471 if (argv[1][0] == '-') {
473 if (strcmp(argv[1], "-help") == 0) {
479 cmd_SetBeforeProc(MyBeforeProc, NULL);
481 ts = cmd_CreateSyntax("dump", bc_DumpCmd, NULL, "start dump");
482 cmd_AddParm(ts, "-volumeset", CMD_SINGLE, CMD_OPTIONAL,
484 cmd_AddParm(ts, "-dump", CMD_SINGLE, CMD_OPTIONAL, "dump level name");
485 cmd_AddParm(ts, "-portoffset", CMD_SINGLE, CMD_OPTIONAL,
487 cmd_AddParm(ts, "-at", CMD_LIST, CMD_OPTIONAL, "Date/time to start dump");
488 cmd_AddParm(ts, "-append", CMD_FLAG, CMD_OPTIONAL,
489 "append to existing dump set");
490 cmd_AddParm(ts, "-dryrun", CMD_FLAG, CMD_OPTIONAL,
491 "list what would be done, don't do it");
492 cmd_AddParmAlias(ts, 5, "-n");
493 cmd_AddParm(ts, "-file", CMD_SINGLE, CMD_OPTIONAL, "load file");
497 ts = cmd_CreateSyntax("volrestore", bc_VolRestoreCmd, NULL,
499 cmd_AddParm(ts, "-server", CMD_SINGLE, CMD_REQUIRED,
500 "destination machine");
501 cmd_AddParm(ts, "-partition", CMD_SINGLE, CMD_REQUIRED,
502 "destination partition");
503 cmd_AddParm(ts, "-volume", CMD_LIST, CMD_REQUIRED,
504 "volume(s) to restore");
505 cmd_AddParm(ts, "-extension", CMD_SINGLE, CMD_OPTIONAL,
506 "new volume name extension");
507 cmd_AddParm(ts, "-date", CMD_LIST, CMD_OPTIONAL,
508 "date from which to restore");
509 cmd_AddParm(ts, "-portoffset", CMD_LIST, CMD_OPTIONAL, "TC port offsets");
510 cmd_AddParm(ts, "-dryrun", CMD_FLAG, CMD_OPTIONAL,
511 "list what would be done, don't do it");
512 cmd_AddParmAlias(ts, 6, "-n");
513 cmd_AddParm(ts, "-usedump", CMD_SINGLE, CMD_OPTIONAL,
514 "specify the dumpID to restore from");
518 ts = cmd_CreateSyntax("diskrestore", bc_DiskRestoreCmd, NULL,
519 "restore partition");
520 cmd_AddParm(ts, "-server", CMD_SINGLE, CMD_REQUIRED,
521 "machine to restore");
522 cmd_AddParm(ts, "-partition", CMD_SINGLE, CMD_REQUIRED,
523 "partition to restore");
524 cmd_AddParm(ts, "-portoffset", CMD_LIST, CMD_OPTIONAL, "TC port offset");
526 cmd_AddParm(ts, "-newserver", CMD_SINGLE, CMD_OPTIONAL,
527 "destination machine");
528 cmd_AddParm(ts, "-newpartition", CMD_SINGLE, CMD_OPTIONAL,
529 "destination partition");
530 cmd_AddParm(ts, "-extension", CMD_SINGLE, CMD_OPTIONAL,
531 "new volume name extension");
532 cmd_AddParm(ts, "-dryrun", CMD_FLAG, CMD_OPTIONAL,
533 "list what would be done, don't do it");
534 cmd_AddParmAlias(ts, 11, "-n");
538 cmd_CreateSyntax("quit", bc_QuitCmd, NULL, "leave the program");
540 ts = cmd_CreateSyntax("volsetrestore", bc_VolsetRestoreCmd, NULL,
541 "restore a set of volumes");
542 cmd_AddParm(ts, "-name", CMD_SINGLE, CMD_OPTIONAL, "volume set name");
543 cmd_AddParm(ts, "-file", CMD_SINGLE, CMD_OPTIONAL, "file name");
544 cmd_AddParm(ts, "-portoffset", CMD_LIST, CMD_OPTIONAL, "TC port offset");
545 cmd_AddParm(ts, "-extension", CMD_SINGLE, CMD_OPTIONAL,
546 "new volume name extension");
547 cmd_AddParm(ts, "-dryrun", CMD_FLAG, CMD_OPTIONAL,
548 "list what would be done, don't do it");
549 cmd_AddParmAlias(ts, 4, "-n");
553 ts = cmd_CreateSyntax("addhost", bc_AddHostCmd, NULL, "add host to config");
554 cmd_AddParm(ts, "-tapehost", CMD_SINGLE, CMD_REQUIRED,
555 "tape machine name");
556 cmd_AddParm(ts, "-portoffset", CMD_SINGLE, CMD_OPTIONAL,
561 ts = cmd_CreateSyntax("delhost", bc_DeleteHostCmd, NULL,
562 "delete host to config");
563 cmd_AddParm(ts, "-tapehost", CMD_SINGLE, CMD_REQUIRED,
564 "tape machine name");
565 cmd_AddParm(ts, "-portoffset", CMD_SINGLE, CMD_OPTIONAL,
570 ts = cmd_CreateSyntax("listhosts", bc_ListHostsCmd, NULL,
571 "list config hosts");
575 cmd_CreateSyntax("jobs", bc_JobsCmd, NULL, "list running jobs");
577 ts = cmd_CreateSyntax("kill", bc_KillCmd, NULL, "kill running job");
578 cmd_AddParm(ts, "-id", CMD_SINGLE, CMD_REQUIRED,
579 "job ID or dump set name");
581 ts = cmd_CreateSyntax("listvolsets", bc_ListVolSetCmd, NULL,
583 cmd_AddParm(ts, "-name", CMD_SINGLE, CMD_OPTIONAL, "volume set name");
587 ts = cmd_CreateSyntax("listdumps", bc_ListDumpScheduleCmd, NULL,
588 "list dump schedules");
592 ts = cmd_CreateSyntax("addvolset", bc_AddVolSetCmd, NULL,
593 "create a new volume set");
594 cmd_AddParm(ts, "-name", CMD_SINGLE, CMD_REQUIRED, "volume set name");
595 cmd_AddParm(ts, "-temporary", CMD_FLAG, CMD_OPTIONAL,
596 "temporary volume set");
600 ts = cmd_CreateSyntax("status", bc_GetTapeStatusCmd, NULL,
601 "get tape coordinator status");
602 cmd_AddParm(ts, "-portoffset", CMD_SINGLE, CMD_OPTIONAL,
607 ts = cmd_CreateSyntax("delvolset", bc_DeleteVolSetCmd, NULL,
608 "delete a volume set");
609 cmd_AddParm(ts, "-name", CMD_LIST, CMD_REQUIRED, "volume set name");
613 ts = cmd_CreateSyntax("addvolentry", bc_AddVolEntryCmd, NULL,
614 "add a new volume entry");
615 cmd_AddParm(ts, "-name", CMD_SINGLE, CMD_REQUIRED, "volume set name");
616 cmd_AddParm(ts, "-server", CMD_SINGLE, CMD_REQUIRED, "machine name");
617 cmd_AddParm(ts, "-partition", CMD_SINGLE, CMD_REQUIRED, "partition name");
618 cmd_AddParm(ts, "-volumes", CMD_SINGLE, CMD_REQUIRED,
619 "volume name (regular expression)");
623 ts = cmd_CreateSyntax("delvolentry", bc_DeleteVolEntryCmd, NULL,
624 "delete a volume set sub-entry");
625 cmd_AddParm(ts, "-name", CMD_SINGLE, CMD_REQUIRED, "volume set name");
626 cmd_AddParm(ts, "-entry", CMD_SINGLE, CMD_REQUIRED, "volume set index");
630 ts = cmd_CreateSyntax("adddump", bc_AddDumpCmd, NULL, "add dump schedule");
631 cmd_AddParm(ts, "-dump", CMD_LIST, CMD_REQUIRED, "dump level name");
632 cmd_AddParm(ts, "-expires", CMD_LIST, CMD_OPTIONAL, "expiration date");
636 ts = cmd_CreateSyntax("deldump", bc_DeleteDumpCmd, NULL,
637 "delete dump schedule");
638 cmd_AddParm(ts, "-dump", CMD_SINGLE, CMD_REQUIRED, "dump level name");
642 ts = cmd_CreateSyntax("labeltape", bc_LabelTapeCmd, NULL, "label a tape");
643 cmd_AddParm(ts, "-name", CMD_SINGLE, CMD_OPTIONAL,
644 "AFS tape name, defaults to NULL");
645 cmd_AddParm(ts, "-size", CMD_SINGLE, CMD_OPTIONAL,
646 "tape size in Kbytes, defaults to size in tapeconfig");
647 cmd_AddParm(ts, "-portoffset", CMD_SINGLE, CMD_OPTIONAL,
649 cmd_AddParm(ts, "-pname", CMD_SINGLE, CMD_OPTIONAL,
650 "permanent tape name");
654 ts = cmd_CreateSyntax("readlabel", bc_ReadLabelCmd, NULL,
655 "read the label on tape");
656 cmd_AddParm(ts, "-portoffset", CMD_SINGLE, CMD_OPTIONAL,
661 ts = cmd_CreateSyntax("scantape", bc_ScanDumpsCmd, NULL,
662 "dump information recovery from tape");
663 cmd_AddParm(ts, "-dbadd", CMD_FLAG, CMD_OPTIONAL,
664 "add information to the database");
665 cmd_AddParm(ts, "-portoffset", CMD_SINGLE, CMD_OPTIONAL,
670 ts = cmd_CreateSyntax("volinfo", bc_dblookupCmd, NULL,
671 "query the backup database");
672 cmd_AddParm(ts, "-volume", CMD_SINGLE, CMD_REQUIRED, "volume name");
676 ts = cmd_CreateSyntax("setexp", bc_SetExpCmd, NULL,
677 "set/clear dump expiration dates");
678 cmd_AddParm(ts, "-dump", CMD_LIST, CMD_REQUIRED, "dump level name");
679 cmd_AddParm(ts, "-expires", CMD_LIST, CMD_OPTIONAL, "expiration date");
683 ts = cmd_CreateSyntax("savedb", bc_saveDbCmd, NULL, "save backup database");
684 cmd_AddParm(ts, "-portoffset", CMD_SINGLE, CMD_OPTIONAL,
686 cmd_AddParm(ts, "-archive", CMD_LIST, CMD_OPTIONAL, "date time");
690 ts = cmd_CreateSyntax("restoredb", bc_restoreDbCmd, NULL,
691 "restore backup database");
692 cmd_AddParm(ts, "-portoffset", CMD_SINGLE, CMD_OPTIONAL,
697 ts = cmd_CreateSyntax("dumpinfo", bc_dumpInfoCmd, NULL,
698 "provide information about a dump in the database");
699 cmd_AddParm(ts, "-ndumps", CMD_SINGLE, CMD_OPTIONAL, "no. of dumps");
700 cmd_AddParm(ts, "-id", CMD_SINGLE, CMD_OPTIONAL, "dump id");
701 cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL,
702 "detailed description");
706 ts = cmd_CreateSyntax("dbverify", bc_dbVerifyCmd, NULL,
707 "check ubik database integrity");
708 cmd_AddParm(ts, "-detail", CMD_FLAG, CMD_OPTIONAL, "additional details");
712 ts = cmd_CreateSyntax("deletedump", bc_deleteDumpCmd, NULL,
713 "delete dumps from the database");
714 cmd_AddParm(ts, "-dumpid", CMD_LIST, CMD_OPTIONAL, "dump id");
715 cmd_AddParm(ts, "-from", CMD_LIST, CMD_OPTIONAL, "date time");
716 cmd_AddParm(ts, "-to", CMD_LIST, CMD_OPTIONAL, "date time");
717 cmd_AddParm(ts, "-port", CMD_SINGLE, CMD_OPTIONAL, "TC port offset");
718 cmd_AddParm(ts, "-groupid", CMD_SINGLE, CMD_OPTIONAL, "group ID");
719 cmd_AddParm(ts, "-dbonly", CMD_FLAG, CMD_OPTIONAL,
720 "delete the dump from the backup database only");
721 cmd_AddParm(ts, "-force", CMD_FLAG, CMD_OPTIONAL,
722 "always delete from backup database");
723 cmd_AddParm(ts, "-noexecute", CMD_FLAG, CMD_OPTIONAL|CMD_HIDDEN, "");
724 cmd_AddParm(ts, "-dryrun", CMD_FLAG, CMD_OPTIONAL,
725 "list the dumps, don't delete anything");
726 cmd_AddParmAlias(ts, 8, "-n");
731 ts = cmd_CreateSyntax("interactive", bc_interactCmd, NULL,
732 "enter interactive mode");
736 * Now execute the command.
740 targv[targc++] = argv[0];
742 targv[targc++] = "interactive";
743 for (i = 1; i < argc; i++)
744 targv[targc++] = argv[i];
746 code = doDispatch(targc, targv, 1);
748 if (!interact || !bcInit) { /* Non-interactive mode */
752 code = bc_WaitForNoJobs(); /* wait for any jobs to finish */
753 exit(code); /* and exit */
756 /* Iterate on command lines, interpreting user commands (interactive mode) */
764 while ((ret = LWP_GetLine(lineBuffer, sizeof(lineBuffer))) == 0)
765 printf("%s: Command line too long\n", whoami); /* line too long */
768 return 0; /* Got EOF */
770 if (!LineIsBlank(lineBuffer)) {
771 code = cmd_ParseLine(lineBuffer, targv, &targc, MAXV);
773 afs_com_err(whoami, code, "; Can't parse line: '%s'",
774 afs_error_message(code));
776 doDispatch(targc, targv, 1);