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