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