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