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