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