suricata
util-daemon.c
Go to the documentation of this file.
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
39static volatile sig_atomic_t sigflag = 0;
40
41/**
42 * \brief Signal handler used to take the parent process out of stand-by
43 */
44static 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 */
54static 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 */
64static 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("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 */
85static 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 */
101void 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 we allow more than 1 instance
109 to run simultaneously. Maybe change the behaviour
110 through conf file */
111
112 /* Creates a new process */
113#if defined(OS_DARWIN) && defined(__clang__)
114#pragma clang diagnostic push
115#pragma clang diagnostic ignored "-Wdeprecated-declarations"
116#endif
117 pid = fork();
118#if defined(OS_DARWIN) && defined(__clang__)
119#pragma clang diagnostic pop
120#endif
121
122 if (pid < 0) {
123 /* Fork error */
124 FatalError("Error forking the process");
125 } else if (pid == 0) {
126 /* Child continues here */
127 const char *daemondir;
128
129 sid = setsid();
130 if (sid < 0) {
131 FatalError("Error creating new session");
132 }
133
134 if (SCConfGet("daemon-directory", &daemondir) == 1) {
135 if ((chdir(daemondir)) < 0) {
136 FatalError("Error changing to working directory");
137 }
138 }
139#ifndef OS_WIN32
140 else {
141 if (chdir("/") < 0) {
142 SCLogError("Error changing to working directory '/'");
143 }
144 }
145#endif
146
147 SetupLogging();
148
149 /* Child is ready, tell its parent */
150 TellWaitingParent(getppid());
151
152 /* Daemon is up and running */
153 SCLogDebug("Daemon is running");
154 return;
155 }
156 /* Parent continues here, waiting for child to be ready */
157 SCLogDebug("Parent is waiting for child to be ready");
158 WaitForChild(pid);
159
160 /* Parent exits */
161 SCLogDebug("Child is ready, parent exiting");
162 exit(EXIT_SUCCESS);
163
164}
165
166#endif /* ifndef OS_WIN32 */
167
168/**
169 * \brief Check for a valid combination daemon/mode
170 *
171 * \param daemon daemon on or off
172 * \param mode selected mode
173 *
174 * \retval 1 valid combination
175 * \retval 0 invalid combination
176 */
177int CheckValidDaemonModes (int daemon, int mode)
178{
179 if (daemon) {
180 switch (mode) {
182 SCLogError("ERROR: pcap offline mode cannot run as daemon");
183 return 0;
184 case RUNMODE_UNITTEST:
185 SCLogError("ERROR: unittests cannot run as daemon");
186 return 0;
187 default:
188 SCLogDebug("Allowed mode");
189 break;
190 }
191 }
192 return 1;
193}
int SCConfGet(const char *name, const char **vptr)
Retrieve the value of a configuration node.
Definition conf.c:350
@ RUNMODE_UNITTEST
Definition runmodes.h:41
@ RUNMODE_PCAP_FILE
Definition runmodes.h:30
int CheckValidDaemonModes(int daemon, int mode)
Check for a valid combination daemon/mode.
void Daemonize(void)
Daemonize the process.
#define FatalError(...)
Definition util-debug.h:510
#define SCLogDebug(...)
Definition util-debug.h:275
#define SCLogError(...)
Macro used to log ERROR messages.
Definition util-debug.h:267