bozo: bosserver man page updates
[openafs.git] / src / bozo / fsbnodeops.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 #include <afs/procmgmt.h>
14 #include <roken.h>
15 #include <afs/opr.h>
16
17 #include <lwp.h>
18 #include <rx/rx.h>
19 #include <afs/afsutil.h>
20
21 #include "bnode.h"
22 #include "bosprototypes.h"
23
24 extern char *DoPidFiles;
25 static int emergency = 0;
26
27 /* if this file exists, then we have to salvage the file system */
28 #define SALFILE     "SALVAGE."
29
30 #define POLLTIME        20      /* for handling below */
31 #define SDTIME          60      /* time in seconds given to a process to evaporate */
32
33 /*  basic rules:
34     Normal operation involves having the file server and the vol server both running.
35
36     If the vol server terminates, it can simply be restarted.
37
38     If the file server terminates, the disk must salvaged before the file server
39     can be restarted.  In order to restart either the file server or the salvager,
40     the vol server must be shut down.
41
42     If the file server terminates *normally* (exits after receiving a SIGQUIT)
43     then we don't have to salvage it.
44
45     The needsSalvage flag is set when the file server is started.  It is cleared
46     if the file server exits when fileSDW is true but fileKillSent is false,
47     indicating that it exited after receiving a quit, but before we sent it a kill.
48
49     The needsSalvage flag is cleared when the salvager exits.
50 */
51
52 struct fsbnode {
53     struct bnode b;
54     afs_int32 timeSDStarted;    /* time shutdown operation started */
55     char *filecmd;              /* command to start primary file server */
56     char *volcmd;               /* command to start secondary vol server */
57     char *salsrvcmd;            /* command to start salvageserver (demand attach fs) */
58     char *salcmd;               /* command to start salvager */
59     char *scancmd;              /* command to start scanner (MR-AFS) */
60     struct bnode_proc *fileProc;        /* process for file server */
61     struct bnode_proc *volProc; /* process for vol server */
62     struct bnode_proc *salsrvProc;      /* process for salvageserver (demand attach fs) */
63     struct bnode_proc *salProc; /* process for salvager */
64     struct bnode_proc *scanProc;        /* process for scanner (MR-AFS) */
65     afs_int32 lastFileStart;    /* last start for file */
66     afs_int32 lastVolStart;     /* last start for vol */
67     afs_int32 lastSalsrvStart;  /* last start for salvageserver (demand attach fs) */
68     afs_int32 lastScanStart;    /* last start for scanner (MR-AFS) */
69     char fileRunning;           /* file process is running */
70     char volRunning;            /* volser is running */
71     char salsrvRunning;         /* salvageserver is running (demand attach fs) */
72     char salRunning;            /* salvager is running */
73     char scanRunning;           /* scanner is running (MR_AFS) */
74     char fileSDW;               /* file shutdown wait */
75     char volSDW;                /* vol shutdown wait */
76     char salsrvSDW;             /* salvageserver shutdown wait (demand attach fs) */
77     char salSDW;                /* waiting for the salvager to shutdown */
78     char scanSDW;               /* scanner shutdown wait (MR_AFS) */
79     char fileKillSent;          /* kill signal has been sent */
80     char volKillSent;
81     char salsrvKillSent;        /* kill signal has been sent (demand attach fs) */
82     char salKillSent;
83     char scanKillSent;          /* kill signal has been sent (MR_AFS) */
84     char needsSalvage;          /* salvage before running */
85     char needsClock;            /* do we need clock ticks */
86 };
87
88 struct bnode * fs_create(char *ainstance, char *afilecmd, char *avolcmd,
89                          char *asalcmd, char *ascancmd, char *dummy);
90 struct bnode * dafs_create(char *ainstance, char *afilecmd, char *avolcmd,
91                            char * asalsrvcmd, char *asalcmd, char *ascancmd);
92
93 static int fs_hascore(struct bnode *abnode);
94 static int fs_restartp(struct bnode *abnode);
95 static int fs_delete(struct bnode *abnode);
96 static int fs_timeout(struct bnode *abnode);
97 static int fs_getstat(struct bnode *abnode, afs_int32 * astatus);
98 static int fs_setstat(struct bnode *abnode, afs_int32 astatus);
99 static int fs_procstarted(struct bnode *abnode, struct bnode_proc *aproc);
100 static int fs_procexit(struct bnode *abnode, struct bnode_proc *aproc);
101 static int fs_getstring(struct bnode *abnode, char *abuffer, afs_int32 alen);
102 static int fs_getparm(struct bnode *abnode, afs_int32 aindex,
103                       char *abuffer, afs_int32 alen);
104 static int dafs_getparm(struct bnode *abnode, afs_int32 aindex,
105                         char *abuffer, afs_int32 alen);
106
107 static int SetSalFlag(struct fsbnode *abnode, int aflag);
108 static int RestoreSalFlag(struct fsbnode *abnode);
109 static void SetNeedsClock(struct fsbnode *);
110 static int NudgeProcs(struct fsbnode *);
111
112 #ifdef AFS_NT40_ENV
113 static void AppendExecutableExtension(char *cmd);
114 #else
115 #define AppendExecutableExtension(x)
116 #endif
117
118 struct bnode_ops fsbnode_ops = {
119     fs_create,
120     fs_timeout,
121     fs_getstat,
122     fs_setstat,
123     fs_delete,
124     fs_procexit,
125     fs_getstring,
126     fs_getparm,
127     fs_restartp,
128     fs_hascore,
129     fs_procstarted,
130 };
131
132 /* demand attach fs bnode ops */
133 struct bnode_ops dafsbnode_ops = {
134     dafs_create,
135     fs_timeout,
136     fs_getstat,
137     fs_setstat,
138     fs_delete,
139     fs_procexit,
140     fs_getstring,
141     dafs_getparm,
142     fs_restartp,
143     fs_hascore,
144     fs_procstarted,
145 };
146
147 /* Quick inline function to safely convert a fsbnode to a bnode without
148  * dropping type information
149  */
150
151 static_inline struct bnode *
152 fsbnode2bnode(struct fsbnode *abnode) {
153     return (struct bnode *) abnode;
154 }
155
156 /* Function to tell whether this bnode has a core file or not.  You might
157  * think that this could be in bnode.c, and decide what core files to check
158  * for based on the bnode's coreName property, but that doesn't work because
159  * there may not be an active process for a bnode that dumped core at the
160  * time the query is done.
161  */
162 static int
163 fs_hascore(struct bnode *abnode)
164 {
165     char tbuffer[256];
166
167     /* see if file server has a core file */
168     bnode_CoreName(abnode, "file", tbuffer);
169     if (access(tbuffer, 0) == 0)
170         return 1;
171
172     /* see if volserver has a core file */
173     bnode_CoreName(abnode, "vol", tbuffer);
174     if (access(tbuffer, 0) == 0)
175         return 1;
176
177     /* see if salvageserver left a core file */
178     bnode_CoreName(abnode, "salsrv", tbuffer);
179     if (access(tbuffer, 0) == 0)
180         return 1;
181
182     /* see if salvager left a core file */
183     bnode_CoreName(abnode, "salv", tbuffer);
184     if (access(tbuffer, 0) == 0)
185         return 1;
186
187     /* see if scanner left a core file (MR-AFS) */
188     bnode_CoreName(abnode, "scan", tbuffer);
189     if (access(tbuffer, 0) == 0)
190         return 1;
191
192     /* no one left a core file */
193     return 0;
194 }
195
196 static int
197 fs_restartp(struct bnode *bn)
198 {
199     struct fsbnode *abnode = (struct fsbnode *)bn;
200     struct bnode_token *tt;
201     afs_int32 code;
202     struct stat tstat;
203
204     code = bnode_ParseLine(abnode->filecmd, &tt);
205     if (code)
206         return 0;
207     if (!tt)
208         return 0;
209     code = stat(tt->key, &tstat);
210     if (code) {
211         bnode_FreeTokens(tt);
212         return 0;
213     }
214     if (tstat.st_ctime > abnode->lastFileStart)
215         code = 1;
216     else
217         code = 0;
218     bnode_FreeTokens(tt);
219     if (code)
220         return code;
221
222     /* now do same for volcmd */
223     code = bnode_ParseLine(abnode->volcmd, &tt);
224     if (code)
225         return 0;
226     if (!tt)
227         return 0;
228     code = stat(tt->key, &tstat);
229     if (code) {
230         bnode_FreeTokens(tt);
231         return 0;
232     }
233     if (tstat.st_ctime > abnode->lastVolStart)
234         code = 1;
235     else
236         code = 0;
237     bnode_FreeTokens(tt);
238     if (code)
239         return code;
240
241     if (abnode->salsrvcmd) {    /* only in demand attach fs */
242         /* now do same for salsrvcmd (demand attach fs) */
243         code = bnode_ParseLine(abnode->salsrvcmd, &tt);
244         if (code)
245             return 0;
246         if (!tt)
247             return 0;
248         code = stat(tt->key, &tstat);
249         if (code) {
250             bnode_FreeTokens(tt);
251             return 0;
252         }
253         if (tstat.st_ctime > abnode->lastSalsrvStart)
254             code = 1;
255         else
256             code = 0;
257         bnode_FreeTokens(tt);
258     }
259
260     if (abnode->scancmd) {      /* Only in MR-AFS */
261         /* now do same for scancmd (MR-AFS) */
262         code = bnode_ParseLine(abnode->scancmd, &tt);
263         if (code)
264             return 0;
265         if (!tt)
266             return 0;
267         code = stat(tt->key, &tstat);
268         if (code) {
269             bnode_FreeTokens(tt);
270             return 0;
271         }
272         if (tstat.st_ctime > abnode->lastScanStart)
273             code = 1;
274         else
275             code = 0;
276         bnode_FreeTokens(tt);
277     }
278
279     return code;
280 }
281
282 /* set needsSalvage flag, creating file SALVAGE.<instancename> if
283     we need to salvage the file system (so we can tell over panic reboots */
284 static int
285 SetSalFlag(struct fsbnode *abnode, int aflag)
286 {
287     char tbuffer[AFSDIR_PATH_MAX];
288     int fd;
289
290     /* don't use the salvage flag for demand attach fs */
291     if (abnode->salsrvcmd == NULL) {
292         abnode->needsSalvage = aflag;
293         strcompose(tbuffer, AFSDIR_PATH_MAX, AFSDIR_SERVER_LOCAL_DIRPATH, "/",
294                    SALFILE, abnode->b.name, NULL);
295         if (aflag) {
296             fd = open(tbuffer, O_CREAT | O_TRUNC | O_RDWR, 0666);
297             close(fd);
298         } else {
299             unlink(tbuffer);
300         }
301     }
302     return 0;
303 }
304
305 /* set the needsSalvage flag according to the existence of the salvage file */
306 static int
307 RestoreSalFlag(struct fsbnode *abnode)
308 {
309     char tbuffer[AFSDIR_PATH_MAX];
310
311     /* never set needs salvage flag for demand attach fs */
312     if (abnode->salsrvcmd != NULL) {
313         abnode->needsSalvage = 0;
314     } else {
315         strcompose(tbuffer, AFSDIR_PATH_MAX, AFSDIR_SERVER_LOCAL_DIRPATH, "/",
316                    SALFILE, abnode->b.name, NULL);
317         if (access(tbuffer, 0) == 0) {
318             /* file exists, so need to salvage */
319             abnode->needsSalvage = 1;
320         } else {
321             abnode->needsSalvage = 0;
322         }
323     }
324     return 0;
325 }
326
327 char *
328 copystr(char *a)
329 {
330     char *b;
331     b = (char *)malloc(strlen(a) + 1);
332     strcpy(b, a);
333     return b;
334 }
335
336 static int
337 fs_delete(struct bnode *bn)
338 {
339     struct fsbnode *abnode = (struct fsbnode *)bn;
340
341     free(abnode->filecmd);
342     free(abnode->volcmd);
343     free(abnode->salcmd);
344     if (abnode->salsrvcmd)
345         free(abnode->salsrvcmd);
346     if (abnode->scancmd)
347         free(abnode->scancmd);
348     free(abnode);
349     return 0;
350 }
351
352
353 #ifdef AFS_NT40_ENV
354 static void
355 AppendExecutableExtension(char *cmd)
356 {
357     char cmdext[_MAX_EXT];
358
359     _splitpath(cmd, NULL, NULL, NULL, cmdext);
360     if (*cmdext == '\0') {
361         /* no filename extension supplied for cmd; append .exe */
362         strcat(cmd, ".exe");
363     }
364 }
365 #endif /* AFS_NT40_ENV */
366
367
368 struct bnode *
369 fs_create(char *ainstance, char *afilecmd, char *avolcmd, char *asalcmd,
370           char *ascancmd, char *dummy)
371 {
372     struct stat tstat;
373     struct fsbnode *te;
374     char cmdname[AFSDIR_PATH_MAX];
375     char *fileCmdpath, *volCmdpath, *salCmdpath, *scanCmdpath;
376     int bailout = 0;
377
378     fileCmdpath = volCmdpath = salCmdpath = scanCmdpath = NULL;
379     te = NULL;
380
381     /* construct local paths from canonical (wire-format) paths */
382     if (ConstructLocalBinPath(afilecmd, &fileCmdpath)) {
383         bozo_Log("BNODE: command path invalid '%s'\n", afilecmd);
384         bailout = 1;
385         goto done;
386     }
387     if (ConstructLocalBinPath(avolcmd, &volCmdpath)) {
388         bozo_Log("BNODE: command path invalid '%s'\n", avolcmd);
389         bailout = 1;
390         goto done;
391     }
392     if (ConstructLocalBinPath(asalcmd, &salCmdpath)) {
393         bozo_Log("BNODE: command path invalid '%s'\n", asalcmd);
394         bailout = 1;
395         goto done;
396     }
397
398     if (ascancmd && strlen(ascancmd)) {
399         if (ConstructLocalBinPath(ascancmd, &scanCmdpath)) {
400             bozo_Log("BNODE: command path invalid '%s'\n", ascancmd);
401             bailout = 1;
402             goto done;
403         }
404     }
405
406     if (!bailout) {
407         sscanf(fileCmdpath, "%s", cmdname);
408         AppendExecutableExtension(cmdname);
409         if (stat(cmdname, &tstat)) {
410             bozo_Log("BNODE: file server binary '%s' not found\n", cmdname);
411             bailout = 1;
412             goto done;
413         }
414
415         sscanf(volCmdpath, "%s", cmdname);
416         AppendExecutableExtension(cmdname);
417         if (stat(cmdname, &tstat)) {
418             bozo_Log("BNODE: volume server binary '%s' not found\n", cmdname);
419             bailout = 1;
420             goto done;
421         }
422
423         sscanf(salCmdpath, "%s", cmdname);
424         AppendExecutableExtension(cmdname);
425         if (stat(cmdname, &tstat)) {
426             bozo_Log("BNODE: salvager binary '%s' not found\n", cmdname);
427             bailout = 1;
428             goto done;
429         }
430
431         if (ascancmd && strlen(ascancmd)) {
432             sscanf(scanCmdpath, "%s", cmdname);
433             AppendExecutableExtension(cmdname);
434             if (stat(cmdname, &tstat)) {
435                 bozo_Log("BNODE: scanner binary '%s' not found\n", cmdname);
436                 bailout = 1;
437                 goto done;
438             }
439         }
440     }
441
442     te = (struct fsbnode *)malloc(sizeof(struct fsbnode));
443     if (te == NULL) {
444         bailout = 1;
445         goto done;
446     }
447     memset(te, 0, sizeof(struct fsbnode));
448     te->filecmd = fileCmdpath;
449     te->volcmd = volCmdpath;
450     te->salsrvcmd = NULL;
451     te->salcmd = salCmdpath;
452     if (ascancmd && strlen(ascancmd))
453         te->scancmd = scanCmdpath;
454     else
455         te->scancmd = NULL;
456     if (bnode_InitBnode(fsbnode2bnode(te), &fsbnode_ops, ainstance) != 0) {
457         bailout = 1;
458         goto done;
459     }
460     bnode_SetTimeout(fsbnode2bnode(te), POLLTIME);
461                 /* ask for timeout activations every 10 seconds */
462     RestoreSalFlag(te);         /* restore needsSalvage flag based on file's existence */
463     SetNeedsClock(te);          /* compute needsClock field */
464
465  done:
466     if (bailout) {
467         if (te)
468             free(te);
469         if (fileCmdpath)
470             free(fileCmdpath);
471         if (volCmdpath)
472             free(volCmdpath);
473         if (salCmdpath)
474             free(salCmdpath);
475         if (scanCmdpath)
476             free(scanCmdpath);
477         return NULL;
478     }
479
480     return fsbnode2bnode(te);
481 }
482
483 /* create a demand attach fs bnode */
484 struct bnode *
485 dafs_create(char *ainstance, char *afilecmd, char *avolcmd,
486             char * asalsrvcmd, char *asalcmd, char *ascancmd)
487 {
488     struct stat tstat;
489     struct fsbnode *te;
490     char cmdname[AFSDIR_PATH_MAX];
491     char *fileCmdpath, *volCmdpath, *salsrvCmdpath, *salCmdpath, *scanCmdpath;
492     int bailout = 0;
493
494     fileCmdpath = volCmdpath = salsrvCmdpath = salCmdpath = scanCmdpath = NULL;
495     te = NULL;
496
497     /* construct local paths from canonical (wire-format) paths */
498     if (ConstructLocalBinPath(afilecmd, &fileCmdpath)) {
499         bozo_Log("BNODE: command path invalid '%s'\n", afilecmd);
500         bailout = 1;
501         goto done;
502     }
503     if (ConstructLocalBinPath(avolcmd, &volCmdpath)) {
504         bozo_Log("BNODE: command path invalid '%s'\n", avolcmd);
505         bailout = 1;
506         goto done;
507     }
508     if (ConstructLocalBinPath(asalsrvcmd, &salsrvCmdpath)) {
509         bozo_Log("BNODE: command path invalid '%s'\n", asalsrvcmd);
510         bailout = 1;
511         goto done;
512     }
513     if (ConstructLocalBinPath(asalcmd, &salCmdpath)) {
514         bozo_Log("BNODE: command path invalid '%s'\n", asalcmd);
515         bailout = 1;
516         goto done;
517     }
518
519     if (ascancmd && strlen(ascancmd)) {
520         if (ConstructLocalBinPath(ascancmd, &scanCmdpath)) {
521             bozo_Log("BNODE: command path invalid '%s'\n", ascancmd);
522             bailout = 1;
523             goto done;
524         }
525     }
526
527     if (!bailout) {
528         sscanf(fileCmdpath, "%s", cmdname);
529         AppendExecutableExtension(cmdname);
530         if (stat(cmdname, &tstat)) {
531             bozo_Log("BNODE: file server binary '%s' not found\n", cmdname);
532             bailout = 1;
533             goto done;
534         }
535
536         sscanf(volCmdpath, "%s", cmdname);
537         AppendExecutableExtension(cmdname);
538         if (stat(cmdname, &tstat)) {
539             bozo_Log("BNODE: volume server binary '%s' not found\n", cmdname);
540             bailout = 1;
541             goto done;
542         }
543
544         sscanf(salsrvCmdpath, "%s", cmdname);
545         AppendExecutableExtension(cmdname);
546         if (stat(cmdname, &tstat)) {
547             bozo_Log("BNODE: salvageserver binary '%s' not found\n", cmdname);
548             bailout = 1;
549             goto done;
550         }
551
552         sscanf(salCmdpath, "%s", cmdname);
553         AppendExecutableExtension(cmdname);
554         if (stat(cmdname, &tstat)) {
555             bozo_Log("BNODE: salvager binary '%s' not found\n", cmdname);
556             bailout = 1;
557             goto done;
558         }
559
560         if (ascancmd && strlen(ascancmd)) {
561             sscanf(scanCmdpath, "%s", cmdname);
562             AppendExecutableExtension(cmdname);
563             if (stat(cmdname, &tstat)) {
564                 bozo_Log("BNODE: scanner binary '%s' not found\n", cmdname);
565                 bailout = 1;
566                 goto done;
567             }
568         }
569     }
570
571     te = (struct fsbnode *)malloc(sizeof(struct fsbnode));
572     if (te == NULL) {
573         bailout = 1;
574         goto done;
575     }
576     memset(te, 0, sizeof(struct fsbnode));
577     te->filecmd = fileCmdpath;
578     te->volcmd = volCmdpath;
579     te->salsrvcmd = salsrvCmdpath;
580     te->salcmd = salCmdpath;
581     if (ascancmd && strlen(ascancmd))
582         te->scancmd = scanCmdpath;
583     else
584         te->scancmd = NULL;
585     if (bnode_InitBnode(fsbnode2bnode(te), &dafsbnode_ops, ainstance) != 0) {
586         bailout = 1;
587         goto done;
588     }
589     bnode_SetTimeout(fsbnode2bnode(te), POLLTIME);
590                 /* ask for timeout activations every 10 seconds */
591     RestoreSalFlag(te);         /* restore needsSalvage flag based on file's existence */
592     SetNeedsClock(te);          /* compute needsClock field */
593
594  done:
595     if (bailout) {
596         if (te)
597             free(te);
598         if (fileCmdpath)
599             free(fileCmdpath);
600         if (volCmdpath)
601             free(volCmdpath);
602         if (salsrvCmdpath)
603             free(salsrvCmdpath);
604         if (salCmdpath)
605             free(salCmdpath);
606         if (scanCmdpath)
607             free(scanCmdpath);
608         return NULL;
609     }
610
611     return fsbnode2bnode(te);
612 }
613
614 /* called to SIGKILL a process if it doesn't terminate normally */
615 static int
616 fs_timeout(struct bnode *bn)
617 {
618     struct fsbnode *abnode = (struct fsbnode *)bn;
619
620     afs_int32 now;
621
622     now = FT_ApproxTime();
623     /* shutting down */
624     if (abnode->volSDW) {
625         if (!abnode->volKillSent && now - abnode->timeSDStarted > SDTIME) {
626             bnode_StopProc(abnode->volProc, SIGKILL);
627             abnode->volKillSent = 1;
628             bozo_Log
629                 ("bos shutdown: volserver failed to shutdown within %d seconds\n",
630                  SDTIME);
631         }
632     }
633     if (abnode->salSDW) {
634         if (!abnode->salKillSent && now - abnode->timeSDStarted > SDTIME) {
635             bnode_StopProc(abnode->salProc, SIGKILL);
636             abnode->salKillSent = 1;
637             bozo_Log
638                 ("bos shutdown: salvager failed to shutdown within %d seconds\n",
639                  SDTIME);
640         }
641     }
642     if (abnode->fileSDW) {
643         if (!abnode->fileKillSent && now - abnode->timeSDStarted > FSSDTIME) {
644             bnode_StopProc(abnode->fileProc, SIGKILL);
645             abnode->fileKillSent = 1;
646             bozo_Log
647                 ("bos shutdown: fileserver failed to shutdown within %d seconds\n",
648                  FSSDTIME);
649         }
650     }
651     if (abnode->salsrvSDW) {
652         if (!abnode->salsrvKillSent && now - abnode->timeSDStarted > SDTIME) {
653             bnode_StopProc(abnode->salsrvProc, SIGKILL);
654             abnode->salsrvKillSent = 1;
655             bozo_Log
656                 ("bos shutdown: salvageserver failed to shutdown within %d seconds\n",
657                  SDTIME);
658         }
659     }
660     if (abnode->scanSDW) {
661         if (!abnode->scanKillSent && now - abnode->timeSDStarted > SDTIME) {
662             bnode_StopProc(abnode->scanProc, SIGKILL);
663             abnode->scanKillSent = 1;
664             bozo_Log
665                 ("bos shutdown: scanner failed to shutdown within %d seconds\n",
666                  SDTIME);
667         }
668     }
669     SetNeedsClock(abnode);
670     return 0;
671 }
672
673 static int
674 fs_getstat(struct bnode *bn, afs_int32 * astatus)
675 {
676     struct fsbnode *abnode = (struct fsbnode *) bn;
677
678     afs_int32 temp;
679     if (abnode->volSDW || abnode->fileSDW || abnode->salSDW
680         || abnode->scanSDW || abnode->salsrvSDW)
681         temp = BSTAT_SHUTTINGDOWN;
682     else if (abnode->salRunning)
683         temp = BSTAT_NORMAL;
684     else if (abnode->volRunning && abnode->fileRunning
685              && (!abnode->scancmd || abnode->scanRunning)
686              && (!abnode->salsrvcmd || abnode->salsrvRunning))
687         temp = BSTAT_NORMAL;
688     else if (!abnode->salRunning && !abnode->volRunning
689              && !abnode->fileRunning && !abnode->scanRunning
690              && !abnode->salsrvRunning)
691         temp = BSTAT_SHUTDOWN;
692     else
693         temp = BSTAT_STARTINGUP;
694     *astatus = temp;
695     return 0;
696 }
697
698 static int
699 fs_setstat(struct bnode *abnode, afs_int32 astatus)
700 {
701     return NudgeProcs((struct fsbnode *) abnode);
702 }
703
704 static int
705 fs_procstarted(struct bnode *bn, struct bnode_proc *aproc)
706 {
707     int code = 0;
708
709     if (DoPidFiles) {
710         code = bozo_CreatePidFile(bn->name, aproc->coreName, aproc->pid);
711     }
712     return code;
713 }
714
715 static int
716 fs_procexit(struct bnode *bn, struct bnode_proc *aproc)
717 {
718    struct fsbnode *abnode = (struct fsbnode *)bn;
719
720     /* process has exited */
721
722     if (DoPidFiles) {
723         bozo_DeletePidFile(bn->name, aproc->coreName);
724     }
725
726     if (aproc == abnode->volProc) {
727         abnode->volProc = 0;
728         abnode->volRunning = 0;
729         abnode->volSDW = 0;
730         abnode->volKillSent = 0;
731     } else if (aproc == abnode->fileProc) {
732         /* if we were expecting a shutdown and we didn't send a kill signal
733          * and exited (didn't have a signal termination), then we assume that
734          * the file server exited after putting the appropriate volumes safely
735          * offline, and don't salvage next time.
736          */
737         if (abnode->fileSDW && !abnode->fileKillSent
738             && aproc->lastSignal == 0)
739             SetSalFlag(abnode, 0);      /* shut down normally */
740         abnode->fileProc = 0;
741         abnode->fileRunning = 0;
742         abnode->fileSDW = 0;
743         abnode->fileKillSent = 0;
744     } else if (aproc == abnode->salProc) {
745         /* if we didn't shutdown the salvager, then assume it exited ok, and thus
746          * that we don't have to salvage again */
747         if (!abnode->salSDW)
748             SetSalFlag(abnode, 0);      /* salvage just completed */
749         abnode->salProc = 0;
750         abnode->salRunning = 0;
751         abnode->salSDW = 0;
752         abnode->salKillSent = 0;
753     } else if (aproc == abnode->scanProc) {
754         abnode->scanProc = 0;
755         abnode->scanRunning = 0;
756         abnode->scanSDW = 0;
757         abnode->scanKillSent = 0;
758     } else if (aproc == abnode->salsrvProc) {
759         abnode->salsrvProc = 0;
760         abnode->salsrvRunning = 0;
761         abnode->salsrvSDW = 0;
762         abnode->salsrvKillSent = 0;
763     }
764
765     /* now restart anyone who needs to restart */
766     return NudgeProcs(abnode);
767 }
768
769 /* make sure we're periodically checking the state if we need to */
770 static void
771 SetNeedsClock(struct fsbnode *ab)
772 {
773     if (ab->b.goal == 1 && ab->fileRunning && ab->volRunning
774         && (!ab->scancmd || ab->scanRunning)
775         && (!ab->salsrvcmd || ab->salsrvRunning))
776         ab->needsClock = 0;     /* running normally */
777     else if (ab->b.goal == 0 && !ab->fileRunning && !ab->volRunning
778              && !ab->salRunning && !ab->scanRunning && !ab->salsrvRunning)
779         ab->needsClock = 0;     /* halted normally */
780     else
781         ab->needsClock = 1;     /* other */
782     if (ab->needsClock && !bnode_PendingTimeout(fsbnode2bnode(ab)))
783         bnode_SetTimeout(fsbnode2bnode(ab), POLLTIME);
784     if (!ab->needsClock)
785         bnode_SetTimeout(fsbnode2bnode(ab), 0);
786 }
787
788 static int
789 NudgeProcs(struct fsbnode *abnode)
790 {
791     struct bnode_proc *tp;      /* not register */
792     afs_int32 code;
793     afs_int32 now;
794
795     now = FT_ApproxTime();
796     if (abnode->b.goal == 1) {
797         /* we're trying to run the system. If the file server is running, then we
798          * are trying to start up the system.  If it is not running, then needsSalvage
799          * tells us if we need to run the salvager or not */
800         if (abnode->fileRunning) {
801             if (abnode->salRunning) {
802                 bozo_Log("Salvager running along with file server!\n");
803                 bozo_Log("Emergency shutdown\n");
804                 emergency = 1;
805                 bnode_SetGoal(fsbnode2bnode(abnode), BSTAT_SHUTDOWN);
806                 bnode_StopProc(abnode->salProc, SIGKILL);
807                 SetNeedsClock(abnode);
808                 return -1;
809             }
810             if (!abnode->volRunning) {
811                 abnode->lastVolStart = FT_ApproxTime();
812                 code = bnode_NewProc(fsbnode2bnode(abnode), abnode->volcmd, "vol", &tp);
813                 if (code == 0) {
814                     abnode->volProc = tp;
815                     abnode->volRunning = 1;
816                 }
817             }
818             if (abnode->salsrvcmd) {
819                 if (!abnode->salsrvRunning) {
820                     abnode->lastSalsrvStart = FT_ApproxTime();
821                     code =
822                         bnode_NewProc(fsbnode2bnode(abnode), abnode->salsrvcmd, "salsrv",
823                                       &tp);
824                     if (code == 0) {
825                         abnode->salsrvProc = tp;
826                         abnode->salsrvRunning = 1;
827                     }
828                 }
829             }
830             if (abnode->scancmd) {
831                 if (!abnode->scanRunning) {
832                     abnode->lastScanStart = FT_ApproxTime();
833                     code =
834                         bnode_NewProc(fsbnode2bnode(abnode), abnode->scancmd, "scanner",
835                                       &tp);
836                     if (code == 0) {
837                         abnode->scanProc = tp;
838                         abnode->scanRunning = 1;
839                     }
840                 }
841             }
842         } else {                /* file is not running */
843             /* see how to start */
844             /* for demand attach fs, needsSalvage flag is ignored */
845             if (!abnode->needsSalvage || abnode->salsrvcmd) {
846                 /* no crash apparent, just start up normally */
847                 if (!abnode->fileRunning) {
848                     abnode->lastFileStart = FT_ApproxTime();
849                     code =
850                         bnode_NewProc(fsbnode2bnode(abnode), abnode->filecmd, "file", &tp);
851                     if (code == 0) {
852                         abnode->fileProc = tp;
853                         abnode->fileRunning = 1;
854                         SetSalFlag(abnode, 1);
855                     }
856                 }
857                 if (!abnode->volRunning) {
858                     abnode->lastVolStart = FT_ApproxTime();
859                     code = bnode_NewProc(fsbnode2bnode(abnode), abnode->volcmd, "vol", &tp);
860                     if (code == 0) {
861                         abnode->volProc = tp;
862                         abnode->volRunning = 1;
863                     }
864                 }
865                 if (abnode->salsrvcmd && !abnode->salsrvRunning) {
866                     abnode->lastSalsrvStart = FT_ApproxTime();
867                     code =
868                         bnode_NewProc(fsbnode2bnode(abnode), abnode->salsrvcmd, "salsrv",
869                                       &tp);
870                     if (code == 0) {
871                         abnode->salsrvProc = tp;
872                         abnode->salsrvRunning = 1;
873                     }
874                 }
875                 if (abnode->scancmd && !abnode->scanRunning) {
876                     abnode->lastScanStart = FT_ApproxTime();
877                     code =
878                         bnode_NewProc(fsbnode2bnode(abnode), abnode->scancmd, "scanner",
879                                       &tp);
880                     if (code == 0) {
881                         abnode->scanProc = tp;
882                         abnode->scanRunning = 1;
883                     }
884                 }
885             } else {            /* needs to be salvaged */
886                 /* make sure file server and volser are gone */
887                 if (abnode->volRunning) {
888                     bnode_StopProc(abnode->volProc, SIGTERM);
889                     if (!abnode->volSDW)
890                         abnode->timeSDStarted = now;
891                     abnode->volSDW = 1;
892                 }
893                 if (abnode->fileRunning) {
894                     bnode_StopProc(abnode->fileProc, SIGQUIT);
895                     if (!abnode->fileSDW)
896                         abnode->timeSDStarted = now;
897                     abnode->fileSDW = 1;
898                 }
899                 if (abnode->scanRunning) {
900                     bnode_StopProc(abnode->scanProc, SIGTERM);
901                     if (!abnode->scanSDW)
902                         abnode->timeSDStarted = now;
903                     abnode->scanSDW = 1;
904                 }
905                 if (abnode->volRunning || abnode->fileRunning
906                     || abnode->scanRunning)
907                     return 0;
908                 /* otherwise, it is safe to start salvager */
909                 if (!abnode->salRunning) {
910                     code = bnode_NewProc(fsbnode2bnode(abnode), abnode->salcmd, "salv", &tp);
911                     if (code == 0) {
912                         abnode->salProc = tp;
913                         abnode->salRunning = 1;
914                     }
915                 }
916             }
917         }
918     } else {                    /* goal is 0, we're shutting down */
919         /* trying to shutdown */
920         if (abnode->salRunning && !abnode->salSDW) {
921             bnode_StopProc(abnode->salProc, SIGTERM);
922             abnode->salSDW = 1;
923             abnode->timeSDStarted = now;
924         }
925         if (abnode->fileRunning && !abnode->fileSDW) {
926             bnode_StopProc(abnode->fileProc, SIGQUIT);
927             abnode->fileSDW = 1;
928             abnode->timeSDStarted = now;
929         }
930         if (abnode->volRunning && !abnode->volSDW) {
931             bnode_StopProc(abnode->volProc, SIGTERM);
932             abnode->volSDW = 1;
933             abnode->timeSDStarted = now;
934         }
935         if (abnode->salsrvRunning && !abnode->salsrvSDW) {
936             bnode_StopProc(abnode->salsrvProc, SIGTERM);
937             abnode->salsrvSDW = 1;
938             abnode->timeSDStarted = now;
939         }
940         if (abnode->scanRunning && !abnode->scanSDW) {
941             bnode_StopProc(abnode->scanProc, SIGTERM);
942             abnode->scanSDW = 1;
943             abnode->timeSDStarted = now;
944         }
945     }
946     SetNeedsClock(abnode);
947     return 0;
948 }
949
950 static int
951 fs_getstring(struct bnode *bn, char *abuffer, afs_int32 alen)
952 {
953     struct fsbnode *abnode = (struct fsbnode *)bn;
954
955     if (alen < 40)
956         return -1;
957     if (abnode->b.goal == 1) {
958         if (abnode->fileRunning) {
959             if (abnode->fileSDW)
960                 strcpy(abuffer, "file server shutting down");
961             else if (abnode->scancmd) {
962                 if (!abnode->volRunning && !abnode->scanRunning)
963                     strcpy(abuffer,
964                            "file server up; volser and scanner down");
965                 else if (abnode->volRunning && !abnode->scanRunning)
966                     strcpy(abuffer,
967                            "file server up; volser up; scanner down");
968                 else if (!abnode->volRunning && abnode->scanRunning)
969                     strcpy(abuffer,
970                            "file server up; volser down; scanner up");
971
972                 else
973                     strcpy(abuffer, "file server running");
974             } else if (!abnode->volRunning)
975                 strcpy(abuffer, "file server up; volser down");
976             else
977                 strcpy(abuffer, "file server running");
978         } else if (abnode->salRunning) {
979             strcpy(abuffer, "salvaging file system");
980         } else
981             strcpy(abuffer, "starting file server");
982     } else {
983         /* shutting down */
984         if (abnode->fileRunning || abnode->volRunning || abnode->scanRunning) {
985             strcpy(abuffer, "file server shutting down");
986         } else if (abnode->salRunning)
987             strcpy(abuffer, "salvager shutting down");
988         else
989             strcpy(abuffer, "file server shut down");
990     }
991     return 0;
992 }
993
994 static int
995 fs_getparm(struct bnode *bn, afs_int32 aindex, char *abuffer,
996            afs_int32 alen)
997 {
998     struct fsbnode *abnode = (struct fsbnode *)bn;
999
1000     if (aindex == 0)
1001         strcpy(abuffer, abnode->filecmd);
1002     else if (aindex == 1)
1003         strcpy(abuffer, abnode->volcmd);
1004     else if (aindex == 2)
1005         strcpy(abuffer, abnode->salcmd);
1006     else if (aindex == 3 && abnode->scancmd)
1007         strcpy(abuffer, abnode->scancmd);
1008     else
1009         return BZDOM;
1010     return 0;
1011 }
1012
1013 static int
1014 dafs_getparm(struct bnode *bn, afs_int32 aindex, char *abuffer,
1015              afs_int32 alen)
1016 {
1017     struct fsbnode *abnode = (struct fsbnode *)bn;
1018
1019     if (aindex == 0)
1020         strcpy(abuffer, abnode->filecmd);
1021     else if (aindex == 1)
1022         strcpy(abuffer, abnode->volcmd);
1023     else if (aindex == 2)
1024         strcpy(abuffer, abnode->salsrvcmd);
1025     else if (aindex == 3)
1026         strcpy(abuffer, abnode->salcmd);
1027     else if (aindex == 4 && abnode->scancmd)
1028         strcpy(abuffer, abnode->scancmd);
1029     else
1030         return BZDOM;
1031     return 0;
1032 }