daemon.c
上传用户:xxcykj
上传日期:2007-01-04
资源大小:727k
文件大小:5k
源码类别:

Email客户端

开发平台:

Unix_Linux

  1. /*
  2.  * daemon.c -- turn a process into a daemon under POSIX, SYSV, BSD.
  3.  *
  4.  * For license terms, see the file COPYING in this directory.
  5.  */
  6. #include "config.h"
  7. #include <stdio.h>
  8. #include <errno.h>
  9. #include <signal.h>
  10. #include <sys/types.h>
  11. #ifdef HAVE_SYS_WAIT_H
  12. #include <sys/wait.h>
  13. #endif
  14. #ifdef HAVE_FCNTL_H
  15. #include <fcntl.h>
  16. #else /* !HAVE_FCNTL_H */
  17. #ifdef HAVE_SYS_FCNTL_H
  18. #include <sys/fcntl.h>
  19. #endif /* HAVE_SYS_FCNTL_H */
  20. #endif /* !HAVE_FCNTL_H */
  21. #include <sys/stat.h> /* get umask(2) prototyped */
  22. #if defined(HAVE_UNISTD_H)
  23. #include <unistd.h>
  24. #endif
  25. #if defined(STDC_HEADERS)
  26. #include <stdlib.h>
  27. #endif
  28. #if defined(QNX)
  29. #include <unix.h>
  30. #endif
  31. #if !defined(HAVE_SETSID) && defined(SIGTSTP)
  32. #if defined(HAVE_TERMIOS_H)
  33. #  include <termios.h> /* for TIOCNOTTY under Linux */
  34. #endif
  35. #if !defined(TIOCNOTTY) && defined(HAVE_SGTTY_H)
  36. #  include <sgtty.h> /* for TIOCNOTTY under NEXTSTEP */
  37. #endif
  38. #endif /* !defined(HAVE_SETSID) && defined(SIGTSTP) */
  39. /* BSD portability hack */
  40. #if !defined(SIGCHLD) && defined(SIGCLD)
  41. #define SIGCHLD SIGCLD
  42. #endif
  43. #include "fetchmail.h"
  44. #include "tunable.h"
  45. RETSIGTYPE
  46. sigchld_handler (int sig)
  47. /* process SIGCHLD to obtain the exit code of the terminating process */
  48. {
  49.     extern volatile int lastsig; /* last signal received */
  50.     pid_t pid;
  51. #if  defined(HAVE_WAITPID) /* the POSIX way */
  52.     int status;
  53.     while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
  54. continue; /* swallow 'em up. */
  55. #elif  defined(HAVE_WAIT3) /* the BSD way */
  56. #if defined(HAVE_UNION_WAIT) && !defined(__FreeBSD__)
  57.     union wait status;
  58. #else
  59.     int status;
  60. #endif
  61.     while ((pid = wait3(&status, WNOHANG, 0)) > 0)
  62. continue; /* swallow 'em up. */
  63. #else /* Zooks! Nothing to do but wait(), and hope we don't block... */
  64.     int status;
  65.     wait(&status);
  66. #endif
  67.     lastsig = SIGCHLD;
  68. }
  69. int
  70. daemonize (const char *logfile, void (*termhook)(int))
  71. /* detach from control TTY, become process group leader, catch SIGCHLD */
  72. {
  73.   int fd;
  74.   pid_t childpid;
  75.   RETSIGTYPE sigchld_handler(int);
  76.   /* if we are started by init (process 1) via /etc/inittab we needn't 
  77.      bother to detach from our process group context */
  78.   if (getppid() == 1) 
  79.     goto nottyDetach;
  80.   /* Ignore BSD terminal stop signals */
  81. #ifdef  SIGTTOU
  82.   signal(SIGTTOU, SIG_IGN);
  83. #endif
  84. #ifdef SIGTTIN
  85.   signal(SIGTTIN, SIG_IGN);
  86. #endif
  87. #ifdef SIGTSTP
  88.   signal(SIGTSTP, SIG_IGN);
  89. #endif
  90.   /* In case we were not started in the background, fork and let
  91.      the parent exit.  Guarantees that the child is not a process
  92.      group leader */
  93.   if ((childpid = fork()) < 0) {
  94.     report(stderr, "fork (%s)n", strerror(errno));
  95.     return(PS_IOERR);
  96.   }
  97.   else if (childpid > 0) 
  98.     exit(0);  /* parent */
  99.   
  100.   /* Make ourselves the leader of a new process group with no
  101.      controlling terminal */
  102. #if defined(HAVE_SETSID) /* POSIX */
  103.   /* POSIX makes this soooo easy to do */
  104.   if (setsid() < 0) {
  105.     report(stderr, "setsid (%s)n", strerror(errno));
  106.     return(PS_IOERR);
  107.   }
  108. #elif defined(SIGTSTP) /* BSD */
  109.   /* change process group */
  110. #ifndef __EMX__
  111.   setpgrp(0, getpid());
  112. #endif
  113.   /* lose controlling tty */
  114.   if ((fd = open("/dev/tty", O_RDWR)) >= 0) {
  115.     ioctl(fd, TIOCNOTTY, (char *) 0);
  116.     close(fd); /* not checking should be safe, there were no writes */
  117.   }
  118. #else /* SVR3 and older */
  119.   /* change process group */
  120. #ifndef __EMX__
  121.   setpgrp();
  122. #endif
  123.   
  124.   /* lose controlling tty */
  125.   signal(SIGHUP, SIG_IGN);
  126.   if ((childpid = fork()) < 0) {
  127.     report(stderr, "fork (%)n", strerror(errno));
  128.     return(PS_IOERR);
  129.   }
  130.   else if (childpid > 0) {
  131.     exit(0);  /* parent */
  132.   }
  133. #endif
  134. nottyDetach:
  135.   /* Close any/all open file descriptors */
  136. #if  defined(HAVE_GETDTABLESIZE)
  137.   for (fd = getdtablesize()-1;  fd >= 0;  fd--)
  138. #elif defined(NOFILE)
  139.   for (fd = NOFILE-1;  fd >= 0;  fd--)
  140. #else /* make an educated guess */
  141.   for (fd = 19;  fd >= 0;  fd--)
  142. #endif
  143.   {
  144.     close(fd); /* not checking this should be safe, no writes */
  145.   }
  146.   /* Reopen stdin descriptor on /dev/null */
  147.   if ((fd = open("/dev/null", O_RDWR)) < 0) {   /* stdin */
  148.     report(stderr, "open: /dev/null (%s)n", strerror(errno));
  149.     return(PS_IOERR);
  150.   }
  151.   if (logfile)
  152.     fd = open(logfile, O_CREAT|O_WRONLY|O_APPEND, 0666); /* stdout */
  153.   else
  154.     if (dup(fd) < 0) { /* stdout */
  155.       report(stderr, "dup (%s)n", strerror(errno));
  156.       return(PS_IOERR);
  157.     }
  158.   if (dup(fd) < 0) { /* stderr */
  159.     report(stderr, "dup (%s)n", strerror(errno));
  160.     return(PS_IOERR);
  161.   }
  162.   /* move to root directory, so we don't prevent filesystem unmounts */
  163.   chdir("/");
  164.   /* set our umask to something reasonable (we hope) */
  165. #if defined(DEF_UMASK)
  166.   umask(DEF_UMASK);
  167. #else
  168.   umask(022);
  169. #endif
  170.   /* set up to catch child process termination signals */ 
  171.   signal(SIGCHLD, sigchld_handler); 
  172. #if defined(SIGPWR)
  173.   signal(SIGPWR, sigchld_handler); 
  174. #endif
  175.   return(0);
  176. }
  177. /* daemon.c ends here */