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