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