Allocate pathname buffers dynamically
[openafs.git] / src / bozo / fsbnodeops.c
index f06eb39..7893599 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Copyright 2000, International Business Machines Corporation and others.
  * All Rights Reserved.
- * 
+ *
  * This software has been released under the terms of the IBM Public
  * License.  For details, see the LICENSE file in the top-level source
  * directory or online at http://www.openafs.org/dl/license10.html
 #include <afsconfig.h>
 #include <afs/param.h>
 
-RCSID
-    ("$Header$");
+#include <afs/procmgmt.h>
+#include <roken.h>
+#include <afs/opr.h>
 
-#include <sys/types.h>
 #include <lwp.h>
-#include <errno.h>
-#include <stdio.h>
-#ifdef AFS_SUN5_ENV
-#include <fcntl.h>
-#endif
-#ifdef AFS_NT40_ENV
-#include <io.h>
-#include <fcntl.h>
-#else
-#include <sys/file.h>
-
-#include <string.h>
-#include <stdlib.h>
-
-#endif /* AFS_NT40_ENV */
-#include <sys/stat.h>
-#include <afs/procmgmt.h>      /* signal(), kill(), wait(), etc. */
+#include <rx/rx.h>
 #include <afs/afsutil.h>
-#include "bnode.h"
+#include <opr/queue.h>
 
+#include "bnode.h"
+#include "bnode_internal.h"
+#include "bosprototypes.h"
 
+extern char *DoPidFiles;
 static int emergency = 0;
 
 /* if this file exists, then we have to salvage the file system */
@@ -46,20 +34,20 @@ static int emergency = 0;
 
 /*  basic rules:
     Normal operation involves having the file server and the vol server both running.
-    
+
     If the vol server terminates, it can simply be restarted.
-    
+
     If the file server terminates, the disk must salvaged before the file server
     can be restarted.  In order to restart either the file server or the salvager,
     the vol server must be shut down.
-    
+
     If the file server terminates *normally* (exits after receiving a SIGQUIT)
     then we don't have to salvage it.
-    
+
     The needsSalvage flag is set when the file server is started.  It is cleared
     if the file server exits when fileSDW is true but fileKillSent is false,
     indicating that it exited after receiving a quit, but before we sent it a kill.
-    
+
     The needsSalvage flag is cleared when the salvager exits.
 */
 
@@ -99,41 +87,36 @@ struct fsbnode {
     char needsClock;           /* do we need clock ticks */
 };
 
