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>
16 #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_ExecuteRequest();
54 extern int bc_AddDumpCmd();
55 extern int bc_AddHostCmd();
56 extern int bc_AddVolEntryCmd();
57 extern int bc_AddVolSetCmd();
58 /* extern int bc_CheckDumpStatCmd(); */
59 extern int bc_DeleteDumpCmd();
60 extern int bc_DeleteHostCmd();
61 extern int bc_DeleteVolEntryCmd();
62 extern int bc_DeleteVolSetCmd();
63 extern int bc_DiskRestoreCmd();
64 extern int bc_VolsetRestoreCmd();
65 extern int bc_DumpCmd();
66 extern int bc_GetTapeStatusCmd();
67 extern int bc_JobsCmd();
68 extern int bc_KillCmd();
69 extern int bc_LabelTapeCmd();
70 extern int bc_ListDumpScheduleCmd();
71 extern int bc_ListHostsCmd();
72 extern int bc_ListVolSetCmd();
73 extern int bc_QuitCmd();
74 extern int bc_ReadLabelCmd();
75 extern int bc_ScanDumpsCmd();
76 extern int bc_SetExpCmd();
77 extern int bc_VolRestoreCmd();
78 extern int bc_dblookupCmd();
79 extern int bc_dbVerifyCmd();
80 extern int bc_deleteDumpCmd();
81 extern int bc_dumpInfoCmd();
82 extern int bc_restoreDbCmd();
83 extern int bc_saveDbCmd();
88 * Global configuration information for the Backup Coordinator.
90 struct bc_config *bc_globalConfig; /*Ptr to global BC configuration info*/
92 extern struct rx_securityClass *rxnull_NewServerSecurityObject();
94 struct ubik_client *cstruct; /* Ptr to Ubik client structure*/
95 struct ktc_token ttoken; /* The token */
97 static const char *DefaultConfDir; /*Default backup config directory*/
98 static int bcInit = 0; /* backupInit called yet ? */
99 char *whoami = "backup";
101 /* dummy routine for the audit work. It should do nothing since audits */
102 /* occur at the server level and bos is not a server. */
103 osi_audit() {return 0;}
106 * Initialize all the error tables that may be used by com_err
111 initialize_acfg_error_table();
112 initialize_ka_error_table();
113 initialize_rxk_error_table();
114 initialize_cmd_error_table();
115 initialize_vl_error_table();
116 initialize_butm_error_table();
117 initialize_vols_error_table();
118 initialize_butc_error_table();
119 initialize_butx_error_table();
120 initialize_budb_error_table();
121 initialize_bucd_error_table();
122 initialize_ktc_error_table();
126 * got to account for the errors which are volume related but
127 * not dealt with by standard errno and com_err stuff.
129 void bc_HandleMisc(code)
132 if(((code <= VMOVED) && (code >= VSALVAGE)) || (code < 0)){
134 case -1 : fprintf(STDERR,"Possible communication failure\n");
136 case VSALVAGE: fprintf(STDERR,"Volume needs salvage\n");
138 case VNOVNODE: fprintf(STDERR,"Bad vnode number quoted\n");
140 case VNOVOL: fprintf(STDERR,"Volume not attached, does not exist, or not on line\n");
142 case VVOLEXISTS:fprintf(STDERR,"Volume already exists\n");
144 case VNOSERVICE:fprintf(STDERR,"Volume is not in service\n");
146 case VOFFLINE: fprintf(STDERR,"Volume is off line\n");
148 case VONLINE: fprintf(STDERR,"Volume is already on line\n");
150 case VDISKFULL: fprintf(STDERR,"Partition is full\n");
152 case VOVERQUOTA:fprintf(STDERR,"Volume max quota exceeded\n");
154 case VBUSY: fprintf(STDERR,"Volume temporarily unavailable\n");
156 case VMOVED:fprintf(STDERR,"Volume has moved to another server\n");
165 /* Return true if line is all whitespace */
166 static LineIsBlank(aline)
167 register char *aline;
171 while (tc = *aline++)
172 if ( (tc != ' ') && (tc != '\t') && (tc != '\n') ) return(0);
179 * initialize configuration information that is stored as text blocks
185 udbClientTextP ctPtr;
189 extern struct bc_config *bc_globalConfig;
191 mkdir(DefaultConfDir, 777); /* temporary */
193 /* initialize the client text structures */
194 ctPtr = &bc_globalConfig->configText[0];
196 for ( i = 0; i < TB_NUM; i++ )
198 memset(ctPtr, 0, sizeof(*ctPtr));
200 ctPtr->textVersion = -1;
207 /*----------------------------------------------------------------------------
211 * Routine that is called when the backup coordinator is invoked, responsible for
212 * basic initialization and some command line parsing.
215 * Zero (but may exit the entire program on error!)
218 * Nothing interesting.
221 * Initializes this program.
222 *----------------------------------------------------------------------------
225 static int backupInit()
227 register afs_int32 code;
228 static int initd = 0; /* ever called? */
230 PROCESS pid; /* LWP process ID*/
232 extern statusWatcher();
235 initialize_cmd_error_table();
237 /* don't run more than once */
240 com_err(whoami,0,"Backup already initialized.");
245 code = bc_InitConfig(DefaultConfDir);
248 com_err(whoami, code, "Can't initialize from config files in directory '%s'",
256 code = LWP_InitializeProcessSupport(LWP_NORMAL_PRIORITY, &pid);
259 com_err(whoami, code,"; Can't initialize LWP");
263 code = rx_Init(htons(0));
266 com_err(whoami, code, "; Can't initialize Rx");
270 rx_SetRxDeadTime(60);
272 /* VLDB initialization */
273 vldbClientInit(0, localauth, tcell, &cstruct, &ttoken);
274 if (code) return(code);
276 /* Backup database initialization */
277 code = udbClientInit(0, localauth, tcell);
278 if (code) return(code);
280 /* setup status monitoring thread */
282 code = LWP_CreateProcess(statusWatcher, 20480, LWP_NORMAL_PRIORITY, 2,
283 "statusWatcher", &watcherPid);
286 com_err(whoami, code, "; Can't create status monitor task");
293 /*----------------------------------------------------------------------------
297 * Make sure we mark down when we need to exit the Backup Coordinator.
298 * Specifically, we don't want to continue when our help and apropos
299 * routines are called from the command line.
302 * as : Ptr to the command syntax descriptor.
308 * This routine is called right before each of the Backup Coordinator
309 * opcode routines are invoked.
311 *----------------------------------------------------------------------------
314 static int MyBeforeProc(as)
315 register struct cmd_syndesc *as;
320 /* Handling the command line opcode */
323 localauth = ((as && as->parms[14].items) ? 1 : 0);
324 if (as && as->parms[15].items) strcpy(tcell, as->parms[15].items->data);
325 else tcell[0] = '\0';
330 com_err(whoami,code,"; Can't initialize backup");
334 /* Get initial information from the database */
335 code = bc_InitTextConfig();
338 com_err(whoami, code, "; Can't obtain configuration text from backup database");
350 #include "AFS_component_version_number.c"
352 #define MAXRECURSION 20
353 extern int dontExecute; /* declared in commands.c */
354 extern char *loadFile; /* declared in commands.c */
355 char lineBuffer[1024]; /* Line typed in by user or read from load file */
358 * This will dispatch a command. It holds a recursive loop for the
359 * "dump -file" option. This option reads backup commands from a file.
361 * Cannot put this code on other side of cmd_Dispatch call (in
362 * commands.c) because when make a dispatch call when in a dispatch
363 * call, environment is mucked up.
365 * To avoid multiple processes stepping on each other in the dispatch code,
366 * put a lock around it so only 1 process gets in at a time.
369 struct Lock dispatchLock; /* lock on the Dispatch call */
370 #define lock_Dispatch() ObtainWriteLock(&dispatchLock)
371 #define unlock_Dispatch() ReleaseWriteLock(&dispatchLock)
373 afs_int32 doDispatch(targc, targv, dispatchCount)
376 afs_int32 dispatchCount; /* to prevent infinite recursion */
384 int noExecute; /* local capy of global variable */
385 char *internalLoadFile;
389 loadFile = (char *) 0;
390 code = cmd_Dispatch(targc, targv);
391 internalLoadFile = loadFile;
395 if (internalLoadFile) /* Load a file in */
397 if (dispatchCount > MAXRECURSION) /* Beware recursive loops. */
399 com_err(whoami,0,"Potential recursion: will not load file %s", internalLoadFile);
404 fd = fopen(internalLoadFile, "r"); /* Open the load file */
407 com_err(whoami,errno,"; Cannot open file %s", internalLoadFile);
412 noExecute = dontExecute;
414 printf("Would have executed the following commands:\n");
417 while ( fgets(lineBuffer, sizeof(lineBuffer)-1, fd) ) /* Get commands from file */
421 i = strlen(lineBuffer) - 1;
422 if (lineBuffer[i] == '\n') /* Drop return at end of line */
423 lineBuffer[i] = '\0';
426 printf(" %s\n", lineBuffer); /* echo */
428 printf("------> %s\n", lineBuffer); /* echo */
430 if ( !LineIsBlank(lineBuffer) && /* Skip if blank line */
431 (lineBuffer[0] != '#') && /* or comment */
432 (!noExecute) ) /* or no execute */
434 c = cmd_ParseLine(lineBuffer, sargv, &sargc, MAXV);
437 com_err(whoami, c, "; Can't parse line");
441 doDispatch(sargc, sargv, dispatchCount+1); /* Recursive - ignore error */
442 cmd_FreeArgv(sargv); /* Free up arguments */
451 if (internalLoadFile) free(internalLoadFile);
455 int bc_interactCmd(as, arock)
456 struct cmd_syndesc *as;
462 static void add_std_args(ts)
463 register struct cmd_syndesc *ts;
466 cmd_AddParm(ts, "-localauth", CMD_FLAG, CMD_OPTIONAL, "local authentication");
467 cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");
475 char **targv[MAXV]; /*Ptr to parsed argv stuff*/
476 afs_int32 targc; /*Num parsed arguments*/
477 afs_int32 code; /*Return code*/
478 char *tp; /*Result of gets()*/
479 register struct cmd_syndesc *ts; /*Ptr to parsed command line*/
485 * The following signal action for AIX is necessary so that in case of a
486 * crash (i.e. core is generated) we can include the user's data section
487 * in the core dump. Unfortunately, by default, only a partial core is
488 * generated which, in many cases, isn't too useful.
490 struct sigaction nsa;
492 sigemptyset(&nsa.sa_mask);
493 nsa.sa_handler = SIG_DFL;
494 nsa.sa_flags = SA_FULLDUMP;
495 sigaction(SIGSEGV, &nsa, NULL);
497 Lock_Init(&dispatchLock);
498 InitErrTabs(); /* init all the error tables which may be used */
500 /* setup the default backup dir */
501 DefaultConfDir = AFSDIR_SERVER_BACKUP_DIRPATH;
502 /* Get early warning if the command is interacive mode or not */
503 interact = ( ((argc < 2) || (argv[1][0] == '-')) ? 1 : 0 );
505 cmd_SetBeforeProc(MyBeforeProc, (char *)0);
507 ts = cmd_CreateSyntax("dump", bc_DumpCmd, 0, "start dump");
508 cmd_AddParm(ts, "-volumeset", CMD_SINGLE, CMD_OPTIONAL, "volume set name");
509 cmd_AddParm(ts, "-dump", CMD_SINGLE, CMD_OPTIONAL, "dump level name");
510 cmd_AddParm(ts, "-portoffset", CMD_SINGLE, CMD_OPTIONAL, "TC port offset");
511 cmd_AddParm(ts, "-at", CMD_LIST, CMD_OPTIONAL, "Date/time to start dump");
512 cmd_AddParm(ts, "-append", CMD_FLAG, CMD_OPTIONAL, "append to existing dump set");
513 cmd_AddParm(ts, "-n", CMD_FLAG, CMD_OPTIONAL, "don't really execute it");
514 cmd_AddParm(ts, "-file", CMD_SINGLE, CMD_OPTIONAL, "load file");
515 if (!interact) add_std_args(ts);
517 ts = cmd_CreateSyntax("volrestore", bc_VolRestoreCmd, 0, "restore volume");
518 cmd_AddParm(ts, "-server", CMD_SINGLE, CMD_REQUIRED, "destination machine");
519 cmd_AddParm(ts, "-partition", CMD_SINGLE, CMD_REQUIRED, "destination partition");
520 cmd_AddParm(ts, "-volume", CMD_LIST, CMD_REQUIRED, "volume(s) to restore");
521 cmd_AddParm(ts, "-extension", CMD_SINGLE, CMD_OPTIONAL, "new volume name extension");
522 cmd_AddParm(ts, "-date", CMD_LIST, CMD_OPTIONAL, "date from which to restore");
523 cmd_AddParm(ts, "-portoffset", CMD_LIST, CMD_OPTIONAL, "TC port offsets");
524 cmd_AddParm(ts, "-n", CMD_FLAG, CMD_OPTIONAL, "don't really execute it");
525 if (!interact) add_std_args(ts);
527 ts = cmd_CreateSyntax("diskrestore", bc_DiskRestoreCmd, 0, "restore partition");
528 cmd_AddParm(ts, "-server", CMD_SINGLE, CMD_REQUIRED, "machine to restore");
529 cmd_AddParm(ts, "-partition", CMD_SINGLE, CMD_REQUIRED, "partition to restore");
530 cmd_AddParm(ts, "-portoffset", CMD_LIST, CMD_OPTIONAL, "TC port offset");
532 cmd_AddParm(ts, "-newserver", CMD_SINGLE, CMD_OPTIONAL, "destination machine");
533 cmd_AddParm(ts, "-newpartition", CMD_SINGLE, CMD_OPTIONAL, "destination partition");
534 cmd_AddParm(ts, "-extension", CMD_SINGLE, CMD_OPTIONAL, "new volume name extension");
535 cmd_AddParm(ts, "-n", CMD_FLAG, CMD_OPTIONAL, "don't really execute it");
536 if (!interact) add_std_args(ts);
538 ts = cmd_CreateSyntax("quit", bc_QuitCmd, 0, "leave the program");
540 ts = cmd_CreateSyntax("volsetrestore", bc_VolsetRestoreCmd, 0, "restore a set of volumes");
541 cmd_AddParm(ts, "-name", CMD_SINGLE, CMD_OPTIONAL, "volume set name");
542 cmd_AddParm(ts, "-file", CMD_SINGLE, CMD_OPTIONAL, "file name");
543 cmd_AddParm(ts, "-portoffset", CMD_LIST, CMD_OPTIONAL, "TC port offset");
544 cmd_AddParm(ts, "-extension", CMD_SINGLE, CMD_OPTIONAL, "new volume name extension");
545 cmd_AddParm(ts, "-n", CMD_FLAG, CMD_OPTIONAL, "don't really execute it");
546 if (!interact) add_std_args(ts);
548 ts = cmd_CreateSyntax("addhost", bc_AddHostCmd, 0, "add host to config");
549 cmd_AddParm(ts, "-tapehost", CMD_SINGLE, CMD_REQUIRED, "tape machine name");
550 cmd_AddParm(ts, "-portoffset", CMD_SINGLE, CMD_OPTIONAL, "TC port offset");
551 if (!interact) add_std_args(ts);
553 ts = cmd_CreateSyntax("delhost", bc_DeleteHostCmd, 0, "delete host to config");
554 cmd_AddParm(ts, "-tapehost", CMD_SINGLE, CMD_REQUIRED, "tape machine name");
555 cmd_AddParm(ts, "-portoffset", CMD_SINGLE, CMD_OPTIONAL, "TC port offset");
556 if (!interact) add_std_args(ts);
558 ts = cmd_CreateSyntax("listhosts", bc_ListHostsCmd, 0, "list config hosts");
559 if (!interact) add_std_args(ts);
561 ts = cmd_CreateSyntax("jobs", bc_JobsCmd, 0, "list running jobs");
563 ts = cmd_CreateSyntax("kill", bc_KillCmd, 0, "kill running job");
564 cmd_AddParm(ts, "-id", CMD_SINGLE, CMD_REQUIRED, "job ID or dump set name");
566 ts = cmd_CreateSyntax("listvolsets", bc_ListVolSetCmd, 0, "list volume sets");
567 cmd_AddParm(ts, "-name", CMD_SINGLE, CMD_OPTIONAL, "volume set name");
568 if (!interact) add_std_args(ts);
570 ts = cmd_CreateSyntax("listdumps", bc_ListDumpScheduleCmd, 0, "list dump schedules");
571 if (!interact) add_std_args(ts);
573 ts = cmd_CreateSyntax("addvolset", bc_AddVolSetCmd, 0, "create a new volume set");
574 cmd_AddParm(ts, "-name", CMD_SINGLE, CMD_REQUIRED, "volume set name");
575 cmd_AddParm(ts, "-temporary", CMD_FLAG, CMD_OPTIONAL, "temporary volume set");
576 if (!interact) add_std_args(ts);
578 ts = cmd_CreateSyntax("status", bc_GetTapeStatusCmd, 0,
579 "get tape coordinator status");
580 cmd_AddParm(ts, "-portoffset", CMD_SINGLE, CMD_OPTIONAL, "TC port offset");
581 if (!interact) add_std_args(ts);
583 ts = cmd_CreateSyntax("delvolset", bc_DeleteVolSetCmd, 0, "delete a volume set");
584 cmd_AddParm(ts, "-name", CMD_LIST, CMD_REQUIRED, "volume set name");
585 if (!interact) add_std_args(ts);
587 ts = cmd_CreateSyntax("addvolentry", bc_AddVolEntryCmd, 0, "add a new volume entry");
588 cmd_AddParm(ts, "-name", CMD_SINGLE, CMD_REQUIRED, "volume set name");
589 cmd_AddParm(ts, "-server", CMD_SINGLE, CMD_REQUIRED, "machine name");
590 cmd_AddParm(ts, "-partition", CMD_SINGLE, CMD_REQUIRED, "partition name");
591 cmd_AddParm(ts, "-volumes", CMD_SINGLE, CMD_REQUIRED, "volume name (regular expression)");
592 if (!interact) add_std_args(ts);
594 ts = cmd_CreateSyntax("delvolentry", bc_DeleteVolEntryCmd, 0, "delete a volume set sub-entry");
595 cmd_AddParm(ts, "-name", CMD_SINGLE, CMD_REQUIRED, "volume set name");
596 cmd_AddParm(ts, "-entry", CMD_SINGLE, CMD_REQUIRED, "volume set index");
597 if (!interact) add_std_args(ts);
599 ts = cmd_CreateSyntax("adddump", bc_AddDumpCmd, 0, "add dump schedule");
600 cmd_AddParm(ts, "-dump", CMD_LIST, CMD_REQUIRED, "dump level name");
601 cmd_AddParm(ts, "-expires", CMD_LIST, CMD_OPTIONAL, "expiration date");
602 if (!interact) add_std_args(ts);
604 ts = cmd_CreateSyntax("deldump", bc_DeleteDumpCmd, 0, "delete dump schedule");
605 cmd_AddParm(ts, "-dump", CMD_SINGLE, CMD_REQUIRED, "dump level name");
606 if (!interact) add_std_args(ts);
608 ts = cmd_CreateSyntax("labeltape", bc_LabelTapeCmd, 0, "label a tape");
609 cmd_AddParm(ts, "-name", CMD_SINGLE, CMD_OPTIONAL, "AFS tape name, defaults to NULL");
610 cmd_AddParm(ts, "-size", CMD_SINGLE, CMD_OPTIONAL,
611 "tape size in Kbytes, defaults to size in tapeconfig");
612 cmd_AddParm(ts, "-portoffset", CMD_SINGLE, CMD_OPTIONAL, "TC port offset");
613 cmd_AddParm(ts, "-pname", CMD_SINGLE, CMD_OPTIONAL, "permanent tape name");
614 if (!interact) add_std_args(ts);
616 ts = cmd_CreateSyntax("readlabel", bc_ReadLabelCmd, 0, "read the label on tape");
617 cmd_AddParm(ts, "-portoffset", CMD_SINGLE, CMD_OPTIONAL, "TC port offset");
618 if (!interact) add_std_args(ts);
620 ts = cmd_CreateSyntax("scantape", bc_ScanDumpsCmd, 0, "dump information recovery from tape");
621 cmd_AddParm(ts, "-dbadd", CMD_FLAG, CMD_OPTIONAL, "add information to the database");
622 cmd_AddParm(ts, "-portoffset", CMD_SINGLE, CMD_OPTIONAL, "TC port offset");
623 if (!interact) add_std_args(ts);
625 ts = cmd_CreateSyntax("volinfo", bc_dblookupCmd, 0, "query the backup database");
626 cmd_AddParm(ts, "-volume", CMD_SINGLE, CMD_REQUIRED, "volume name");
627 if (!interact) add_std_args(ts);
629 ts = cmd_CreateSyntax("setexp", bc_SetExpCmd, 0, "set/clear dump expiration dates");
630 cmd_AddParm(ts, "-dump", CMD_LIST, CMD_REQUIRED, "dump level name");
631 cmd_AddParm(ts, "-expires", CMD_LIST, CMD_OPTIONAL, "expiration date");
632 if (!interact) add_std_args(ts);
634 ts = cmd_CreateSyntax("savedb", bc_saveDbCmd, 0, "save backup database");
635 cmd_AddParm(ts, "-portoffset", CMD_SINGLE, CMD_OPTIONAL, "TC port offset");
636 cmd_AddParm(ts, "-archive", CMD_LIST, CMD_OPTIONAL, "date time");
637 if (!interact) add_std_args(ts);
639 ts = cmd_CreateSyntax("restoredb", bc_restoreDbCmd, 0, "restore backup database");
640 cmd_AddParm(ts, "-portoffset", CMD_SINGLE, CMD_OPTIONAL, "TC port offset");
641 if (!interact) add_std_args(ts);
643 ts = cmd_CreateSyntax("dumpinfo", bc_dumpInfoCmd, 0,
644 "provide information about a dump in the database");
645 cmd_AddParm(ts, "-ndumps", CMD_SINGLE, CMD_OPTIONAL, "no. of dumps");
646 cmd_AddParm(ts, "-id", CMD_SINGLE, CMD_OPTIONAL, "dump id");
647 cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, "detailed description");
648 if (!interact) add_std_args(ts);
650 ts = cmd_CreateSyntax("dbverify", bc_dbVerifyCmd, 0, "check ubik database integrity");
651 cmd_AddParm(ts, "-detail", CMD_FLAG, CMD_OPTIONAL, "additional details");
652 if (!interact) add_std_args(ts);
654 ts = cmd_CreateSyntax("deletedump", bc_deleteDumpCmd, 0, "delete dumps from the database");
655 cmd_AddParm(ts, "-dumpid", CMD_LIST, CMD_OPTIONAL, "dump id");
656 cmd_AddParm(ts, "-from", CMD_LIST, CMD_OPTIONAL, "date time");
657 cmd_AddParm(ts, "-to", CMD_LIST, CMD_OPTIONAL, "date time");
658 cmd_AddParm(ts, "-port", CMD_SINGLE, CMD_OPTIONAL, "TC port offset");
659 cmd_AddParm(ts, "-groupid", CMD_SINGLE, CMD_OPTIONAL, "group ID");
660 cmd_AddParm(ts, "-dbonly", CMD_FLAG, CMD_OPTIONAL,
661 "delete the dump from the backup database only");
662 cmd_AddParm(ts, "-force", CMD_FLAG, CMD_OPTIONAL,
663 "always delete from backup database");
664 cmd_AddParm(ts, "-noexecute", CMD_FLAG, CMD_OPTIONAL, "Just list the dumps");
666 if (!interact) add_std_args(ts);
668 ts = cmd_CreateSyntax("interactive", bc_interactCmd, 0, "enter interactive mode");
672 * Now execute the command.
675 targc = 0; targv[targc++] = argv[0];
676 if (interact) targv[targc++] = "interactive";
677 for (i=1; i<argc; i++) targv[targc++] = argv[i];
679 code = doDispatch(targc, targv, 1);
681 if (!interact || !bcInit) /* Non-interactive mode */
684 if (bcInit) code = bc_WaitForNoJobs(); /* wait for any jobs to finish */
685 exit(code); /* and exit */
688 /* Iterate on command lines, interpreting user commands (interactive mode) */
697 while ((ret = LWP_GetLine(lineBuffer, sizeof(lineBuffer))) == 0)
698 printf("%s: Command line too long\n", whoami); /* line too long */
700 if (ret == -1) return 0; /* Got EOF */
702 if ( !LineIsBlank(lineBuffer) )
704 code = cmd_ParseLine(lineBuffer, targv, &targc, MAXV);
706 com_err(whoami,code,"; Can't parse line: '%s'",
707 error_message(code));
710 doDispatch(targc, targv, 1);