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