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