e93a6d7324c6f3fe5c33d80dbac618e77f205d68
[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, (char *)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, (char *)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 static int
328 fs_delete(struct bnode *bn)
329 {
330     struct fsbnode *abnode = (struct fsbnode *)bn;
331
332     free(abnode->filecmd);
333     free(abnode->volcmd);
334     free(abnode->salcmd);
335     if (abnode->salsrvcmd)
336         free(abnode->salsrvcmd);
337     if (abnode->scancmd)
338         free(abnode->scancmd);
339     free(abnode);
340     return 0;
341 }
342
343
344 #ifdef AFS_NT40_ENV
345 static void
346 AppendExecutableExtension(char *cmd)
347 {
348     char cmdext[_MAX_EXT];
349
350     _splitpath(cmd, NULL, NULL, NULL, cmdext);
351     if (*cmdext == '\0') {
352         /* no filename extension supplied for cmd; append .exe */
353         strcat(cmd, ".exe");
354     }
355 }
356 #endif /* AFS_NT40_ENV */
357
358
359 struct bnode *
360 fs_create(char *ainstance, char *afilecmd, char *avolcmd, char *asalcmd,
361           char *ascancmd, char *dummy)
362 {
363     struct stat tstat;
364     struct fsbnode *te;
365     char cmdname[AFSDIR_PATH_MAX];
366     char *fileCmdpath, *volCmdpath, *salCmdpath, *scanCmdpath;
367     int bailout = 0;
368
369     fileCmdpath = volCmdpath = salCmdpath = scanCmdpath = NULL;
370     te = NULL;
371
372     /* construct local paths from canonical (wire-format) paths */
373     if (ConstructLocalBinPath(afilecmd, &fileCmdpath)) {
374         bozo_Log("BNODE: command path invalid '%s'\n", afilecmd);
375         bailout = 1;
376         goto done;
377     }
378     if (ConstructLocalBinPath(avolcmd, &volCmdpath)) {
379         bozo_Log("BNODE: command path invalid '%s'\n", avolcmd);
380         bailout = 1;
381         goto done;
382     }
383     if (ConstructLocalBinPath(asalcmd, &salCmdpath)) {
384         bozo_Log("BNODE: command path invalid '%s'\n", asalcmd);
385         bailout = 1;
386         goto done;
387     }
388
389     if (ascancmd && strlen(ascancmd)) {
390         if (ConstructLocalBinPath(ascancmd, &scanCmdpath)) {
391             bozo_Log("BNODE: command path invalid '%s'\n", ascancmd);
392             bailout = 1;
393             goto done;
394         }
395     }
396
397     if (!bailout) {
398         sscanf(fileCmdpath, "%s", cmdname);
399         AppendExecutableExtension(cmdname);
400         if (stat(cmdname, &tstat)) {
401             bozo_Log("BNODE: file server binary '%s' not found\n", cmdname);
402             bailout = 1;
403             goto done;
404         }
405
406         sscanf(volCmdpath, "%s", cmdname);
407         AppendExecutableExtension(cmdname);
408         if (stat(cmdname, &tstat)) {
409             bozo_Log("BNODE: volume server binary '%s' not found\n", cmdname);
410             bailout = 1;
411             goto done;
412         }
413
414         sscanf(salCmdpath, "%s", cmdname);
415         AppendExecutableExtension(cmdname);
416         if (stat(cmdname, &tstat)) {
417             bozo_Log("BNODE: salvager binary '%s' not found\n", cmdname);
418             bailout = 1;
419             goto done;
420         }
421
422         if (ascancmd && strlen(ascancmd)) {
423             sscanf(scanCmdpath, "%s", cmdname);
424             AppendExecutableExtension(cmdname);
425             if (stat(cmdname, &tstat)) {
426                 bozo_Log("BNODE: scanner binary '%s' not found\n", cmdname);
427                 bailout = 1;
428                 goto done;
429             }
430         }
431     }
432
433     te = calloc(1, sizeof(struct fsbnode));
434     if (te == NULL) {
435         bailout = 1;
436         goto done;
437     }
438     te->filecmd = fileCmdpath;
439     te->volcmd = volCmdpath;
440     te->salsrvcmd = NULL;
441     te->salcmd = salCmdpath;
442     if (ascancmd && strlen(ascancmd))
443         te->scancmd = scanCmdpath;
444     else
445         te->scancmd = NULL;
446     if (bnode_InitBnode(fsbnode2bnode(te), &fsbnode_ops, ainstance) != 0) {
447         bailout = 1;
448         goto done;
449     }
450     bnode_SetTimeout(fsbnode2bnode(te), POLLTIME);
451                 /* ask for timeout activations every 20 seconds */
452     RestoreSalFlag(te);         /* restore needsSalvage flag based on file's existence */
453     SetNeedsClock(te);          /* compute needsClock field */
454
455  done:
456     if (bailout) {
457         if (te)
458             free(te);
459         if (fileCmdpath)
460             free(fileCmdpath);
461         if (volCmdpath)
462             free(volCmdpath);
463         if (salCmdpath)
464             free(salCmdpath);
465         if (scanCmdpath)
466             free(scanCmdpath);
467         return NULL;
468     }
469
470     return fsbnode2bnode(te);
471 }
472
473 /* create a demand attach fs bnode */
474 struct bnode *
475 dafs_create(char *ainstance, char *afilecmd, char *avolcmd,
476             char * asalsrvcmd, char *asalcmd, char *ascancmd)
477 {
478     struct stat tstat;
479     struct fsbnode *te;
480     char cmdname[AFSDIR_PATH_MAX];
481     char *fileCmdpath, *volCmdpath, *salsrvCmdpath, *salCmdpath, *scanCmdpath;
482     int bailout = 0;
483
484     fileCmdpath = volCmdpath = salsrvCmdpath = salCmdpath = scanCmdpath = NULL;
485     te = NULL;
486
487     /* construct local paths from canonical (wire-format) paths */
488     if (ConstructLocalBinPath(afilecmd, &fileCmdpath)) {
489         bozo_Log("BNODE: command path invalid '%s'\n", afilecmd);
490         bailout = 1;
491         goto done;
492     }
493     if (ConstructLocalBinPath(avolcmd, &volCmdpath)) {
494         bozo_Log("BNODE: command path invalid '%s'\n", avolcmd);
495         bailout = 1;
496         goto done;
497     }
498     if (ConstructLocalBinPath(asalsrvcmd, &salsrvCmdpath)) {
499         bozo_Log("BNODE: command path invalid '%s'\n", asalsrvcmd);
500         bailout = 1;
501         goto done;
502     }
503     if (ConstructLocalBinPath(asalcmd, &salCmdpath)) {
504         bozo_Log("BNODE: command path invalid '%s'\n", asalcmd);
505         bailout = 1;
506         goto done;
507     }
508
509     if (ascancmd && strlen(ascancmd)) {
510         if (ConstructLocalBinPath(ascancmd, &scanCmdpath)) {
511             bozo_Log("BNODE: command path invalid '%s'\n", ascancmd);
512             bailout = 1;
513             goto done;
514         }
515     }
516
517     if (!bailout) {
518         sscanf(fileCmdpath, "%s", cmdname);
519         AppendExecutableExtension(cmdname);
520         if (stat(cmdname, &tstat)) {
521             bozo_Log("BNODE: file server binary '%s' not found\n", cmdname);
522             bailout = 1;
523             goto done;
524         }
525
526         sscanf(volCmdpath, "%s", cmdname);
527         AppendExecutableExtension(cmdname);
528         if (stat(cmdname, &tstat)) {
529             bozo_Log("BNODE: volume server binary '%s' not found\n", cmdname);
530             bailout = 1;
531             goto done;
532         }
533
534         sscanf(salsrvCmdpath, "%s", cmdname);
535         AppendExecutableExtension(cmdname);
536         if (stat(cmdname, &tstat)) {
537             bozo_Log("BNODE: salvageserver binary '%s' not found\n", cmdname);
538             bailout = 1;
539             goto done;
540         }
541
542         sscanf(salCmdpath, "%s", cmdname);
543         AppendExecutableExtension(cmdname);
544         if (stat(cmdname, &tstat)) {
545             bozo_Log("BNODE: salvager binary '%s' not found\n", cmdname);
546             bailout = 1;
547             goto done;
548         }
549
550         if (ascancmd && strlen(ascancmd)) {
551             sscanf(scanCmdpath, "%s", cmdname);
552             AppendExecutableExtension(cmdname);
553             if (stat(cmdname, &tstat)) {
554                 bozo_Log("BNODE: scanner binary '%s' not found\n", cmdname);
555                 bailout = 1;
556                 goto done;
557             }
558         }
559     }
560
561     te = calloc(1, sizeof(struct fsbnode));
562     if (te == NULL) {
563         bailout = 1;
564         goto done;
565     }
566     te->filecmd = fileCmdpath;
567     te->volcmd = volCmdpath;
568     te->salsrvcmd = salsrvCmdpath;
569     te->salcmd = salCmdpath;
570     if (ascancmd && strlen(ascancmd))
571         te->scancmd = scanCmdpath;
572     else
573         te->scancmd = NULL;
574     if (bnode_InitBnode(fsbnode2bnode(te), &dafsbnode_ops, ainstance) != 0) {
575         bailout = 1;
576         goto done;
577     }
578     bnode_SetTimeout(fsbnode2bnode(te), POLLTIME);
579                 /* ask for timeout activations every 20 seconds */
580     RestoreSalFlag(te);         /* restore needsSalvage flag based on file's existence */
581     SetNeedsClock(te);          /* compute needsClock field */
582
583  done:
584     if (bailout) {
585         if (te)
586             free(te);
587         if (fileCmdpath)
588             free(fileCmdpath);
589         if (volCmdpath)
590             free(volCmdpath);
591         if (salsrvCmdpath)
592             free(salsrvCmdpath);
593         if (salCmdpath)
594             free(salCmdpath);
595         if (scanCmdpath)
596             free(scanCmdpath);
597         return NULL;
598     }
599
600     return fsbnode2bnode(te);
601 }
602
603 /* called to SIGKILL a process if it doesn't terminate normally */
604 static int
605 fs_timeout(struct bnode *bn)
606 {
607     struct fsbnode *abnode = (struct fsbnode *)bn;
608
609     afs_int32 now;
610
611     now = FT_ApproxTime();
612     /* shutting down */
613     if (abnode->volSDW) {
614         if (!abnode->volKillSent && now - abnode->timeSDStarted > SDTIME) {
615             bnode_StopProc(abnode->volProc, SIGKILL);
616             abnode->volKillSent = 1;
617             bozo_Log
618                 ("bos shutdown: volserver failed to shutdown within %d seconds\n",
619                  SDTIME);
620         }
621     }
622     if (abnode->salSDW) {
623         if (!abnode->salKillSent && now - abnode->timeSDStarted > SDTIME) {
624             bnode_StopProc(abnode->salProc, SIGKILL);
625             abnode->salKillSent = 1;
626             bozo_Log
627                 ("bos shutdown: salvager failed to shutdown within %d seconds\n",
628                  SDTIME);
629         }
630     }
631     if (abnode->fileSDW) {
632         if (!abnode->fileKillSent && now - abnode->timeSDStarted > FSSDTIME) {
633             bnode_StopProc(abnode->fileProc, SIGKILL);
634             abnode->fileKillSent = 1;
635             bozo_Log
636                 ("bos shutdown: fileserver failed to shutdown within %d seconds\n",
637                  FSSDTIME);
638         }
639     }
640     if (abnode->salsrvSDW) {
641         if (!abnode->salsrvKillSent && now - abnode->timeSDStarted > SDTIME) {
642             bnode_StopProc(abnode->salsrvProc, SIGKILL);
643             abnode->salsrvKillSent = 1;
644             bozo_Log
645                 ("bos shutdown: salvageserver failed to shutdown within %d seconds\n",
646                  SDTIME);
647         }
648     }
649     if (abnode->scanSDW) {
650         if (!abnode->scanKillSent && now - abnode->timeSDStarted > SDTIME) {
651             bnode_StopProc(abnode->scanProc, SIGKILL);
652             abnode->scanKillSent = 1;
653             bozo_Log
654                 ("bos shutdown: scanner failed to shutdown within %d seconds\n",
655                  SDTIME);
656         }
657     }
658
659     if ((abnode->b.flags & BNODE_ERRORSTOP) && !abnode->salRunning
660         && !abnode->volRunning && !abnode->fileRunning && !abnode->scanRunning
661         && !abnode->salsrvRunning) {
662         bnode_SetStat(bn, BSTAT_NORMAL);
663     }
664     else {
665         bnode_ResetErrorCount(bn);
666     }
667
668     SetNeedsClock(abnode);
669     return 0;
670 }
671
672 static int
673 fs_getstat(struct bnode *bn, afs_int32 * astatus)
674 {
675     struct fsbnode *abnode = (struct fsbnode *) bn;
676
677     afs_int32 temp;
678     if (abnode->volSDW || abnode->fileSDW || abnode->salSDW
679         || abnode->scanSDW || abnode->salsrvSDW)
680         temp = BSTAT_SHUTTINGDOWN;
681     else if (abnode->salRunning)
682         temp = BSTAT_NORMAL;
683     else if (abnode->volRunning && abnode->fileRunning
684              && (!abnode->scancmd || abnode->scanRunning)
685              && (!abnode->salsrvcmd || abnode->salsrvRunning))
686         temp = BSTAT_NORMAL;
687     else if (!abnode->salRunning && !abnode->volRunning
688              && !abnode->fileRunning && !abnode->scanRunning
689              && !abnode->salsrvRunning)
690         temp = BSTAT_SHUTDOWN;
691     else
692         temp = BSTAT_STARTINGUP;
693     *astatus = temp;
694     return 0;
695 }
696
697 static int
698 fs_setstat(struct bnode *abnode, afs_int32 astatus)
699 {
700     return NudgeProcs((struct fsbnode *) abnode);
701 }
702
703 static int
704 fs_procstarted(struct bnode *bn, struct bnode_proc *aproc)
705 {
706     int code = 0;
707
708     if (DoPidFiles) {
709         code = bozo_CreatePidFile(bn->name, aproc->coreName, aproc->pid);
710     }
711     return code;
712 }
713
714 static int
715 fs_procexit(struct bnode *bn, struct bnode_proc *aproc)
716 {
717    struct fsbnode *abnode = (struct fsbnode *)bn;
718
719     /* process has exited */
720
721     if (DoPidFiles) {
722         bozo_DeletePidFile(bn->name, aproc->coreName);
723     }
724
725     if (aproc == abnode->volProc) {
726         abnode->volProc = 0;
727         abnode->volRunning = 0;
728         abnode->volSDW = 0;
729         abnode->volKillSent = 0;
730     } else if (aproc == abnode->fileProc) {
731         /* if we were expecting a shutdown and we didn't send a kill signal
732          * and exited (didn't have a signal termination), then we assume that
733          * the file server exited after putting the appropriate volumes safely
734          * offline, and don't salvage next time.
735          */
736         if (abnode->fileSDW && !abnode->fileKillSent
737             && aproc->lastSignal == 0)
738             SetSalFlag(abnode, 0);      /* shut down normally */
739         abnode->fileProc = 0;
740         abnode->fileRunning = 0;
741         abnode->fileSDW = 0;
742         abnode->fileKillSent = 0;
743     } else if (aproc == abnode->salProc) {
744         /* if we didn't shutdown the salvager, then assume it exited ok, and thus
745          * that we don't have to salvage again */
746         if (!abnode->salSDW)
747             SetSalFlag(abnode, 0);      /* salvage just completed */
748         abnode->salProc = 0;
749         abnode->salRunning = 0;
750         abnode->salSDW = 0;
751         abnode->salKillSent = 0;
752     } else if (aproc == abnode->scanProc) {
753         abnode->scanProc = 0;
754         abnode->scanRunning = 0;
755         abnode->scanSDW = 0;
756         abnode->scanKillSent = 0;
757     } else if (aproc == abnode->salsrvProc) {
758         abnode->salsrvProc = 0;
759         abnode->salsrvRunning = 0;
760         abnode->salsrvSDW = 0;
761         abnode->salsrvKillSent = 0;
762     }
763
764     /* now restart anyone who needs to restart */
765     return NudgeProcs(abnode);
766 }
767
768 /* make sure we're periodically checking the state if we need to */
769 static void
770 SetNeedsClock(struct fsbnode *ab)
771 {
772     afs_int32 timeout = POLLTIME;
773
774     if ((ab->fileSDW && !ab->fileKillSent) || (ab->volSDW && !ab->volKillSent)
775         || (ab->scanSDW && !ab->scanKillSent) || (ab->salSDW && !ab->salKillSent)
776         || (ab->salsrvSDW && !ab->salsrvKillSent)) {
777         /* SIGQUIT sent, will send SIGKILL if process does not exit */
778         ab->needsClock = 1;
779     } else if (ab->b.goal == 1 && ab->fileRunning && ab->volRunning
780         && (!ab->scancmd || ab->scanRunning)
781         && (!ab->salsrvcmd || ab->salsrvRunning)) {
782         if (ab->b.errorStopCount) {
783             /* reset error count after running for a bit */
784             ab->needsClock = 1;
785         } else {
786             ab->needsClock = 0; /* running normally */
787         }
788     } else if ((ab->b.goal == 0) && !ab->fileRunning && !ab->volRunning
789                && !ab->salRunning && !ab->scanRunning && !ab->salsrvRunning) {
790         if (ab->b.flags & BNODE_ERRORSTOP && ab->b.errorStopDelay) {
791             bozo_Log("%s will retry start in %d seconds\n", ab->b.name,
792                      ab->b.errorStopDelay);
793             ab->needsClock = 1; /* halted for errors, retry later */
794             timeout = ab->b.errorStopDelay;
795         } else {
796             ab->needsClock = 0; /* halted normally */
797         }
798     } else
799         ab->needsClock = 1;     /* other */
800
801     if (ab->needsClock && (!bnode_PendingTimeout(fsbnode2bnode(ab))
802                            || ab->b.period != timeout))
803         bnode_SetTimeout(fsbnode2bnode(ab), timeout);
804     if (!ab->needsClock)
805         bnode_SetTimeout(fsbnode2bnode(ab), 0);
806 }
807
808 static int
809 NudgeProcs(struct fsbnode *abnode)
810 {
811     struct bnode_proc *tp;      /* not register */
812     afs_int32 code;
813     afs_int32 now;
814
815     now = FT_ApproxTime();
816     if (abnode->b.goal == 1) {
817         /* we're trying to run the system. If the file server is running, then we
818          * are trying to start up the system.  If it is not running, then needsSalvage
819          * tells us if we need to run the salvager or not */
820         if (abnode->fileRunning) {
821             if (abnode->salRunning) {
822                 bozo_Log("Salvager running along with file server!\n");
823                 bozo_Log("Emergency shutdown\n");
824                 emergency = 1;
825                 bnode_SetGoal(fsbnode2bnode(abnode), BSTAT_SHUTDOWN);
826                 bnode_StopProc(abnode->salProc, SIGKILL);
827                 SetNeedsClock(abnode);
828                 return -1;
829             }
830             if (!abnode->volRunning) {
831                 abnode->lastVolStart = FT_ApproxTime();
832                 code = bnode_NewProc(fsbnode2bnode(abnode), abnode->volcmd, "vol", &tp);
833                 if (code == 0) {
834                     abnode->volProc = tp;
835                     abnode->volRunning = 1;
836                 }
837             }
838             if (abnode->salsrvcmd) {
839                 if (!abnode->salsrvRunning) {
840                     abnode->lastSalsrvStart = FT_ApproxTime();
841                     code =
842                         bnode_NewProc(fsbnode2bnode(abnode), abnode->salsrvcmd, "salsrv",
843                                       &tp);
844                     if (code == 0) {
845                         abnode->salsrvProc = tp;
846                         abnode->salsrvRunning = 1;
847                     }
848                 }
849             }
850             if (abnode->scancmd) {
851                 if (!abnode->scanRunning) {
852                     abnode->lastScanStart = FT_ApproxTime();
853                     code =
854                         bnode_NewProc(fsbnode2bnode(abnode), abnode->scancmd, "scanner",
855                                       &tp);
856                     if (code == 0) {
857                         abnode->scanProc = tp;
858                         abnode->scanRunning = 1;
859                     }
860                 }
861             }
862         } else {                /* file is not running */
863             /* see how to start */
864             /* for demand attach fs, needsSalvage flag is ignored */
865             if (!abnode->needsSalvage || abnode->salsrvcmd) {
866                 /* no crash apparent, just start up normally */
867                 if (!abnode->fileRunning) {
868                     abnode->lastFileStart = FT_ApproxTime();
869                     code =
870                         bnode_NewProc(fsbnode2bnode(abnode), abnode->filecmd, "file", &tp);
871                     if (code == 0) {
872                         abnode->fileProc = tp;
873                         abnode->fileRunning = 1;
874                         SetSalFlag(abnode, 1);
875                     }
876                 }
877                 if (!abnode->volRunning) {
878                     abnode->lastVolStart = FT_ApproxTime();
879                     code = bnode_NewProc(fsbnode2bnode(abnode), abnode->volcmd, "vol", &tp);
880                     if (code == 0) {
881                         abnode->volProc = tp;
882                         abnode->volRunning = 1;
883                     }
884                 }
885                 if (abnode->salsrvcmd && !abnode->salsrvRunning) {
886                     abnode->lastSalsrvStart = FT_ApproxTime();
887                     code =
888                         bnode_NewProc(fsbnode2bnode(abnode), abnode->salsrvcmd, "salsrv",
889                                       &tp);
890                     if (code == 0) {
891                         abnode->salsrvProc = tp;
892                         abnode->salsrvRunning = 1;
893                     }
894                 }
895                 if (abnode->scancmd && !abnode->scanRunning) {
896                     abnode->lastScanStart = FT_ApproxTime();
897                     code =
898                         bnode_NewProc(fsbnode2bnode(abnode), abnode->scancmd, "scanner",
899                                       &tp);
900                     if (code == 0) {
901                         abnode->scanProc = tp;
902                         abnode->scanRunning = 1;
903                     }
904                 }
905             } else {            /* needs to be salvaged */
906                 /* make sure file server and volser are gone */
907                 if (abnode->volRunning) {
908                     bnode_StopProc(abnode->volProc, SIGTERM);
909                     if (!abnode->volSDW)
910                         abnode->timeSDStarted = now;
911                     abnode->volSDW = 1;
912                 }
913                 if (abnode->fileRunning) {
914                     bnode_StopProc(abnode->fileProc, SIGQUIT);
915                     if (!abnode->fileSDW)
916                         abnode->timeSDStarted = now;
917                     abnode->fileSDW = 1;
918                 }
919                 if (abnode->scanRunning) {
920                     bnode_StopProc(abnode->scanProc, SIGTERM);
921                     if (!abnode->scanSDW)
922                         abnode->timeSDStarted = now;
923                     abnode->scanSDW = 1;
924                 }
925                 if (abnode->volRunning || abnode->fileRunning
926                     || abnode->scanRunning)
927                     return 0;
928                 /* otherwise, it is safe to start salvager */
929                 if (!abnode->salRunning) {
930                     code = bnode_NewProc(fsbnode2bnode(abnode), abnode->salcmd, "salv", &tp);
931                     if (code == 0) {
932                         abnode->salProc = tp;
933                         abnode->salRunning = 1;
934                     }
935                 }
936             }
937         }
938     } else {                    /* goal is 0, we're shutting down */
939         /* trying to shutdown */
940         if (abnode->salRunning && !abnode->salSDW) {
941             bnode_StopProc(abnode->salProc, SIGTERM);
942             abnode->salSDW = 1;
943             abnode->timeSDStarted = now;
944         }
945         if (abnode->fileRunning && !abnode->fileSDW) {
946             bnode_StopProc(abnode->fileProc, SIGQUIT);
947             abnode->fileSDW = 1;
948             abnode->timeSDStarted = now;
949         }
950         if (abnode->volRunning && !abnode->volSDW) {
951             bnode_StopProc(abnode->volProc, SIGTERM);
952             abnode->volSDW = 1;
953             abnode->timeSDStarted = now;
954         }
955         if (abnode->salsrvRunning && !abnode->salsrvSDW) {
956             bnode_StopProc(abnode->salsrvProc, SIGTERM);
957             abnode->salsrvSDW = 1;
958             abnode->timeSDStarted = now;
959         }
960         if (abnode->scanRunning && !abnode->scanSDW) {
961             bnode_StopProc(abnode->scanProc, SIGTERM);
962             abnode->scanSDW = 1;
963             abnode->timeSDStarted = now;
964         }
965     }
966     SetNeedsClock(abnode);
967     return 0;
968 }
969
970 static int
971 fs_getstring(struct bnode *bn, char *abuffer, afs_int32 alen)
972 {
973     struct fsbnode *abnode = (struct fsbnode *)bn;
974
975     if (alen < 40)
976         return -1;
977     if (abnode->b.goal == 1) {
978         if (abnode->fileRunning) {
979             if (abnode->fileSDW)
980                 strcpy(abuffer, "file server shutting down");
981             else if (abnode->scancmd) {
982                 if (!abnode->volRunning && !abnode->scanRunning)
983                     strcpy(abuffer,
984                            "file server up; volser and scanner down");
985                 else if (abnode->volRunning && !abnode->scanRunning)
986                     strcpy(abuffer,
987                            "file server up; volser up; scanner down");
988                 else if (!abnode->volRunning && abnode->scanRunning)
989                     strcpy(abuffer,
990                            "file server up; volser down; scanner up");
991
992                 else
993                     strcpy(abuffer, "file server running");
994             } else if (!abnode->volRunning)
995                 strcpy(abuffer, "file server up; volser down");
996             else
997                 strcpy(abuffer, "file server running");
998         } else if (abnode->salRunning) {
999             strcpy(abuffer, "salvaging file system");
1000         } else
1001             strcpy(abuffer, "starting file server");
1002     } else {
1003         /* shutting down */
1004         if (abnode->fileRunning || abnode->volRunning || abnode->scanRunning) {
1005             strcpy(abuffer, "file server shutting down");
1006         } else if (abnode->salRunning)
1007             strcpy(abuffer, "salvager shutting down");
1008         else
1009             strcpy(abuffer, "file server shut down");
1010     }
1011     return 0;
1012 }
1013
1014 static int
1015 fs_getparm(struct bnode *bn, afs_int32 aindex, char *abuffer,
1016            afs_int32 alen)
1017 {
1018     struct fsbnode *abnode = (struct fsbnode *)bn;
1019
1020     if (aindex == 0)
1021         strcpy(abuffer, abnode->filecmd);
1022     else if (aindex == 1)
1023         strcpy(abuffer, abnode->volcmd);
1024     else if (aindex == 2)
1025         strcpy(abuffer, abnode->salcmd);
1026     else if (aindex == 3 && abnode->scancmd)
1027         strcpy(abuffer, abnode->scancmd);
1028     else
1029         return BZDOM;
1030     return 0;
1031 }
1032
1033 static int
1034 dafs_getparm(struct bnode *bn, afs_int32 aindex, char *abuffer,
1035              afs_int32 alen)
1036 {
1037     struct fsbnode *abnode = (struct fsbnode *)bn;
1038
1039     if (aindex == 0)
1040         strcpy(abuffer, abnode->filecmd);
1041     else if (aindex == 1)
1042         strcpy(abuffer, abnode->volcmd);
1043     else if (aindex == 2)
1044         strcpy(abuffer, abnode->salsrvcmd);
1045     else if (aindex == 3)
1046         strcpy(abuffer, abnode->salcmd);
1047     else if (aindex == 4 && abnode->scancmd)
1048         strcpy(abuffer, abnode->scancmd);
1049     else
1050         return BZDOM;
1051     return 0;
1052 }