Fawkes API Fawkes Development Version
daemonize.cpp
1
2/***************************************************************************
3 * daemonize.cpp - Fawkes daemonization functions
4 *
5 * Created: Wed May 04 23:33:33 2011
6 * Copyright 2006-2011 Tim Niemueller [www.niemueller.de]
7 *
8 ****************************************************************************/
9
10/* This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version. A runtime exception applies to
14 * this software (see LICENSE.GPL_WRE file mentioned below for details).
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * Read the full text in the LICENSE.GPL_WRE file in the doc directory.
22 */
23
24#include <baseapp/daemonize.h>
25#include <sys/types.h>
26#include <utils/system/argparser.h>
27
28#include <cstdio>
29#include <unistd.h>
30#ifdef HAVE_LIBDAEMON
31# include <libdaemon/dfork.h>
32# include <libdaemon/dlog.h>
33# include <libdaemon/dpid.h>
34# include <sys/stat.h>
35# include <sys/wait.h>
36
37# include <cerrno>
38# include <csignal>
39# include <cstring>
40#endif
41
42namespace fawkes {
43namespace daemon {
44
45#ifdef HAVE_LIBDAEMON
46/** Global variable containing the path to the PID file.
47 * unfortunately needed for libdaemon */
48const char *fawkes_pid_file;
49
50/** Function that returns the PID file name.
51 * @return PID file name
52 */
53const char *
54fawkes_daemon_pid_file_proc()
55{
56 return fawkes_pid_file;
57}
58#endif // HAVE_LIBDAEMON
59
60pid_t
61daemonize()
62{
63#ifdef HAVE_LIBDAEMON
64 pid_t pid;
65 mode_t old_umask = umask(0);
66
67 // Prepare for return value passing
68 daemon_retval_init();
69
70 // Do the fork
71 if ((pid = daemon_fork()) < 0) {
72 return -1;
73
74 } else if (pid) { // the parent
75 int ret;
76
77 // Wait for 20 seconds for the return value passed from the daemon process
78 if ((ret = daemon_retval_wait(20)) < 0) {
79 daemon_log(LOG_ERR, "Could not recieve return value from daemon process.");
80 return -1;
81 }
82
83 if (ret != 0) {
84 daemon_log(LOG_ERR, "*** Daemon startup failed, see syslog for details. ***");
85 switch (ret) {
86 case 1: daemon_log(LOG_ERR, "Daemon failed to close file descriptors"); break;
87 case 2: daemon_log(LOG_ERR, "Daemon failed to create PID file"); break;
88 }
89 return -1;
90 } else {
91 return pid;
92 }
93
94 } else { // the daemon
95# ifdef DAEMON_CLOSE_ALL_AVAILABLE
96 if (daemon_close_all(-1) < 0) {
97 daemon_log(LOG_ERR, "Failed to close all file descriptors: %s", strerror(errno));
98 // Send the error condition to the parent process
99 daemon_retval_send(1);
100 return -1;
101 }
102# endif
103
104 // Create the PID file
105 if (daemon_pid_file_create() < 0) {
106 printf("Could not create PID file (%s).", strerror(errno));
107 daemon_log(LOG_ERR, "Could not create PID file (%s).", strerror(errno));
108
109 // Send the error condition to the parent process
110 daemon_retval_send(2);
111 return -1;
112 }
113
114 // Send OK to parent process
115 daemon_retval_send(0);
116
117 daemon_log(LOG_INFO, "Sucessfully started");
118
119 umask(old_umask);
120 return 0;
121 }
122#else
123 throw Exception("Daemonizing support is not available.\n"
124 "(libdaemon[-devel] was not available at compile time)\n");
125#endif
126}
127
128void
129init(const char *pidfile, const char *progname)
130{
131#ifdef HAVE_LIBDAEMON
132 // Set identification string for the daemon for both syslog and PID file
133 daemon_pid_file_ident = daemon_log_ident = daemon_ident_from_argv0((char *)progname);
134 if (pidfile != NULL) {
135 fawkes_pid_file = pidfile;
136 daemon_pid_file_proc = fawkes_daemon_pid_file_proc;
137 }
138#else
139 throw Exception("Daemonizing support is not available.\n"
140 "(libdaemon[-devel] was not available at compile time)\n");
141#endif
142}
143
144bool
145start()
146{
147#ifdef HAVE_LIBDAEMON
148 pid_t pid;
149
150 // Check that the daemon is not run twice a the same time
151 if ((pid = daemon_pid_file_is_running()) >= 0) {
152 daemon_log(LOG_ERR, "Daemon already running on (PID %u)", pid);
153 throw Exception("Daemon already running on (PID %u)", pid);
154 }
155
156 pid = daemonize();
157 if (pid < 0) {
158 cleanup();
159 throw Exception("Failed to daemonize");
160 } else if (pid) {
161 // parent
162 return true;
163 } else {
164 // child
165 return false;
166 }
167#else
168 throw Exception("Daemonizing support is not available.\n"
169 "(libdaemon[-devel] was not available at compile time)\n");
170#endif
171}
172
173bool
174running()
175{
176#ifdef HAVE_LIBDAEMON
177 return (daemon_pid_file_is_running() >= 0);
178#else
179 throw Exception("Daemonizing support is not available.\n"
180 "(libdaemon[-devel] was not available at compile time)\n");
181#endif
182}
183
184void
185kill()
186{
187#ifdef HAVE_LIBDAEMON
188 pid_t pid;
189 int ret;
190
191 // Check that the daemon is not run twice a the same time
192 if ((pid = daemon_pid_file_is_running()) < 0) {
193 daemon_log(LOG_WARNING, "Fawkes daemon not running.");
194 }
195
196 // Kill daemon with SIGINT
197 if ((ret = daemon_pid_file_kill_wait(SIGINT, 5)) < 0) {
198 daemon_log(LOG_WARNING, "Failed to kill daemon");
199 }
200
201 daemon_pid_file_remove();
202#else
203 throw Exception("Daemonizing support is not available.\n"
204 "(libdaemon[-devel] was not available at compile time)\n");
205#endif
206}
207
208void
209cleanup()
210{
211#ifdef HAVE_LIBDAEMON
212 daemon_retval_send(-1);
213 daemon_retval_done();
214 daemon_pid_file_remove();
215#else
216 throw Exception("Daemonizing support is not available.\n"
217 "(libdaemon[-devel] was not available at compile time)\n");
218#endif
219}
220
221} // namespace daemon
222} // end namespace fawkes
Fawkes library namespace.