12#include "wvlinklist.h"
16#include "wvcrashlog.h"
18#include "wvatomicfile.h"
29# define CAN_SYSLOG true
30# define CAN_DAEMONIZE true
32# define CAN_SYSLOG false
33# define CAN_DAEMONIZE false
37static const int STDOUT_FILENO = 0;
46static void sighup_handler(
int signum)
48 signal(signum, SIG_IGN);
50 WvDaemon::me()->log(WvLog::Notice,
"Restarting on signal %s.\n", signum);
51 WvDaemon::me()->restart();
55static void sigterm_handler(
int signum)
57 signal(signum, SIG_DFL);
59 WvDaemon::me()->log(WvLog::Notice,
"Dying on signal %s.\n", signum);
60 WvDaemon::me()->die();
64static void sigquit_handler(
int signum)
66 signal(signum, SIG_IGN);
73void WvDaemon::init(WvStringParm _name,
74 WvStringParm _version,
75 WvDaemonCallback _start_callback,
76 WvDaemonCallback _run_callback,
77 WvDaemonCallback _stop_callback)
81 pid_file = WvString(
"/var/run/%s.pid", _name);
83 log_level = WvLog::Info;
85 start_callback = _start_callback;
86 run_callback = _run_callback;
87 stop_callback = _stop_callback;
89 assert(singleton == NULL);
92 args.add_option(
'q',
"quiet",
93 "Decrease log level (can be used multiple times)",
94 wv::bind(&WvDaemon::dec_log_level,
this, _1));
95 args.add_option(
'v',
"verbose",
96 "Increase log level (can be used multiple times)",
97 wv::bind(&WvDaemon::inc_log_level,
this, _1));
99 args.add_option(
'd',
"daemonize",
100 "Fork into background and return (implies --syslog)",
101 wv::bind(&WvDaemon::set_daemonize,
this, _1));
104 args.add_set_bool_option(
's',
"syslog",
105 "Write log entries to syslog", syslog);
106 args.add_reset_bool_option(0,
"no-syslog",
107 "Do not write log entries to syslog", syslog);
110 args.set_version(WvString(
"%s version %s",
name, version).cstr());
124 pid_t pid = ::fork();
127 wverr->print(
"Failed to fork daemon: %s\n",
137 wverr->print(
"Failed to double-fork daemon: %s\n",
151 null_fd = ::open(
"/dev/null", O_RDWR);
154 log(WvLog::Error,
"Failed to open /dev/null: %s\n",
158 }
while (null_fd == 0 || null_fd == 1 || null_fd == 2);
160 if (::dup2(null_fd, 0) == -1
161 || ::dup2(null_fd, 1) == -1
162 || ::dup2(null_fd, 2) == -1)
164 log(WvLog::Error,
"Failed to dup2(null_fd, (0|1|2)): %s\n",
173 if (::fcntl(0, F_SETFD, 0) == -1
174 || ::fcntl(1, F_SETFD, 0) == -1
175 || ::fcntl(2, F_SETFD, 0) == -1)
177 log(WvLog::Warning,
"Failed to fcntl((0|1|2), F_SETFD, 0): %s\n",
193 if (CAN_SYSLOG && syslog)
206 if (!
args.process(argc, argv, &_extra_args))
212int WvDaemon::_run(
const char *argv0)
217 wvcrash_setup(argv0, version);
220 if (CAN_SYSLOG && syslog)
223 _want_to_die =
false;
227 _want_to_restart =
false;
245void WvDaemon::do_load()
253 WvFile old_pid_fd(
pid_file, O_RDONLY);
254 if (old_pid_fd.isok())
256 WvString line = old_pid_fd.getline(0);
259 pid_t old_pid = line.
num();
260 if (old_pid > 0 && (kill(old_pid, 0) == 0 || errno == EPERM))
263 "%s is already running (pid %s); exiting\n",
274 WvAtomicFile pid_fd(
pid_file, O_WRONLY, 0600);
275 pid_fd.print(
"%s\n", getpid());
277 log(WvLog::Warning,
"Failed to write PID file %s: %s\n",
282 log(WvLog::Notice,
"Starting %s version %s.\n",
name, version);
286 signal(SIGINT, SIG_IGN);
288 signal(SIGINT, sigterm_handler);
289 signal(SIGTERM, sigterm_handler);
290 signal(SIGQUIT, sigquit_handler);
291 signal(SIGHUP, sighup_handler);
299void WvDaemon::do_start()
306void WvDaemon::do_run()
313void WvDaemon::do_stop()
320void WvDaemon::do_unload()
326 signal(SIGHUP, SIG_DFL);
327 signal(SIGQUIT, SIG_DFL);
328 signal(SIGINT, SIG_DFL);
329 signal(SIGTERM, SIG_DFL);
332 log(WvLog::Notice,
"Exiting with status %s\n", _exit_status);
341bool WvDaemon::set_daemonize(
void *)
WvLogRcv that sticks log messages in the wvcrash_ring_buffer.
WvDaemon - High-level abstraction for creating daemon processes.
WvString name
The name and version of the daemon; used for -V and logging.
WvDaemonCallback load_callback
See the class description.
bool should_run() const
Whether the daemon should continue runnning.
int run(const char *argv0)
Run the daemon with no argument processing. Returns exit status.
WvLog log
The daemon's log mechanism.
void die(int status=0)
Force the daemon to exit as soon as the run callback exits.
bool want_to_die() const
Whether the daemon will quit when the run callback exits.
int num() const
Return a stdc++ string with the contents of this string.
Captures formatted log messages and outputs them to the specified file descriptor.
WvLogRcv adds some intelligence to WvLogRcvBase, to keep track of line-prefix-printing and other form...
WvSyslog is a descendant of WvLogRcv that sends messages to the syslogd daemon.