Logo Search packages:      
Sourcecode: nfs-user-server version File versions  Download package

failsafe.c

/*
 * failsafe.c
 *
 * Copyright (C) 1998, <okir@monad.swb.de>
 *
 * Implements fail-safe mode for nfsd/mountd.
 */

#include "system.h"
#include "logging.h"
#include "signals.h"
#include <sys/wait.h>

static const char *     get_signame(int signo);

void
failsafe(int level, int ncopies)
{
      int   *servers, running, child, i;
      int   pid, signo, status;
      time_t      last_restart = 0, now;
      int   restarts = 0, backoff = 60;

      servers = (int *) xmalloc(ncopies * sizeof(int));
      memset(servers, 0, ncopies * sizeof(int));

      /* Loop forever, until we get SIGTERM */
      running = 0;
      while (1) {
            while (running < ncopies) {
                  if ((now = time(NULL)) == last_restart) {
                        if (++restarts > 2 * ncopies) {
                              Dprintf(L_ERROR,
                                    "Servers restarting too "
                                    "quickly, backing off.");
                              if (backoff < 60 * 60)
                                    backoff <<= 1;
                              sleep(backoff);
                        }
                  } else {
                        last_restart = now;
                        restarts = 0;
                        backoff = 60;
                  }

                  /* Locate a free pid slot */
                  for (i = 0, child = -1; i < ncopies; i++) {
                        if (servers[i] == 0) {
                              child = i;
                              break;
                        }
                  }

                  if (child < 0)
                        Dprintf(L_FATAL, "failsafe: no pid slot?!");

                  Dprintf(D_GENERAL,
                        "starting server thread %d...\n", child + 1);

                  pid = fork();
                  if (pid < 0)
                        Dprintf(L_FATAL,
                              "Unable to fork for failsafe: %s",
                              strerror(errno));

                  if (pid == 0) {
                        /* Child process: continue with execution. */
                        return;
                  }

                  servers[child] = pid;
                  running++;
            }

            /* Ignore some signals */
            ignore_signal(SIGTERM);
            ignore_signal(SIGHUP);
            ignore_signal(SIGINT);
            ignore_signal(SIGCHLD);

            if ((pid = wait(&status)) < 0) {
                  Dprintf((errno == ECHILD)? L_FATAL : L_WARNING,
                        "failsafe: wait(): %s", strerror(errno));
                  continue;
            }

            /* Locate the child */
            for (i = 0, child = -1; i < ncopies; i++) {
                  if (servers[i] == pid) {
                        child = i;
                        break;
                  }
            }

            if (child < 0) {
                  Dprintf(L_WARNING,
                        "failsafe: unknown child (pid %d) terminated",
                        pid);
                  continue;
            }

            /* Book-keeping */
            servers[child] = 0;
            running--;

            if (WIFSIGNALED(status)) {
                  signo = WTERMSIG(status);
                  if (signo == SIGTERM) {
                        Dprintf(L_NOTICE, "failsafe: "
                              "child %d terminated by SIGTERM. %s.",
                              pid, running? "Continue" : "Exit");
                  } else {
                        Dprintf(L_WARNING, "failsafe: "
                              "child %d terminated by %s. "
                              "Restarting.",
                              pid, get_signame(signo));
                        child = -1; /* Restart */
                  }
            } else if (WIFEXITED(status)) {
                  Dprintf(L_NOTICE, "failsafe: "
                        "child %d exited, status %d.",
                        pid, WEXITSTATUS(status));
            } else {
                  Dprintf(L_ERROR, "failsafe: "
                        "abnormal child termination, "
                        "pid=%d status=%d. Restarting.",
                        pid, status);
                  child = -1; /* Restart */
            }

            /* If child >= 0, we should not restart */
            if (child >= 0) {
                  if (!running) {
                        Dprintf(D_GENERAL,
                              "No more children, exiting.");
                        exit(0);
                  }
                  for (i = child; i < ncopies-1; i++)
                        servers[i] = servers[i+1];
                  ncopies--; /* Make sure we start no new servers */
            }
      }
}

/*
 * Failsafe session, catch core file.
 *
 * Not yet implemented.
 * General outline: we need to fork first, because nfsd changes
 * uids frequently, and the kernel won't write out a core file after
 * that. The forked proc starts out with a clean dumpable flag though.
 *
 * After the fork, we might want to make sure we end up in some common
 * directory that the failsafe loop knows about.
 */
void
failsafe_loop(int level, void (*function)(void))
{
      /* NOP */
}

static const char *
get_signame(int signo)
{
      static char namebuf[30];

      switch (signo) {
      case SIGHUP:      return "SIGHUP";
      case SIGINT:      return "SIGINT";
      case SIGQUIT:     return "SIGQUIT";
      case SIGILL:      return "SIGILL";
      case SIGTRAP:     return "SIGTRAP";
      case SIGIOT:      return "SIGIOT";
      case SIGBUS:      return "SIGBUS";
      case SIGFPE:      return "SIGFPE";
      case SIGKILL:     return "SIGKILL";
      case SIGUSR1:     return "SIGUSR1";
      case SIGSEGV:     return "SIGSEGV";
      case SIGUSR2:     return "SIGUSR2";
      case SIGPIPE:     return "SIGPIPE";
      case SIGALRM:     return "SIGALRM";
      case SIGTERM:     return "SIGTERM";
      case SIGCHLD:     return "SIGCHLD";
      case SIGCONT:     return "SIGCONT";
      case SIGSTOP:     return "SIGSTOP";
      case SIGTSTP:     return "SIGTSTP";
      case SIGTTIN:     return "SIGTTIN";
      case SIGTTOU:     return "SIGTTOU";
      case SIGURG:      return "SIGURG";
      case SIGXCPU:     return "SIGXCPU";
      case SIGXFSZ:     return "SIGXFSZ";
      case SIGVTALRM:   return "SIGVTALRM";
      case SIGPROF:     return "SIGPROF";
      case SIGWINCH:    return "SIGWINCH";
      case SIGIO: return "SIGIO";
      case SIGPWR:      return "SIGPWR";
      }

      sprintf(namebuf, "signal #%d", signo);
      return namebuf;
}

Generated by  Doxygen 1.6.0   Back to index