Fawkes API  Fawkes Development Version
daemonize.cpp
00001 
00002 /***************************************************************************
00003  *  daemonize.cpp - Fawkes daemonization functions
00004  *
00005  *  Created: Wed May 04 23:33:33 2011
00006  *  Copyright  2006-2011  Tim Niemueller [www.niemueller.de]
00007  *
00008  ****************************************************************************/
00009 
00010 /*  This program is free software; you can redistribute it and/or modify
00011  *  it under the terms of the GNU General Public License as published by
00012  *  the Free Software Foundation; either version 2 of the License, or
00013  *  (at your option) any later version. A runtime exception applies to
00014  *  this software (see LICENSE.GPL_WRE file mentioned below for details).
00015  *
00016  *  This program is distributed in the hope that it will be useful,
00017  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  *  GNU Library General Public License for more details.
00020  *
00021  *  Read the full text in the LICENSE.GPL_WRE file in the doc directory.
00022  */
00023 
00024 #include <baseapp/daemonize.h>
00025 
00026 #include <utils/system/argparser.h>
00027 
00028 #include <unistd.h>
00029 #include <sys/types.h>
00030 #include <cstdio>
00031 #ifdef HAVE_LIBDAEMON
00032 #  include <cerrno>
00033 #  include <cstring>
00034 #  include <csignal>
00035 #  include <libdaemon/dfork.h>
00036 #  include <libdaemon/dlog.h>
00037 #  include <libdaemon/dpid.h>
00038 #  include <sys/stat.h>
00039 #  include <sys/wait.h>
00040 #endif
00041 
00042 namespace fawkes {
00043   namespace daemon {
00044 #if 0 /* just to make Emacs auto-indent happy */
00045   }
00046 }
00047 #endif
00048 
00049 #ifdef HAVE_LIBDAEMON
00050 /** Global variable containing the path to the PID file.
00051  * unfortunately needed for libdaemon */
00052 const char *fawkes_pid_file;
00053 
00054 /** Function that returns the PID file name.
00055  * @return PID file name
00056  */
00057 const char *
00058 fawkes_daemon_pid_file_proc()
00059 {
00060   return fawkes_pid_file;
00061 }
00062 #endif // HAVE_LIBDAEMON
00063 
00064 
00065 pid_t
00066 daemonize()
00067 {
00068 #ifdef HAVE_LIBDAEMON
00069   pid_t pid;
00070   mode_t old_umask = umask(0);
00071 
00072   // Prepare for return value passing
00073   daemon_retval_init();
00074 
00075   // Do the fork
00076   if ((pid = daemon_fork()) < 0) {
00077     return -1;
00078         
00079   } else if (pid) { // the parent
00080     int ret;
00081 
00082     // Wait for 20 seconds for the return value passed from the daemon process
00083     if ((ret = daemon_retval_wait(20)) < 0) {
00084       daemon_log(LOG_ERR, "Could not recieve return value from daemon process.");
00085       return -1;
00086     }
00087 
00088     if ( ret != 0 ) {
00089       daemon_log(LOG_ERR, "*** Daemon startup failed, see syslog for details. ***");
00090       switch (ret) {
00091       case 1:
00092         daemon_log(LOG_ERR, "Daemon failed to close file descriptors");
00093         break;
00094       case 2:
00095         daemon_log(LOG_ERR, "Daemon failed to create PID file");
00096         break;
00097       }
00098       return -1;
00099     } else {
00100       return pid;
00101     }
00102 
00103   } else { // the daemon
00104 #ifdef DAEMON_CLOSE_ALL_AVAILABLE
00105     if (daemon_close_all(-1) < 0) {
00106       daemon_log(LOG_ERR, "Failed to close all file descriptors: %s", strerror(errno));
00107       // Send the error condition to the parent process
00108       daemon_retval_send(1);
00109       return -1;
00110     }
00111 #endif
00112 
00113     // Create the PID file
00114     if (daemon_pid_file_create() < 0) {
00115       printf("Could not create PID file (%s).", strerror(errno));
00116       daemon_log(LOG_ERR, "Could not create PID file (%s).", strerror(errno));
00117 
00118       // Send the error condition to the parent process
00119       daemon_retval_send(2);
00120       return -1;
00121     }
00122 
00123     // Send OK to parent process
00124     daemon_retval_send(0);
00125 
00126     daemon_log(LOG_INFO, "Sucessfully started");
00127 
00128     umask(old_umask);
00129     return 0;
00130   }
00131 #else
00132   throw Exception("Daemonizing support is not available.\n"
00133                   "(libdaemon[-devel] was not available at compile time)\n");
00134 #endif
00135 }
00136 
00137 
00138 void
00139 init(const char *pidfile, const char *progname)
00140 {
00141 #ifdef HAVE_LIBDAEMON
00142   // Set identification string for the daemon for both syslog and PID file
00143   daemon_pid_file_ident = daemon_log_ident =
00144     daemon_ident_from_argv0((char *)progname);
00145   if ( pidfile != NULL ) {
00146     fawkes_pid_file      = pidfile;
00147     daemon_pid_file_proc = fawkes_daemon_pid_file_proc;
00148   }
00149 #else
00150   throw Exception("Daemonizing support is not available.\n"
00151                   "(libdaemon[-devel] was not available at compile time)\n");
00152 #endif
00153 }
00154 
00155 bool
00156 start()
00157 {
00158 #ifdef HAVE_LIBDAEMON
00159   pid_t pid;
00160 
00161   // Check that the daemon is not run twice a the same time
00162   if ((pid = daemon_pid_file_is_running()) >= 0) {
00163     daemon_log(LOG_ERR, "Daemon already running on (PID %u)", pid);
00164     throw Exception("Daemon already running on (PID %u)", pid);
00165   }
00166 
00167   pid = daemonize();
00168   if ( pid < 0 ) {
00169     cleanup();
00170     throw Exception("Failed to daemonize");
00171   } else if (pid) {
00172     // parent
00173     return true;
00174   } else {
00175     // child
00176     return false;
00177   }
00178 #else
00179   throw Exception("Daemonizing support is not available.\n"
00180                   "(libdaemon[-devel] was not available at compile time)\n");
00181 #endif
00182 }
00183 
00184 bool
00185 running()
00186 {
00187 #ifdef HAVE_LIBDAEMON
00188   return (daemon_pid_file_is_running() >= 0);
00189 #else
00190   throw Exception("Daemonizing support is not available.\n"
00191                   "(libdaemon[-devel] was not available at compile time)\n");
00192 #endif
00193 }
00194 
00195 
00196 void
00197 kill()
00198 {
00199 #ifdef HAVE_LIBDAEMON
00200   pid_t pid;
00201   int ret;
00202 
00203   // Check that the daemon is not run twice a the same time
00204   if ((pid = daemon_pid_file_is_running()) < 0) {
00205     daemon_log(LOG_WARNING, "Fawkes daemon not running.");
00206   }
00207 
00208   // Kill daemon with SIGINT
00209   if ((ret = daemon_pid_file_kill_wait(SIGINT, 5)) < 0) {
00210     daemon_log(LOG_WARNING, "Failed to kill daemon");
00211   }
00212 #else
00213   throw Exception("Daemonizing support is not available.\n"
00214                   "(libdaemon[-devel] was not available at compile time)\n");
00215 #endif
00216 }
00217 
00218 
00219 void
00220 cleanup()
00221 {
00222 #ifdef HAVE_LIBDAEMON
00223   daemon_retval_send(-1);
00224   daemon_retval_done();
00225   daemon_pid_file_remove();
00226 #else
00227   throw Exception("Daemonizing support is not available.\n"
00228                   "(libdaemon[-devel] was not available at compile time)\n");
00229 #endif
00230 }
00231 
00232 
00233 
00234 } // end namespace fawkes::daemon
00235 } // end namespace fawkes