1 /* Copyright (C) 2007-2010 Open Information Security Foundation
2 *
3 * You can copy, redistribute or modify this Program under the terms of
4 * the GNU General Public License version 2 as published by the Free
5 * Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * version 2 along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15 * 02110-1301, USA.
16 */
17
18 /**
19 * \file
20 *
21 * \author Gerardo Iglesias Galvan <iglesiasg@gmail.com>
22 *
23 * Daemonization process
24 */
25
26 #include "suricata.h"
27 #include "suricata-common.h"
28 #include "runmodes.h"
29 #include "util-daemon.h"
30 #include "util-debug.h"
31 #include "conf.h"
32
33 #ifndef OS_WIN32
34
35 #include <sys/wait.h>
36 #include <sys/stat.h>
37 #include <fcntl.h>
38
39 static volatile sig_atomic_t sigflag = 0;
40
41 /**
42 * \brief Signal handler used to take the parent process out of stand-by
43 */
SignalHandlerSigusr1(int signo)44 static void SignalHandlerSigusr1 (int signo)
45 {
46 sigflag = 1;
47 }
48
49 /**
50 * \brief Tell the parent process the child is ready
51 *
52 * \param pid pid of the parent process to signal
53 */
TellWaitingParent(pid_t pid)54 static void TellWaitingParent (pid_t pid)
55 {
56 kill(pid, SIGUSR1);
57 }
58
59 /**
60 * \brief Set the parent on stand-by until the child is ready
61 *
62 * \param pid pid of the child process to wait
63 */
WaitForChild(pid_t pid)64 static void WaitForChild (pid_t pid)
65 {
66 int status;
67 SCLogDebug("Daemon: Parent waiting for child to be ready...");
68 /* Wait until child signals is ready */
69 while (sigflag == 0) {
70 if (waitpid(pid, &status, WNOHANG)) {
71 /* Check if the child is still there, otherwise the parent should exit */
72 if (WIFEXITED(status) || WIFSIGNALED(status)) {
73 FatalError(SC_ERR_FATAL, "Child died unexpectedly");
74 }
75 }
76 /* sigsuspend(); */
77 sleep(1);
78 }
79 }
80
81 /**
82 * \brief Close stdin, stdout, stderr.Redirect logging info to syslog
83 *
84 */
SetupLogging(void)85 static void SetupLogging (void)
86 {
87 /* Redirect stdin, stdout, stderr to /dev/null */
88 int fd = open("/dev/null", O_RDWR);
89 if (fd < 0)
90 return;
91 (void)dup2(fd, 0);
92 (void)dup2(fd, 1);
93 (void)dup2(fd, 2);
94 close(fd);
95 }
96
97 /**
98 * \brief Daemonize the process
99 *
100 */
Daemonize(void)101 void Daemonize (void)
102 {
103 pid_t pid, sid;
104
105 /* Register the signal handler */
106 signal(SIGUSR1, SignalHandlerSigusr1);
107
108 /** \todo We should check if wie allow more than 1 instance
109 to run simultaneously. Maybe change the behaviour
110 through conf file */
111
112 /* Creates a new process */
113 pid = fork();
114
115 if (pid < 0) {
116 /* Fork error */
117 FatalError(SC_ERR_FATAL, "Error forking the process");
118 } else if (pid == 0) {
119 /* Child continues here */
120 const char *daemondir;
121
122 sid = setsid();
123 if (sid < 0) {
124 FatalError(SC_ERR_FATAL, "Error creating new session");
125 }
126
127 if (ConfGet("daemon-directory", &daemondir) == 1) {
128 if ((chdir(daemondir)) < 0) {
129 FatalError(SC_ERR_FATAL,
130 "Error changing to working directory");
131 }
132 }
133 #ifndef OS_WIN32
134 else {
135 if (chdir("/") < 0) {
136 SCLogError(SC_ERR_DAEMON, "Error changing to working directory '/'");
137 }
138 }
139 #endif
140
141 SetupLogging();
142
143 /* Child is ready, tell its parent */
144 TellWaitingParent(getppid());
145
146 /* Daemon is up and running */
147 SCLogDebug("Daemon is running");
148 return;
149 }
150 /* Parent continues here, waiting for child to be ready */
151 SCLogDebug("Parent is waiting for child to be ready");
152 WaitForChild(pid);
153
154 /* Parent exits */
155 SCLogDebug("Child is ready, parent exiting");
156 exit(EXIT_SUCCESS);
157
158 }
159
160 #endif /* ifndef OS_WIN32 */
161
162 /**
163 * \brief Check for a valid combination daemon/mode
164 *
165 * \param daemon daemon on or off
166 * \param mode selected mode
167 *
168 * \retval 1 valid combination
169 * \retval 0 invalid combination
170 */
CheckValidDaemonModes(int daemon,int mode)171 int CheckValidDaemonModes (int daemon, int mode)
172 {
173 if (daemon) {
174 switch (mode) {
175 case RUNMODE_PCAP_FILE:
176 SCLogError(SC_ERR_INVALID_RUNMODE, "ERROR: pcap offline mode cannot run as daemon");
177 return 0;
178 case RUNMODE_UNITTEST:
179 SCLogError(SC_ERR_INVALID_RUNMODE, "ERROR: unittests cannot run as daemon");
180 return 0;
181 default:
182 SCLogDebug("Allowed mode");
183 break;
184 }
185 }
186 return 1;
187 }
188