home *** CD-ROM | disk | FTP | other *** search
/ kermit.columbia.edu / kermit.columbia.edu.tar / kermit.columbia.edu / sredird / telnetcpcd-1.09.tar.gz / telnetcpcd-1.09.tar / mydaemon.c < prev    next >
C/C++ Source or Header  |  2003-08-12  |  6KB  |  276 lines

  1. /*
  2.     mydaemon.c
  3.  
  4.     Copyright (c) 2002,2003 Thomas J Pinkl <tom@pinkl.com>
  5.  
  6.     Initialize a daemon process.
  7.  
  8.     This code was derived from W. Richard Stevens' _Unix Network Programming_.
  9.  
  10.     Version 1.02    01/28/1997
  11.     Version 1.03    08/08/1997
  12.     Version 1.04    08/15/1997
  13.     Version 1.05    08/19/1997
  14.     Version 1.06    08/21/1997
  15.     Version 1.07    09/02/1997
  16.     Version 1.08    05/04/1999        Under Linux, call this function mydaemon()
  17. */
  18.  
  19. #include "telnetcpcd.h"
  20.  
  21. #ifndef NOFILE
  22. #define NOFILE    60
  23. #endif
  24. #ifndef DAEMON_STDIN
  25. #define DAEMON_STDIN    "/dev/null"
  26. #endif
  27. #ifndef DAEMON_STDOUT
  28. #define DAEMON_STDOUT    "/dev/console"
  29. #endif
  30. #ifndef DAEMON_STDERR
  31. #define DAEMON_STDERR    DAEMON_STDOUT
  32. #endif
  33. #ifndef FAILSAFE
  34. #define FAILSAFE        "/dev/null"
  35. #endif
  36.  
  37. /*
  38.     Detach a daemon process from login session context.
  39.     ignore_sigcld nonzero means handle SIGCLD so zombies 
  40.     don't clog up the process table.
  41. */
  42. void mydaemon(int ignore_sigcld,char *dir)
  43. {
  44.     int childpid;                        /* child pid */
  45.     struct sigaction act;
  46.  
  47.     /*
  48.      * If we were started by init (process 1) from the /etc/inittab file
  49.      * there's no need to detach.
  50.      * This test is unreliable due to an unavoidable ambiguity
  51.       * if the process is started by some other process and orphaned
  52.      * (i.e., if the parent process terminates before we are started).
  53.        */
  54.     if (getppid() == 1)
  55.           goto out;
  56.  
  57.     /*
  58.      * Ignore the terminal stop signals 
  59.      */
  60.     act.sa_handler = SIG_IGN;
  61.     sigemptyset(&act.sa_mask);            /* required before sigaction() */
  62.  
  63. #ifdef SIGTTOU
  64.     sigaction(SIGTTOU,&act,NULL);
  65. #endif
  66. #ifdef SIGTTIN
  67.     sigaction(SIGTTIN,&act,NULL);
  68. #endif
  69. #ifdef SIGTSTP
  70.     sigaction(SIGTSTP,&act,NULL);
  71. #endif
  72.  
  73.     /*
  74.      * If we were not started in the background, fork and
  75.      * let the parent exit.  This also guarantees the first child
  76.      * is not a process group leader.
  77.      */
  78.     if ((childpid = fork()) < 0) {
  79.         syslog_perror("can't fork() first child");
  80.         exit(1);
  81.     } else {
  82.         if (childpid > 0)
  83.             _exit(0);                    /* parent */
  84.     }
  85.  
  86.     /*
  87.      * First child process.
  88.      *
  89.      * Disassociate from controlling terminal and process group.
  90.      * Ensure the process can't reacquire a new controlling terminal.
  91.      */
  92.  
  93. /*
  94.     Note: Digital OSF/1 v3.2 (not sure about other versions) defines 
  95.           BSD by default.
  96. */
  97. #ifdef __osf__
  98. #undef BSD
  99. #endif
  100.  
  101. #ifdef BSD
  102. #if defined(__osf__) 
  103.     if (setpgrp((pid_t) 0, getpid()) == -1) {
  104. #else
  105.     if (setpgrp() == -1) {
  106. #endif
  107.         syslog_perror("can't change process group");
  108.         exit(1);
  109.     }
  110.  
  111.     /*
  112.         lose controlling tty 
  113.     */
  114.     if ((fd = open("/dev/tty", O_RDWR)) >= 0) {
  115.         ioctl(fd, TIOCNOTTY, (char *)NULL); 
  116.         close(fd);
  117.     }
  118.  
  119. #else    /* System V */
  120.  
  121. #ifndef NO_SETSID
  122.     if (setsid() < 0) {                    /* create a new session and become */
  123.                                         /* the process group leader */
  124.         syslog_perror("setsid() error");
  125.         exit(1);
  126.     }
  127. #else
  128.     if (setpgrp() == -1) {
  129.         syslog_perror("setpgrp() error");
  130.         exit(1);
  131.     }
  132. #endif    /* NO_SETSID */
  133.  
  134.     act.sa_handler = SIG_IGN;
  135.     sigemptyset(&act.sa_mask);            /* required before sigaction() */
  136.     sigaction(SIGHUP,&act,NULL);        /* immune from pgrp leader death */
  137.  
  138.     if ((childpid = fork()) < 0) {
  139.         syslog_perror("can't fork() second child");
  140.         exit(1);
  141.     } else {
  142.         if (childpid > 0)
  143.             _exit(0);                    /* first child */
  144.     }
  145.  
  146.     /* second child continues */
  147. #endif    /* BSD or System V */
  148.  
  149. out:
  150.     /*
  151.         reopen stdin/stdout/stderr
  152.     */
  153.     reopen_stdfds();
  154.  
  155.     /*
  156.         Close any remaining open file descriptors.
  157.     */
  158.     close_all_fds(3);
  159.  
  160.     /*
  161.      * Move the current directory to root (probably), to make sure we
  162.      * aren't on a mounted filesystem.
  163.      */
  164.     if ((dir == NULL) || (*dir == 0x00)) {
  165.         chdir("/");
  166.     } else {
  167.         chdir(dir);
  168.     }
  169.  
  170.     /*
  171.      * Clear any inherited file mode creation mask.
  172.      */
  173.     umask(0);
  174.  
  175.     /*
  176.      * See if the caller isn't interested in the exit status of its
  177.      * children, and doesn't want to have them become zombies and
  178.      * clog up the system's process table.
  179.      * With System V all we need do is ignore the signal.
  180.      * With BSD, however, we have to catch each signal
  181.      * and execute the wait3() system call.
  182.      */
  183.     if (ignore_sigcld) {
  184. #if defined(BSD) && !defined(__osf__)
  185.         int    sig_child();
  186.  
  187.         signal(SIGCLD, sig_child);            /* BSD */
  188. #else
  189.         act.sa_handler = SIG_IGN;
  190.         sigemptyset(&act.sa_mask);            /* required before sigaction() */
  191.         sigaction(SIGCLD,&act,NULL);        /* System V */
  192. #endif
  193.     }
  194. }
  195.  
  196. void daemon_start(int ignore_sigcld)
  197. {
  198.     mydaemon(ignore_sigcld,"/");
  199. }
  200.  
  201. /*
  202.     reopen stdin/stdout/stderr
  203. */
  204. void reopen_stdfds(void)
  205. {
  206.     close(0);
  207.     close(1);
  208.     close(2);
  209.  
  210.     /* stdin */
  211.     reopen_fd(DAEMON_STDIN,O_RDONLY|O_NOCTTY|O_NONBLOCK);
  212.     reopen_FILE(DAEMON_STDIN,"r",stdin);
  213.  
  214.     /* stdout */
  215.     reopen_fd(DAEMON_STDOUT,O_WRONLY|O_APPEND|O_NOCTTY|O_NONBLOCK);
  216.     reopen_FILE(DAEMON_STDOUT,"a",stdout);
  217.  
  218.     /* stderr */
  219.     reopen_fd(DAEMON_STDERR,O_WRONLY|O_APPEND|O_NOCTTY|O_NONBLOCK);
  220.     reopen_FILE(DAEMON_STDERR,"a",stderr);
  221. }
  222.  
  223. void reopen_fd(char *file,int mode)
  224. {
  225.     extern int errno;
  226.     int fd;
  227.  
  228.     fd = open(file,mode);
  229.     if (fd == -1) {
  230.         syslog(LOG_ERR,"open(%s,%d) error: %s",file,mode,strerror(errno));
  231.         fd = open(FAILSAFE,mode);
  232.         if (fd == -1) {
  233.             syslog(LOG_ERR,"open(%s,%d) error: %s",FAILSAFE,mode,strerror(errno));
  234.         } else {
  235.             /* use LOG_ERR for this too */
  236.             syslog(LOG_ERR,"open(%s,%d) succeeded",FAILSAFE,mode);
  237.         }
  238.     }
  239. }
  240.  
  241. void reopen_FILE(char *file,char *mode,FILE *stream)
  242. {
  243.     extern int errno;
  244.     FILE *fp;
  245.  
  246.     fp = freopen(file,mode,stream);
  247.     if (fp == NULL) {
  248.         syslog(LOG_ERR,"freopen(%s,%s,...) error: %s",file,mode,strerror(errno));
  249.         fp = freopen(FAILSAFE,mode,stream);
  250.         if (fp == NULL) {
  251.             syslog(LOG_ERR,"freopen(%s,%s,...) error: %s",FAILSAFE,mode,strerror(errno));
  252.         } else {
  253.             /* use LOG_ERR for this too */
  254.             syslog(LOG_ERR,"freopen(%s,%s,...) succeeded",FAILSAFE,mode);
  255.         }
  256.     }
  257. }
  258.  
  259. void close_all_fds(int begin)
  260. {
  261.     extern int errno;
  262.     int fd;                                /* file descriptor */
  263.     long open_max;                        /* max open fd's */
  264.  
  265.     open_max = sysconf(_SC_OPEN_MAX);
  266.     if (open_max == -1) {
  267.         syslog_perror("sysconf(_SC_OPEN_MAX) error");
  268.         open_max = NOFILE;
  269.     }
  270.     closelog();
  271.     for (fd = begin; fd < open_max; fd++) {
  272.         close(fd);
  273.     }
  274.     errno = 0;                            /* probably got EBADF from close() */
  275. }
  276.