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