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