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