2ac65e46210cdae8c388fc99e6d98e172176a2df
[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 static int fs_timeout(), fs_getstat(), fs_setstat(), fs_delete();
45 static int fs_procexit(), fs_getstring(), fs_getparm(), fs_restartp();
46 static int fs_hascore();
47 struct bnode *fs_create();
48
49 static SetNeedsClock();
50 static NudgeProcs();
51
52 static int emergency = 0;
53
54 /* if this file exists, then we have to salvage the file system */
55 #define SALFILE     "SALVAGE."
56
57 #define POLLTIME        20      /* for handling below */
58 #define SDTIME          60      /* time in seconds given to a process to evaporate */
59
60 /*  basic rules:
61     Normal operation involves having the file server and the vol server both running.
62     
63     If the vol server terminates, it can simply be restarted.
64     
65     If the file server terminates, the disk must salvaged before the file server
66     can be restarted.  In order to restart either the file server or the salvager,
67     the vol server must be shut down.
68     
69     If the file server terminates *normally* (exits after receiving a SIGQUIT)
70     then we don't have to salvage it.
71     
72     The needsSalvage flag is set when the file server is started.  It is cleared
73     if the file server exits when fileSDW is true but fileKillSent is false,
74     indicating that it exited after receiving a quit, but before we sent it a kill.
75     
76     The needsSalvage flag is cleared when the salvager exits.
77 */
78
79 struct bnode_ops fsbnode_ops = {
80     fs_create,
81     fs_timeout,
82     fs_getstat,
83     fs_setstat,
84     fs_delete,
85     fs_procexit,
86     fs_getstring,
87     fs_getparm,
88     fs_restartp,
89     fs_hascore,
90 };
91
92 struct fsbnode {
93     struct bnode b;
94     afs_int32 timeSDStarted;    /* time shutdown operation started */
95     char *filecmd;              /* command to start primary file server */
96     char *volcmd;               /* command to start secondary vol server */
97     char *salcmd;               /* command to start salvager */
98     char *scancmd;              /* command to start scanner (MR-AFS) */
99     struct bnode_proc *fileProc;        /* process for file server */
100     struct bnode_proc *volProc; /* process for vol server */
101     struct bnode_proc *salProc; /* process for salvager */
102     struct bnode_proc *scanProc;        /* process for scanner (MR-AFS) */
103     afs_int32 lastFileStart;    /* last start for file */
104     afs_int32 lastVolStart;     /* last start for vol */
105     afs_int32 lastScanStart;    /* last start for scanner (MR-AFS) */
106     char fileRunning;           /* file process is running */
107     char volRunning;            /* volser is running */
108     char salRunning;            /* salvager is running */
109     char scanRunning;           /* scanner is running (MR_AFS) */
110     char fileSDW;               /* file shutdown wait */
111     char volSDW;                /* vol shutdown wait */
112     char salSDW;                /* waiting for the salvager to shutdown */
113     char scanSDW;               /* scanner shutdown wait (MR_AFS) */
114     char fileKillSent;          /* kill signal has been sent */
115     char volKillSent;
116     char salKillSent;
117     char scanKillSent;          /* kill signal has been sent (MR_AFS) */
118     char needsSalvage;          /* salvage before running */
119     char needsClock;            /* do we need clock ticks */
120 };
121
122 /* Function to tell whether this bnode has a core file or not.  You might
123  * think that this could be in bnode.c, and decide what core files to check
124  * for based on the bnode's coreName property, but that doesn't work because
125  * there may not be an active process for a bnode that dumped core at the
126  * time the query is done.
127  */
128 static int
129 fs_hascore(register struct ezbnode *abnode)
130 {
131     char tbuffer[256];
132
133     /* see if file server has a core file */
134     bnode_CoreName(abnode, "file", tbuffer);
135     if (access(tbuffer, 0) == 0)
136         return 1;
137
138     /* see if volserver has a core file */
139     bnode_CoreName(abnode, "vol", tbuffer);
140     if (access(tbuffer, 0) == 0)
141         return 1;
142
143     /* see if salvager left a core file */
144     bnode_CoreName(abnode, "salv", tbuffer);
145     if (access(tbuffer, 0) == 0)
146         return 1;
147
148     /* see if scanner left a core file (MR-AFS) */
149     bnode_CoreName(abnode, "scan", tbuffer);
150     if (access(tbuffer, 0) == 0)
151         return 1;
152
153     /* no one left a core file */
154     return 0;
155 }
156
157 static int
158 fs_restartp(register struct fsbnode *abnode)
159 {
160     struct bnode_token *tt;
161     register afs_int32 code;
162     struct stat tstat;
163
164     code = bnode_ParseLine(abnode->filecmd, &tt);
165     if (code)
166         return 0;
167     if (!tt)
168         return 0;
169     code = stat(tt->key, &tstat);
170     if (code) {
171         bnode_FreeTokens(tt);
172         return 0;
173     }
174     if (tstat.st_ctime > abnode->lastFileStart)
175         code = 1;
176     else
177         code = 0;
178     bnode_FreeTokens(tt);
179     if (code)
180         return code;
181
182     /* now do same for volcmd */
183     code = bnode_ParseLine(abnode->volcmd, &tt);
184     if (code)
185         return 0;
186     if (!tt)
187         return 0;
188     code = stat(tt->key, &tstat);
189     if (code) {
190         bnode_FreeTokens(tt);
191         return 0;
192     }
193     if (tstat.st_ctime > abnode->lastVolStart)
194         code = 1;
195     else
196         code = 0;
197     bnode_FreeTokens(tt);
198     if (code)
199         return code;
200
201     if (abnode->scancmd) {      /* Only in MR-AFS */
202         /* now do same for scancmd (MR-AFS) */
203         code = bnode_ParseLine(abnode->scancmd, &tt);
204         if (code)
205             return 0;
206         if (!tt)
207             return 0;
208         code = stat(tt->key, &tstat);
209         if (code) {
210             bnode_FreeTokens(tt);
211             return 0;
212         }
213         if (tstat.st_ctime > abnode->lastScanStart)
214             code = 1;
215         else
216             code = 0;
217         bnode_FreeTokens(tt);
218     }
219
220     return code;
221 }
222
223 /* set needsSalvage flag, creating file SALVAGE.<instancename> if
224     we need to salvage the file system (so we can tell over panic reboots */
225 static int
226 SetSalFlag(register struct fsbnode *abnode, register int aflag)
227 {
228     char tbuffer[AFSDIR_PATH_MAX];
229     int fd;
230
231     abnode->needsSalvage = aflag;
232     strcompose(tbuffer, AFSDIR_PATH_MAX, AFSDIR_SERVER_LOCAL_DIRPATH, "/",
233                SALFILE, abnode->b.name, NULL);
234     if (aflag) {
235         fd = open(tbuffer, O_CREAT | O_TRUNC | O_RDWR, 0666);
236         close(fd);
237     } else {
238         unlink(tbuffer);
239     }
240     return 0;
241 }
242
243 /* set the needsSalvage flag according to the existence of the salvage file */
244 static int
245 RestoreSalFlag(register struct fsbnode *abnode)
246 {
247     char tbuffer[AFSDIR_PATH_MAX];
248
249     strcompose(tbuffer, AFSDIR_PATH_MAX, AFSDIR_SERVER_LOCAL_DIRPATH, "/",
250                SALFILE, abnode->b.name, NULL);
251     if (access(tbuffer, 0) == 0) {
252         /* file exists, so need to salvage */
253         abnode->needsSalvage = 1;
254     } else {
255         abnode->needsSalvage = 0;
256     }
257     return 0;
258 }
259
260 char *
261 copystr(register char *a)
262 {
263     register char *b;
264     b = (char *)malloc(strlen(a) + 1);
265     strcpy(b, a);
266     return b;
267 }
268
269 static int
270 fs_delete(struct fsbnode *abnode)
271 {
272     free(abnode->filecmd);
273     free(abnode->volcmd);
274     free(abnode->salcmd);
275     if (abnode->scancmd)
276         free(abnode->scancmd);
277     free(abnode);
278     return 0;
279 }
280
281
282 #ifdef AFS_NT40_ENV
283 static void
284 AppendExecutableExtension(char *cmd)
285 {
286     char cmdext[_MAX_EXT];
287
288     _splitpath(cmd, NULL, NULL, NULL, cmdext);
289     if (*cmdext == '\0') {
290         /* no filename extension supplied for cmd; append .exe */
291         strcat(cmd, ".exe");
292     }
293 }
294 #endif /* AFS_NT40_ENV */
295
296
297 struct bnode *
298 fs_create(char *ainstance, char *afilecmd, char *avolcmd, char *asalcmd,
299           char *ascancmd)
300 {
301     struct stat tstat;
302     register struct fsbnode *te;
303     char cmdname[AFSDIR_PATH_MAX];
304     char *fileCmdpath, *volCmdpath, *salCmdpath, *scanCmdpath;
305     int bailout = 0;
306
307     fileCmdpath = volCmdpath = salCmdpath = NULL;
308
309     /* construct local paths from canonical (wire-format) paths */
310     if (ConstructLocalBinPath(afilecmd, &fileCmdpath)) {
311         bozo_Log("BNODE: command path invalid '%s'\n", afilecmd);
312         bailout = 1;
313     }
314     if (ConstructLocalBinPath(avolcmd, &volCmdpath)) {
315         bozo_Log("BNODE: command path invalid '%s'\n", avolcmd);
316         bailout = 1;
317     }
318     if (ConstructLocalBinPath(asalcmd, &salCmdpath)) {
319         bozo_Log("BNODE: command path invalid '%s'\n", asalcmd);
320         bailout = 1;
321     }
322
323     if (ascancmd && strlen(ascancmd)) {
324         if (ConstructLocalBinPath(ascancmd, &scanCmdpath)) {
325             bozo_Log("BNODE: command path invalid '%s'\n", ascancmd);
326             bailout = 1;
327         }
328     }
329
330     if (!bailout) {
331         sscanf(fileCmdpath, "%s", cmdname);
332 #ifdef AFS_NT40_ENV
333         AppendExecutableExtension(cmdname);
334 #endif
335         if (stat(cmdname, &tstat)) {
336             bozo_Log("BNODE: file server binary '%s' not found\n", cmdname);
337             bailout = 1;
338         }
339
340         sscanf(volCmdpath, "%s", cmdname);
341 #ifdef AFS_NT40_ENV
342         AppendExecutableExtension(cmdname);
343 #endif
344         if (stat(cmdname, &tstat)) {
345             bozo_Log("BNODE: volume server binary '%s' not found\n", cmdname);
346             bailout = 1;
347         }
348
349         sscanf(salCmdpath, "%s", cmdname);
350 #ifdef AFS_NT40_ENV
351         AppendExecutableExtension(cmdname);
352 #endif
353         if (stat(cmdname, &tstat)) {
354             bozo_Log("BNODE: salvager binary '%s' not found\n", cmdname);
355             bailout = 1;
356         }
357
358         if (ascancmd && strlen(ascancmd)) {
359             sscanf(scanCmdpath, "%s", cmdname);
360 #ifdef AFS_NT40_ENV
361             AppendExecutableExtension(cmdname);
362 #endif
363             if (stat(cmdname, &tstat)) {
364                 bozo_Log("BNODE: scanner binary '%s' not found\n", cmdname);
365                 bailout = 1;
366             }
367         }
368     }
369
370     if (bailout) {
371         free(fileCmdpath);
372         free(volCmdpath);
373         free(salCmdpath);
374         return NULL;
375     }
376
377     te = (struct fsbnode *)malloc(sizeof(struct fsbnode));
378     memset(te, 0, sizeof(struct fsbnode));
379     te->filecmd = fileCmdpath;
380     te->volcmd = volCmdpath;
381     te->salcmd = salCmdpath;
382     if (ascancmd && strlen(ascancmd))
383         te->scancmd = scanCmdpath;
384     else
385         te->scancmd = NULL;
386     if (bnode_InitBnode(te, &fsbnode_ops, ainstance) != 0) {
387         free(te);
388         free(fileCmdpath);
389         free(volCmdpath);
390         free(salCmdpath);
391         return NULL;
392     }
393     bnode_SetTimeout(te, POLLTIME);     /* ask for timeout activations every 10 seconds */
394     RestoreSalFlag(te);         /* restore needsSalvage flag based on file's existence */
395     SetNeedsClock(te);          /* compute needsClock field */
396     return (struct bnode *)te;
397 }
398
399 /* called to SIGKILL a process if it doesn't terminate normally */
400 static int
401 fs_timeout(struct fsbnode *abnode)
402 {
403     register afs_int32 now;
404
405     now = FT_ApproxTime();
406     /* shutting down */
407     if (abnode->volSDW) {
408         if (!abnode->volKillSent && now - abnode->timeSDStarted > SDTIME) {
409             bnode_StopProc(abnode->volProc, SIGKILL);
410             abnode->volKillSent = 1;
411             bozo_Log
412                 ("bos shutdown: volserver failed to shutdown within %d seconds\n",
413                  SDTIME);
414         }
415     }
416     if (abnode->salSDW) {
417         if (!abnode->salKillSent && now - abnode->timeSDStarted > SDTIME) {
418             bnode_StopProc(abnode->salProc, SIGKILL);
419             abnode->salKillSent = 1;
420             bozo_Log
421                 ("bos shutdown: salvager failed to shutdown within %d seconds\n",
422                  SDTIME);
423         }
424     }
425     if (abnode->fileSDW) {
426         if (!abnode->fileKillSent && now - abnode->timeSDStarted > FSSDTIME) {
427             bnode_StopProc(abnode->fileProc, SIGKILL);
428             abnode->fileKillSent = 1;
429             bozo_Log
430                 ("bos shutdown: fileserver failed to shutdown within %d seconds\n",
431                  FSSDTIME);
432         }
433     }
434     if (abnode->scanSDW) {
435         if (!abnode->scanKillSent && now - abnode->timeSDStarted > SDTIME) {
436             bnode_StopProc(abnode->scanProc, SIGKILL);
437             abnode->scanKillSent = 1;
438             bozo_Log
439                 ("bos shutdown: scanner failed to shutdown within %d seconds\n",
440                  SDTIME);
441         }
442     }
443     SetNeedsClock(abnode);
444     return 0;
445 }
446
447 static int
448 fs_getstat(struct fsbnode *abnode, afs_int32 * astatus)
449 {
450     register afs_int32 temp;
451     if (abnode->volSDW || abnode->fileSDW || abnode->salSDW
452         || abnode->scanSDW)
453         temp = BSTAT_SHUTTINGDOWN;
454     else if (abnode->salRunning)
455         temp = BSTAT_NORMAL;
456     else if (abnode->volRunning && abnode->fileRunning
457              && (!abnode->scancmd || abnode->scanRunning))
458         temp = BSTAT_NORMAL;
459     else if (!abnode->salRunning && !abnode->volRunning
460              && !abnode->fileRunning && !abnode->scanRunning)
461         temp = BSTAT_SHUTDOWN;
462     else
463         temp = BSTAT_STARTINGUP;
464     *astatus = temp;
465     return 0;
466 }
467
468 static int
469 fs_setstat(register struct fsbnode *abnode, afs_int32 astatus)
470 {
471     return NudgeProcs(abnode);
472 }
473
474 static int
475 fs_procexit(struct fsbnode *abnode, struct bnode_proc *aproc)
476 {
477     /* process has exited */
478
479     if (aproc == abnode->volProc) {
480         abnode->volProc = 0;
481         abnode->volRunning = 0;
482         abnode->volSDW = 0;
483         abnode->volKillSent = 0;
484     } else if (aproc == abnode->fileProc) {
485         /* if we were expecting a shutdown and we didn't send a kill signal
486          * and exited (didn't have a signal termination), then we assume that
487          * the file server exited after putting the appropriate volumes safely
488          * offline, and don't salvage next time.
489          */
490         if (abnode->fileSDW && !abnode->fileKillSent
491             && aproc->lastSignal == 0)
492             SetSalFlag(abnode, 0);      /* shut down normally */
493         abnode->fileProc = 0;
494         abnode->fileRunning = 0;
495         abnode->fileSDW = 0;
496         abnode->fileKillSent = 0;
497     } else if (aproc == abnode->salProc) {
498         /* if we didn't shutdown the salvager, then assume it exited ok, and thus
499          * that we don't have to salvage again */
500         if (!abnode->salSDW)
501             SetSalFlag(abnode, 0);      /* salvage just completed */
502         abnode->salProc = 0;
503         abnode->salRunning = 0;
504         abnode->salSDW = 0;
505         abnode->salKillSent = 0;
506     } else if (aproc == abnode->scanProc) {
507         abnode->scanProc = 0;
508         abnode->scanRunning = 0;
509         abnode->scanSDW = 0;
510         abnode->scanKillSent = 0;
511     }
512
513     /* now restart anyone who needs to restart */
514     return NudgeProcs(abnode);
515 }
516
517 /* make sure we're periodically checking the state if we need to */
518 static int
519 SetNeedsClock(register struct fsbnode *ab)
520 {
521     if (ab->b.goal == 1 && ab->fileRunning && ab->volRunning
522         && (!ab->scancmd || ab->scanRunning))
523         ab->needsClock = 0;     /* running normally */
524     else if (ab->b.goal == 0 && !ab->fileRunning && !ab->volRunning
525              && !ab->salRunning && !ab->scanRunning)
526         ab->needsClock = 0;     /* halted normally */
527     else
528         ab->needsClock = 1;     /* other */
529     if (ab->needsClock && !bnode_PendingTimeout(ab))
530         bnode_SetTimeout(ab, POLLTIME);
531     if (!ab->needsClock)
532         bnode_SetTimeout(ab, 0);
533 }
534
535 static int
536 NudgeProcs(register struct fsbnode *abnode)
537 {
538     struct bnode_proc *tp;      /* not register */
539     register afs_int32 code;
540     afs_int32 now;
541
542     now = FT_ApproxTime();
543     if (abnode->b.goal == 1) {
544         /* we're trying to run the system. If the file server is running, then we
545          * are trying to start up the system.  If it is not running, then needsSalvage
546          * tells us if we need to run the salvager or not */
547         if (abnode->fileRunning) {
548             if (abnode->salRunning) {
549                 bozo_Log("Salvager running along with file server!\n");
550                 bozo_Log("Emergency shutdown\n");
551                 emergency = 1;
552                 bnode_SetGoal(abnode, BSTAT_SHUTDOWN);
553                 bnode_StopProc(abnode->salProc, SIGKILL);
554                 SetNeedsClock(abnode);
555                 return -1;
556             }
557             if (!abnode->volRunning) {
558                 abnode->lastVolStart = FT_ApproxTime();
559                 code = bnode_NewProc(abnode, abnode->volcmd, "vol", &tp);
560                 if (code == 0) {
561                     abnode->volProc = tp;
562                     abnode->volRunning = 1;
563                 }
564             }
565             if (abnode->scancmd) {
566                 if (!abnode->scanRunning) {
567                     abnode->lastScanStart = FT_ApproxTime();
568                     code =
569                         bnode_NewProc(abnode, abnode->scancmd, "scanner",
570                                       &tp);
571                     if (code == 0) {
572                         abnode->scanProc = tp;
573                         abnode->scanRunning = 1;
574                     }
575                 }
576             }
577         } else {                /* file is not running */
578             /* see how to start */
579             if (!abnode->needsSalvage) {
580                 /* no crash apparent, just start up normally */
581                 if (!abnode->fileRunning) {
582                     abnode->lastFileStart = FT_ApproxTime();
583                     code =
584                         bnode_NewProc(abnode, abnode->filecmd, "file", &tp);
585                     if (code == 0) {
586                         abnode->fileProc = tp;
587                         abnode->fileRunning = 1;
588                         SetSalFlag(abnode, 1);
589                     }
590                 }
591                 if (!abnode->volRunning) {
592                     abnode->lastVolStart = FT_ApproxTime();
593                     code = bnode_NewProc(abnode, abnode->volcmd, "vol", &tp);
594                     if (code == 0) {
595                         abnode->volProc = tp;
596                         abnode->volRunning = 1;
597                     }
598                 }
599                 if (abnode->scancmd && !abnode->scanRunning) {
600                     abnode->lastScanStart = FT_ApproxTime();
601                     code =
602                         bnode_NewProc(abnode, abnode->scancmd, "scanner",
603                                       &tp);
604                     if (code == 0) {
605                         abnode->scanProc = tp;
606                         abnode->scanRunning = 1;
607                     }
608                 }
609             } else {            /* needs to be salvaged */
610                 /* make sure file server and volser are gone */
611                 if (abnode->volRunning) {
612                     bnode_StopProc(abnode->volProc, SIGTERM);
613                     if (!abnode->volSDW)
614                         abnode->timeSDStarted = now;
615                     abnode->volSDW = 1;
616                 }
617                 if (abnode->fileRunning) {
618                     bnode_StopProc(abnode->fileProc, SIGQUIT);
619                     if (!abnode->fileSDW)
620                         abnode->timeSDStarted = now;
621                     abnode->fileSDW = 1;
622                 }
623                 if (abnode->scanRunning) {
624                     bnode_StopProc(abnode->scanProc, SIGTERM);
625                     if (!abnode->scanSDW)
626                         abnode->timeSDStarted = now;
627                     abnode->scanSDW = 1;
628                 }
629                 if (abnode->volRunning || abnode->fileRunning
630                     || abnode->scanRunning)
631                     return 0;
632                 /* otherwise, it is safe to start salvager */
633                 if (!abnode->salRunning) {
634                     code = bnode_NewProc(abnode, abnode->salcmd, "salv", &tp);
635                     if (code == 0) {
636                         abnode->salProc = tp;
637                         abnode->salRunning = 1;
638                     }
639                 }
640             }
641         }
642     } else {                    /* goal is 0, we're shutting down */
643         /* trying to shutdown */
644         if (abnode->salRunning && !abnode->salSDW) {
645             bnode_StopProc(abnode->salProc, SIGTERM);
646             abnode->salSDW = 1;
647             abnode->timeSDStarted = now;
648         }
649         if (abnode->fileRunning && !abnode->fileSDW) {
650             bnode_StopProc(abnode->fileProc, SIGQUIT);
651             abnode->fileSDW = 1;
652             abnode->timeSDStarted = now;
653         }
654         if (abnode->volRunning && !abnode->volSDW) {
655             bnode_StopProc(abnode->volProc, SIGTERM);
656             abnode->volSDW = 1;
657             abnode->timeSDStarted = now;
658         }
659         if (abnode->scanRunning && !abnode->scanSDW) {
660             bnode_StopProc(abnode->scanProc, SIGTERM);
661             abnode->scanSDW = 1;
662             abnode->timeSDStarted = now;
663         }
664     }
665     SetNeedsClock(abnode);
666     return 0;
667 }
668
669 static int
670 fs_getstring(struct fsbnode *abnode, char *abuffer, afs_int32 alen)
671 {
672     if (alen < 40)
673         return -1;
674     if (abnode->b.goal == 1) {
675         if (abnode->fileRunning) {
676             if (abnode->fileSDW)
677                 strcpy(abuffer, "file server shutting down");
678             else if (abnode->scancmd) {
679                 if (!abnode->volRunning && !abnode->scanRunning)
680                     strcpy(abuffer,
681                            "file server up; volser and scanner down");
682                 else if (abnode->volRunning && !abnode->scanRunning)
683                     strcpy(abuffer,
684                            "file server up; volser up; scanner down");
685                 else if (!abnode->volRunning && abnode->scanRunning)
686                     strcpy(abuffer,
687                            "file server up; volser down; scanner up");
688
689                 else
690                     strcpy(abuffer, "file server running");
691             } else if (!abnode->volRunning)
692                 strcpy(abuffer, "file server up; volser down");
693             else
694                 strcpy(abuffer, "file server running");
695         } else if (abnode->salRunning) {
696             strcpy(abuffer, "salvaging file system");
697         } else
698             strcpy(abuffer, "starting file server");
699     } else {
700         /* shutting down */
701         if (abnode->fileRunning || abnode->volRunning || abnode->scanRunning) {
702             strcpy(abuffer, "file server shutting down");
703         } else if (abnode->salRunning)
704             strcpy(abuffer, "salvager shutting down");
705         else
706             strcpy(abuffer, "file server shut down");
707     }
708     return 0;
709 }
710
711 static int
712 fs_getparm(struct fsbnode *abnode, afs_int32 aindex, char *abuffer,
713            afs_int32 alen)
714 {
715     if (aindex == 0)
716         strcpy(abuffer, abnode->filecmd);
717     else if (aindex == 1)
718         strcpy(abuffer, abnode->volcmd);
719     else if (aindex == 2)
720         strcpy(abuffer, abnode->salcmd);
721     else if (aindex == 3 && abnode->scancmd)
722         strcpy(abuffer, abnode->scancmd);
723     else
724         return BZDOM;
725     return 0;
726 }