Logo Search packages:      
Sourcecode: maildrop version File versions  Download package

lockdaemon.c

/*
** Copyright 2000-2001 Double Precision, Inc.  See COPYING for
** distribution information.
*/

#include    "config.h"
#include    "liblock.h"
#include    <stdio.h>
#include    <signal.h>
#include    <stdlib.h>
#include    <string.h>
#include    <unistd.h>
#include    <errno.h>
#if   HAVE_FCNTL_H
#include    <fcntl.h>
#endif
#include    <sys/types.h>
#include    "../numlib/numlib.h"
#if HAVE_SYS_WAIT_H
#include <sys/wait.h>
#endif
#ifndef WEXITSTATUS
#define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
#endif
#ifndef WIFEXITED
#define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
#endif
#if   HAVE_SYS_IOCTL_H
#include    <sys/ioctl.h>
#endif

#define exit(_a_) _exit(_a_)

static const char rcsid[]="$Id: lockdaemon.c,v 1.7 2003/01/05 04:01:16 mrsam Exp $";

static int start1(const char *, int);

#define CONSOLE "/dev/null"

int ll_daemon_start(const char *lockfile)
{
pid_t p;
int   pipefd[2];
char  c;
int   i;

      /*
      ** Close any open file descriptors.
      */

      for (i=3; i < 256; i++)
            close(i);

      /*
      ** We fork, and set up a pipe from the child process.  If we read
      ** a single 0 byte from the pipe, it means that the child has
      ** succesfully initialized, and will return to main, so we exit(0).
      ** If we do not read a single 0 byte from the pipe, it means that
      ** there was an initialization error, so we return -1 to main.
      */

      if (pipe(pipefd) < 0)
      {
            perror("pipe");
            return (-1);
      }

      if ((p=fork()) == -1)
      {
            close(pipefd[0]);
            close(pipefd[1]);
            perror("fork");
            return (-1);
      }

      if (p == 0)
      {
            close(pipefd[0]);

            /*
            ** We fork once more, so that the daemon process will not
            ** be the child process of anyone.
            */

            p=fork();
            if (p == -1)
            {
                  perror("fork");
                  exit(0);
            }
            if (p)
                  exit(0);

            /*
            ** Continue initialization in start1()
            */
            return (start1(lockfile, pipefd[1]));
      }

      close(pipefd[1]);
      if (read(pipefd[0], &c, 1) <= 0)
            c=1;
      close(pipefd[0]);
      if (c == 0)
            exit (0);   /* Successful start of daemon */
      errno=EAGAIN;
      return (-1);
}

static int start1(const char *lockfile, int fd)
{
int   lockfd;

#if     HAVE_SETPGRP
#if     SETPGRP_VOID
      setpgrp();
#else
      setpgrp(0, 0);
#endif
#endif
#ifdef  TIOCNOTTY

      {
      int fd=open("/dev/tty", O_RDWR);

            if (fd >= 0)
            {
                  ioctl(fd, TIOCNOTTY, 0);
                  close(fd);
            }
      }
#endif


      /* Attempt to obtain a lock */

      if ((lockfd=open(lockfile, O_RDWR|O_CREAT, 0600)) < 0)
      {
            perror(lockfile);
            exit(1);
      }

#ifdef      FD_CLOEXEC
      if (fcntl(lockfd, F_SETFD, FD_CLOEXEC) < 0)
      {
            perror("fcntl");
            close(lockfd);
            exit(1);
      }
#endif

      if (ll_lock_ex_test(lockfd))
      {
            write(fd, "", 1);
            close(fd);
            exit (0);   /* Already running, pretend success */
      }

      /*
      ** Return >0 to main, so it can continue main's setup.
      */

      return (fd);
}

int ll_daemon_resetio()
{
int   i;

      close(0);
      if (open("/dev/null", O_RDONLY) != 0)
            return (-1);

      close(1);
      i=open(CONSOLE, O_WRONLY);
      if (i < 0)  i=open("/dev/null", O_WRONLY);
      if (i != 1) return (-1);

      close(2);
      i=open(CONSOLE, O_WRONLY);
      if (i < 0)  i=open("/dev/null", O_WRONLY);
      if (i != 2) return (-1);
      return (0);
}

