4ff921ccbc23bb6b6787ec8f79f74121f624b9aa
[openafs.git] / src / bozo / bos.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 <stdlib.h>
18 #include <stddef.h>
19 #include <sys/types.h>
20 #ifdef AFS_NT40_ENV
21 #include <winsock2.h>
22 #include <io.h>
23 #include <fcntl.h>
24 #else
25 #include <sys/file.h>
26 #include <netinet/in.h>
27 #include <netdb.h>
28 #include <sys/socket.h>
29 #include <strings.h>
30 #endif /* AFS_NT40_ENV */
31 #include <string.h>
32 #include <afs/procmgmt.h>       /* signal(), kill(), wait(), etc. */
33 #include <time.h>
34 #include "bnode.h"
35 #include <errno.h>
36 #include <afs/afsutil.h>
37 #include <afs/cellconfig.h>
38 #include <rx/rx.h>
39 #include <sys/stat.h>
40 #include <rx/xdr.h>
41 #include <afs/auth.h>
42 #include <afs/cellconfig.h>
43 #include <stdio.h>
44 #include <afs/cmd.h>
45 #include <afs/com_err.h>
46 #include <ubik.h>
47 #include <afs/ktime.h>
48
49 static IStatServer();
50 static DoStat();
51
52 #include "bosint.h"
53
54 /* command offsets for bos salvage command */
55 #define MRAFS_OFFSET  10
56 #define ADDPARMOFFSET 27
57
58 /* MR-AFS salvage parameters */
59 struct MRAFSSalvageParms {
60     afs_int32 Optdebug;
61     afs_int32 Optnowrite;
62     afs_int32 Optforce;
63     afs_int32 Optoktozap;
64     afs_int32 Optrootfiles;
65     afs_int32 Optsalvagedirs;
66     afs_int32 Optblockreads;
67     afs_int32 OptListResidencies;
68     afs_int32 OptSalvageRemote;
69     afs_int32 OptSalvageArchival;
70     afs_int32 OptIgnoreCheck;
71     afs_int32 OptForceOnLine;
72     afs_int32 OptUseRootDirACL;
73     afs_int32 OptTraceBadLinkCounts;
74     afs_int32 OptDontAskFS;
75     afs_int32 OptLogLevel;
76     afs_int32 OptRxDebug;
77     afs_uint32 OptResidencies;
78 };
79
80 /* dummy routine for the audit work.  It should do nothing since audits */
81 /* occur at the server level and bos is not a server. */
82 osi_audit()
83 {
84     return 0;
85 }
86
87 /* keep those lines small */
88 static char *
89 em(acode)
90      afs_int32 acode;
91 {
92     if (acode == -1)
93         return "communications failure (-1)";
94     else if (acode == -3)
95         return "communications timeout (-3)";
96     else
97         return (char *)afs_error_message(acode);
98 }
99
100 /* get partition id from a name */
101 static afs_int32
102 GetPartitionID(aname)
103      char *aname;
104 {
105     register char tc;
106     char ascii[3];
107
108     tc = *aname;
109     if (tc == 0)
110         return -1;              /* unknown */
111     /* numbers go straight through */
112     if (tc >= '0' && tc <= '9') {
113         return atoi(aname);
114     }
115     /* otherwise check for vicepa or /vicepa, or just plain "a" */
116     ascii[2] = 0;
117     if (strlen(aname) <= 2) {
118         strcpy(ascii, aname);
119     } else if (!strncmp(aname, "/vicep", 6)) {
120         strncpy(ascii, aname + 6, 2);
121     } else if (!strncmp(aname, "vicep", 5)) {
122         strncpy(ascii, aname + 5, 2);
123     } else
124         return -1;              /* bad partition name */
125     /* now partitions are named /vicepa ... /vicepz, /vicepaa, /vicepab,
126      * .../vicepzz, and are numbered from 0.  Do the appropriate conversion */
127     if (ascii[1] == 0) {
128         /* one char name, 0..25 */
129         if (ascii[0] < 'a' || ascii[0] > 'z')
130             return -1;          /* wrongo */
131         return ascii[0] - 'a';
132     } else {
133         /* two char name, 26 .. <whatever> */
134         if (ascii[0] < 'a' || ascii[0] > 'z')
135             return -1;          /* wrongo */
136         if (ascii[1] < 'a' || ascii[1] > 'z')
137             return -1;          /* just as bad */
138         return (ascii[0] - 'a') * 26 + (ascii[1] - 'a') + 26;
139     }
140 }
141
142 /* make ctime easier to use */
143 static char *
144 DateOf(atime)
145      afs_int32 atime;
146 {
147     static char tbuffer[30];
148     register char *tp;
149     time_t t = (time_t) atime;
150     tp = ctime(&t);
151     if (tp) {
152         strcpy(tbuffer, tp);
153         tbuffer[24] = 0;        /* get rid of new line */
154     } else
155         strcpy(tbuffer, "BAD TIME");
156     return tbuffer;
157 }
158
159 /* global stuff from main for communicating with GetConn */
160 static struct rx_securityClass *sc[3];
161 static int scIndex;
162
163 /* use the syntax descr to get a connection, authenticated appropriately.
164  * aencrypt is set if we want to encrypt the data on the wire.
165  */
166 static struct rx_connection *
167 GetConn(as, aencrypt)
168      int aencrypt;
169      struct cmd_syndesc *as;
170 {
171     struct hostent *th;
172     char *hostname;
173     register afs_int32 code;
174     register struct rx_connection *tconn;
175     afs_int32 addr;
176     register struct afsconf_dir *tdir;
177     int encryptLevel;
178     struct ktc_principal sname;
179     struct ktc_token ttoken;
180     int localauth;
181     const char *confdir;
182
183     hostname = as->parms[0].items->data;
184     th = hostutil_GetHostByName(hostname);
185     if (!th) {
186         printf("bos: can't find address for host '%s'\n", hostname);
187         exit(1);
188     }
189     memcpy(&addr, th->h_addr, sizeof(afs_int32));
190
191     /* get tokens for making authenticated connections */
192     localauth = (as->parms[ADDPARMOFFSET + 2].items != 0);
193     confdir =
194         (localauth ? AFSDIR_SERVER_ETC_DIRPATH : AFSDIR_CLIENT_ETC_DIRPATH);
195     tdir = afsconf_Open(confdir);
196     if (tdir) {
197         struct afsconf_cell info;
198         char *tname;
199
200         if (as->parms[ADDPARMOFFSET].items)
201             tname = as->parms[ADDPARMOFFSET].items->data;
202         else
203             tname = NULL;
204         /* next call expands cell name abbrevs for us and handles looking up
205          * local cell */
206         code = afsconf_GetCellInfo(tdir, tname, NULL, &info);
207         if (code) {
208             afs_com_err("bos", code, "(can't find cell '%s' in cell database)",
209                     (tname ? tname : "<default>"));
210             exit(1);
211         } else
212             strcpy(sname.cell, info.name);
213     } else {
214         printf("bos: can't open cell database (%s)\n", confdir);
215         exit(1);
216     }
217     sname.instance[0] = 0;
218     strcpy(sname.name, "afs");
219     sc[0] = rxnull_NewClientSecurityObject();
220     sc[1] = 0;
221     sc[2] = 0;
222     scIndex = 0;
223
224     if (!as->parms[ADDPARMOFFSET + 1].items) {  /* not -noauth */
225         if (as->parms[ADDPARMOFFSET + 2].items) {       /* -localauth */
226             code = afsconf_GetLatestKey(tdir, 0, 0);
227             if (code)
228                 afs_com_err("bos", code, "(getting key from local KeyFile)");
229             else {
230                 if (aencrypt)
231                     code = afsconf_ClientAuthSecure(tdir, &sc[2], &scIndex);
232                 else
233                     code = afsconf_ClientAuth(tdir, &sc[2], &scIndex);
234                 if (code)
235                     afs_com_err("bos", code, "(calling ClientAuth)");
236                 else if (scIndex != 2)  /* this shouldn't happen */
237                     sc[scIndex] = sc[2];
238             }
239         } else {                /* not -localauth, check for tickets */
240             code = ktc_GetToken(&sname, &ttoken, sizeof(ttoken), NULL);
241             if (code == 0) {
242                 /* have tickets, will travel */
243                 if (ttoken.kvno >= 0 && ttoken.kvno <= 256);
244                 else {
245                     fprintf(stderr,
246                             "bos: funny kvno (%d) in ticket, proceeding\n",
247                             ttoken.kvno);
248                 }
249                 /* kerberos tix */
250                 if (aencrypt)
251                     encryptLevel = rxkad_crypt;
252                 else
253                     encryptLevel = rxkad_clear;
254                 sc[2] = (struct rx_securityClass *)
255                     rxkad_NewClientSecurityObject(encryptLevel,
256                                                   &ttoken.sessionKey,
257                                                   ttoken.kvno,
258                                                   ttoken.ticketLen,
259                                                   ttoken.ticket);
260                 scIndex = 2;
261             } else
262                 afs_com_err("bos", code, "(getting tickets)");
263         }
264         if ((scIndex == 0) || (sc[scIndex] == 0)) {
265             fprintf(stderr, "bos: running unauthenticated\n");
266             scIndex = 0;
267         }
268     }
269     tconn =
270         rx_NewConnection(addr, htons(AFSCONF_NANNYPORT), 1, sc[scIndex],
271                          scIndex);
272     if (!tconn) {
273         fprintf(stderr, "bos: could not create rx connection\n");
274         exit(1);
275     }
276     rxs_Release(sc[scIndex]);
277
278     return tconn;
279 }
280
281 static
282 SetAuth(as)
283      struct cmd_syndesc *as;
284 {
285     register afs_int32 code;
286     register struct rx_connection *tconn;
287     afs_int32 flag;
288     register char *tp;
289
290     tconn = GetConn(as, 0);
291     tp = as->parms[1].items->data;
292     if (strcmp(tp, "on") == 0)
293         flag = 0;               /* auth req.: noauthflag is false */
294     else if (strcmp(tp, "off") == 0)
295         flag = 1;
296     else {
297         printf
298             ("bos: illegal authentication specifier '%s', must be 'off' or 'on'.\n",
299              tp);
300         return 1;
301     }
302     code = BOZO_SetNoAuthFlag(tconn, flag);
303     if (code)
304         afs_com_err("bos", code, "(failed to set authentication flag)");
305     return 0;
306 }
307
308 /* take a name (e.g. foo/bar, and a dir e.g. /usr/afs/bin, and construct
309  * /usr/afs/bin/bar */
310 static
311 ComputeDestDir(aname, adir, aresult, alen)
312      char *aname, *adir, *aresult;
313      afs_int32 alen;
314 {
315     register char *tp;
316
317     strcpy(aresult, adir);
318     tp = strrchr(aname, '/');
319     if (!tp) {
320         /* no '/' in name */
321         strcat(aresult, "/");
322         strcat(aresult, aname);
323     } else {
324         /* tp points at the / character */
325         strcat(aresult, tp);
326     }
327     return 0;
328 }
329
330 /* copy data from fd afd to rx call acall */
331 static
332 CopyBytes(afd, acall)
333      int afd;
334      register struct rx_call *acall;
335 {
336     register afs_int32 code;
337     register afs_int32 len;
338     char tbuffer[256];
339
340     while (1) {
341         len = read(afd, tbuffer, sizeof(tbuffer));
342         if (len < 0)
343             return errno;
344         if (len == 0)
345             return 0;           /* all done */
346         code = rx_Write(acall, tbuffer, len);
347         if (code != len)
348             return -1;
349     }
350 }
351
352 static
353 Prune(as)
354      register struct cmd_syndesc *as;
355 {
356     register afs_int32 code;
357     register struct rx_connection *tconn;
358     register afs_int32 flags;
359
360     tconn = GetConn(as, 0);
361     flags = 0;
362     if (as->parms[1].items)
363         flags |= BOZO_PRUNEBAK;
364     if (as->parms[2].items)
365         flags |= BOZO_PRUNEOLD;
366     if (as->parms[3].items)
367         flags |= BOZO_PRUNECORE;
368     if (as->parms[4].items)
369         flags |= 0xff;
370     code = BOZO_Prune(tconn, flags);
371     if (code)
372         afs_com_err("bos", code, "(failed to prune server files)");
373     return code;
374 }
375
376 static
377 Exec(as)
378      register struct cmd_syndesc *as;
379 {
380     register struct rx_connection *tconn;
381     register afs_int32 code;
382
383     tconn = GetConn(as, 0);
384     code = BOZO_Exec(tconn, as->parms[1].items->data);
385     if (code)
386         printf("bos: failed to execute command (%s)\n", em(code));
387     return code;
388 }
389
390 static
391 GetDate(as)
392      register struct cmd_syndesc *as;
393 {
394     register afs_int32 code;
395     char tbuffer[256];
396     char destDir[256];
397     afs_int32 time, bakTime, oldTime;
398     register struct rx_connection *tconn;
399     register struct cmd_item *ti;
400
401     tconn = GetConn(as, 0);
402     if (!as->parms[1].items) {
403         printf("bos: no files to check\n");
404         return 1;
405     }
406
407     /* compute dest dir or file; default MUST be canonical form of dir path */
408     if (as->parms[2].items)
409         strcpy(destDir, as->parms[2].items->data);
410     else
411         strcpy(destDir, AFSDIR_CANONICAL_SERVER_BIN_DIRPATH);
412
413     for (ti = as->parms[1].items; ti; ti = ti->next) {
414         /* check date for each file */
415         ComputeDestDir(ti->data, destDir, tbuffer, sizeof(tbuffer));
416         code = BOZO_GetDates(tconn, tbuffer, &time, &bakTime, &oldTime);
417         if (code) {
418             printf("bos: failed to check date on %s (%s)\n", ti->data,
419                    em(code));
420             return 1;
421         } else {
422             printf("File %s ", tbuffer);
423             if (time == 0)
424                 printf("does not exist, ");
425             else
426                 printf("dated %s, ", DateOf(time));
427             if (bakTime == 0)
428                 printf("no .BAK file, ");
429             else
430                 printf(".BAK file dated %s, ", DateOf(bakTime));
431             if (oldTime == 0)
432                 printf("no .OLD file.");
433             else
434                 printf(".OLD file dated %s.", DateOf(oldTime));
435             printf("\n");
436         }
437     }
438     return 0;
439 }
440
441 static
442 UnInstall(as)
443      register struct cmd_syndesc *as;
444 {
445     register afs_int32 code;
446     char tbuffer[256];
447     char destDir[256];
448     register struct cmd_item *ti;
449     register struct rx_connection *tconn;
450
451     tconn = GetConn(as, 0);
452     if (!as->parms[1].items) {
453         printf("bos: no files to uninstall\n");
454         return 1;
455     }
456
457     /* compute dest dir or file; default MUST be canonical form of dir path */
458     if (as->parms[2].items)
459         strcpy(destDir, as->parms[2].items->data);
460     else
461         strcpy(destDir, AFSDIR_CANONICAL_SERVER_BIN_DIRPATH);
462
463     for (ti = as->parms[1].items; ti; ti = ti->next) {
464         /* uninstall each file */
465         ComputeDestDir(ti->data, destDir, tbuffer, sizeof(tbuffer));
466         code = BOZO_UnInstall(tconn, tbuffer);
467         if (code) {
468             printf("bos: failed to uninstall %s (%s)\n", ti->data, em(code));
469             return 1;
470         } else
471             printf("bos: uninstalled file %s\n", ti->data);
472     }
473     return 0;
474 }
475
476 static afs_int32
477 GetServerGoal(aconn, aname)
478      char *aname;
479      struct rx_connection *aconn;
480 {
481     char buffer[500];
482     char *tp;
483     register afs_int32 code;
484     struct bozo_status istatus;
485
486     tp = buffer;
487     code = BOZO_GetInstanceInfo(aconn, aname, &tp, &istatus);
488     if (code) {
489         printf("bos: failed to get instance info for '%s' (%s)\n", aname,
490                em(code));
491         /* if we can't get the answer, assume its running */
492         return BSTAT_NORMAL;
493     }
494     if (istatus.goal == 0)
495         return BSTAT_SHUTDOWN;
496     else
497         return BSTAT_NORMAL;
498 }
499
500 static
501 Install(as)
502      struct cmd_syndesc *as;
503 {
504     struct rx_connection *tconn;
505     register afs_int32 code;
506     register struct cmd_item *ti;
507     struct stat tstat;
508     char tbuffer[256];
509     int fd;
510     struct rx_call *tcall;
511     char destDir[256];
512
513     tconn = GetConn(as, 0);
514     if (!as->parms[1].items) {
515         printf("bos: no files to install\n");
516         return 1;
517     }
518
519     /* compute dest dir or file; default MUST be canonical form of dir path */
520     if (as->parms[2].items)
521         strcpy(destDir, as->parms[2].items->data);
522     else
523         strcpy(destDir, AFSDIR_CANONICAL_SERVER_BIN_DIRPATH);
524
525     for (ti = as->parms[1].items; ti; ti = ti->next) {
526         /* install each file */
527         fd = open(ti->data, O_RDONLY);
528         if (fd < 0) {
529             /* better to quit on error than continue for install command */
530             printf("bos: can't find file '%s', quitting\n", ti->data);
531             return 1;
532         }
533         code = fstat(fd, &tstat);
534         if (code) {
535             printf("bos: failed to stat file %s, errno is %d\n", ti->data,
536                    errno);
537             return 1;
538         }
539         /* compute destination dir */
540         ComputeDestDir(ti->data, destDir, tbuffer, sizeof(tbuffer));
541         tcall = rx_NewCall(tconn);
542         code =
543             StartBOZO_Install(tcall, tbuffer, tstat.st_size,
544                               (afs_int32) tstat.st_mode, tstat.st_mtime);
545         if (code == 0) {
546             code = CopyBytes(fd, tcall);
547         }
548         code = rx_EndCall(tcall, code);
549         if (code) {
550             printf("bos: failed to install %s (%s)\n", ti->data, em(code));
551             return 1;
552         } else
553             printf("bos: installed file %s\n", ti->data);
554     }
555     return 0;
556 }
557
558 static
559 Shutdown(as)
560      struct cmd_syndesc *as;
561 {
562     register struct rx_connection *tconn;
563     register afs_int32 code;
564     register struct cmd_item *ti;
565
566     tconn = GetConn(as, 0);
567     if (as->parms[1].items == 0) {
568         code = BOZO_ShutdownAll(tconn);
569         if (code)
570             printf("bos: failed to shutdown servers (%s)\n", em(code));
571     } else {
572         for (ti = as->parms[1].items; ti; ti = ti->next) {
573             code = BOZO_SetTStatus(tconn, ti->data, BSTAT_SHUTDOWN);
574             if (code)
575                 printf("bos: failed to shutdown instance %s (%s)\n", ti->data,
576                        em(code));
577         }
578     }
579     if (as->parms[8].items) {
580         code = BOZO_WaitAll(tconn);
581         if (code)
582             printf("bos: can't wait for processes to shutdown (%s)\n",
583                    em(code));
584     }
585     return 0;
586 }
587
588 static
589 BlockScannerCmd(as, arock)
590      struct cmd_syndesc *as;
591      char *arock;
592 {
593     register afs_int32 code;
594     struct rx_connection *tconn;
595     char BlockCommand[] = "/usr/afs/bin/scanner -block";
596
597     tconn = GetConn(as, 0);
598     code = BOZO_Exec(tconn, BlockCommand);
599     if (code)
600         printf
601             ("bos: failed to block scanner from making migration requests (%s)\n",
602              em(code));
603     return 0;
604 }
605
606 static
607 UnBlockScannerCmd(as, arock)
608      struct cmd_syndesc *as;
609      char *arock;
610 {
611     register afs_int32 code;
612     struct rx_connection *tconn;
613     char UnBlockCommand[] = "/usr/afs/bin/scanner -unblock";
614
615     tconn = GetConn(as, 0);
616     code = BOZO_Exec(tconn, UnBlockCommand);
617     if (code)
618         printf
619             ("bos: failed to allow scanner daemon to make migration requests again (%s)\n",
620              em(code));
621     return 0;
622 }
623
624 static
625 GetRestartCmd(as, arock)
626      struct cmd_syndesc *as;
627      char *arock;
628 {
629     register afs_int32 code;
630     struct ktime generalTime, newBinaryTime;
631     char messageBuffer[256];
632     struct rx_connection *tconn;
633     char *hostp;
634
635     hostp = as->parms[0].items->data;   /* host name for messages */
636     tconn = GetConn(as, 0);
637
638     code = BOZO_GetRestartTime(tconn, 1, &generalTime);
639     if (code) {
640         printf("bos: failed to retrieve restart information (%s)\n",
641                em(code));
642         return code;
643     }
644     code = BOZO_GetRestartTime(tconn, 2, &newBinaryTime);
645     if (code) {
646         printf("bos: failed to retrieve restart information (%s)\n",
647                em(code));
648         return code;
649     }
650
651     code = ktime_DisplayString(&generalTime, messageBuffer);
652     if (code) {
653         printf("bos: failed to decode restart time (%s)\n", em(code));
654         return code;
655     }
656     printf("Server %s restarts %s\n", hostp, messageBuffer);
657
658     code = ktime_DisplayString(&newBinaryTime, messageBuffer);
659     if (code) {
660         printf("bos: failed to decode restart time (%s)\n", em(code));
661         return code;
662     }
663     printf("Server %s restarts for new binaries %s\n", hostp, messageBuffer);
664
665     /* all done now */
666     return 0;
667 }
668
669 static
670 SetRestartCmd(as, arock)
671      struct cmd_syndesc *as;
672      char *arock;
673 {
674     afs_int32 count;
675     register afs_int32 code;
676     struct ktime restartTime;
677     afs_int32 type;
678     struct rx_connection *tconn;
679
680     count = 0;
681     tconn = GetConn(as, 0);
682     if (as->parms[2].items) {
683         count++;
684         type = 1;
685     }
686     if (as->parms[3].items) {
687         count++;
688         type = 2;
689     }
690     if (count > 1) {
691         printf("bos: can't specify more than one restart time at a time\n");
692         return -1;
693     }
694     if (count == 0)
695         type = 1;               /* by default set general restart time */
696
697     if (code = ktime_ParsePeriodic(as->parms[1].items->data, &restartTime)) {
698         printf("bos: failed to parse '%s' as periodic restart time(%s)\n",
699                as->parms[1].items->data, em(code));
700         return code;
701     }
702
703     code = BOZO_SetRestartTime(tconn, type, &restartTime);
704     if (code) {
705         printf("bos: failed to set restart time at server (%s)\n", em(code));
706         return code;
707     }
708     return 0;
709 }
710
711 static
712 Startup(as)
713      struct cmd_syndesc *as;
714 {
715     register struct rx_connection *tconn;
716     register afs_int32 code;
717     register struct cmd_item *ti;
718
719     tconn = GetConn(as, 0);
720     if (as->parms[1].items == 0) {
721         code = BOZO_StartupAll(tconn);
722         if (code)
723             printf("bos: failed to startup servers (%s)\n", em(code));
724     } else {
725         for (ti = as->parms[1].items; ti; ti = ti->next) {
726             code = BOZO_SetTStatus(tconn, ti->data, BSTAT_NORMAL);
727             if (code)
728                 printf("bos: failed to start instance %s (%s)\n", ti->data,
729                        em(code));
730         }
731     }
732     return 0;
733 }
734
735 static
736 Restart(as)
737      struct cmd_syndesc *as;
738 {
739     register struct rx_connection *tconn;
740     register afs_int32 code;
741     register struct cmd_item *ti;
742
743     tconn = GetConn(as, 0);
744     if (as->parms[2].items) {
745         /* this is really a rebozo command */
746         if (as->parms[1].items) {
747             /* specified specific things to restart, can't do this at the same
748              * time */
749             printf
750                 ("bos: can't specify both '-bos' and specific servers to restart.\n");
751             return 1;
752         }
753         /* otherwise do a rebozo */
754         code = BOZO_ReBozo(tconn);
755         if (code)
756             printf("bos: failed to restart bosserver (%s)\n", em(code));
757         return code;
758     }
759     if (as->parms[1].items == 0) {
760         if (as->parms[3].items) {       /* '-all' */
761             code = BOZO_RestartAll(tconn);
762             if (code)
763                 printf("bos: failed to restart servers (%s)\n", em(code));
764         } else
765             printf("bos: To restart all processes please specify '-all'\n");
766     } else {
767         if (as->parms[3].items) {
768             printf("bos: Can't use '-all' along with individual instances\n");
769         } else {
770             for (ti = as->parms[1].items; ti; ti = ti->next) {
771                 code = BOZO_Restart(tconn, ti->data);
772                 if (code)
773                     printf("bos: failed to restart instance %s (%s)\n",
774                            ti->data, em(code));
775             }
776         }
777     }
778     return 0;
779 }
780
781 static
782 SetCellName(as)
783      struct cmd_syndesc *as;
784 {
785     register struct rx_connection *tconn;
786     register afs_int32 code;
787
788     tconn = GetConn(as, 0);
789     code = BOZO_SetCellName(tconn, as->parms[1].items->data);
790     if (code)
791         printf("bos: failed to set cell (%s)\n", em(code));
792     return 0;
793 }
794
795 static
796 AddHost(as)
797      register struct cmd_syndesc *as;
798 {
799     register struct rx_connection *tconn;
800     register afs_int32 code;
801     register struct cmd_item *ti;
802     char name[MAXHOSTCHARS];
803
804     tconn = GetConn(as, 0);
805     for (ti = as->parms[1].items; ti; ti = ti->next) {
806         if (as->parms[2].items) {
807             if (strlen(ti->data) > MAXHOSTCHARS - 3) {
808                 fprintf(stderr, "bos: host name too long\n");
809                 return E2BIG;
810             }
811             name[0] = '[';
812             strcpy(&name[1], ti->data);
813             strcat((char *)&name, "]");
814             code = BOZO_AddCellHost(tconn, name);
815         } else
816             code = BOZO_AddCellHost(tconn, ti->data);
817         if (code)
818             printf("bos: failed to add host %s (%s)\n", ti->data, em(code));
819     }
820     return 0;
821 }
822
823 static
824 RemoveHost(as)
825      register struct cmd_syndesc *as;
826 {
827     register struct rx_connection *tconn;
828     register afs_int32 code;
829     register struct cmd_item *ti;
830
831     tconn = GetConn(as, 0);
832     for (ti = as->parms[1].items; ti; ti = ti->next) {
833         code = BOZO_DeleteCellHost(tconn, ti->data);
834         if (code)
835             printf("bos: failed to delete host %s (%s)\n", ti->data,
836                    em(code));
837     }
838     return 0;
839 }
840
841 static
842 ListHosts(as)
843      register struct cmd_syndesc *as;
844 {
845     register struct rx_connection *tconn;
846     register afs_int32 code;
847     char tbuffer[256];
848     char *tp;
849     register afs_int32 i;
850
851     tp = tbuffer;
852     tconn = GetConn(as, 0);
853     code = BOZO_GetCellName(tconn, &tp);
854     if (code) {
855         printf("bos: failed to get cell name (%s)\n", em(code));
856         exit(1);
857     }
858     printf("Cell name is %s\n", tbuffer);
859     for (i = 0;; i++) {
860         code = BOZO_GetCellHost(tconn, i, &tp);
861         if (code == BZDOM)
862             break;
863         if (code != 0) {
864             printf("bos: failed to get cell host %d (%s)\n", i, em(code));
865             exit(1);
866         }
867         printf("    Host %d is %s\n", i + 1, tbuffer);
868     }
869     return 0;
870 }
871
872 static
873 AddKey(as)
874      register struct cmd_syndesc *as;
875 {
876     register struct rx_connection *tconn;
877     register afs_int32 code;
878     struct ktc_encryptionKey tkey;
879     afs_int32 temp;
880     char *tcell;
881     char cellBuffer[256];
882     char buf[BUFSIZ], ver[BUFSIZ];
883
884     tconn = GetConn(as, 1);
885     memset(&tkey, 0, sizeof(struct ktc_encryptionKey));
886
887     if (as->parms[1].items)
888         strcpy(buf, as->parms[1].items->data);
889     else {
890         /* prompt for key */
891         code = des_read_pw_string(buf, sizeof(buf), "input key: ", 0);
892         if (code || strlen(buf) == 0) {
893             fprintf(stderr, "Bad key: \n");
894             exit(1);
895         }
896         code = des_read_pw_string(ver, sizeof(ver), "Retype input key: ", 0);
897         if (code || strlen(ver) == 0) {
898             fprintf(stderr, "Bad key: \n");
899             exit(1);
900         }
901         if (strcmp(ver, buf) != 0) {
902             fprintf(stderr, "\nInput key mismatch\n");
903             exit(1);
904         }
905
906     }
907
908     temp = atoi(as->parms[2].items->data);
909     if (temp == 999) {
910         /* bcrypt key */
911 /*
912         strcpy((char *)&tkey, as->parms[1].items->data);
913 */
914         strcpy((char *)&tkey, buf);
915     } else {                    /* kerberos key */
916         if (as->parms[ADDPARMOFFSET].items) {
917             strcpy(cellBuffer, as->parms[ADDPARMOFFSET].items->data);
918
919             /* string to key needs upper-case cell names */
920
921             /* I don't believe this is true.  The string to key function
922              * actually expands the cell name, then LOWER-CASES it.  Perhaps it
923              * didn't use to??? */
924             ucstring(cellBuffer, cellBuffer, strlen(cellBuffer));
925             tcell = cellBuffer;
926         } else
927             tcell = NULL;       /* no cell specified, use current */
928 /*
929         ka_StringToKey(as->parms[1].items->data, tcell, &tkey);
930 */
931         ka_StringToKey(buf, tcell, &tkey);
932     }
933     tconn = GetConn(as, 1);
934     code = BOZO_AddKey(tconn, temp, &tkey);
935     if (code) {
936         printf("bos: failed to set key %d (%s)\n", temp, em(code));
937         exit(1);
938     }
939     return 0;
940 }
941
942 static
943 RemoveKey(as)
944      register struct cmd_syndesc *as;
945 {
946     register struct rx_connection *tconn;
947     register afs_int32 code;
948     afs_int32 temp;
949     register struct cmd_item *ti;
950
951     tconn = GetConn(as, 0);
952     for (ti = as->parms[1].items; ti; ti = ti->next) {
953         temp = atoi(ti->data);
954         code = BOZO_DeleteKey(tconn, temp);
955         if (code) {
956             printf("bos: failed to delete key %d (%s)\n", temp, em(code));
957             exit(1);
958         }
959     }
960     return 0;
961 }
962
963 static
964 ListKeys(as)
965      IN register struct cmd_syndesc *as;
966 {
967     register struct rx_connection *tconn;
968     register afs_int32 code;
969     struct ktc_encryptionKey tkey;
970     afs_int32 kvno;
971     struct bozo_keyInfo keyInfo;
972     int everWorked;
973     register afs_int32 i;
974
975     tconn = GetConn(as, 1);
976     everWorked = 0;
977     for (i = 0;; i++) {
978         code = BOZO_ListKeys(tconn, i, &kvno, &tkey, &keyInfo);
979         if (code)
980             break;
981         everWorked = 1;
982         /* first check if key is returned */
983         if ((!ka_KeyIsZero(&tkey, sizeof(tkey))) && (as->parms[1].items)) {
984             printf("key %d is '", kvno);
985             ka_PrintBytes(&tkey, sizeof(tkey));
986             printf("'\n");
987         } else {
988             if (keyInfo.keyCheckSum == 0)       /* shouldn't happen */
989                 printf("key version is %d\n", kvno);
990             else
991                 printf("key %d has cksum %u\n", kvno, keyInfo.keyCheckSum);
992         }
993     }
994     if (everWorked) {
995         printf("Keys last changed on %s.\n", DateOf(keyInfo.mod_sec));
996     }
997     if (code != BZDOM)
998         printf("bos: %s error encountered while listing keys\n", em(code));
999     else
1000         printf("All done.\n");
1001     return 0;
1002 }
1003
1004 static
1005 AddSUser(as)
1006      register struct cmd_syndesc *as;
1007 {
1008     register struct rx_connection *tconn;
1009     register afs_int32 code;
1010     int failed;
1011     register struct cmd_item *ti;
1012
1013     failed = 0;
1014     tconn = GetConn(as, 0);
1015     for (ti = as->parms[1].items; ti; ti = ti->next) {
1016         code = BOZO_AddSUser(tconn, ti->data);
1017         if (code) {
1018             printf("bos: failed to add user '%s' (%s)\n", ti->data, em(code));
1019             failed = 1;
1020         }
1021     }
1022     return failed;
1023 }
1024
1025 static
1026 RemoveSUser(as)
1027      register struct cmd_syndesc *as;
1028 {
1029     register struct rx_connection *tconn;
1030     register struct cmd_item *ti;
1031     register afs_int32 code;
1032     int failed;
1033
1034     failed = 0;
1035     tconn = GetConn(as, 0);
1036     for (ti = as->parms[1].items; ti; ti = ti->next) {
1037         code = BOZO_DeleteSUser(tconn, ti->data);
1038         if (code) {
1039             printf("bos: failed to delete user '%s', ", ti->data);
1040             if (code == ENOENT)
1041                 printf("(no such user)\n");
1042             else
1043                 printf("(%s)\n", em(code));
1044             failed = 1;
1045         }
1046     }
1047     return failed;
1048 }
1049
1050 #define NPERLINE    10          /* dudes to print per line */
1051 static
1052 ListSUsers(as)
1053      register struct cmd_syndesc *as;
1054 {
1055     register struct rx_connection *tconn;
1056     register int i;
1057     register afs_int32 code;
1058     char tbuffer[256];
1059     char *tp;
1060     int lastNL, printGreeting;
1061
1062     tconn = GetConn(as, 0);
1063     lastNL = 0;
1064     printGreeting = 1;
1065     for (i = 0;; i++) {
1066         tp = tbuffer;
1067         code = BOZO_ListSUsers(tconn, i, &tp);
1068         if (code)
1069             break;
1070         if (printGreeting) {
1071             printGreeting = 0;  /* delay until after first call succeeds */
1072             printf("SUsers are: ");
1073         }
1074         printf("%s ", tbuffer);
1075         if ((i % NPERLINE) == NPERLINE - 1) {
1076             printf("\n");
1077             lastNL = 1;
1078         } else
1079             lastNL = 0;
1080     }
1081     if (code != 1) {
1082         /* a real error code, instead of scanned past end */
1083         printf("bos: failed to retrieve super-user list (%s)\n", em(code));
1084         return code;
1085     }
1086     if (lastNL == 0)
1087         printf("\n");
1088     return 0;
1089 }
1090
1091 static
1092 StatServer(as)
1093      register struct cmd_syndesc *as;
1094 {
1095     register struct rx_connection *tconn;
1096     register afs_int32 code;
1097     register int i;
1098     char ibuffer[BOZO_BSSIZE];
1099     char *tp;
1100     int int32p;
1101
1102     /* int32p==1 is obsolete, smaller, printout */
1103     int32p = (as->parms[2].items != 0 ? 2 : 0);
1104
1105     /* no parms does something pretty different */
1106     if (as->parms[1].items)
1107         return IStatServer(as, int32p);
1108
1109     tconn = GetConn(as, 0);
1110     for (i = 0;; i++) {
1111         /* for each instance */
1112         tp = ibuffer;
1113         code = BOZO_EnumerateInstance(tconn, i, &tp);
1114         if (code == BZDOM)
1115             break;
1116         if (code) {
1117             printf("bos: failed to contact host's bosserver (%s).\n",
1118                    em(code));
1119             break;
1120         }
1121         DoStat(ibuffer, tconn, int32p, (i == 0));       /* print status line */
1122     }
1123     return 0;
1124 }
1125
1126 static
1127 CreateServer(as)
1128      register struct cmd_syndesc *as;
1129 {
1130     register struct rx_connection *tconn;
1131     register afs_int32 code;
1132     char *parms[6];
1133     register struct cmd_item *ti;
1134     register int i;
1135     char *type, *name, *notifier = NONOTIFIER;
1136
1137     tconn = GetConn(as, 0);
1138     for (i = 0; i < 6; i++)
1139         parms[i] = "";
1140     for (i = 0, ti = as->parms[3].items; (ti && i < 6); ti = ti->next, i++) {
1141         parms[i] = ti->data;
1142     }
1143     name = as->parms[1].items->data;
1144     type = as->parms[2].items->data;
1145     if (ti = as->parms[4].items) {
1146         notifier = ti->data;
1147     }
1148     code =
1149         BOZO_CreateBnode(tconn, type, name, parms[0], parms[1], parms[2],
1150                          parms[3], parms[4], notifier);
1151     if (code) {
1152         printf
1153             ("bos: failed to create new server instance %s of type '%s' (%s)\n",
1154              name, type, em(code));
1155     }
1156     return code;
1157 }
1158
1159 static
1160 DeleteServer(as)
1161      register struct cmd_syndesc *as;
1162 {
1163     register struct rx_connection *tconn;
1164     register afs_int32 code;
1165     register struct cmd_item *ti;
1166
1167     code = 0;
1168     tconn = GetConn(as, 0);
1169     for (ti = as->parms[1].items; ti; ti = ti->next) {
1170         code = BOZO_DeleteBnode(tconn, ti->data);
1171         if (code) {
1172             if (code == BZBUSY)
1173                 printf("bos: can't delete running instance '%s'\n", ti->data);
1174             else
1175                 printf("bos: failed to delete instance '%s' (%s)\n", ti->data,
1176                        em(code));
1177         }
1178     }
1179     return code;
1180 }
1181
1182 static
1183 StartServer(as)
1184      register struct cmd_syndesc *as;
1185 {
1186     register struct rx_connection *tconn;
1187     register afs_int32 code;
1188     register struct cmd_item *ti;
1189
1190     code = 0;
1191     tconn = GetConn(as, 0);
1192     for (ti = as->parms[1].items; ti; ti = ti->next) {
1193         code = BOZO_SetStatus(tconn, ti->data, BSTAT_NORMAL);
1194         if (code)
1195             printf("bos: failed to start instance '%s' (%s)\n", ti->data,
1196                    em(code));
1197     }
1198     return code;
1199 }
1200
1201 static
1202 StopServer(as)
1203      register struct cmd_syndesc *as;
1204 {
1205     register struct rx_connection *tconn;
1206     register afs_int32 code;
1207     register struct cmd_item *ti;
1208
1209     code = 0;
1210     tconn = GetConn(as, 0);
1211     for (ti = as->parms[1].items; ti; ti = ti->next) {
1212         code = BOZO_SetStatus(tconn, ti->data, BSTAT_SHUTDOWN);
1213         if (code)
1214             printf("bos: failed to change stop instance '%s' (%s)\n",
1215                    ti->data, em(code));
1216     }
1217     if (as->parms[8].items) {
1218         code = BOZO_WaitAll(tconn);
1219         if (code)
1220             printf("bos: can't wait for processes to shutdown (%s)\n",
1221                    em(code));
1222     }
1223     return code;
1224 }
1225
1226 #define PARMBUFFERSSIZE 32
1227
1228 static afs_int32
1229 DoSalvage(struct rx_connection * aconn, char * aparm1, char * aparm2, 
1230           char * aoutName, afs_int32 showlog, char * parallel, 
1231           char * atmpDir, char * orphans, int dafs, 
1232           struct MRAFSSalvageParms * mrafsParm)
1233 {
1234     register afs_int32 code;
1235     char *parms[6];
1236     char buffer;
1237     char tbuffer[BOZO_BSSIZE];
1238     struct bozo_status istatus;
1239     struct rx_call *tcall;
1240     char *tp;
1241     FILE *outFile;
1242     int closeIt;
1243     char partName[20];          /* canonical name for partition */
1244     char pbuffer[PARMBUFFERSSIZE];
1245     afs_int32 partNumber;
1246     char *notifier = NONOTIFIER;
1247
1248     /* if a partition was specified, canonicalize the name, since
1249      * the salvager has a stupid partition ID parser */
1250     if (aparm1) {
1251         partNumber = volutil_GetPartitionID(aparm1);
1252         if (partNumber < 0) {
1253             printf("bos: could not parse partition ID '%s'\n", aparm1);
1254             return EINVAL;
1255         }
1256         tp = volutil_PartitionName(partNumber);
1257         if (!tp) {
1258             printf("bos: internal error parsing partition ID '%s'\n", aparm1);
1259             return EINVAL;
1260         }
1261         strcpy(partName, tp);
1262     } else
1263         partName[0] = 0;
1264
1265     /* open the file name */
1266     if (aoutName) {
1267         outFile = fopen(aoutName, "w");
1268         if (!outFile) {
1269             printf("bos: can't open specified SalvageLog file '%s'\n",
1270                    aoutName);
1271             return ENOENT;
1272         }
1273         closeIt = 1;            /* close this file later */
1274     } else {
1275         outFile = stdout;
1276         closeIt = 0;            /* don't close this file later */
1277     }
1278
1279     for (code = 2; code < 6; code++)
1280         parms[code] = "";
1281     if (!aparm2)
1282         aparm2 = "";
1283
1284     /* MUST pass canonical (wire-format) salvager path to bosserver */
1285     if (*aparm2 != 0) {
1286         /* single volume salvage */
1287         if (dafs) {
1288             /* for DAFS, we call the salvagserver binary with special options.
1289              * in this mode, it simply uses SALVSYNC to tell the currently
1290              * running salvageserver to offline and salvage the volume in question */
1291             strncpy(tbuffer, AFSDIR_CANONICAL_SERVER_SALSRV_FILEPATH, BOZO_BSSIZE);
1292
1293             if ((strlen(tbuffer) + 9 + strlen(partName) + 1 + strlen(aparm2) +
1294                  1) > BOZO_BSSIZE) {
1295                 printf("bos: command line too big\n");
1296                 return (E2BIG);
1297             }
1298
1299             strcat(tbuffer, " -client ");
1300             strcat(tbuffer, partName);
1301             strcat(tbuffer, " ");
1302             strcat(tbuffer, aparm2);
1303         } else {
1304             strncpy(tbuffer, AFSDIR_CANONICAL_SERVER_SALVAGER_FILEPATH, BOZO_BSSIZE);
1305
1306             if ((strlen(tbuffer) + 1 + strlen(partName) + 1 + strlen(aparm2) +
1307                  1) > BOZO_BSSIZE) {
1308                 printf("bos: command line too big\n");
1309                 return (E2BIG);
1310             }
1311
1312             strcat(tbuffer, " ");
1313             strcat(tbuffer, partName);
1314             strcat(tbuffer, " ");
1315             strcat(tbuffer, aparm2);
1316         }
1317     } else {
1318         /* partition salvage */
1319         strncpy(tbuffer, AFSDIR_CANONICAL_SERVER_SALVAGER_FILEPATH, BOZO_BSSIZE);
1320         if ((strlen(tbuffer) + 4 + strlen(partName) + 1) > BOZO_BSSIZE) {
1321             printf("bos: command line too big\n");
1322             return (E2BIG);
1323         }
1324         strcat(tbuffer, " -f ");
1325         strcat(tbuffer, partName);
1326     }
1327
1328     /* For DAFS, specifying a single volume does not result in a standard
1329      * salvager call.  Instead, it simply results in a SALVSYNC call to the
1330      * online salvager daemon.  This interface does not give us the same rich
1331      * set of call flags.  Thus, we skip these steps for DAFS single-volume 
1332      * calls */
1333     if (!dafs || (*aparm2 == 0)) {
1334         /* add the parallel option if given */
1335         if (parallel != NULL) {
1336             if ((strlen(tbuffer) + 11 + strlen(parallel) + 1) > BOZO_BSSIZE) {
1337                 printf("bos: command line too big\n");
1338                 return (E2BIG);
1339             }
1340             strcat(tbuffer, " -parallel ");
1341             strcat(tbuffer, parallel);
1342         }
1343
1344         /* add the tmpdir option if given */
1345         if (atmpDir != NULL) {
1346             if ((strlen(tbuffer) + 9 + strlen(atmpDir) + 1) > BOZO_BSSIZE) {
1347                 printf("bos: command line too big\n");
1348                 return (E2BIG);
1349             }
1350             strcat(tbuffer, " -tmpdir ");
1351             strcat(tbuffer, atmpDir);
1352         }
1353
1354         /* add the orphans option if given */
1355         if (orphans != NULL) {
1356             if ((strlen(tbuffer) + 10 + strlen(orphans) + 1) > BOZO_BSSIZE) {
1357                 printf("bos: command line too big\n");
1358                 return (E2BIG);
1359             }
1360             strcat(tbuffer, " -orphans ");
1361             strcat(tbuffer, orphans);
1362         }
1363
1364         if (mrafsParm->Optdebug)
1365             strcat(tbuffer, " -debug");
1366         if (mrafsParm->Optnowrite)
1367             strcat(tbuffer, " -nowrite");
1368         if (mrafsParm->Optforce)
1369             strcat(tbuffer, " -force");
1370         if (mrafsParm->Optoktozap)
1371             strcat(tbuffer, " -oktozap");
1372         if (mrafsParm->Optrootfiles)
1373             strcat(tbuffer, " -rootfiles");
1374         if (mrafsParm->Optsalvagedirs)
1375             strcat(tbuffer, " -salvagedirs");
1376         if (mrafsParm->Optblockreads)
1377             strcat(tbuffer, " -blockreads");
1378         if (mrafsParm->OptListResidencies)
1379             strcat(tbuffer, " -ListResidencies");
1380         if (mrafsParm->OptSalvageRemote)
1381             strcat(tbuffer, " -SalvageRemote");
1382         if (mrafsParm->OptSalvageArchival)
1383             strcat(tbuffer, " -SalvageArchival");
1384         if (mrafsParm->OptIgnoreCheck)
1385             strcat(tbuffer, " -IgnoreCheck");
1386         if (mrafsParm->OptForceOnLine)
1387             strcat(tbuffer, " -ForceOnLine");
1388         if (mrafsParm->OptUseRootDirACL)
1389             strcat(tbuffer, " -UseRootDirACL");
1390         if (mrafsParm->OptTraceBadLinkCounts)
1391             strcat(tbuffer, " -TraceBadLinkCounts");
1392         if (mrafsParm->OptDontAskFS)
1393             strcat(tbuffer, " -DontAskFS");
1394         if (mrafsParm->OptLogLevel) {
1395             sprintf(pbuffer, " -LogLevel %ld", mrafsParm->OptLogLevel);
1396             strcat(tbuffer, pbuffer);
1397         }
1398         if (mrafsParm->OptRxDebug)
1399             strcat(tbuffer, " -rxdebug");
1400         if (mrafsParm->OptResidencies) {
1401             sprintf(pbuffer, " -Residencies %lu", mrafsParm->OptResidencies);
1402             strcat(tbuffer, pbuffer);
1403         }
1404     }
1405
1406     parms[0] = tbuffer;
1407     parms[1] = "now";           /* when to do it */
1408     code =
1409         BOZO_CreateBnode(aconn, "cron", "salvage-tmp", parms[0], parms[1],
1410                          parms[2], parms[3], parms[4], notifier);
1411     if (code) {
1412         printf("bos: failed to start 'salvager' (%s)\n", em(code));
1413         goto done;
1414     }
1415     /* now wait for bnode to disappear */
1416     while (1) {
1417         IOMGR_Sleep(5);
1418         tp = tbuffer;
1419         code = BOZO_GetInstanceInfo(aconn, "salvage-tmp", &tp, &istatus);
1420         if (code)
1421             break;
1422         printf("bos: waiting for salvage to complete.\n");
1423     }
1424     if (code != BZNOENT) {
1425         printf("bos: salvage failed (%s)\n", em(code));
1426         goto done;
1427     }
1428     code = 0;
1429
1430     /* now print the log file to the output file */
1431     printf("bos: salvage completed\n");
1432     if (aoutName || showlog) {
1433         fprintf(outFile, "SalvageLog:\n");
1434         tcall = rx_NewCall(aconn);
1435         /* MUST pass canonical (wire-format) salvager log path to bosserver */
1436         code =
1437             StartBOZO_GetLog(tcall, AFSDIR_CANONICAL_SERVER_SLVGLOG_FILEPATH);
1438         if (code) {
1439             rx_EndCall(tcall, code);
1440             goto done;
1441         }
1442         /* copy data */
1443         while (1) {
1444             code = rx_Read(tcall, &buffer, 1);
1445             if (code != 1)
1446                 break;
1447             putc(buffer, outFile);
1448             if (buffer == 0)
1449                 break;          /* the end delimeter */
1450         }
1451         code = rx_EndCall(tcall, 0);
1452         /* fall through into cleanup code */
1453     }
1454
1455   done:
1456     if (closeIt && outFile)
1457         fclose(outFile);
1458     return code;
1459 }
1460
1461 static
1462 GetLogCmd(as)
1463      register struct cmd_syndesc *as;
1464 {
1465     struct rx_connection *tconn;
1466     register struct rx_call *tcall;
1467     register afs_int32 code;
1468     char buffer;
1469     int error;
1470
1471     printf("Fetching log file '%s'...\n", as->parms[1].items->data);
1472     tconn = GetConn(as, 0);
1473     tcall = rx_NewCall(tconn);
1474     code = StartBOZO_GetLog(tcall, as->parms[1].items->data);
1475     if (code) {
1476         rx_EndCall(tcall, code);
1477         goto done;
1478     }
1479     /* copy data */
1480     error = 0;
1481     while (1) {
1482         code = rx_Read(tcall, &buffer, 1);
1483         if (code != 1) {
1484             error = EIO;
1485             break;
1486         }
1487         if (buffer == 0)
1488             break;              /* the end delimeter */
1489         putchar(buffer);
1490     }
1491     code = rx_EndCall(tcall, error);
1492     /* fall through into cleanup code */
1493
1494   done:
1495     if (code)
1496         afs_com_err("bos", code, "(while reading log)");
1497     return code;
1498 }
1499
1500 static
1501 SalvageCmd(as)
1502      struct cmd_syndesc *as;
1503 {
1504     register struct rx_connection *tconn;
1505     register afs_int32 code, rc, i;
1506     char *outName;
1507     char tname[BOZO_BSSIZE];
1508     afs_int32 newID;
1509     extern struct ubik_client *cstruct;
1510     afs_int32 curGoal, showlog = 0, dafs = 0, mrafs = 0;
1511     char *parallel;
1512     char *tmpDir;
1513     char *orphans;
1514     char *tp;
1515     char * serviceName;
1516     struct MRAFSSalvageParms mrafsParm;
1517
1518     memset(&mrafsParm, 0, sizeof(mrafsParm));
1519
1520     /* parm 0 is machine name, 1 is partition, 2 is volume, 3 is -all flag */
1521     tconn = GetConn(as, 0);
1522
1523     tp = &tname[0];
1524
1525     /* find out whether fileserver is running demand attach fs */
1526     if (code = BOZO_GetInstanceParm(tconn, "dafs", 0, &tp) == 0) {
1527         dafs = 1;
1528         serviceName = "dafs";
1529         /* Find out whether fileserver is running MR-AFS (has a scanner instance) */
1530         /* XXX this should really be done some other way, potentially by RPC */
1531         if (code = BOZO_GetInstanceParm(tconn, serviceName, 4, &tp) == 0)
1532             mrafs = 1;
1533     } else {
1534         serviceName = "fs";
1535         /* Find out whether fileserver is running MR-AFS (has a scanner instance) */
1536         /* XXX this should really be done some other way, potentially by RPC */
1537         if (code = BOZO_GetInstanceParm(tconn, serviceName, 3, &tp) == 0)
1538             mrafs = 1;
1539     }
1540
1541     /* we can do a volume, a partition or the whole thing, but not mixtures
1542      * thereof */
1543     if (!as->parms[1].items && as->parms[2].items) {
1544         printf("bos: must specify partition to salvage individual volume.\n");
1545         return -1;
1546     }
1547     if (as->parms[5].items && as->parms[3].items) {
1548         printf("bos: can not specify both -file and -showlog.\n");
1549         return -1;
1550     }
1551     if (as->parms[4].items && (as->parms[1].items || as->parms[2].items)) {
1552         printf("bos: can not specify -all with other flags.\n");
1553         return -1;
1554     }
1555
1556     /* get the output file name, if any */
1557     if (as->parms[3].items)
1558         outName = as->parms[3].items->data;
1559     else
1560         outName = NULL;
1561
1562     if (as->parms[5].items)
1563         showlog = 1;
1564
1565     /* parallel option */
1566     parallel = NULL;
1567     if (as->parms[6].items)
1568         parallel = as->parms[6].items->data;
1569
1570     /* get the tmpdir filename if any */
1571     tmpDir = NULL;
1572     if (as->parms[7].items)
1573         tmpDir = as->parms[7].items->data;
1574
1575     /* -orphans option */
1576     orphans = NULL;
1577     if (as->parms[8].items) {
1578         if (mrafs) {
1579             printf("Can't specify -orphans for MR-AFS fileserver\n");
1580             return EINVAL;
1581         }
1582         orphans = as->parms[8].items->data;
1583     }
1584
1585     if (dafs) {
1586         if (!as->parms[9].items) { /* -forceDAFS flag */
1587             printf("This is a demand attach fileserver.  Are you sure you want to proceed with a manual salvage?\n");
1588             printf("must specify -forceDAFS flag in order to proceed.\n");
1589             return EINVAL;
1590         }
1591     }
1592
1593     if (mrafs) {
1594         if (as->parms[MRAFS_OFFSET].items)
1595             mrafsParm.Optdebug = 1;
1596         if (as->parms[MRAFS_OFFSET + 1].items)
1597             mrafsParm.Optnowrite = 1;
1598         if (as->parms[MRAFS_OFFSET + 2].items)
1599             mrafsParm.Optforce = 1;
1600         if (as->parms[MRAFS_OFFSET + 3].items)
1601             mrafsParm.Optoktozap = 1;
1602         if (as->parms[MRAFS_OFFSET + 4].items)
1603             mrafsParm.Optrootfiles = 1;
1604         if (as->parms[MRAFS_OFFSET + 5].items)
1605             mrafsParm.Optsalvagedirs = 1;
1606         if (as->parms[MRAFS_OFFSET + 6].items)
1607             mrafsParm.Optblockreads = 1;
1608         if (as->parms[MRAFS_OFFSET + 7].items)
1609             mrafsParm.OptListResidencies = 1;
1610         if (as->parms[MRAFS_OFFSET + 8].items)
1611             mrafsParm.OptSalvageRemote = 1;
1612         if (as->parms[MRAFS_OFFSET + 9].items)
1613             mrafsParm.OptSalvageArchival = 1;
1614         if (as->parms[MRAFS_OFFSET + 10].items)
1615             mrafsParm.OptIgnoreCheck = 1;
1616         if (as->parms[MRAFS_OFFSET + 11].items)
1617             mrafsParm.OptForceOnLine = 1;
1618         if (as->parms[MRAFS_OFFSET + 12].items)
1619             mrafsParm.OptUseRootDirACL = 1;
1620         if (as->parms[MRAFS_OFFSET + 13].items)
1621             mrafsParm.OptTraceBadLinkCounts = 1;
1622         if (as->parms[MRAFS_OFFSET + 14].items)
1623             mrafsParm.OptDontAskFS = 1;
1624         if (as->parms[MRAFS_OFFSET + 15].items)
1625             mrafsParm.OptLogLevel =
1626                 atoi(as->parms[MRAFS_OFFSET + 15].items->data);
1627         if (as->parms[MRAFS_OFFSET + 16].items)
1628             mrafsParm.OptRxDebug = 1;
1629         if (as->parms[MRAFS_OFFSET + 17].items) {
1630             if (as->parms[MRAFS_OFFSET + 8].items
1631                 || as->parms[MRAFS_OFFSET + 9].items) {
1632                 printf
1633                     ("Can't specify -Residencies with -SalvageRemote or -SalvageArchival\n");
1634                 return EINVAL;
1635             }
1636             code =
1637                 util_GetUInt32(as->parms[MRAFS_OFFSET + 17].items->data,
1638                                &mrafsParm.OptResidencies);
1639             if (code) {
1640                 printf("bos: '%s' is not a valid residency mask.\n",
1641                        as->parms[MRAFS_OFFSET + 13].items->data);
1642                 return code;
1643             }
1644         }
1645     } else {
1646         int stop = 0;
1647
1648         for (i = MRAFS_OFFSET; i < ADDPARMOFFSET; i++) {
1649             if (as->parms[i].items) {
1650                 printf(" %s only possible for MR-AFS fileserver.\n",
1651                        as->parms[i].name);
1652                 stop = 1;
1653             }
1654         }
1655         if (stop)
1656             exit(1);
1657     }
1658
1659     if (as->parms[4].items) {
1660         /* salvage whole enchilada */
1661         curGoal = GetServerGoal(tconn, serviceName);
1662         if (curGoal == BSTAT_NORMAL) {
1663             printf("bos: shutting down '%s'.\n", serviceName);
1664             code = BOZO_SetTStatus(tconn, serviceName, BSTAT_SHUTDOWN);
1665             if (code) {
1666                 printf("bos: failed to stop '%s' (%s)\n", serviceName, em(code));
1667                 return code;
1668             }
1669             code = BOZO_WaitAll(tconn); /* wait for shutdown to complete */
1670             if (code)
1671                 printf
1672                     ("bos: failed to wait for file server shutdown, continuing.\n");
1673         }
1674         /* now do the salvage operation */
1675         printf("Starting salvage.\n");
1676         rc = DoSalvage(tconn, NULL, NULL, outName, showlog, parallel, tmpDir,
1677                        orphans, dafs, &mrafsParm);
1678         if (curGoal == BSTAT_NORMAL) {
1679             printf("bos: restarting %s.\n", serviceName);
1680             code = BOZO_SetTStatus(tconn, serviceName, BSTAT_NORMAL);
1681             if (code) {
1682                 printf("bos: failed to restart '%s' (%s)\n", serviceName, em(code));
1683                 return code;
1684             }
1685         }
1686         if (rc)
1687             return rc;
1688     } else if (!as->parms[2].items) {
1689         if (!as->parms[1].items) {
1690             printf
1691                 ("bos: must specify -all switch to salvage all partitions.\n");
1692             return -1;
1693         }
1694         if (volutil_GetPartitionID(as->parms[1].items->data) < 0) {
1695             /* can't parse volume ID, so complain before shutting down
1696              * file server.
1697              */
1698             printf("bos: can't interpret %s as partition ID.\n",
1699                    as->parms[1].items->data);
1700             return -1;
1701         }
1702         curGoal = GetServerGoal(tconn, serviceName);
1703         /* salvage a whole partition (specified by parms[1]) */
1704         if (curGoal == BSTAT_NORMAL) {
1705             printf("bos: shutting down '%s'.\n", serviceName);
1706             code = BOZO_SetTStatus(tconn, serviceName, BSTAT_SHUTDOWN);
1707             if (code) {
1708                 printf("bos: can't stop '%s' (%s)\n", serviceName, em(code));
1709                 return code;
1710             }
1711             code = BOZO_WaitAll(tconn); /* wait for shutdown to complete */
1712             if (code)
1713                 printf
1714                     ("bos: failed to wait for file server shutdown, continuing.\n");
1715         }
1716         /* now do the salvage operation */
1717         printf("Starting salvage.\n");
1718         rc = DoSalvage(tconn, as->parms[1].items->data, NULL, outName,
1719                        showlog, parallel, tmpDir, orphans, dafs, &mrafsParm);
1720         if (curGoal == BSTAT_NORMAL) {
1721             printf("bos: restarting '%s'.\n", serviceName);
1722             code = BOZO_SetTStatus(tconn, serviceName, BSTAT_NORMAL);
1723             if (code) {
1724                 printf("bos: failed to restart '%s' (%s)\n", serviceName, em(code));
1725                 return code;
1726             }
1727         }
1728         if (rc)
1729             return rc;
1730     } else {
1731         /* salvage individual volume (don't shutdown fs first), just use
1732          * single-shot cron bnode.  Must leave server running when using this
1733          * option, since salvager will ask file server for the volume */
1734         char *tmpname;
1735         afs_int32 err;
1736         const char *confdir;
1737         int localauth;
1738
1739         if (as->parms[ADDPARMOFFSET].items)
1740             tmpname = as->parms[ADDPARMOFFSET].items->data;
1741         else
1742             tmpname = NULL;
1743
1744         localauth = (as->parms[ADDPARMOFFSET + 2].items != 0);
1745         confdir =
1746             (localauth ? AFSDIR_SERVER_ETC_DIRPATH :
1747              AFSDIR_CLIENT_ETC_DIRPATH);
1748         code = vsu_ClientInit( /* noauth */ 1, confdir, tmpname,
1749                               /* server auth */ 0, &cstruct, (int (*)())0);
1750         if (code == 0) {
1751             newID = vsu_GetVolumeID(as->parms[2].items->data, cstruct, &err);
1752             if (newID == 0) {
1753                 printf("bos: can't interpret %s as volume name or ID\n",
1754                        as->parms[2].items->data);
1755                 return -1;
1756             }
1757             sprintf(tname, "%u", newID);
1758         } else {
1759             printf
1760                 ("bos: can't initialize volume system client (code %d), trying anyway.\n",
1761                  code);
1762             strncpy(tname, as->parms[2].items->data, sizeof(tname));
1763         }
1764         if (volutil_GetPartitionID(as->parms[1].items->data) < 0) {
1765             /* can't parse volume ID, so complain before shutting down
1766              * file server.
1767              */
1768             printf("bos: can't interpret %s as partition ID.\n",
1769                    as->parms[1].items->data);
1770             return -1;
1771         }
1772         printf("Starting salvage.\n");
1773         rc = DoSalvage(tconn, as->parms[1].items->data, tname, outName,
1774                        showlog, parallel, tmpDir, orphans, dafs, &mrafsParm);
1775         if (rc)
1776             return rc;
1777     }
1778     return 0;
1779 }
1780
1781 static
1782 IStatServer(as, int32p)
1783      int int32p;
1784      register struct cmd_syndesc *as;
1785 {
1786     register struct rx_connection *tconn;
1787     register struct cmd_item *ti;
1788     int firstTime = 1;
1789
1790     tconn = GetConn(as, 0);
1791     for (ti = as->parms[1].items; ti; ti = ti->next) {
1792         DoStat(ti->data, tconn, int32p, firstTime);
1793         firstTime = 0;
1794     }
1795     return 0;
1796 }
1797
1798 static
1799 DoStat(aname, aconn, aint32p, firstTime)
1800      IN char *aname;
1801      IN register struct rx_connection *aconn;
1802      IN int aint32p;
1803      IN int firstTime;          /* true iff first instance in cmd */
1804 {
1805     afs_int32 temp;
1806     char buffer[500];
1807     register afs_int32 code;
1808     register afs_int32 i;
1809     struct bozo_status istatus;
1810     char *tp;
1811     char *is1, *is2, *is3, *is4;        /* instance strings */
1812
1813     tp = buffer;
1814     code = BOZO_GetInstanceInfo(aconn, aname, &tp, &istatus);
1815     if (code) {
1816         printf("bos: failed to get instance info for '%s' (%s)\n", aname,
1817                em(code));
1818         return -1;
1819     }
1820     if (firstTime && aint32p && (istatus.flags & BOZO_BADDIRACCESS))
1821         printf
1822             ("Bosserver reports inappropriate access on server directories\n");
1823     printf("Instance %s, ", aname);
1824     if (aint32p)
1825         printf("(type is %s) ", buffer);
1826     if (istatus.fileGoal == istatus.goal) {
1827         if (!istatus.goal)
1828             printf("disabled, ");
1829     } else {
1830         if (istatus.fileGoal)
1831             printf("temporarily disabled, ");
1832         else
1833             printf("temporarily enabled, ");
1834     }
1835
1836     if (istatus.flags & BOZO_ERRORSTOP)
1837         printf("stopped for too many errors, ");
1838     if (istatus.flags & BOZO_HASCORE)
1839         printf("has core file, ");
1840
1841     tp = buffer;
1842     code = BOZO_GetStatus(aconn, aname, &temp, &tp);
1843     if (code)
1844         printf("bos: failed to get status for instance '%s' (%s)\n", aname,
1845                em(code));
1846     else {
1847         printf("currently ");
1848         if (temp == BSTAT_NORMAL)
1849             printf("running normally.\n");
1850         else if (temp == BSTAT_SHUTDOWN)
1851             printf("shutdown.\n");
1852         else if (temp == BSTAT_STARTINGUP)
1853             printf("starting up.\n");
1854         else if (temp == BSTAT_SHUTTINGDOWN)
1855             printf("shutting down.\n");
1856         if (buffer[0] != 0) {
1857             printf("    Auxiliary status is: %s.\n", buffer);
1858         }
1859     }
1860
1861     /* are we done yet? */
1862     if (!aint32p)
1863         return 0;
1864
1865     if (istatus.procStartTime)
1866         printf("    Process last started at %s (%d proc starts)\n",
1867                DateOf(istatus.procStartTime), istatus.procStarts);
1868     if (istatus.lastAnyExit) {
1869         printf("    Last exit at %s\n", DateOf(istatus.lastAnyExit));
1870     }
1871     if (istatus.lastErrorExit) {
1872         is1 = is2 = is3 = is4 = NULL;
1873         printf("    Last error exit at %s, ", DateOf(istatus.lastErrorExit));
1874         code = BOZO_GetInstanceStrings(aconn, aname, &is1, &is2, &is3, &is4);
1875         /* don't complain about failing call, since could simply mean
1876          * interface mismatch.
1877          */
1878         if (code == 0) {
1879             if (*is1 != 0) {
1880                 /* non-null instance string */
1881                 printf("by %s, ", is1);
1882             }
1883             free(is1);
1884             free(is2);
1885             free(is3);
1886             free(is4);
1887         }
1888         if (istatus.errorSignal) {
1889             if (istatus.errorSignal == SIGTERM)
1890                 printf("due to shutdown request\n");
1891             else
1892                 printf("due to signal %d\n", istatus.errorSignal);
1893         } else
1894             printf("by exiting with code %d\n", istatus.errorCode);
1895     }
1896
1897     if (aint32p > 1) {
1898         /* try to display all the parms */
1899         for (i = 0;; i++) {
1900             tp = buffer;
1901             code = BOZO_GetInstanceParm(aconn, aname, i, &tp);
1902             if (code)
1903                 break;
1904             printf("    Command %d is '%s'\n", i + 1, buffer);
1905         }
1906         tp = buffer;
1907         code = BOZO_GetInstanceParm(aconn, aname, 999, &tp);
1908         if (!code) {
1909             /* Any type of failure is treated as not having a notifier program */
1910             printf("    Notifier  is '%s'\n", buffer);
1911         }
1912         printf("\n");
1913     }
1914     return 0;
1915 }
1916
1917 #ifdef BOS_RESTRICTED_MODE
1918 static
1919 GetRestrict(as)
1920      struct cmd_syndesc *as;
1921 {
1922     register struct rx_connection *tconn;
1923     afs_int32 code, val;
1924
1925     tconn = GetConn(as, 0);
1926     code = BOZO_GetRestrictedMode(tconn, &val);
1927     if (code)
1928         printf("bos: failed to get restricted mode (%s)\n", em(code));
1929     else
1930         printf("Restricted mode is %s\n", val ? "on" : "off");
1931
1932     return 0;
1933 }
1934
1935 static
1936 SetRestrict(as)
1937      struct cmd_syndesc *as;
1938 {
1939     register struct rx_connection *tconn;
1940     afs_int32 code, val;
1941
1942     tconn = GetConn(as, 0);
1943     util_GetInt32(as->parms[1].items->data, &val);
1944     code = BOZO_SetRestrictedMode(tconn, val);
1945     if (code)
1946         printf("bos: failed to set restricted mode (%s)\n", em(code));
1947     return 0;
1948 }
1949 #endif
1950
1951 static void
1952 add_std_args(ts)
1953      register struct cmd_syndesc *ts;
1954 {
1955     cmd_Seek(ts, ADDPARMOFFSET);
1956     /* + 0 */ cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");
1957     /* + 1 */ cmd_AddParm(ts, "-noauth", CMD_FLAG, CMD_OPTIONAL,
1958                           "don't authenticate");
1959     /* + 2 */ cmd_AddParm(ts, "-localauth", CMD_FLAG, CMD_OPTIONAL,
1960                           "create tickets from KeyFile");
1961 }
1962
1963 #include "AFS_component_version_number.c"
1964
1965 main(argc, argv)
1966      int argc;
1967      char **argv;
1968 {
1969     register afs_int32 code;
1970     register struct cmd_syndesc *ts;
1971     extern int afsconf_SawCell;
1972
1973 #ifdef  AFS_AIX32_ENV
1974     /*
1975      * The following signal action for AIX is necessary so that in case of a 
1976      * crash (i.e. core is generated) we can include the user's data section 
1977      * in the core dump. Unfortunately, by default, only a partial core is
1978      * generated which, in many cases, isn't too useful.
1979      */
1980     struct sigaction nsa;
1981
1982     sigemptyset(&nsa.sa_mask);
1983     nsa.sa_handler = SIG_DFL;
1984     nsa.sa_flags = SA_FULLDUMP;
1985     sigaction(SIGSEGV, &nsa, NULL);
1986     sigaction(SIGABRT, &nsa, NULL);
1987 #endif
1988
1989     /* start up rx */
1990     code = rx_Init(0);
1991     if (code) {
1992         printf("bos: could not initialize rx (%s)\n", em(code));
1993         exit(1);
1994     }
1995
1996     /* To resolve a AFSCELL environment "Note: ..." problem: Because bos calls ka_Init (why?) before any
1997      * checkup on the existance of a "-cell" option on the particular bos command we don't print the
1998      * message if a cell is passed in. Luckily the rest of the programs don't call these adhoc routines
1999      * and things work fine. Note that if the "-cell" isn't passed then we're still ok since later on
2000      * the proper routine (afsconf_GetCellInfo) is going to be called to do the right thing.
2001      */
2002     afsconf_SawCell = 1;        /* Means don't print warning if AFSCELL is set */
2003     ka_Init(0);
2004     afsconf_SawCell = 0;        /* Reset it */
2005     /* don't check error code, since fails sometimes when we're setting up a
2006      * system */
2007     initialize_CMD_error_table();
2008     initialize_BZ_error_table();
2009
2010     ts = cmd_CreateSyntax("start", StartServer, 0, "start running a server");
2011     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name");
2012     cmd_AddParm(ts, "-instance", CMD_LIST, 0, "server process name");
2013     add_std_args(ts);
2014
2015     ts = cmd_CreateSyntax("stop", StopServer, 0, "halt a server instance");
2016     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name");
2017     cmd_AddParm(ts, "-instance", CMD_LIST, 0, "server process name");
2018     cmd_Seek(ts, 8);
2019     cmd_AddParm(ts, "-wait", CMD_FLAG, CMD_OPTIONAL,
2020                 "wait for process to stop");
2021     add_std_args(ts);
2022
2023     ts = cmd_CreateSyntax("status", StatServer, 0,
2024                           "show server instance status");
2025     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name");
2026     cmd_AddParm(ts, "-instance", CMD_LIST, CMD_OPTIONAL,
2027                 "server process name");
2028     cmd_AddParm(ts, "-long", CMD_FLAG, CMD_OPTIONAL, "long status");
2029     add_std_args(ts);
2030
2031     ts = cmd_CreateSyntax("shutdown", Shutdown, 0, "shutdown all processes");
2032     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name");
2033     cmd_AddParm(ts, "-instance", CMD_LIST, CMD_OPTIONAL, "instances");
2034     cmd_Seek(ts, 8);
2035     cmd_AddParm(ts, "-wait", CMD_FLAG, CMD_OPTIONAL,
2036                 "wait for process to stop");
2037     add_std_args(ts);
2038
2039     ts = cmd_CreateSyntax("startup", Startup, 0, "start all processes");
2040     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name");
2041     cmd_AddParm(ts, "-instance", CMD_LIST, CMD_OPTIONAL, "instances");
2042     add_std_args(ts);
2043
2044     ts = cmd_CreateSyntax("restart", Restart, 0, "restart processes");
2045     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name");
2046     cmd_AddParm(ts, "-instance", CMD_LIST, CMD_OPTIONAL, "instances");
2047     cmd_AddParm(ts, "-bosserver", CMD_FLAG, CMD_OPTIONAL,
2048                 "restart bosserver");
2049     cmd_AddParm(ts, "-all", CMD_FLAG, CMD_OPTIONAL, "restart all processes");
2050     add_std_args(ts);
2051
2052 #ifndef OPBOS
2053
2054     ts = cmd_CreateSyntax("create", CreateServer, 0,
2055                           "create a new server instance");
2056     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name");
2057     cmd_AddParm(ts, "-instance", CMD_SINGLE, 0, "server process name");
2058     cmd_AddParm(ts, "-type", CMD_SINGLE, 0, "server type");
2059     cmd_AddParm(ts, "-cmd", CMD_LIST, 0, "command lines");
2060     cmd_AddParm(ts, "-notifier", CMD_SINGLE, CMD_OPTIONAL,
2061                 "Notifier program");
2062     add_std_args(ts);
2063
2064     ts = cmd_CreateSyntax("delete", DeleteServer, 0,
2065                           "delete a server instance");
2066     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name");
2067     cmd_AddParm(ts, "-instance", CMD_LIST, 0, "server process name");
2068     add_std_args(ts);
2069
2070     ts = cmd_CreateSyntax("adduser", AddSUser, 0,
2071                           "add users to super-user list");
2072     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name");
2073     cmd_AddParm(ts, "-user", CMD_LIST, 0, "user names");
2074     add_std_args(ts);
2075
2076     ts = cmd_CreateSyntax("removeuser", RemoveSUser, 0,
2077                           "remove users from super-user list");
2078     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name");
2079     cmd_AddParm(ts, "-user", CMD_LIST, 0, "user names");
2080     add_std_args(ts);
2081
2082     ts = cmd_CreateSyntax("listusers", ListSUsers, 0, "list super-users");
2083     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name");
2084     add_std_args(ts);
2085
2086     ts = cmd_CreateSyntax("addkey", AddKey, 0,
2087                           "add keys to key dbase (kvno 999 is bcrypt)");
2088     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name");
2089     cmd_AddParm(ts, "-key", CMD_SINGLE, CMD_OPTIONAL, "key");
2090     cmd_AddParm(ts, "-kvno", CMD_SINGLE, 0, "key version number");
2091     add_std_args(ts);
2092
2093     ts = cmd_CreateSyntax("removekey", RemoveKey, 0,
2094                           "remove keys from key dbase");
2095     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name");
2096     cmd_AddParm(ts, "-kvno", CMD_LIST, 0, "key version number");
2097     add_std_args(ts);
2098
2099     ts = cmd_CreateSyntax("listkeys", ListKeys, 0, "list keys");
2100     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name");
2101     cmd_AddParm(ts, "-showkey", CMD_FLAG, CMD_OPTIONAL,
2102                 "show the actual key rather than the checksum");
2103     add_std_args(ts);
2104
2105     ts = cmd_CreateSyntax("listhosts", ListHosts, 0, "get cell host list");
2106     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name");
2107     add_std_args(ts);
2108     cmd_CreateAlias(ts, "getcell");
2109
2110     ts = cmd_CreateSyntax("setcellname", SetCellName, 0, "set cell name");
2111     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name");
2112     cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "cell name");
2113     add_std_args(ts);
2114
2115     ts = cmd_CreateSyntax("addhost", AddHost, 0, "add host to cell dbase");
2116     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name");
2117     cmd_AddParm(ts, "-host", CMD_LIST, 0, "host name");
2118     cmd_AddParm(ts, "-clone", CMD_FLAG, CMD_OPTIONAL, "vote doesn't count");
2119     add_std_args(ts);
2120
2121     ts = cmd_CreateSyntax("removehost", RemoveHost, 0,
2122                           "remove host from cell dbase");
2123     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name");
2124     cmd_AddParm(ts, "-host", CMD_LIST, 0, "host name");
2125     add_std_args(ts);
2126
2127     ts = cmd_CreateSyntax("setauth", SetAuth, 0,
2128                           "set authentication required flag");
2129     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name");
2130     cmd_AddParm(ts, "-authrequired", CMD_SINGLE, 0,
2131                 "on or off: authentication required for admin requests");
2132     add_std_args(ts);
2133
2134     ts = cmd_CreateSyntax("install", Install, 0, "install program");
2135     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name");
2136     cmd_AddParm(ts, "-file", CMD_LIST, 0, "files to install");
2137     cmd_AddParm(ts, "-dir", CMD_SINGLE, CMD_OPTIONAL, "destination dir");
2138     add_std_args(ts);
2139
2140     ts = cmd_CreateSyntax("uninstall", UnInstall, 0, "uninstall program");
2141     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name");
2142     cmd_AddParm(ts, "-file", CMD_LIST, 0, "files to uninstall");
2143     cmd_AddParm(ts, "-dir", CMD_SINGLE, CMD_OPTIONAL, "destination dir");
2144     add_std_args(ts);
2145
2146     ts = cmd_CreateSyntax("getlog", GetLogCmd, 0, "examine log file");
2147     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name");
2148     cmd_AddParm(ts, "-file", CMD_SINGLE, 0, "log file to examine");
2149     add_std_args(ts);
2150
2151     ts = cmd_CreateSyntax("getdate", GetDate, 0, "get dates for programs");
2152     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name");
2153     cmd_AddParm(ts, "-file", CMD_LIST, 0, "files to check");
2154     cmd_AddParm(ts, "-dir", CMD_SINGLE, CMD_OPTIONAL, "destination dir");
2155     add_std_args(ts);
2156
2157     ts = cmd_CreateSyntax("exec", Exec, 0, "execute shell command on server");
2158     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name");
2159     cmd_AddParm(ts, "-cmd", CMD_SINGLE, 0, "command to execute");
2160     add_std_args(ts);
2161
2162     ts = cmd_CreateSyntax("prune", Prune, 0, "prune server files");
2163     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name");
2164     cmd_AddParm(ts, "-bak", CMD_FLAG, CMD_OPTIONAL, "delete .BAK files");
2165     cmd_AddParm(ts, "-old", CMD_FLAG, CMD_OPTIONAL, "delete .OLD files");
2166     cmd_AddParm(ts, "-core", CMD_FLAG, CMD_OPTIONAL, "delete core files");
2167     cmd_AddParm(ts, "-all", CMD_FLAG, CMD_OPTIONAL, "delete all junk files");
2168     add_std_args(ts);
2169
2170     ts = cmd_CreateSyntax("setrestart", SetRestartCmd, 0,
2171                           "set restart times");
2172     cmd_AddParm(ts, "-server", CMD_SINGLE, CMD_REQUIRED, "machine name");
2173     cmd_AddParm(ts, "-time", CMD_SINGLE, CMD_REQUIRED,
2174                 "time to restart server");
2175     cmd_AddParm(ts, "-general", CMD_FLAG, CMD_OPTIONAL,
2176                 "set general restart time");
2177     cmd_AddParm(ts, "-newbinary", CMD_FLAG, CMD_OPTIONAL,
2178                 "set new binary restart time");
2179     add_std_args(ts);
2180
2181     ts = cmd_CreateSyntax("getrestart", GetRestartCmd, 0,
2182                           "get restart times");
2183     cmd_AddParm(ts, "-server", CMD_SINGLE, CMD_REQUIRED, "machine name");
2184     add_std_args(ts);
2185
2186     ts = cmd_CreateSyntax("salvage", SalvageCmd, 0,
2187                           "salvage partition or volumes");
2188     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name");
2189     cmd_AddParm(ts, "-partition", CMD_SINGLE, CMD_OPTIONAL,
2190                 "salvage partition");
2191     cmd_AddParm(ts, "-volume", CMD_SINGLE, CMD_OPTIONAL,
2192                 "salvage volume number or volume name");
2193     cmd_AddParm(ts, "-file", CMD_SINGLE, CMD_OPTIONAL,
2194                 "salvage log output file");
2195     cmd_AddParm(ts, "-all", CMD_FLAG, CMD_OPTIONAL, "salvage whole server");
2196     cmd_AddParm(ts, "-showlog", CMD_FLAG, CMD_OPTIONAL,
2197                 "display salvage log");
2198     cmd_AddParm(ts, "-parallel", CMD_SINGLE, CMD_OPTIONAL,
2199                 "# of max parallel partition salvaging");
2200     cmd_AddParm(ts, "-tmpdir", CMD_SINGLE, CMD_OPTIONAL,
2201                 "directory to place tmp files");
2202     cmd_AddParm(ts, "-orphans", CMD_SINGLE, CMD_OPTIONAL,
2203                 "ignore | remove | attach");
2204     cmd_AddParm(ts, "-forceDAFS", CMD_FLAG, CMD_OPTIONAL,
2205                 "(DAFS) force salvage of demand attach fileserver");
2206     cmd_AddParm(ts, "-debug", CMD_FLAG, CMD_OPTIONAL,
2207                 "(MR-AFS) Run in Debugging mode");
2208     cmd_AddParm(ts, "-nowrite", CMD_FLAG, CMD_OPTIONAL,
2209                 "(MR-AFS) Run readonly/test mode");
2210     cmd_AddParm(ts, "-force", CMD_FLAG, CMD_OPTIONAL,
2211                 "(MR-AFS) Force full salvaging");
2212     cmd_AddParm(ts, "-oktozap", CMD_FLAG, CMD_OPTIONAL,
2213                 "(MR-AFS) Give permission to destroy bogus file residencies/volumes - debugging flag");
2214     cmd_AddParm(ts, "-rootfiles", CMD_FLAG, CMD_OPTIONAL,
2215                 "(MR-AFS) Show files owned by root - debugging flag");
2216     cmd_AddParm(ts, "-salvagedirs", CMD_FLAG, CMD_OPTIONAL,
2217                 "(MR-AFS) Force rebuild/salvage of all directories");
2218     cmd_AddParm(ts, "-blockreads", CMD_FLAG, CMD_OPTIONAL,
2219                 "(MR-AFS) Read smaller blocks to handle IO/bad blocks");
2220     cmd_AddParm(ts, "-ListResidencies", CMD_FLAG, CMD_OPTIONAL,
2221                 "(MR-AFS) Just list affected file residencies - debugging flag");
2222     cmd_AddParm(ts, "-SalvageRemote", CMD_FLAG, CMD_OPTIONAL,
2223                 "(MR-AFS) Salvage storage systems that are not directly attached");
2224     cmd_AddParm(ts, "-SalvageArchival", CMD_FLAG, CMD_OPTIONAL,
2225                 "(MR-AFS) Salvage HSM storage systems");
2226     cmd_AddParm(ts, "-IgnoreCheck", CMD_FLAG, CMD_OPTIONAL,
2227                 "(MR-AFS) Don't perform VLDB safety check when deleting unreferenced files.  Only a good idea in single server cell.");
2228     cmd_AddParm(ts, "-ForceOnLine", CMD_FLAG, CMD_OPTIONAL,
2229                 "(MR-AFS) Force the volume to come online, even if it hasn't salvaged cleanly.");
2230     cmd_AddParm(ts, "-UseRootDirACL", CMD_FLAG, CMD_OPTIONAL,
2231                 "(MR-AFS) Use the root directory ACL for lost+found directory if it is created.");
2232     cmd_AddParm(ts, "-TraceBadLinkCounts", CMD_FLAG, CMD_OPTIONAL,
2233                 "(MR-AFS) Print out lines about volume reference count changes.");
2234     cmd_AddParm(ts, "-DontAskFS", CMD_FLAG, CMD_OPTIONAL,
2235                 "(MR-AFS) Don't ask fileserver to take volume offline.  THIS IS VERY DANGEROUS.");
2236     cmd_AddParm(ts, "-LogLevel", CMD_SINGLE, CMD_OPTIONAL,
2237                 "(MR-AFS) log level");
2238     cmd_AddParm(ts, "-rxdebug", CMD_FLAG, CMD_OPTIONAL,
2239                 "(MR-AFS) Write out rx debug information.");
2240     cmd_AddParm(ts, "-Residencies", CMD_SINGLE, CMD_OPTIONAL,
2241                 "(MR-AFS) Numeric mask of residencies to be included in the salvage.  Do not use with -SalvageRemote or -SalvageArchival");
2242     add_std_args(ts);
2243
2244     ts = cmd_CreateSyntax("blockscanner", BlockScannerCmd, 0,
2245                           "block scanner daemon from making migration requests");
2246     cmd_AddParm(ts, "-server", CMD_SINGLE, CMD_REQUIRED, "machine name");
2247     add_std_args(ts);
2248
2249     ts = cmd_CreateSyntax("unblockscanner", UnBlockScannerCmd, 0,
2250                           "allow scanner daemon to make migration requests again");
2251     cmd_AddParm(ts, "-server", CMD_SINGLE, CMD_REQUIRED, "machine name");
2252     add_std_args(ts);
2253
2254 #ifdef BOS_RESTRICTED_MODE
2255     ts = cmd_CreateSyntax("getrestricted", GetRestrict, 0,
2256                           "get restrict mode");
2257     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name");
2258     add_std_args(ts);
2259
2260     ts = cmd_CreateSyntax("setrestricted", SetRestrict, 0,
2261                           "set restrict mode");
2262     cmd_AddParm(ts, "-server", CMD_SINGLE, 0, "machine name");
2263     cmd_AddParm(ts, "-mode", CMD_SINGLE, 0, "mode to set");
2264     add_std_args(ts);
2265 #endif
2266 #endif
2267
2268     code = cmd_Dispatch(argc, argv);
2269     rx_Finalize();
2270     exit(code);
2271 }