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 
42 namespace fawkes {
43 namespace daemon {
44 
45 #ifdef HAVE_LIBDAEMON
46 /** Global variable containing the path to the PID file.
47  * unfortunately needed for libdaemon */
48 const char *fawkes_pid_file;
49 
50 /** Function that returns the PID file name.
51  * @return PID file name
52  */
53 const char *
54 fawkes_daemon_pid_file_proc()
55 {
56  return fawkes_pid_file;
57 }
58 #endif // HAVE_LIBDAEMON
59 
60 pid_t
61 daemonize()
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 
128 void
129 init(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 
144 bool
145 start()
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 
173 bool
174 running()
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 
184 void
185 kill()
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 
208 void
209 cleanup()
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