Back to index

courier  0.68.2
lockdaemon.c
Go to the documentation of this file.
00001 /*
00002 ** Copyright 2000-2007 Double Precision, Inc.  See COPYING for
00003 ** distribution information.
00004 */
00005 
00006 #include      "config.h"
00007 #include      "liblock.h"
00008 #include      <stdio.h>
00009 #include      <signal.h>
00010 #include      <limits.h>
00011 #include      <stdlib.h>
00012 #include      <string.h>
00013 #include      <unistd.h>
00014 #include      <ctype.h>
00015 #include      <errno.h>
00016 #if    HAVE_FCNTL_H
00017 #include      <fcntl.h>
00018 #endif
00019 #include      <sys/types.h>
00020 #include      "../numlib/numlib.h"
00021 #if HAVE_SYS_WAIT_H
00022 #include <sys/wait.h>
00023 #endif
00024 #ifndef WEXITSTATUS
00025 #define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
00026 #endif
00027 #ifndef WIFEXITED
00028 #define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
00029 #endif
00030 #if    HAVE_SYS_IOCTL_H
00031 #include      <sys/ioctl.h>
00032 #endif
00033 
00034 #define exit(_a_) _exit(_a_)
00035 
00036 
00037 static int start1(const char *, int);
00038 
00039 #define CONSOLE "/dev/null"
00040 
00041 int ll_daemon_start(const char *lockfile)
00042 {
00043 pid_t  p;
00044 int    pipefd[2];
00045 char   c;
00046 int    i;
00047 
00048        /*
00049        ** Close any open file descriptors.
00050        */
00051 
00052        for (i=3; i < 256; i++)
00053               close(i);
00054 
00055        /*
00056        ** We fork, and set up a pipe from the child process.  If we read
00057        ** a single 0 byte from the pipe, it means that the child has
00058        ** successfully initialized, and will return to main, so we exit(0).
00059        ** If we do not read a single 0 byte from the pipe, it means that
00060        ** there was an initialization error, so we return -1 to main.
00061        */
00062 
00063        if (pipe(pipefd) < 0)
00064        {
00065               perror("pipe");
00066               return (-1);
00067        }
00068 
00069        if ((p=fork()) == -1)
00070        {
00071               close(pipefd[0]);
00072               close(pipefd[1]);
00073               perror("fork");
00074               return (-1);
00075        }
00076 
00077        if (p == 0)
00078        {
00079               close(pipefd[0]);
00080 
00081               /*
00082               ** We fork once more, so that the daemon process will not
00083               ** be the child process of anyone.
00084               */
00085 
00086               p=fork();
00087               if (p == -1)
00088               {
00089                      perror("fork");
00090                      exit(0);
00091               }
00092               if (p)
00093                      exit(0);
00094 
00095               /*
00096               ** Continue initialization in start1()
00097               */
00098               return (start1(lockfile, pipefd[1]));
00099        }
00100 
00101        close(pipefd[1]);
00102        if (read(pipefd[0], &c, 1) <= 0)
00103               c=1;
00104        close(pipefd[0]);
00105        if (c == 0)
00106               exit (0);     /* Successful start of daemon */
00107        errno=EAGAIN;
00108        return (-1);
00109 }
00110 
00111 static int start1(const char *lockfile, int fd)
00112 {
00113 int    lockfd, maxfd;
00114 
00115 #if     HAVE_SETPGRP
00116 #if     SETPGRP_VOID
00117        setpgrp();
00118 #else
00119        setpgrp(0, 0);
00120 #endif
00121 #endif
00122 #ifdef  TIOCNOTTY
00123 
00124        {
00125        int fd=open("/dev/tty", O_RDWR);
00126 
00127               if (fd >= 0)
00128               {
00129                      ioctl(fd, TIOCNOTTY, 0);
00130                      close(fd);
00131               }
00132        }
00133 #endif
00134 
00135 
00136        /* Attempt to obtain a lock */
00137 
00138        lockfd=open(lockfile, O_RDWR|O_CREAT, 0600);
00139 
00140        if (lockfd < 0)
00141        {
00142               /* Perhaps an upgraded daemon runs under new uid? */
00143 
00144               unlink(lockfile);
00145               lockfd=open(lockfile, O_RDWR|O_CREAT, 0600);
00146        }
00147 
00148 #if HAVE_GETDTABLESIZE
00149        maxfd=getdtablesize()-1;
00150 #elif defined(OPEN_MAX)
00151        maxfd=OPEN_MAX-1;
00152 #elif HAVE_SYSCONF && defined(_SC_OPEN_MAX)
00153        if ((maxfd=sysconf(_SC_OPEN_MAX)) < 0)
00154               maxfd=63;
00155        else if (maxfd > 0)
00156               maxfd--;
00157 #else
00158        maxfd=63;
00159 #endif
00160 
00161        if (lockfd < 0 || dup2(lockfd, maxfd) != maxfd)
00162        {
00163               perror(lockfile);
00164               exit(1);
00165        }
00166 
00167        close(lockfd);
00168        lockfd=maxfd;
00169 
00170 #ifdef FD_CLOEXEC
00171        if (fcntl(lockfd, F_SETFD, FD_CLOEXEC) < 0)
00172        {
00173               perror("fcntl");
00174               close(lockfd);
00175               exit(1);
00176        }
00177 #endif
00178 
00179        if (ll_lock_ex_test(lockfd))
00180        {
00181               if (write(fd, "", 1) != 1)
00182                      exit(1); /* Shouldn't happen */
00183 
00184               close(fd);
00185               exit (0);     /* Already running, pretend success */
00186        }
00187 
00188        /*
00189        ** Return >0 to main, so it can continue main's setup.
00190        */
00191 
00192        return (fd);
00193 }
00194 
00195 int ll_daemon_resetio()
00196 {
00197 int    i;
00198 
00199        close(0);
00200        if (open("/dev/null", O_RDONLY) != 0)
00201               return (-1);
00202 
00203        close(1);
00204        i=open(CONSOLE, O_WRONLY);
00205        if (i < 0)    i=open("/dev/null", O_WRONLY);
00206        if (i != 1)   return (-1);
00207 
00208        close(2);
00209        i=open(CONSOLE, O_WRONLY);
00210        if (i < 0)    i=open("/dev/null", O_WRONLY);
00211        if (i != 2)   return (-1);
00212        return (0);
00213 }
00214 
00215 void ll_daemon_started(const char *pidfile, int fd)
00216 {
00217 char   buf[NUMBUFSIZE+1];
00218 char   *p=strcat(libmail_str_pid_t(getpid(), buf), "\n");
00219 FILE   *fp;
00220 
00221        unlink(pidfile); 
00222        if ((fp=fopen(pidfile, "w")) == NULL ||
00223               fprintf(fp, "%s", p) < 0 || fflush(fp) < 0 || fclose(fp))
00224        {
00225               perror(pidfile);
00226               exit(1);
00227        }
00228 
00229        if (write(fd, "", 1) != 1)  /* Signal waiting parent */
00230               exit(1); /* Shouldn't happen */
00231        close(fd);
00232 }
00233 
00234 static void stop1(const char *, const char *);
00235 
00236 int ll_daemon_stop(const char *lockfile, const char *pidfile)
00237 {
00238 pid_t  p, p2;
00239 int    waitstat;
00240 
00241        /*
00242        ** We fork, and the child process attempts to stop the daemon,
00243        ** then communicates the success to us, via its exit code.
00244        */
00245 
00246        signal(SIGCHLD, SIG_DFL);
00247        if ((p=fork()) == -1)
00248        {
00249               perror("fork");
00250               return (1);
00251        }
00252        if (p == 0)   stop1(lockfile, pidfile);
00253 
00254        while ((p2=wait(&waitstat)) != p)
00255               ;
00256 
00257        if (WIFEXITED(waitstat))
00258               return (WEXITSTATUS(waitstat));
00259        return (0);
00260 }
00261 
00262 /*
00263 **     The child process forks too.  The parent process goes in a loop,
00264 **     trying to kill the daemon process.
00265 **
00266 **     The child process attempts to lock the lock file.  When it
00267 **     succeeds, it exits.  When the child process exits, the parent
00268 **     process kills itself.
00269 */
00270 
00271 static RETSIGTYPE sigexit(int signum)
00272 {
00273        kill(getpid(), SIGKILL);
00274 #if     RETSIGTYPE != void
00275        return (0);
00276 #endif
00277 }
00278 
00279 static void stop1(const char *lockfile, const char *pidfile)
00280 {
00281 int    lockfd;
00282 pid_t  p;
00283 
00284        if ((lockfd=open(lockfile, O_RDWR|O_CREAT, 0600)) < 0)
00285        {
00286               perror(lockfile);
00287               exit(1);
00288        }
00289 
00290        if ( ll_lock_ex_test(lockfd) == 0) /* No daemon process running */
00291        {
00292               close(lockfd);
00293               exit (0);     /* That was easy! */
00294        }
00295 
00296        signal(SIGCHLD, sigexit);
00297 
00298        if ((p=fork()) == -1)
00299        {
00300               perror("fork");
00301               exit(1);
00302        }
00303 
00304        if (p) /* Parent - first sends a SIGTERM, then a SIGKILL */
00305        {
00306        int    signum=SIGTERM;
00307 
00308               close(lockfd);
00309               for (;; sleep(10))
00310               {
00311               FILE   *fp;
00312               int    c;
00313 
00314                      if ((fp=fopen(pidfile, "r")) == NULL)
00315                             continue;
00316 
00317                      p=0;
00318 
00319                      while ((c=getc(fp)) != EOF && c != '\n')
00320                      {
00321                             if (isdigit(c))
00322                                    p=p*10+(c-'0');
00323                      }
00324 
00325                      fclose(fp);
00326                      if (p)
00327                             kill(p, signum);
00328                      signum=SIGKILL;
00329               }
00330        }
00331 
00332        if (ll_lock_ex(lockfd))
00333               perror("lock");
00334        close(lockfd);
00335        exit(0);
00336 }
00337 
00338 int ll_daemon_restart(const char *lockfile, const char *pidfile)
00339 {
00340 int    lockfd;
00341 pid_t  p;
00342 FILE   *fp;
00343 int    c;
00344 
00345        if ((lockfd=open(lockfile, O_RDWR|O_CREAT, 0600)) < 0)
00346        {
00347               perror(lockfile);
00348               return (1);
00349        }
00350 
00351        if ( ll_lock_ex_test(lockfd) == 0) /* No daemon process running */
00352        {
00353               close(lockfd);
00354               return (0);   /* That was easy! */
00355        }
00356        close(lockfd);
00357 
00358        if ((fp=fopen(pidfile, "r")) == NULL)
00359               return (0);
00360 
00361        p=0;
00362 
00363        while ((c=getc(fp)) != EOF && c != '\n')
00364        {
00365               if (isdigit(c))
00366                      p=p*10+(c-'0');
00367        }
00368 
00369        fclose(fp);
00370        if (p)
00371               kill(p, SIGHUP);
00372        return (0);
00373 }
00374