bozo: retry start after error stops
[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 20 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 20 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
670     if ((abnode->b.flags & BNODE_ERRORSTOP) && !abnode->salRunning
671         && !abnode->volRunning && !abnode->fileRunning && !abnode->scanRunning
672         && !abnode->salsrvRunning) {
673         bnode_SetStat(bn, BSTAT_NORMAL);
674     }
675     else {
676         bnode_ResetErrorCount(bn);
677     }
678
679     SetNeedsClock(abnode);
680     return 0;
681 }
682
683 static int
684 fs_getstat(struct bnode *bn, afs_int32 * astatus)
685 {
686     struct fsbnode *abnode = (struct fsbnode *) bn;
687
688     afs_int32 temp;
689     if (abnode->volSDW || abnode->fileSDW || abnode->salSDW
690         || abnode->scanSDW || abnode->salsrvSDW)
691         temp = BSTAT_SHUTTINGDOWN;
692     else if (abnode->salRunning)
693         temp = BSTAT_NORMAL;
694     else if (abnode->volRunning && abnode->fileRunning
695              && (!abnode->scancmd || abnode->scanRunning)
696              && (!abnode->salsrvcmd || abnode->salsrvRunning))
697         temp = BSTAT_NORMAL;
698     else if (!abnode->salRunning && !abnode->volRunning
699              && !abnode->fileRunning && !abnode->scanRunning
700              && !abnode->salsrvRunning)
701         temp = BSTAT_SHUTDOWN;
702     else
703         temp = BSTAT_STARTINGUP;
704     *astatus = temp;
705     return 0;
706 }
707
708 static int
709 fs_setstat(struct bnode *abnode, afs_int32 astatus)
710 {
711     return NudgeProcs((struct fsbnode *) abnode);
712 }
713
714 static int
715 fs_procstarted(struct bnode *bn, struct bnode_proc *aproc)
716 {
717     int code = 0;
718
719     if (DoPidFiles) {
720         code = bozo_CreatePidFile(bn->name, aproc->coreName, aproc->pid);
721     }
722     return code;
723 }
724
725 static int
726 fs_procexit(struct bnode *bn, struct bnode_proc *aproc)
727 {
728    struct fsbnode *abnode = (struct fsbnode *)bn;
729
730     /* process has exited */
731
732     if (DoPidFiles) {
733         bozo_DeletePidFile(bn->name, aproc->coreName);
734     }
735
736     if (aproc == abnode->volProc) {
737         abnode->volProc = 0;
738         abnode->volRunning = 0;
739         abnode->volSDW = 0;
740         abnode->volKillSent = 0;
741     } else if (aproc == abnode->fileProc) {
742         /* if we were expecting a shutdown and we didn't send a kill signal
743          * and exited (didn't have a signal termination), then we assume that
744          * the file server exited after putting the appropriate volumes safely
745          * offline, and don't salvage next time.
746          */
747         if (abnode->fileSDW && !abnode->fileKillSent
748             && aproc->lastSignal == 0)
749             SetSalFlag(abnode, 0);      /* shut down normally */
750         abnode->fileProc = 0;
751         abnode->fileRunning = 0;
752         abnode->fileSDW = 0;
753         abnode->fileKillSent = 0;
754     } else if (aproc == abnode->salProc) {
755         /* if we didn't shutdown the salvager, then assume it exited ok, and thus
756          * that we don't have to salvage again */
757         if (!abnode->salSDW)
758             SetSalFlag(abnode, 0);      /* salvage just completed */
759         abnode->salProc = 0;
760         abnode->salRunning = 0;
761         abnode->salSDW = 0;
762         abnode->salKillSent = 0;
763     } else if (aproc == abnode->scanProc) {
764         abnode->scanProc = 0;
765         abnode->scanRunning = 0;
766         abnode->scanSDW = 0;
767         abnode->scanKillSent = 0;
768     } else if (aproc == abnode->salsrvProc) {
769         abnode->salsrvProc = 0;
770         abnode->salsrvRunning = 0;
771         abnode->salsrvSDW = 0;
772         abnode->salsrvKillSent = 0;
773     }
774
775     /* now restart anyone who needs to restart */
776     return NudgeProcs(abnode);
777 }
778
779 /* make sure we're periodically checking the state if we need to */
780 static void
781 SetNeedsClock(struct fsbnode *ab)
782 {
783     afs_int32 timeout = POLLTIME;
784
785     if (ab->b.goal == 1 && ab->fileRunning && ab->volRunning
786         && (!ab->scancmd || ab->scanRunning)
787         && (!ab->salsrvcmd || ab->salsrvRunning)) {
788         if (ab->b.errorStopCount) {
789             /* reset error count after running for a bit */
790             ab->needsClock = 1;
791         } else {
792             ab->needsClock = 0; /* running normally */
793         }
794     } else if ((ab->b.goal == 0) && !ab->fileRunning && !ab->volRunning
795                && !ab->salRunning && !ab->scanRunning && !ab->salsrvRunning) {
796         if (ab->b.flags & BNODE_ERRORSTOP && ab->b.errorStopDelay) {
797             bozo_Log("%s will retry start in %d seconds\n", ab->b.name,
798                      ab->b.errorStopDelay);
799             ab->needsClock = 1; /* halted for errors, retry later */
800             timeout = ab->b.errorStopDelay;
801         } else {
802             ab->needsClock = 0; /* halted normally */
803         }
804     } else
805         ab->needsClock = 1;     /* other */
806
807     if (ab->needsClock && (!bnode_PendingTimeout(fsbnode2bnode(ab))
808                            || ab->b.period != timeout))
809         bnode_SetTimeout(fsbnode2bnode(ab), timeout);
810     if (!ab->needsClock)
811         bnode_SetTimeout(fsbnode2bnode(ab), 0);
812 }
813
814 static int
815 NudgeProcs(struct fsbnode *abnode)
816 {
817     struct bnode_proc *tp;      /* not register */
818     afs_int32 code;
819     afs_int32 now;
820
821     now = FT_ApproxTime();
822     if (abnode->b.goal == 1) {
823         /* we're trying to run the system. If the file server is running, then we
824          * are trying to start up the system.  If it is not running, then needsSalvage
825          * tells us if we need to run the salvager or not */
826         if (abnode->fileRunning) {
827             if (abnode->salRunning) {
828                 bozo_Log("Salvager running along with file server!\n");
829                 bozo_Log("Emergency shutdown\n");
830                 emergency = 1;
831                 bnode_SetGoal(fsbnode2bnode(abnode), BSTAT_SHUTDOWN);
832                 bnode_StopProc(abnode->salProc, SIGKILL);
833                 SetNeedsClock(abnode);
834                 return -1;
835             }
836             if (!abnode->volRunning) {
837                 abnode->lastVolStart = FT_ApproxTime();
838                 code = bnode_NewProc(fsbnode2bnode(abnode), abnode->volcmd, "vol", &tp);
839                 if (code == 0) {
840                     abnode->volProc = tp;
841                     abnode->volRunning = 1;
842                 }
843             }
844             if (abnode->salsrvcmd) {
845                 if (!abnode->salsrvRunning) {
846                     abnode->lastSalsrvStart = FT_ApproxTime();
847                     code =
848                         bnode_NewProc(fsbnode2bnode(abnode), abnode->salsrvcmd, "salsrv",
849                                       &tp);
850                     if (code == 0) {
851                         abnode->salsrvProc = tp;
852                         abnode->salsrvRunning = 1;
853                     }
854                 }
855             }
856             if (abnode->scancmd) {
857                 if (!abnode->scanRunning) {
858                     abnode->lastScanStart = FT_ApproxTime();
859                     code =
860                         bnode_NewProc(fsbnode2bnode(abnode), abnode->scancmd, "scanner",
861                                       &tp);
862                     if (code == 0) {
863                         abnode->scanProc = tp;
864                         abnode->scanRunning = 1;
865                     }
866                 }
867             }
868         } else {                /* file is not running */
869             /* see how to start */
870             /* for demand attach fs, needsSalvage flag is ignored */
871             if (!abnode->needsSalvage || abnode->salsrvcmd) {
872                 /* no crash apparent, just start up normally */
873                 if (!abnode->fileRunning) {
874                     abnode->lastFileStart = FT_ApproxTime();
875                     code =
876                         bnode_NewProc(fsbnode2bnode(abnode), abnode->filecmd, "file", &tp);
877                     if (code == 0) {
878                         abnode->fileProc = tp;
879                         abnode->fileRunning = 1;
880                         SetSalFlag(abnode, 1);
881                     }
882                 }
883                 if (!abnode->volRunning) {
884                     abnode->lastVolStart = FT_ApproxTime();
885                     code = bnode_NewProc(fsbnode2bnode(abnode), abnode->volcmd, "vol", &tp);
886                     if (code == 0) {
887                         abnode->volProc = tp;
888                         abnode->volRunning = 1;
889                     }
890                 }
891                 if (abnode->salsrvcmd && !abnode->salsrvRunning) {
892                     abnode->lastSalsrvStart = FT_ApproxTime();
893                     code =
894                         bnode_NewProc(fsbnode2bnode(abnode), abnode->salsrvcmd, "salsrv",
895                                       &tp);
896                     if (code == 0) {
897                         abnode->salsrvProc = tp;
898                         abnode->salsrvRunning = 1;
899                     }
900                 }
901                 if (abnode->scancmd && !abnode->scanRunning) {
902                     abnode->lastScanStart = FT_ApproxTime();
903                     code =
904                         bnode_NewProc(fsbnode2bnode(abnode), abnode->scancmd, "scanner",
905                                       &tp);
906                     if (code == 0) {
907                         abnode->scanProc = tp;
908                         abnode->scanRunning = 1;
909                     }
910                 }
911             } else {            /* needs to be salvaged */
912                 /* make sure file server and volser are gone */
913                 if (abnode->volRunning) {
914                     bnode_StopProc(abnode->volProc, SIGTERM);
915                     if (!abnode->volSDW)
916                         abnode->timeSDStarted = now;
917                     abnode->volSDW = 1;
918                 }
919                 if (abnode->fileRunning) {
920                     bnode_StopProc(abnode->fileProc, SIGQUIT);
921                     if (!abnode->fileSDW)
922                         abnode->timeSDStarted = now;
923                     abnode->fileSDW = 1;
924                 }
925                 if (abnode->scanRunning) {
926                     bnode_StopProc(abnode->scanProc, SIGTERM);
927                     if (!abnode->scanSDW)
928                         abnode->timeSDStarted = now;
929                     abnode->scanSDW = 1;
930                 }
931                 if (abnode->volRunning || abnode->fileRunning
932                     || abnode->scanRunning)
933                     return 0;
934                 /* otherwise, it is safe to start salvager */
935                 if (!abnode->salRunning) {
936                     code = bnode_NewProc(fsbnode2bnode(abnode), abnode->salcmd, "salv", &tp);
937                     if (code == 0) {
938                         abnode->salProc = tp;
939                         abnode->salRunning = 1;
940                     }
941                 }
942             }
943         }
944     } else {                    /* goal is 0, we're shutting down */
945         /* trying to shutdown */
946         if (abnode->salRunning && !abnode->salSDW) {
947             bnode_StopProc(abnode->salProc, SIGTERM);
948             abnode->salSDW = 1;
949             abnode->timeSDStarted = now;
950         }
951         if (abnode->fileRunning && !abnode->fileSDW) {
952             bnode_StopProc(abnode->fileProc, SIGQUIT);
953             abnode->fileSDW = 1;
954             abnode->timeSDStarted = now;
955         }
956         if (abnode->volRunning && !abnode->volSDW) {
957             bnode_StopProc(abnode->volProc, SIGTERM);
958             abnode->volSDW = 1;
959             abnode->timeSDStarted = now;
960         }
961         if (abnode->salsrvRunning && !abnode->salsrvSDW) {
962             bnode_StopProc(abnode->salsrvProc, SIGTERM);
963             abnode->salsrvSDW = 1;
964             abnode->timeSDStarted = now;
965         }
966         if (abnode->scanRunning && !abnode->scanSDW) {
967             bnode_StopProc(abnode->scanProc, SIGTERM);
968             abnode->scanSDW = 1;
969             abnode->timeSDStarted = now;
970         }
971     }
972     SetNeedsClock(abnode);
973     return 0;
974 }
975
976 static int
977 fs_getstring(struct bnode *bn, char *abuffer, afs_int32 alen)
978 {
979     struct fsbnode *abnode = (struct fsbnode *)bn;
980
981     if (alen < 40)
982         return -1;
983     if (abnode->b.goal == 1) {
984         if (abnode->fileRunning) {
985             if (abnode->fileSDW)
986                 strcpy(abuffer, "file server shutting down");
987             else if (abnode->scancmd) {
988                 if (!abnode->volRunning && !abnode->scanRunning)
989                     strcpy(abuffer,
990                            "file server up; volser and scanner down");
991                 else if (abnode->volRunning && !abnode->scanRunning)
992                     strcpy(abuffer,
993                            "file server up; volser up; scanner down");
994                 else if (!abnode->volRunning && abnode->scanRunning)
995                     strcpy(abuffer,
996                            "file server up; volser down; scanner up");
997
998                 else
999                     strcpy(abuffer, "file server running");
1000             } else if (!abnode->volRunning)
1001                 strcpy(abuffer, "file server up; volser down");
1002             else
1003                 strcpy(abuffer, "file server running");
1004         } else if (abnode->salRunning) {
1005             strcpy(abuffer, "salvaging file system");
1006         } else
1007             strcpy(abuffer, "starting file server");
1008     } else {
1009         /* shutting down */
1010         if (abnode->fileRunning || abnode->volRunning || abnode->scanRunning) {
1011             strcpy(abuffer, "file server shutting down");
1012         } else if (abnode->salRunning)
1013             strcpy(abuffer, "salvager shutting down");
1014         else
1015             strcpy(abuffer, "file server shut down");
1016     }
1017     return 0;
1018 }
1019
1020 static int
1021 fs_getparm(struct bnode *bn, afs_int32 aindex, char *abuffer,
1022            afs_int32 alen)
1023 {
1024     struct fsbnode *abnode = (struct fsbnode *)bn;
1025
1026     if (aindex == 0)
1027         strcpy(abuffer, abnode->filecmd);
1028     else if (aindex == 1)
1029         strcpy(abuffer, abnode->volcmd);
1030     else if (aindex == 2)
1031         strcpy(abuffer, abnode->salcmd);
1032     else if (aindex == 3 && abnode->scancmd)
1033         strcpy(abuffer, abnode->scancmd);
1034     else
1035         return BZDOM;
1036     return 0;
1037 }
1038
1039 static int
1040 dafs_getparm(struct bnode *bn, afs_int32 aindex, char *abuffer,
1041              afs_int32 alen)
1042 {
1043     struct fsbnode *abnode = (struct fsbnode *)bn;
1044
1045     if (aindex == 0)
1046         strcpy(abuffer, abnode->filecmd);
1047     else if (aindex == 1)
1048         strcpy(abuffer, abnode->volcmd);
1049     else if (aindex == 2)
1050         strcpy(abuffer, abnode->salsrvcmd);
1051     else if (aindex == 3)
1052         strcpy(abuffer, abnode->salcmd);
1053     else if (aindex == 4 && abnode->scancmd)
1054         strcpy(abuffer, abnode->scancmd);
1055     else
1056         return BZDOM;
1057     return 0;
1058 }