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>
17 #include <sys/types.h>
24 #include <sys/socket.h>
25 #include <netinet/in.h>
31 #include <rx/rx_globals.h>
33 #include <afs/bubasics.h>
35 #include <afs/afsutil.h>
37 #include <afs/cellconfig.h>
42 #include <afs/volser.h> /*VLDB_MAXSERVERS */
43 #include <afs/com_err.h>
47 #include "bc.h" /*Backup Coordinator structs and defs */
50 int localauth, interact;
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();
85 * Global configuration information for the Backup Coordinator.
87 struct bc_config *bc_globalConfig; /*Ptr to global BC configuration info */
89 struct ubik_client *cstruct; /* Ptr to Ubik client structure */
90 struct ktc_token ttoken; /* The token */
92 static const char *DefaultConfDir; /*Default backup config directory */
93 static int bcInit = 0; /* backupInit called yet ? */
94 char *whoami = "backup";
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. */
104 * Initialize all the error tables that may be used by com_err
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();
125 * got to account for the errors which are volume related but
126 * not dealt with by standard errno and com_err stuff.
132 if (((code <= VMOVED) && (code >= VSALVAGE)) || (code < 0)) {
135 fprintf(STDERR, "Possible communication failure\n");
138 fprintf(STDERR, "Volume needs salvage\n");
141 fprintf(STDERR, "Bad vnode number quoted\n");
145 "Volume not attached, does not exist, or not on line\n");
148 fprintf(STDERR, "Volume already exists\n");
151 fprintf(STDERR, "Volume is not in service\n");
154 fprintf(STDERR, "Volume is off line\n");
157 fprintf(STDERR, "Volume is already on line\n");
160 fprintf(STDERR, "Partition is full\n");
163 fprintf(STDERR, "Volume max quota exceeded\n");
166 fprintf(STDERR, "Volume temporarily unavailable\n");
169 fprintf(STDERR, "Volume has moved to another server\n");
178 /* Return true if line is all whitespace */
181 register char *aline;
185 while (tc = *aline++)
186 if ((tc != ' ') && (tc != '\t') && (tc != '\n'))
194 * initialize configuration information that is stored as text blocks
200 udbClientTextP ctPtr;
204 extern struct bc_config *bc_globalConfig;
206 mkdir(DefaultConfDir, 777); /* temporary */
208 /* initialize the client text structures */
209 ctPtr = &bc_globalConfig->configText[0];
211 for (i = 0; i < TB_NUM; i++) {
212 memset(ctPtr, 0, sizeof(*ctPtr));
214 ctPtr->textVersion = -1;
221 /*----------------------------------------------------------------------------
225 * Routine that is called when the backup coordinator is invoked, responsible for
226 * basic initialization and some command line parsing.
229 * Zero (but may exit the entire program on error!)
232 * Nothing interesting.
235 * Initializes this program.
236 *----------------------------------------------------------------------------
242 register afs_int32 code;
243 static int initd = 0; /* ever called? */
245 PROCESS pid; /* LWP process ID */
247 extern statusWatcher();
250 initialize_CMD_error_table();
252 /* don't run more than once */
254 afs_com_err(whoami, 0, "Backup already initialized.");
259 code = bc_InitConfig(DefaultConfDir);
261 afs_com_err(whoami, code,
262 "Can't initialize from config files in directory '%s'",
270 code = LWP_InitializeProcessSupport(LWP_NORMAL_PRIORITY, &pid);
272 afs_com_err(whoami, code, "; Can't initialize LWP");
276 code = rx_Init(htons(0));
278 afs_com_err(whoami, code, "; Can't initialize Rx");
282 rx_SetRxDeadTime(60);
284 /* VLDB initialization */
285 code = vldbClientInit(0, localauth, tcell, &cstruct, &ttoken);
289 /* Backup database initialization */
290 code = udbClientInit(0, localauth, tcell);
294 /* setup status monitoring thread */
297 LWP_CreateProcess(statusWatcher, 20480, LWP_NORMAL_PRIORITY,
298 (void *)2, "statusWatcher", &watcherPid);
300 afs_com_err(whoami, code, "; Can't create status monitor task");
307 /*----------------------------------------------------------------------------
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.
316 * as : Ptr to the command syntax descriptor.
322 * This routine is called right before each of the Backup Coordinator
323 * opcode routines are invoked.
325 *----------------------------------------------------------------------------
330 register struct cmd_syndesc *as;
334 /* Handling the command line opcode */
336 localauth = ((as && as->parms[14].items) ? 1 : 0);
337 if (as && as->parms[15].items)
338 strcpy(tcell, as->parms[15].items->data);
344 afs_com_err(whoami, code, "; Can't initialize backup");
348 /* Get initial information from the database */
349 code = bc_InitTextConfig();
351 afs_com_err(whoami, code,
352 "; Can't obtain configuration text from backup database");
364 #include "AFS_component_version_number.c"
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 */
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.
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.
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.
383 struct Lock dispatchLock; /* lock on the Dispatch call */
384 #define lock_Dispatch() ObtainWriteLock(&dispatchLock)
385 #define unlock_Dispatch() ReleaseWriteLock(&dispatchLock)
388 doDispatch(targc, targv, dispatchCount)
391 afs_int32 dispatchCount; /* to prevent infinite recursion */
399 int noExecute; /* local capy of global variable */
400 char *internalLoadFile;
405 code = cmd_Dispatch(targc, targv);
406 internalLoadFile = loadFile;
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",
418 fd = fopen(internalLoadFile, "r"); /* Open the load file */
420 afs_com_err(whoami, errno, "; Cannot open file %s", internalLoadFile);
425 noExecute = dontExecute;
427 printf("Would have executed the following commands:\n");
430 while (fgets(lineBuffer, sizeof(lineBuffer) - 1, fd)) { /* Get commands from file */
433 i = strlen(lineBuffer) - 1;
434 if (lineBuffer[i] == '\n') /* Drop return at end of line */
435 lineBuffer[i] = '\0';
438 printf(" %s\n", lineBuffer); /* echo */
440 printf("------> %s\n", lineBuffer); /* echo */
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);
447 afs_com_err(whoami, c, "; Can't parse line");
449 doDispatch(sargc, sargv, dispatchCount + 1); /* Recursive - ignore error */
450 cmd_FreeArgv(sargv); /* Free up arguments */
459 if (internalLoadFile)
460 free(internalLoadFile);
465 bc_interactCmd(as, arock)
466 struct cmd_syndesc *as;
475 register struct cmd_syndesc *ts;
478 cmd_AddParm(ts, "-localauth", CMD_FLAG, CMD_OPTIONAL,
479 "local authentication");
480 cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");
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 */
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.
502 struct sigaction nsa;
504 sigemptyset(&nsa.sa_mask);
505 nsa.sa_handler = SIG_DFL;
506 nsa.sa_flags = SA_FULLDUMP;
507 sigaction(SIGSEGV, &nsa, NULL);
509 Lock_Init(&dispatchLock);
510 InitErrTabs(); /* init all the error tables which may be used */
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);
517 cmd_SetBeforeProc(MyBeforeProc, NULL);
519 ts = cmd_CreateSyntax("dump", bc_DumpCmd, 0, "start dump");
520 cmd_AddParm(ts, "-volumeset", CMD_SINGLE, CMD_OPTIONAL,
522 cmd_AddParm(ts, "-dump", CMD_SINGLE, CMD_OPTIONAL, "dump level name");
523 cmd_AddParm(ts, "-portoffset", CMD_SINGLE, CMD_OPTIONAL,
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");
533 ts = cmd_CreateSyntax("volrestore", bc_VolRestoreCmd, 0,
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 cmd_AddParm(ts, "-usedump", CMD_SINGLE, CMD_OPTIONAL,
548 "specify the dumpID to restore from");
552 ts = cmd_CreateSyntax("diskrestore", bc_DiskRestoreCmd, 0,
553 "restore partition");
554 cmd_AddParm(ts, "-server", CMD_SINGLE, CMD_REQUIRED,
555 "machine to restore");
556 cmd_AddParm(ts, "-partition", CMD_SINGLE, CMD_REQUIRED,
557 "partition to restore");
558 cmd_AddParm(ts, "-portoffset", CMD_LIST, CMD_OPTIONAL, "TC port offset");
560 cmd_AddParm(ts, "-newserver", CMD_SINGLE, CMD_OPTIONAL,
561 "destination machine");
562 cmd_AddParm(ts, "-newpartition", CMD_SINGLE, CMD_OPTIONAL,
563 "destination partition");
564 cmd_AddParm(ts, "-extension", CMD_SINGLE, CMD_OPTIONAL,
565 "new volume name extension");
566 cmd_AddParm(ts, "-n", CMD_FLAG, CMD_OPTIONAL, "don't really execute it");
570 ts = cmd_CreateSyntax("quit", bc_QuitCmd, 0, "leave the program");
572 ts = cmd_CreateSyntax("volsetrestore", bc_VolsetRestoreCmd, 0,
573 "restore a set of volumes");
574 cmd_AddParm(ts, "-name", CMD_SINGLE, CMD_OPTIONAL, "volume set name");
575 cmd_AddParm(ts, "-file", CMD_SINGLE, CMD_OPTIONAL, "file name");
576 cmd_AddParm(ts, "-portoffset", CMD_LIST, CMD_OPTIONAL, "TC port offset");
577 cmd_AddParm(ts, "-extension", CMD_SINGLE, CMD_OPTIONAL,
578 "new volume name extension");
579 cmd_AddParm(ts, "-n", CMD_FLAG, CMD_OPTIONAL, "don't really execute it");
583 ts = cmd_CreateSyntax("addhost", bc_AddHostCmd, 0, "add host to config");
584 cmd_AddParm(ts, "-tapehost", CMD_SINGLE, CMD_REQUIRED,
585 "tape machine name");
586 cmd_AddParm(ts, "-portoffset", CMD_SINGLE, CMD_OPTIONAL,
591 ts = cmd_CreateSyntax("delhost", bc_DeleteHostCmd, 0,
592 "delete host to config");
593 cmd_AddParm(ts, "-tapehost", CMD_SINGLE, CMD_REQUIRED,
594 "tape machine name");
595 cmd_AddParm(ts, "-portoffset", CMD_SINGLE, CMD_OPTIONAL,
600 ts = cmd_CreateSyntax("listhosts", bc_ListHostsCmd, 0,
601 "list config hosts");
605 ts = cmd_CreateSyntax("jobs", bc_JobsCmd, 0, "list running jobs");
607 ts = cmd_CreateSyntax("kill", bc_KillCmd, 0, "kill running job");
608 cmd_AddParm(ts, "-id", CMD_SINGLE, CMD_REQUIRED,
609 "job ID or dump set name");
611 ts = cmd_CreateSyntax("listvolsets", bc_ListVolSetCmd, 0,
613 cmd_AddParm(ts, "-name", CMD_SINGLE, CMD_OPTIONAL, "volume set name");
617 ts = cmd_CreateSyntax("listdumps", bc_ListDumpScheduleCmd, 0,
618 "list dump schedules");
622 ts = cmd_CreateSyntax("addvolset", bc_AddVolSetCmd, 0,
623 "create a new volume set");
624 cmd_AddParm(ts, "-name", CMD_SINGLE, CMD_REQUIRED, "volume set name");
625 cmd_AddParm(ts, "-temporary", CMD_FLAG, CMD_OPTIONAL,
626 "temporary volume set");
630 ts = cmd_CreateSyntax("status", bc_GetTapeStatusCmd, 0,
631 "get tape coordinator status");
632 cmd_AddParm(ts, "-portoffset", CMD_SINGLE, CMD_OPTIONAL,
637 ts = cmd_CreateSyntax("delvolset", bc_DeleteVolSetCmd, 0,
638 "delete a volume set");
639 cmd_AddParm(ts, "-name", CMD_LIST, CMD_REQUIRED, "volume set name");
643 ts = cmd_CreateSyntax("addvolentry", bc_AddVolEntryCmd, 0,
644 "add a new volume entry");
645 cmd_AddParm(ts, "-name", CMD_SINGLE, CMD_REQUIRED, "volume set name");
646 cmd_AddParm(ts, "-server", CMD_SINGLE, CMD_REQUIRED, "machine name");
647 cmd_AddParm(ts, "-partition", CMD_SINGLE, CMD_REQUIRED, "partition name");
648 cmd_AddParm(ts, "-volumes", CMD_SINGLE, CMD_REQUIRED,
649 "volume name (regular expression)");
653 ts = cmd_CreateSyntax("delvolentry", bc_DeleteVolEntryCmd, 0,
654 "delete a volume set sub-entry");
655 cmd_AddParm(ts, "-name", CMD_SINGLE, CMD_REQUIRED, "volume set name");
656 cmd_AddParm(ts, "-entry", CMD_SINGLE, CMD_REQUIRED, "volume set index");
660 ts = cmd_CreateSyntax("adddump", bc_AddDumpCmd, 0, "add dump schedule");
661 cmd_AddParm(ts, "-dump", CMD_LIST, CMD_REQUIRED, "dump level name");
662 cmd_AddParm(ts, "-expires", CMD_LIST, CMD_OPTIONAL, "expiration date");
666 ts = cmd_CreateSyntax("deldump", bc_DeleteDumpCmd, 0,
667 "delete dump schedule");
668 cmd_AddParm(ts, "-dump", CMD_SINGLE, CMD_REQUIRED, "dump level name");
672 ts = cmd_CreateSyntax("labeltape", bc_LabelTapeCmd, 0, "label a tape");
673 cmd_AddParm(ts, "-name", CMD_SINGLE, CMD_OPTIONAL,
674 "AFS tape name, defaults to NULL");
675 cmd_AddParm(ts, "-size", CMD_SINGLE, CMD_OPTIONAL,
676 "tape size in Kbytes, defaults to size in tapeconfig");
677 cmd_AddParm(ts, "-portoffset", CMD_SINGLE, CMD_OPTIONAL,
679 cmd_AddParm(ts, "-pname", CMD_SINGLE, CMD_OPTIONAL,
680 "permanent tape name");
684 ts = cmd_CreateSyntax("readlabel", bc_ReadLabelCmd, 0,
685 "read the label on tape");
686 cmd_AddParm(ts, "-portoffset", CMD_SINGLE, CMD_OPTIONAL,
691 ts = cmd_CreateSyntax("scantape", bc_ScanDumpsCmd, 0,
692 "dump information recovery from tape");
693 cmd_AddParm(ts, "-dbadd", CMD_FLAG, CMD_OPTIONAL,
694 "add information to the database");
695 cmd_AddParm(ts, "-portoffset", CMD_SINGLE, CMD_OPTIONAL,
700 ts = cmd_CreateSyntax("volinfo", bc_dblookupCmd, 0,
701 "query the backup database");
702 cmd_AddParm(ts, "-volume", CMD_SINGLE, CMD_REQUIRED, "volume name");
706 ts = cmd_CreateSyntax("setexp", bc_SetExpCmd, 0,
707 "set/clear dump expiration dates");
708 cmd_AddParm(ts, "-dump", CMD_LIST, CMD_REQUIRED, "dump level name");
709 cmd_AddParm(ts, "-expires", CMD_LIST, CMD_OPTIONAL, "expiration date");
713 ts = cmd_CreateSyntax("savedb", bc_saveDbCmd, 0, "save backup database");
714 cmd_AddParm(ts, "-portoffset", CMD_SINGLE, CMD_OPTIONAL,
716 cmd_AddParm(ts, "-archive", CMD_LIST, CMD_OPTIONAL, "date time");
720 ts = cmd_CreateSyntax("restoredb", bc_restoreDbCmd, 0,
721 "restore backup database");
722 cmd_AddParm(ts, "-portoffset", CMD_SINGLE, CMD_OPTIONAL,
727 ts = cmd_CreateSyntax("dumpinfo", bc_dumpInfoCmd, 0,
728 "provide information about a dump in the database");
729 cmd_AddParm(ts, "-ndumps", CMD_SINGLE, CMD_OPTIONAL, "no. of dumps");
730 cmd_AddParm(ts, "-id", CMD_SINGLE, CMD_OPTIONAL, "dump id");
731 cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL,
732 "detailed description");
736 ts = cmd_CreateSyntax("dbverify", bc_dbVerifyCmd, 0,
737 "check ubik database integrity");
738 cmd_AddParm(ts, "-detail", CMD_FLAG, CMD_OPTIONAL, "additional details");
742 ts = cmd_CreateSyntax("deletedump", bc_deleteDumpCmd, 0,
743 "delete dumps from the database");
744 cmd_AddParm(ts, "-dumpid", CMD_LIST, CMD_OPTIONAL, "dump id");
745 cmd_AddParm(ts, "-from", CMD_LIST, CMD_OPTIONAL, "date time");
746 cmd_AddParm(ts, "-to", CMD_LIST, CMD_OPTIONAL, "date time");
747 cmd_AddParm(ts, "-port", CMD_SINGLE, CMD_OPTIONAL, "TC port offset");
748 cmd_AddParm(ts, "-groupid", CMD_SINGLE, CMD_OPTIONAL, "group ID");
749 cmd_AddParm(ts, "-dbonly", CMD_FLAG, CMD_OPTIONAL,
750 "delete the dump from the backup database only");
751 cmd_AddParm(ts, "-force", CMD_FLAG, CMD_OPTIONAL,
752 "always delete from backup database");
753 cmd_AddParm(ts, "-noexecute", CMD_FLAG, CMD_OPTIONAL,
754 "Just list the dumps");
759 ts = cmd_CreateSyntax("interactive", bc_interactCmd, 0,
760 "enter interactive mode");
764 * Now execute the command.
768 targv[targc++] = argv[0];
770 targv[targc++] = "interactive";
771 for (i = 1; i < argc; i++)
772 targv[targc++] = argv[i];
774 code = doDispatch(targc, targv, 1);
776 if (!interact || !bcInit) { /* Non-interactive mode */
780 code = bc_WaitForNoJobs(); /* wait for any jobs to finish */
781 exit(code); /* and exit */
784 /* Iterate on command lines, interpreting user commands (interactive mode) */
792 while ((ret = LWP_GetLine(lineBuffer, sizeof(lineBuffer))) == 0)
793 printf("%s: Command line too long\n", whoami); /* line too long */
796 return 0; /* Got EOF */
798 if (!LineIsBlank(lineBuffer)) {
799 code = cmd_ParseLine(lineBuffer, targv, &targc, MAXV);
801 afs_com_err(whoami, code, "; Can't parse line: '%s'",
802 afs_error_message(code));
804 doDispatch(targc, targv, 1);