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