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