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