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