How to daemonize in Linux-silent_wind column-blog channel-csdn. net
How to daemonize in Linux Category: Unix Read by 170 Comment (0) Favorites Report Signalredirectuserterminalfilelogging
Directory (?)[+]
- Simple Example
- A more useful example
One of the things I keep running restart SS isLinuxDaemons that don't properlyDaemonizeThemselves. To properlyDaemonize, The following steps must be followed.
- The fork () call is used to create a separate process.
- The setsid () call is used to detach the process from the parent (normally a shell ).
- The file mask shocould be reset.
- The current directory shocould be changed to something benign.
- The standard files (stdin, stdout and stderr) need to be reopened.
Failure to do any of these steps will lead to a daemon process that can misbehave. The typical symptoms are as follows.
- Starting the daemon and then logging out will cause the terminal to hang. This is particle ly nasty with SSH.
- The directory from which the daemon was launched remains locked.
- Spurious output appears in the shell from which the daemon was started.
Simple Example
The following example program performs the bare minimum steps required to launch a daemon process.
# Include <stdio. h> # include <stdlib. h> # include <unistd. h> # include <sys/types. h> # include <sys/STAT. h> # define exit_success 0 # define exit_failure 1 static void Daemonize (Void) {pid_t PID, Sid;/* already a daemon */If (getppid () = 1) return; /* fork off the parent process */PID = fork (); If (PID <0) {exit (exit_failure);}/* If we got a good PID, then we can exit the parent process. */If (pid> 0) {exit (exit_success );} /* at this point we are executing as the child process * // * change the file mode mask */umask (0 ); /* Create a New Sid for the child process */SID = setsid (); If (SID <0) {exit (exit_failure);}/* change the current working directory. this prevents the current directory from being locked; hence not being able to remove it. */If (chdir ("/") <0) {exit (exit_failure );} /* redirect standard files to/dev/null */freopen ("/dev/null", "r", stdin); freopen ("/dev/null ", "W", stdout); freopen ("/dev/null", "W", stderr);} int main (INT argc, char * argv []) {Daemonize ();/* Now we are a daemon -- do the work for which we were paid */return 0 ;}
It has been brought to my attention that a second call to fork () may be required to fully detach the process from the Controller terminal (in other words: fork, setsid, fork ). this does not seem to be required in Linux . A second fork wocould not cause any problems, although it wowould complicate the child/parent signalling below.
A more useful example
The following program extends the basic daemon by adding the following features.
- logs messages to the System Log (via syslog).
- creates a lock file to prevent the daemon from being run twice.
- changes the valid user (drops privileges).
- startup errors are reported to the main process.
# Include <stdio. h> # include <stdlib. h> # include <string. h> # include <unistd. h> # include <sys/types. h> # include <sys/STAT. h> # include <fcntl. h> # include <syslog. h> # include <errno. h> # include <PWD. h> # include <signal. h>/* change this to whatever your daemon is called */# define daemon_name "mydaemon"/* change this to the user under which to run */# define run_as_user "daemon "# define exit_success 0 # define exit_failure 1 static void child_handler (int signum) {Switch (SIGNUM) {Case sigalrm: exit (exit_failure); break; Case SIGUSR1: exit (exit_success); break; Case sigchld: exit (exit_failure); break;} static void Daemonize (Const char * lockfile) {pid_t PID, Sid, parent; int LFP =-1;/* already a daemon */If (getppid () = 1) return; /* Create the lock file as the current user */If (lockfile & lockfile [0]) {LFP = open (lockfile, o_rdwr | o_creat, 0640 ); if (LFP <0) {syslog (log_err, "unable to create lock file % s, code = % d (% s)", lockfile, errno, strerror (errno )); exit (exit_failure) ;}}/* Drop user if there is one, and we were run as root */If (getuid () = 0 | geteuid () = 0) {struct passwd * PW = getpwnam (run_as_user); If (PW) {syslog (log_notice, "setting user to" run_as_user ); setuid (PW-> pw_uid) ;}}/* trap signals that we expect CT to recieve */signal (sigchld, child_handler); signal (SIGUSR1, child_handler); signal (sigalrm, child_handler);/* fork off the parent process */PID = fork (); If (PID <0) {syslog (log_err, "unable to fork daemon, code = % d (% s) ", errno, strerror (errno); exit (exit_failure);}/* If we got a good PID, then we can exit the parent process. */If (pid> 0) {/* wait for confirmation from the child via sigterm or sigchld, or for two seconds to elapse (sigalrm ). pause () shocould not return. */alarm (2); pause (); exit (exit_failure);}/* at this point we are executing as the child process */parent = getppid (); /* cancel certain signals */signal (sigchld, sig_dfl);/* a child process dies */signal (sigtstp, sig_ign);/* vartty signals */signal (sigttou, sig_ign); signal (sigttin, sig_ign); signal (sighup, sig_ign);/* ignore hangup signal */signal (sigterm, sig_dfl ); /* die on sigterm * // * change the file mode mask */umask (0);/* Create a New Sid for the child process */SID = setsid (); if (SID <0) {syslog (log_err, "unable to create a new session, code % d (% s)", errno, strerror (errno )); exit (exit_failure);}/* change the current working directory. this prevents the current directory from being locked; hence not being able to remove it. */If (chdir ("/") <0) {syslog (log_err, "unable to change directory to % s, code % d (% s )", "/", errno, strerror (errno); exit (exit_failure);}/* redirect standard files to/dev/null */freopen ("/dev/null ", "r", stdin); freopen ("/dev/null", "W", stdout); freopen ("/dev/null", "W", stderr ); /* tell the parent process that we are a-okay */kill (parent, SIGUSR1);} int main (INT argc, char * argv []) {/* initialize the logging interface */openlog (daemon_name, log_pid, log_local5); syslog (log_info, "starting "); /* One may wish to process command line arguments here *//*Daemonize */ Daemonize ("/Var/lock/subsys/" daemon_name ); /* now we are a daemon -- do the work for which we were paid * // * Finish up */syslog (log_notice, "terminated"); closelog (); return 0 ;}