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