1 /*******************************************************************************
2 * Copyright (C) 2004-2008 Intel Corp. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * - Redistributions of source code must retain the above copyright notice,
8 * this list of conditions and the following disclaimer.
9 *
10 * - Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 *
14 * - Neither the name of Intel Corp. nor the names of its
15 * contributors may be used to endorse or promote products derived from this
16 * software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL Intel Corp. OR THE CONTRIBUTORS
22 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 *******************************************************************************/
30
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
34
35 #ifdef DAEMON
36
37 #include <cstdio>
38 #include <cstdlib>
39 #include <cstring>
40 #include <cerrno>
41 #include <csignal>
42 #include <unistd.h>
43 #include <sys/types.h>
44 #include <sys/stat.h>
45 #include <fcntl.h>
46 #include <syslog.h>
47 #include <pwd.h>
48
49 #include "daemonize.h"
50
child_handler(int signum)51 static RETSIGTYPE child_handler(int signum)
52 {
53 switch (signum) {
54 case SIGALRM:
55 exit(EXIT_FAILURE);
56 break;
57 case SIGUSR1:
58 exit(EXIT_SUCCESS);
59 break;
60 case SIGCHLD:
61 exit(EXIT_FAILURE);
62 break;
63 }
64 }
65
daemonize()66 void daemonize()
67 {
68 pid_t pid, sid, parent;
69
70 /* Drop user if there is one, and we were run as root */
71 if (getuid() == 0 || geteuid() == 0) {
72 struct passwd *pw = getpwnam(RUN_AS_USER);
73 if (pw) {
74 //syslog(LOG_NOTICE, "setting user to " RUN_AS_USER);
75 setuid(pw->pw_uid);
76 }
77 }
78
79 /* Trap signals that we expect to recieve */
80 signal(SIGCHLD, child_handler);
81 signal(SIGUSR1, child_handler);
82 signal(SIGALRM, child_handler);
83
84 /* Fork off the parent process */
85 pid = fork();
86 if (pid < 0) {
87 syslog(LOG_ERR, "unable to fork daemon, code=%d (%s)",
88 errno, strerror(errno));
89 exit(EXIT_FAILURE);
90 }
91 /* If we got a good PID, then we can exit the parent process. */
92 if (pid > 0) {
93
94 /* Wait for confirmation from the child via SIGTERM or SIGCHLD, or
95 for two seconds to elapse (SIGALRM). pause() should not return. */
96 alarm(2);
97 pause();
98
99 exit(EXIT_FAILURE);
100 }
101
102 /* At this point we are executing as the child process */
103 parent = getppid();
104
105 signal(SIGCHLD, SIG_DFL);
106 signal(SIGUSR1, SIG_DFL);
107 signal(SIGALRM, SIG_DFL);
108 setTerminationHandler();
109
110 /* Create a new SID for the child process */
111 sid = setsid();
112 if (sid < 0) {
113 syslog(LOG_ERR,
114 "unable to create a new session, code %d (%s)",
115 errno, strerror(errno));
116 exit(EXIT_FAILURE);
117 }
118
119 /* Change the current working directory. This prevents the current
120 directory from being locked; hence not being able to remove it. */
121 if ((chdir("/")) < 0) {
122 syslog(LOG_ERR,
123 "unable to change directory to %s, code %d (%s)",
124 "/", errno, strerror(errno));
125 exit(EXIT_FAILURE);
126 }
127
128 /* Redirect standard files to /dev/null */
129 freopen("/dev/null", "r", stdin);
130 freopen("/dev/null", "w", stdout);
131 freopen("/dev/null", "w", stderr);
132
133 /* Tell the parent process that we are A-okay */
134 kill(parent, SIGUSR1);
135 }
136
137 #endif //DAEMON
138
139