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