-
-
-struct bnode * fs_create(char *ainstance, char *afilecmd, char *avolcmd, 
-                        char *asalcmd, char *ascancmd);
-struct bnode * dafs_create(char *ainstance, char *afilecmd, char *avolcmd, 
+struct bnode * fs_create(char *ainstance, char *afilecmd, char *avolcmd,
+                        char *asalcmd, char *ascancmd, char *dummy);
+struct bnode * dafs_create(char *ainstance, char *afilecmd, char *avolcmd,
                           char * asalsrvcmd, char *asalcmd, char *ascancmd);
 
-static int fs_hascore(register struct ezbnode *abnode);
-static int fs_restartp(register struct fsbnode *abnode);
-static int SetSalFlag(register struct fsbnode *abnode, register int aflag);
-static int RestoreSalFlag(register struct fsbnode *abnode);
-static int fs_delete(struct fsbnode *abnode);
-static int fs_timeout(struct fsbnode *abnode);
-static int fs_getstat(struct fsbnode *abnode, afs_int32 * astatus);
-static int fs_setstat(register struct fsbnode *abnode, afs_int32 astatus);
-static int fs_procexit(struct fsbnode *abnode, struct bnode_proc *aproc);
-static int fs_getstring(struct fsbnode *abnode, char *abuffer, afs_int32 alen);
-
-
-static int fs_getparm(struct fsbnode *abnode, afs_int32 aindex, 
+static int fs_hascore(struct bnode *abnode);
+static int fs_restartp(struct bnode *abnode);
+static int fs_delete(struct bnode *abnode);
+static int fs_timeout(struct bnode *abnode);
+static int fs_getstat(struct bnode *abnode, afs_int32 * astatus);
+static int fs_setstat(struct bnode *abnode, afs_int32 astatus);
+static int fs_procstarted(struct bnode *abnode, struct bnode_proc *aproc);
+static int fs_procexit(struct bnode *abnode, struct bnode_proc *aproc);
+static int fs_getstring(struct bnode *abnode, char *abuffer, afs_int32 alen);
+static int fs_getparm(struct bnode *abnode, afs_int32 aindex,
                      char *abuffer, afs_int32 alen);
-static int dafs_getparm(struct fsbnode *abnode, afs_int32 aindex, 
+static int dafs_getparm(struct bnode *abnode, afs_int32 aindex,
                        char *abuffer, afs_int32 alen);
 
+static int SetSalFlag(struct fsbnode *abnode, int aflag);
+static int RestoreSalFlag(struct fsbnode *abnode);
+static void SetNeedsClock(struct fsbnode *);
+static int NudgeProcs(struct fsbnode *);
+
 #ifdef AFS_NT40_ENV
-static void AppendExecutableExtension(char *cmd);
+static char *AppendExecutableExtension(char *cmd);
 #else
-#define AppendExecutableExtension(x)
+#define AppendExecutableExtension(x) strdup(x)
 #endif
 
-static void SetNeedsClock(register struct fsbnode *ab);
-static int NudgeProcs(register struct fsbnode *abnode);
-
-
-
 struct bnode_ops fsbnode_ops = {
     fs_create,
     fs_timeout,
@@ -145,6 +128,7 @@ struct bnode_ops fsbnode_ops = {
     fs_getparm,
     fs_restartp,
     fs_hascore,
+    fs_procstarted,
 };
 
 /* demand attach fs bnode ops */
@@ -159,8 +143,17 @@ struct bnode_ops dafsbnode_ops = {
     dafs_getparm,
     fs_restartp,
     fs_hascore,
+    fs_procstarted,
 };
 
+/* Quick inline function to safely convert a fsbnode to a bnode without
+ * dropping type information
+ */
+
+static_inline struct bnode *
+fsbnode2bnode(struct fsbnode *abnode) {
+    return (struct bnode *) abnode;
+}
 
 /* Function to tell whether this bnode has a core file or not.  You might
  * think that this could be in bnode.c, and decide what core files to check
@@ -169,7 +162,7 @@ struct bnode_ops dafsbnode_ops = {
  * time the query is done.
  */
 static int
-fs_hascore(register struct ezbnode *abnode)
+fs_hascore(struct bnode *abnode)
 {
     char tbuffer[256];
 
@@ -203,10 +196,11 @@ fs_hascore(register struct ezbnode *abnode)
 }
 
 static int
-fs_restartp(register struct fsbnode *abnode)
+fs_restartp(struct bnode *bn)
 {
+    struct fsbnode *abnode = (struct fsbnode *)bn;
     struct bnode_token *tt;
-    register afs_int32 code;
+    afs_int32 code;
     struct stat tstat;
 
     code = bnode_ParseLine(abnode->filecmd, &tt);
@@ -258,7 +252,7 @@ fs_restartp(register struct fsbnode *abnode)
            bnode_FreeTokens(tt);
            return 0;
        }
-       if (tstat.st_ctime > abnode->lastScanStart)
+       if (tstat.st_ctime > abnode->lastSalsrvStart)
            code = 1;
        else
            code = 0;
@@ -290,60 +284,57 @@ fs_restartp(register struct fsbnode *abnode)
 /* set needsSalvage flag, creating file SALVAGE.<instancename> if
     we need to salvage the file system (so we can tell over panic reboots */
 static int
-SetSalFlag(register struct fsbnode *abnode, register int aflag)
+SetSalFlag(struct fsbnode *abnode, int aflag)
 {
-    char tbuffer[AFSDIR_PATH_MAX];
+    char *filepath;
     int fd;
 
     /* don't use the salvage flag for demand attach fs */
     if (abnode->salsrvcmd == NULL) {
        abnode->needsSalvage = aflag;
-       strcompose(tbuffer, AFSDIR_PATH_MAX, AFSDIR_SERVER_LOCAL_DIRPATH, "/",
-                  SALFILE, abnode->b.name, NULL);
+       if (asprintf(&filepath, "%s/%s%s", AFSDIR_SERVER_LOCAL_DIRPATH,
+                  SALFILE, abnode->b.name) < 0)
+           return ENOMEM;
        if (aflag) {
-           fd = open(tbuffer, O_CREAT | O_TRUNC | O_RDWR, 0666);
+           fd = open(filepath, O_CREAT | O_TRUNC | O_RDWR, 0666);
            close(fd);
        } else {
-           unlink(tbuffer);
+           unlink(filepath);
        }
+       free(filepath);
     }
     return 0;
 }
 
 /* set the needsSalvage flag according to the existence of the salvage file */
 static int
-RestoreSalFlag(register struct fsbnode *abnode)
+RestoreSalFlag(struct fsbnode *abnode)
 {
-    char tbuffer[AFSDIR_PATH_MAX];
+    char *filepath;
 
     /* never set needs salvage flag for demand attach fs */
     if (abnode->salsrvcmd != NULL) {
        abnode->needsSalvage = 0;
     } else {
-       strcompose(tbuffer, AFSDIR_PATH_MAX, AFSDIR_SERVER_LOCAL_DIRPATH, "/",
-                  SALFILE, abnode->b.name, NULL);
-       if (access(tbuffer, 0) == 0) {
+       if (asprintf(&filepath, "%s/%s%s", AFSDIR_SERVER_LOCAL_DIRPATH,
+                    SALFILE, abnode->b.name) < 0)
+           return ENOMEM;
+       if (access(filepath, 0) == 0) {
            /* file exists, so need to salvage */
            abnode->needsSalvage = 1;
        } else {
            abnode->needsSalvage = 0;
        }
+       free(filepath);
     }
     return 0;
 }
 
-char *
-copystr(register char *a)
-{
-    register char *b;
-    b = (char *)malloc(strlen(a) + 1);
-    strcpy(b, a);
-    return b;
-}
-
 static int
-fs_delete(struct fsbnode *abnode)
+fs_delete(struct bnode *bn)
 {
+    struct fsbnode *abnode = (struct fsbnode *)bn;
+
     free(abnode->filecmd);
     free(abnode->volcmd);
     free(abnode->salcmd);
@@ -357,31 +348,35 @@ fs_delete(struct fsbnode *abnode)
 
 
 #ifdef AFS_NT40_ENV
-static void
+static char *
 AppendExecutableExtension(char *cmd)
 {
     char cmdext[_MAX_EXT];
+    char *cmdexe;
 
     _splitpath(cmd, NULL, NULL, NULL, cmdext);
     if (*cmdext == '\0') {
-       /* no filename extension supplied for cmd; append .exe */
-       strcat(cmd, ".exe");
+       if (asprintf(&cmdexe, "%s.exe", cmd) < 0)
+           return NULL;
+       return cmdexe;
     }
+    return strdup(cmd);
 }
 #endif /* AFS_NT40_ENV */
 
 
 struct bnode *
 fs_create(char *ainstance, char *afilecmd, char *avolcmd, char *asalcmd,
-         char *ascancmd)
+         char *ascancmd, char *dummy)
 {
     struct stat tstat;
-    register struct fsbnode *te;
-    char cmdname[AFSDIR_PATH_MAX];
+    struct fsbnode *te;
+    char *cmdname = NULL;
     char *fileCmdpath, *volCmdpath, *salCmdpath, *scanCmdpath;
     int bailout = 0;
 
-    te = fileCmdpath = volCmdpath = salCmdpath = scanCmdpath = NULL;
+    fileCmdpath = volCmdpath = salCmdpath = scanCmdpath = NULL;
+    te = NULL;
 
     /* construct local paths from canonical (wire-format) paths */
     if (ConstructLocalBinPath(afilecmd, &fileCmdpath)) {
@@ -409,24 +404,38 @@ fs_create(char *ainstance, char *afilecmd, char *avolcmd, char *asalcmd,
     }
 
     if (!bailout) {
-       sscanf(fileCmdpath, "%s", cmdname);
-       AppendExecutableExtension(cmdname);
+       cmdname = AppendExecutableExtension(fileCmdpath);
+       if (cmdname == NULL) {
+           bozo_Log("Out of memory constructing binary filename\n");
+           bailout = 1;
+           goto done;
+       }
        if (stat(cmdname, &tstat)) {
            bozo_Log("BNODE: file server binary '%s' not found\n", cmdname);
            bailout = 1;
            goto done;
        }
+       free(cmdname);
 
-       sscanf(volCmdpath, "%s", cmdname);
-       AppendExecutableExtension(cmdname);
+       cmdname = AppendExecutableExtension(volCmdpath);
+       if (cmdname == NULL) {
+           bozo_Log("Out of memory constructing binary filename\n");
+           bailout = 1;
+           goto done;
+       }
        if (stat(cmdname, &tstat)) {
            bozo_Log("BNODE: volume server binary '%s' not found\n", cmdname);
            bailout = 1;
            goto done;
        }
+       free(cmdname);
 
-       sscanf(salCmdpath, "%s", cmdname);
-       AppendExecutableExtension(cmdname);
+       cmdname = AppendExecutableExtension(salCmdpath);
+       if (cmdname == NULL) {
+           bozo_Log("Out of memory constructing binary filename\n");
+           bailout = 1;
+           goto done;
+       }
        if (stat(cmdname, &tstat)) {
            bozo_Log("BNODE: salvager binary '%s' not found\n", cmdname);
            bailout = 1;
@@ -434,8 +443,13 @@ fs_create(char *ainstance, char *afilecmd, char *avolcmd, char *asalcmd,
        }
 
        if (ascancmd && strlen(ascancmd)) {
-           sscanf(scanCmdpath, "%s", cmdname);
-           AppendExecutableExtension(cmdname);
+           free(cmdname);
+           cmdname = AppendExecutableExtension(scanCmdpath);
+           if (cmdname == NULL) {
+               bozo_Log("Out of memory constructing binary filename\n");
+               bailout = 1;
+               goto done;
+           }
            if (stat(cmdname, &tstat)) {
                bozo_Log("BNODE: scanner binary '%s' not found\n", cmdname);
                bailout = 1;
@@ -444,12 +458,11 @@ fs_create(char *ainstance, char *afilecmd, char *avolcmd, char *asalcmd,
        }
     }
 
-    te = (struct fsbnode *)malloc(sizeof(struct fsbnode));
+    te = calloc(1, sizeof(struct fsbnode));
     if (te == NULL) {
        bailout = 1;
        goto done;
     }
-    memset(te, 0, sizeof(struct fsbnode));
     te->filecmd = fileCmdpath;
     te->volcmd = volCmdpath;
     te->salsrvcmd = NULL;
@@ -458,15 +471,17 @@ fs_create(char *ainstance, char *afilecmd, char *avolcmd, char *asalcmd,
        te->scancmd = scanCmdpath;
     else
        te->scancmd = NULL;
-    if (bnode_InitBnode(te, &fsbnode_ops, ainstance) != 0) {
+    if (bnode_InitBnode(fsbnode2bnode(te), &fsbnode_ops, ainstance) != 0) {
        bailout = 1;
        goto done;
     }
-    bnode_SetTimeout(te, POLLTIME);    /* ask for timeout activations every 10 seconds */
+    bnode_SetTimeout(fsbnode2bnode(te), POLLTIME);
+               /* ask for timeout activations every 20 seconds */
     RestoreSalFlag(te);                /* restore needsSalvage flag based on file's existence */
     SetNeedsClock(te);         /* compute needsClock field */
 
  done:
+    free(cmdname);
     if (bailout) {
        if (te)
            free(te);
@@ -481,21 +496,22 @@ fs_create(char *ainstance, char *afilecmd, char *avolcmd, char *asalcmd,
        return NULL;
     }
 
-    return (struct bnode *)te;
+    return fsbnode2bnode(te);
 }
 
 /* create a demand attach fs bnode */
 struct bnode *
-dafs_create(char *ainstance, char *afilecmd, char *avolcmd, 
+dafs_create(char *ainstance, char *afilecmd, char *avolcmd,
            char * asalsrvcmd, char *asalcmd, char *ascancmd)
 {
     struct stat tstat;
-    register struct fsbnode *te;
-    char cmdname[AFSDIR_PATH_MAX];
+    struct fsbnode *te;
+    char *cmdname = NULL;
     char *fileCmdpath, *volCmdpath, *salsrvCmdpath, *salCmdpath, *scanCmdpath;
     int bailout = 0;
 
-    te = fileCmdpath = volCmdpath = salsrvCmdpath = salCmdpath = scanCmdpath = NULL;
+    fileCmdpath = volCmdpath = salsrvCmdpath = salCmdpath = scanCmdpath = NULL;
+    te = NULL;
 
     /* construct local paths from canonical (wire-format) paths */
     if (ConstructLocalBinPath(afilecmd, &fileCmdpath)) {
@@ -528,32 +544,51 @@ dafs_create(char *ainstance, char *afilecmd, char *avolcmd,
     }
 
     if (!bailout) {
-       sscanf(fileCmdpath, "%s", cmdname);
-       AppendExecutableExtension(cmdname);
+       cmdname = AppendExecutableExtension(fileCmdpath);
+       if (cmdname == NULL) {
+           bozo_Log("Out of memory constructing binary filename\n");
+           bailout = 1;
+           goto done;
+       }
        if (stat(cmdname, &tstat)) {
            bozo_Log("BNODE: file server binary '%s' not found\n", cmdname);
            bailout = 1;
            goto done;
        }
+       free(cmdname);
 
-       sscanf(volCmdpath, "%s", cmdname);
-       AppendExecutableExtension(cmdname);
+       cmdname = AppendExecutableExtension(volCmdpath);
+       if (cmdname == NULL) {
+           bozo_Log("Out of memory constructing binary filename\n");
+           bailout = 1;
+           goto done;
+       }
        if (stat(cmdname, &tstat)) {
            bozo_Log("BNODE: volume server binary '%s' not found\n", cmdname);
            bailout = 1;
            goto done;
        }
+       free(cmdname);
 
-       sscanf(salsrvCmdpath, "%s", cmdname);
-       AppendExecutableExtension(cmdname);
+       cmdname = AppendExecutableExtension(salsrvCmdpath);
+       if (cmdname == NULL) {
+           bozo_Log("Out of memory constructing binary filename\n");
+           bailout = 1;
+           goto done;
+       }
        if (stat(cmdname, &tstat)) {
            bozo_Log("BNODE: salvageserver binary '%s' not found\n", cmdname);
            bailout = 1;
            goto done;
        }
+       free(cmdname);
 
-       sscanf(salCmdpath, "%s", cmdname);
-       AppendExecutableExtension(cmdname);
+       cmdname = AppendExecutableExtension(salCmdpath);
+       if (cmdname == NULL) {
+           bozo_Log("Out of memory constructing binary filename\n");
+           bailout = 1;
+           goto done;
+       }
        if (stat(cmdname, &tstat)) {
            bozo_Log("BNODE: salvager binary '%s' not found\n", cmdname);
            bailout = 1;
@@ -561,8 +596,13 @@ dafs_create(char *ainstance, char *afilecmd, char *avolcmd,
        }
 
        if (ascancmd && strlen(ascancmd)) {
-           sscanf(scanCmdpath, "%s", cmdname);
-           AppendExecutableExtension(cmdname);
+           free(cmdname);
+           cmdname = AppendExecutableExtension(scanCmdpath);
+           if (cmdname == NULL) {
+               bozo_Log("Out of memory constructing binary filename\n");
+               bailout = 1;
+               goto done;
+           }
            if (stat(cmdname, &tstat)) {
                bozo_Log("BNODE: scanner binary '%s' not found\n", cmdname);
                bailout = 1;
@@ -571,12 +611,11 @@ dafs_create(char *ainstance, char *afilecmd, char *avolcmd,
        }
     }
 
-    te = (struct fsbnode *)malloc(sizeof(struct fsbnode));
+    te = calloc(1, sizeof(struct fsbnode));
     if (te == NULL) {
        bailout = 1;
        goto done;
     }
-    memset(te, 0, sizeof(struct fsbnode));
     te->filecmd = fileCmdpath;
     te->volcmd = volCmdpath;
     te->salsrvcmd = salsrvCmdpath;
@@ -585,15 +624,17 @@ dafs_create(char *ainstance, char *afilecmd, char *avolcmd,
        te->scancmd = scanCmdpath;
     else
        te->scancmd = NULL;
-    if (bnode_InitBnode(te, &dafsbnode_ops, ainstance) != 0) {
+    if (bnode_InitBnode(fsbnode2bnode(te), &dafsbnode_ops, ainstance) != 0) {
        bailout = 1;
        goto done;
     }
-    bnode_SetTimeout(te, POLLTIME);    /* ask for timeout activations every 10 seconds */
+    bnode_SetTimeout(fsbnode2bnode(te), POLLTIME);
+               /* ask for timeout activations every 20 seconds */
     RestoreSalFlag(te);                /* restore needsSalvage flag based on file's existence */
     SetNeedsClock(te);         /* compute needsClock field */
 
  done:
+    free(cmdname);
     if (bailout) {
        if (te)
            free(te);
@@ -610,14 +651,16 @@ dafs_create(char *ainstance, char *afilecmd, char *avolcmd,
        return NULL;
     }
 
-    return (struct bnode *)te;
+    return fsbnode2bnode(te);
 }
 
 /* called to SIGKILL a process if it doesn't terminate normally */
 static int
-fs_timeout(struct fsbnode *abnode)
+fs_timeout(struct bnode *bn)
 {
-    register afs_int32 now;
+    struct fsbnode *abnode = (struct fsbnode *)bn;
+
+    afs_int32 now;
 
     now = FT_ApproxTime();
     /* shutting down */
@@ -666,14 +709,26 @@ fs_timeout(struct fsbnode *abnode)
                 SDTIME);
        }
     }
+
+    if ((abnode->b.flags & BNODE_ERRORSTOP) && !abnode->salRunning
+       && !abnode->volRunning && !abnode->fileRunning && !abnode->scanRunning
+       && !abnode->salsrvRunning) {
+       bnode_SetStat(bn, BSTAT_NORMAL);
+    }
+    else {
+       bnode_ResetErrorCount(bn);
+    }
+
     SetNeedsClock(abnode);
     return 0;
 }
 
 static int
-fs_getstat(struct fsbnode *abnode, afs_int32 * astatus)
+fs_getstat(struct bnode *bn, afs_int32 * astatus)
 {
-    register afs_int32 temp;
+    struct fsbnode *abnode = (struct fsbnode *) bn;
+
+    afs_int32 temp;
     if (abnode->volSDW || abnode->fileSDW || abnode->salSDW
        || abnode->scanSDW || abnode->salsrvSDW)
        temp = BSTAT_SHUTTINGDOWN;
@@ -694,16 +749,33 @@ fs_getstat(struct fsbnode *abnode, afs_int32 * astatus)
 }
 
 static int
-fs_setstat(register struct fsbnode *abnode, afs_int32 astatus)
+fs_setstat(struct bnode *abnode, afs_int32 astatus)
 {
-    return NudgeProcs(abnode);
+    return NudgeProcs((struct fsbnode *) abnode);
 }
 
 static int
-fs_procexit(struct fsbnode *abnode, struct bnode_proc *aproc)
+fs_procstarted(struct bnode *bn, struct bnode_proc *aproc)
 {
+    int code = 0;
+
+    if (DoPidFiles) {
+       code = bozo_CreatePidFile(bn->name, aproc->coreName, aproc->pid);
+    }
+    return code;
+}
+
+static int
+fs_procexit(struct bnode *bn, struct bnode_proc *aproc)
+{
+   struct fsbnode *abnode = (struct fsbnode *)bn;
+
     /* process has exited */
 
+    if (DoPidFiles) {
+       bozo_DeletePidFile(bn->name, aproc->coreName);
+    }
+
     if (aproc == abnode->volProc) {
        abnode->volProc = 0;
        abnode->volRunning = 0;
@@ -749,28 +821,49 @@ fs_procexit(struct fsbnode *abnode, struct bnode_proc *aproc)
 
 /* make sure we're periodically checking the state if we need to */
 static void
-SetNeedsClock(register struct fsbnode *ab)
+SetNeedsClock(struct fsbnode *ab)
 {
-    if (ab->b.goal == 1 && ab->fileRunning && ab->volRunning
+    afs_int32 timeout = POLLTIME;
+
+    if ((ab->fileSDW && !ab->fileKillSent) || (ab->volSDW && !ab->volKillSent)
+       || (ab->scanSDW && !ab->scanKillSent) || (ab->salSDW && !ab->salKillSent)
+       || (ab->salsrvSDW && !ab->salsrvKillSent)) {
+       /* SIGQUIT sent, will send SIGKILL if process does not exit */
+       ab->needsClock = 1;
+    } else if (ab->b.goal == 1 && ab->fileRunning && ab->volRunning
        && (!ab->scancmd || ab->scanRunning)
-       && (!ab->salsrvcmd || ab->salsrvRunning))
-       ab->needsClock = 0;     /* running normally */
-    else if (ab->b.goal == 0 && !ab->fileRunning && !ab->volRunning
-            && !ab->salRunning && !ab->scanRunning && !ab->salsrvRunning)
-       ab->needsClock = 0;     /* halted normally */
-    else
+       && (!ab->salsrvcmd || ab->salsrvRunning)) {
+       if (ab->b.errorStopCount) {
+           /* reset error count after running for a bit */
+           ab->needsClock = 1;
+       } else {
+           ab->needsClock = 0; /* running normally */
+       }
+    } else if ((ab->b.goal == 0) && !ab->fileRunning && !ab->volRunning
+              && !ab->salRunning && !ab->scanRunning && !ab->salsrvRunning) {
+       if (ab->b.flags & BNODE_ERRORSTOP && ab->b.errorStopDelay) {
+           bozo_Log("%s will retry start in %d seconds\n", ab->b.name,
+                    ab->b.errorStopDelay);
+           ab->needsClock = 1; /* halted for errors, retry later */
+           timeout = ab->b.errorStopDelay;
+       } else {
+           ab->needsClock = 0; /* halted normally */
+       }
+    } else
        ab->needsClock = 1;     /* other */
-    if (ab->needsClock && !bnode_PendingTimeout(ab))
-       bnode_SetTimeout(ab, POLLTIME);
+
+    if (ab->needsClock && (!bnode_PendingTimeout(fsbnode2bnode(ab))
+                          || ab->b.period != timeout))
+       bnode_SetTimeout(fsbnode2bnode(ab), timeout);
     if (!ab->needsClock)
-       bnode_SetTimeout(ab, 0);
+       bnode_SetTimeout(fsbnode2bnode(ab), 0);
 }
 
 static int
-NudgeProcs(register struct fsbnode *abnode)
+NudgeProcs(struct fsbnode *abnode)
 {
     struct bnode_proc *tp;     /* not register */
-    register afs_int32 code;
+    afs_int32 code;
     afs_int32 now;
 
     now = FT_ApproxTime();
@@ -783,14 +876,14 @@ NudgeProcs(register struct fsbnode *abnode)
                bozo_Log("Salvager running along with file server!\n");
                bozo_Log("Emergency shutdown\n");
                emergency = 1;
-               bnode_SetGoal(abnode, BSTAT_SHUTDOWN);
+               bnode_SetGoal(fsbnode2bnode(abnode), BSTAT_SHUTDOWN);
                bnode_StopProc(abnode->salProc, SIGKILL);
                SetNeedsClock(abnode);
                return -1;
            }
            if (!abnode->volRunning) {
                abnode->lastVolStart = FT_ApproxTime();
-               code = bnode_NewProc(abnode, abnode->volcmd, "vol", &tp);
+               code = bnode_NewProc(fsbnode2bnode(abnode), abnode->volcmd, "vol", &tp);
                if (code == 0) {
                    abnode->volProc = tp;
                    abnode->volRunning = 1;
@@ -800,7 +893,7 @@ NudgeProcs(register struct fsbnode *abnode)
                if (!abnode->salsrvRunning) {
                    abnode->lastSalsrvStart = FT_ApproxTime();
                    code =
-                       bnode_NewProc(abnode, abnode->salsrvcmd, "salsrv",
+                       bnode_NewProc(fsbnode2bnode(abnode), abnode->salsrvcmd, "salsrv",
                                      &tp);
                    if (code == 0) {
                        abnode->salsrvProc = tp;
@@ -812,7 +905,7 @@ NudgeProcs(register struct fsbnode *abnode)
                if (!abnode->scanRunning) {
                    abnode->lastScanStart = FT_ApproxTime();
                    code =
-                       bnode_NewProc(abnode, abnode->scancmd, "scanner",
+                       bnode_NewProc(fsbnode2bnode(abnode), abnode->scancmd, "scanner",
                                      &tp);
                    if (code == 0) {
                        abnode->scanProc = tp;
@@ -828,7 +921,7 @@ NudgeProcs(register struct fsbnode *abnode)
                if (!abnode->fileRunning) {
                    abnode->lastFileStart = FT_ApproxTime();
                    code =
-                       bnode_NewProc(abnode, abnode->filecmd, "file", &tp);
+                       bnode_NewProc(fsbnode2bnode(abnode), abnode->filecmd, "file", &tp);
                    if (code == 0) {
                        abnode->fileProc = tp;
                        abnode->fileRunning = 1;
@@ -837,7 +930,7 @@ NudgeProcs(register struct fsbnode *abnode)
                }
                if (!abnode->volRunning) {
                    abnode->lastVolStart = FT_ApproxTime();
-                   code = bnode_NewProc(abnode, abnode->volcmd, "vol", &tp);
+                   code = bnode_NewProc(fsbnode2bnode(abnode), abnode->volcmd, "vol", &tp);
                    if (code == 0) {
                        abnode->volProc = tp;
                        abnode->volRunning = 1;
@@ -846,7 +939,7 @@ NudgeProcs(register struct fsbnode *abnode)
                if (abnode->salsrvcmd && !abnode->salsrvRunning) {
                    abnode->lastSalsrvStart = FT_ApproxTime();
                    code =
-                       bnode_NewProc(abnode, abnode->salsrvcmd, "salsrv",
+                       bnode_NewProc(fsbnode2bnode(abnode), abnode->salsrvcmd, "salsrv",
                                      &tp);
                    if (code == 0) {
                        abnode->salsrvProc = tp;
@@ -856,7 +949,7 @@ NudgeProcs(register struct fsbnode *abnode)
                if (abnode->scancmd && !abnode->scanRunning) {
                    abnode->lastScanStart = FT_ApproxTime();
                    code =
-                       bnode_NewProc(abnode, abnode->scancmd, "scanner",
+                       bnode_NewProc(fsbnode2bnode(abnode), abnode->scancmd, "scanner",
                                      &tp);
                    if (code == 0) {
                        abnode->scanProc = tp;
@@ -888,7 +981,7 @@ NudgeProcs(register struct fsbnode *abnode)
                    return 0;
                /* otherwise, it is safe to start salvager */
                if (!abnode->salRunning) {
-                   code = bnode_NewProc(abnode, abnode->salcmd, "salv", &tp);
+                   code = bnode_NewProc(fsbnode2bnode(abnode), abnode->salcmd, "salv", &tp);
                    if (code == 0) {
                        abnode->salProc = tp;
                        abnode->salRunning = 1;
@@ -929,8 +1022,10 @@ NudgeProcs(register struct fsbnode *abnode)
 }
 
 static int
-fs_getstring(struct fsbnode *abnode, char *abuffer, afs_int32 alen)
+fs_getstring(struct bnode *bn, char *abuffer, afs_int32 alen)
 {
+    struct fsbnode *abnode = (struct fsbnode *)bn;
+
     if (alen < 40)
        return -1;
     if (abnode->b.goal == 1) {
@@ -971,9 +1066,11 @@ fs_getstring(struct fsbnode *abnode, char *abuffer, afs_int32 alen)
 }
 
 static int
-fs_getparm(struct fsbnode *abnode, afs_int32 aindex, char *abuffer,
+fs_getparm(struct bnode *bn, afs_int32 aindex, char *abuffer,
           afs_int32 alen)
 {
+    struct fsbnode *abnode = (struct fsbnode *)bn;
+
     if (aindex == 0)
        strcpy(abuffer, abnode->filecmd);
     else if (aindex == 1)
@@ -988,9 +1085,11 @@ fs_getparm(struct fsbnode *abnode, afs_int32 aindex, char *abuffer,
 }
 
 static int
-dafs_getparm(struct fsbnode *abnode, afs_int32 aindex, char *abuffer,
+dafs_getparm(struct bnode *bn, afs_int32 aindex, char *abuffer,
             afs_int32 alen)
 {
+    struct fsbnode *abnode = (struct fsbnode *)bn;
+
     if (aindex == 0)
        strcpy(abuffer, abnode->filecmd);
     else if (aindex == 1)