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