void ll_daemon_started(const char *pidfile, int fd)
{
char  buf[NUMBUFSIZE+1];
char  *p=strcat(libmail_str_pid_t(getpid(), buf), "\n");
size_t      l=strlen(p);
FILE  *fp;

      if ((fp=fopen(pidfile, "w")) == NULL ||
            fprintf(fp, "%s", p) < 0 || fflush(fp) < 0 || fclose(fp))
      {
            perror(pidfile);
            exit(1);
      }

      write(fd, "", 1); /* Signal waiting parent */
      close(fd);
}

static void stop1(const char *, const char *);

int ll_daemon_stop(const char *lockfile, const char *pidfile)
{
pid_t p, p2;
int   waitstat;

      /*
      ** We fork, and the child process attempts to stop the daemon,
      ** then communicates the success to us, via its exit code.
      */

      signal(SIGCHLD, SIG_DFL);
      if ((p=fork()) == -1)
      {
            perror("fork");
            return (1);
      }
      if (p == 0) stop1(lockfile, pidfile);

      while ((p2=wait(&waitstat)) != p)
            ;

      if (WIFEXITED(waitstat))
            return (WEXITSTATUS(waitstat));
      return (0);
}

/*
**    The child process forks too.  The parent process goes in a loop,
**    trying to kill the daemon process.
**
**    The child process attempts to lock the lock file.  When it
**    succeeds, it exits.  When the child process exits, the parent
**    process kills itself.
*/

static RETSIGTYPE sigexit(int signum)
{
      kill(getpid(), SIGKILL);
#if     RETSIGTYPE != void
      return (0);
#endif
}

static void stop1(const char *lockfile, const char *pidfile)
{
int   lockfd;
pid_t p;

      if ((lockfd=open(lockfile, O_RDWR|O_CREAT, 0600)) < 0)
      {
            perror(lockfile);
            exit(1);
      }

      if ( ll_lock_ex_test(lockfd) == 0)  /* No daemon process running */
      {
            close(lockfd);
            exit (0);   /* That was easy! */
      }

      signal(SIGCHLD, sigexit);

      if ((p=fork()) == -1)
      {
            perror("fork");
            exit(1);
      }

      if (p)      /* Parent - first sends a SIGTERM, then a SIGKILL */
      {
      int   signum=SIGTERM;

            close(lockfd);
            for (;; sleep(10))
            {
            FILE  *fp;
            int   c;

                  if ((fp=fopen(pidfile, "r")) == NULL)
                        continue;

                  p=0;

                  while ((c=getc(fp)) != EOF && c != '\n')
                  {
                        if (isdigit(c))
                              p=p*10+(c-'0');
                  }

                  fclose(fp);
                  if (p)
                        kill(p, signum);
                  signum=SIGKILL;
            }
      }

      if (ll_lock_ex(lockfd))
            perror("lock");
      close(lockfd);
      exit(0);
}

int ll_daemon_restart(const char *lockfile, const char *pidfile)
{
int   lockfd;
pid_t p;
FILE  *fp;
int   c;

      if ((lockfd=open(lockfile, O_RDWR|O_CREAT, 0600)) < 0)
      {
            perror(lockfile);
            return (1);
      }

      if ( ll_lock_ex_test(lockfd) == 0)  /* No daemon process running */
      {
            close(lockfd);
            return (0); /* That was easy! */
      }
      close(lockfd);

      if ((fp=fopen(pidfile, "r")) == NULL)
            return (0);

      p=0;

      while ((c=getc(fp)) != EOF && c != '\n')
      {
            if (isdigit(c))
                  p=p*10+(c-'0');
      }

      fclose(fp);
      if (p)
            kill(p, SIGHUP);
      return (0);
}


Generated by  Doxygen 1.6.0   Back to index