// @(#)root/rpdutils:$Id$ // Author: Fons Rademakers 11/08/97 // Modifified: Gerardo Ganis 8/04/2003 /************************************************************************* * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. * * All rights reserved. * * * * For the licensing terms see $ROOTSYS/LICENSE. * * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ ////////////////////////////////////////////////////////////////////////// // // // DaemonStart // // // // Detach a daemon process from login session context. // // // ////////////////////////////////////////////////////////////////////////// #include #include #include #include #include #include #if defined(__sun) || defined(__sgi) # include #endif #if defined(__linux__) && !defined(linux) # define linux #endif #ifdef SIGTSTP #include #include #include #endif #include #ifndef NOFILE # define NOFILE 0 #endif #if defined(__hpux) #define USE_SIGCHLD #endif #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__) #define USE_SIGCHLD #define SIGCLD SIGCHLD #endif #if defined(linux) || defined(__hpux) || defined(__sun) || defined(__sgi) || \ defined(_AIX) || defined(__FreeBSD__) || defined(__OpenBSD__) || \ defined(__APPLE__) || defined(__MACH__) || \ (defined(__CYGWIN__) && defined(__GNUC__)) #define USE_SETSID #endif #include "rpdp.h" extern int gDebug; namespace ROOT { extern ErrorHandler_t gErrSys; #if defined(USE_SIGCHLD) //////////////////////////////////////////////////////////////////////////////// static void SigChild(int) { int pid; #if defined(__hpux) || defined(__FreeBSD__) || defined(__OpenBSD__) || \ defined(__APPLE__) int status; #else union wait status; #endif while ((pid = wait3(&status, WNOHANG, 0)) > 0) ; } #endif //////////////////////////////////////////////////////////////////////////////// /// Detach a daemon process from login session context. void DaemonStart(int ignsigcld, int fdkeep, EService service) { // If we were started by init (process 1) from the /etc/inittab file // there's no need to detach. // This test is unreliable due to an unavoidable ambiguity // if the process is started by some other process and orphaned // (i.e. if the parent process terminates before we are started). int fd; #if !(defined(__CYGWIN__) && defined(__GNUC__)) if (getppid() == 1) { if (service == kROOTD) printf ("ROOTD_PID=%ld\n", (long) getpid()); goto out; } #endif // Ignore the terminal stop signals (BSD). #ifdef SIGTTOU signal(SIGTTOU, SIG_IGN); #endif #ifdef SIGTTIN signal(SIGTTIN, SIG_IGN); #endif #ifdef SIGTSTP signal(SIGTSTP, SIG_IGN); #endif // If we were not started in the background, fork and let the parent // exit. This also guarantees the first child is not a process // group leader. int childpid; if ((childpid = fork()) < 0) { if (service == kROOTD) fprintf(stderr, "DaemonStart: can't fork first child\n"); Error(gErrSys,kErrFatal, "DaemonStart: can't fork first child"); } else if (childpid > 0) { #ifdef SIGTSTP if (service == kROOTD) printf("ROOTD_PID=%d\n", childpid); #endif exit(0); // parent } else { if (gDebug > 2) ErrorInfo("DaemonStart: this is the child thread ... socket is: %d",fdkeep); } // First child process... // Disassociate from controlling terminal and process group. // Ensure the process can't reacquire a new controlling terminal. #ifdef SIGTSTP #ifdef USE_SETSID if (setsid() == -1) { #else if (setpgrp(0, getpid()) == -1) { #endif if (service == kROOTD) fprintf(stderr, "DaemonStart: can't change process group\n"); Error(gErrSys,kErrFatal, "DaemonStart: can't change process group"); } if ((fd = open("/dev/tty", O_RDWR)) >= 0) { #if !defined(__hpux) && !defined(__sun) && \ !(defined(__CYGWIN__) && defined(__GNUC__)) ioctl(fd, TIOCNOTTY, 0); // loose controlling tty #endif close(fd); } #else if (setpgrp() == -1) { if (service == kROOTD) fprintf(stderr,"DaemonStart: can't change process group\n"); Error(gErrSys,kErrFatal, "DaemonStart: can't change process group"); } signal(SIGHUP, SIG_IGN); // immune from pgrp leader death if ((childpid = fork()) < 0) { if (service == kROOTD) fprintf(stderr, "DaemonStart: can't fork second child\n"); Error(gErrSys,kErrFatal, "DaemonStart: can't fork second child"); } else if (childpid > 0) { if (service == kROOTD) printf("ROOTD_PID=%d (2nd fork)\n", childpid); exit(0); // first child } #endif out: // Close any open file descriptors for (fd = 0; fd < NOFILE; fd++) { if ((fd != fdkeep) || (service == kPROOFD)) close(fd); } ResetErrno(); // probably got set to EBADF from a close // Move current directory to root, make sure we aren't on a mounted // file system. if (chdir("/") == -1) fprintf(stderr, "DaemonStart: cannot chdir to /\n"); // Clear any inherited file mode creation mask umask(0); // See if the caller isn't interested in the exit status of its // children and doesn't want to have them become zombies and // clog up the system. // With SysV all we need to do is ignore the signal. // With BSD, however, we have to catch each signal // and execute the wait3() system call. if (ignsigcld) { #ifdef USE_SIGCHLD signal(SIGCLD, SigChild); #else #if defined(__sun) sigignore(SIGCHLD); #else signal(SIGCLD, SIG_IGN); #endif #endif } } } // namespace ROOT