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