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