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 
26 #include <utils/system/argparser.h>
27 
28 #include <unistd.h>
29 #include <sys/types.h>
30 #include <cstdio>
31 #ifdef HAVE_LIBDAEMON
32 # include <cerrno>
33 # include <cstring>
34 # include <csignal>
35 # include <libdaemon/dfork.h>
36 # include <libdaemon/dlog.h>
37 # include <libdaemon/dpid.h>
38 # include <sys/stat.h>
39 # include <sys/wait.h>
40 #endif
41 
42 namespace fawkes {
43  namespace daemon {
44 #if 0 /* just to make Emacs auto-indent happy */
45  }
46 }
47 #endif
48 
49 #ifdef HAVE_LIBDAEMON
50 /** Global variable containing the path to the PID file.
51  * unfortunately needed for libdaemon */
52 const char *fawkes_pid_file;
53 
54 /** Function that returns the PID file name.
55  * @return PID file name
56  */
57 const char *
58 fawkes_daemon_pid_file_proc()
59 {
60  return fawkes_pid_file;
61 }
62 #endif // HAVE_LIBDAEMON
63 
64 
65 pid_t
66 daemonize()
67 {
68 #ifdef HAVE_LIBDAEMON
69  pid_t pid;
70  mode_t old_umask = umask(0);
71 
72  // Prepare for return value passing
73  daemon_retval_init();
74 
75  // Do the fork
76  if ((pid = daemon_fork()) < 0) {
77  return -1;
78 
79  } else if (pid) { // the parent
80  int ret;
81 
82  // Wait for 20 seconds for the return value passed from the daemon process
83  if ((ret = daemon_retval_wait(20)) < 0) {
84  daemon_log(LOG_ERR, "Could not recieve return value from daemon process.");
85  return -1;
86  }
87 
88  if ( ret != 0 ) {
89  daemon_log(LOG_ERR, "*** Daemon startup failed, see syslog for details. ***");
90  switch (ret) {
91  case 1:
92  daemon_log(LOG_ERR, "Daemon failed to close file descriptors");
93  break;
94  case 2:
95  daemon_log(LOG_ERR, "Daemon failed to create PID file");
96  break;
97  }
98  return -1;
99  } else {
100  return pid;
101  }
102 
103  } else { // the daemon
104 #ifdef DAEMON_CLOSE_ALL_AVAILABLE
105  if (daemon_close_all(-1) < 0) {
106  daemon_log(LOG_ERR, "Failed to close all file descriptors: %s", strerror(errno));
107  // Send the error condition to the parent process
108  daemon_retval_send(1);
109  return -1;
110  }
111 #endif
112 
113  // Create the PID file
114  if (daemon_pid_file_create() < 0) {
115  printf("Could not create PID file (%s).", strerror(errno));
116  daemon_log(LOG_ERR, "Could not create PID file (%s).", strerror(errno));
117 
118  // Send the error condition to the parent process
119  daemon_retval_send(2);
120  return -1;
121  }
122 
123  // Send OK to parent process
124  daemon_retval_send(0);
125 
126  daemon_log(LOG_INFO, "Sucessfully started");
127 
128  umask(old_umask);
129  return 0;
130  }
131 #else
132  throw Exception("Daemonizing support is not available.\n"
133  "(libdaemon[-devel] was not available at compile time)\n");
134 #endif
135 }
136 
137 
138 void
139 init(const char *pidfile, const char *progname)
140 {
141 #ifdef HAVE_LIBDAEMON
142  // Set identification string for the daemon for both syslog and PID file
143  daemon_pid_file_ident = daemon_log_ident =
144  daemon_ident_from_argv0((char *)progname);
145  if ( pidfile != NULL ) {
146  fawkes_pid_file = pidfile;
147  daemon_pid_file_proc = fawkes_daemon_pid_file_proc;
148  }
149 #else
150  throw Exception("Daemonizing support is not available.\n"
151  "(libdaemon[-devel] was not available at compile time)\n");
152 #endif
153 }
154 
155 bool
156 start()
157 {
158 #ifdef HAVE_LIBDAEMON
159  pid_t pid;
160 
161  // Check that the daemon is not run twice a the same time
162  if ((pid = daemon_pid_file_is_running()) >= 0) {
163  daemon_log(LOG_ERR, "Daemon already running on (PID %u)", pid);
164  throw Exception("Daemon already running on (PID %u)", pid);
165  }
166 
167  pid = daemonize();
168  if ( pid < 0 ) {
169  cleanup();
170  throw Exception("Failed to daemonize");
171  } else if (pid) {
172  // parent
173  return true;
174  } else {
175  // child
176  return false;
177  }
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 bool
185 running()
186 {
187 #ifdef HAVE_LIBDAEMON
188  return (daemon_pid_file_is_running() >= 0);
189 #else
190  throw Exception("Daemonizing support is not available.\n"
191  "(libdaemon[-devel] was not available at compile time)\n");
192 #endif
193 }
194 
195 
196 void
197 kill()
198 {
199 #ifdef HAVE_LIBDAEMON
200  pid_t pid;
201  int ret;
202 
203  // Check that the daemon is not run twice a the same time
204  if ((pid = daemon_pid_file_is_running()) < 0) {
205  daemon_log(LOG_WARNING, "Fawkes daemon not running.");
206  }
207 
208  // Kill daemon with SIGINT
209  if ((ret = daemon_pid_file_kill_wait(SIGINT, 5)) < 0) {
210  daemon_log(LOG_WARNING, "Failed to kill daemon");
211  }
212 
213  daemon_pid_file_remove();
214 #else
215  throw Exception("Daemonizing support is not available.\n"
216  "(libdaemon[-devel] was not available at compile time)\n");
217 #endif
218 }
219 
220 
221 void
222 cleanup()
223 {
224 #ifdef HAVE_LIBDAEMON
225  daemon_retval_send(-1);
226  daemon_retval_done();
227  daemon_pid_file_remove();
228 #else
229  throw Exception("Daemonizing support is not available.\n"
230  "(libdaemon[-devel] was not available at compile time)\n");
231 #endif
232 }
233 
234 
235 
236 } // end namespace fawkes::daemon
237 } // end namespace fawkes
Fawkes library namespace.