X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;f=ucw%2Fdaemon.c;h=9b136d8ac2c171434d6d2d893dc4d824b73068f7;hb=0eb6d8317cdbdb28663ff779d31684b3c7a47274;hp=b0ea47672d8cc0c14dbc2a74bb0400d99b174879;hpb=b29e5291d5e94da42e495a44ba6fa6cca2ff82b4;p=libucw.git diff --git a/ucw/daemon.c b/ucw/daemon.c index b0ea4767..9b136d8a 100644 --- a/ucw/daemon.c +++ b/ucw/daemon.c @@ -1,7 +1,7 @@ /* * UCW Library -- Daemonization * - * (c) 2012 Martin Mares + * (c) 2012--2014 Martin Mares * * This software may be freely distributed and used according to the terms * of the GNU Lesser General Public License. @@ -10,21 +10,19 @@ #include #include #include -#include #include #include -#include #include #include #include #include #include -#include +#include +#include #include -#include -static void +void daemon_resolve_ugid(struct daemon_params *dp) { // Resolve user name @@ -34,8 +32,8 @@ daemon_resolve_ugid(struct daemon_params *dp) { if (u[0] == '#') { - uns id; - const char *err = str_to_uns(&id, u, NULL, 10 | STN_WHOLE); + uint id; + const char *err = str_to_uint(&id, u, NULL, 10 | STN_WHOLE); if (err) die("Cannot parse user `%s': %s", u, err); dp->run_as_uid = id; @@ -58,8 +56,8 @@ daemon_resolve_ugid(struct daemon_params *dp) { if (g[0] == '#') { - uns id; - const char *err = str_to_uns(&id, g, NULL, 10 | STN_WHOLE); + uint id; + const char *err = str_to_uint(&id, g, NULL, 10 | STN_WHOLE); if (err) die("Cannot parse group `%s': %s", g, err); dp->run_as_gid = id; @@ -81,11 +79,24 @@ daemon_resolve_ugid(struct daemon_params *dp) } } +void daemon_switch_ugid(struct daemon_params *dp) +{ + if (dp->want_setgid && setresgid(dp->run_as_gid, dp->run_as_gid, dp->run_as_gid) < 0) + die("Cannot set GID to %d: %m", (int) dp->run_as_gid); + if (dp->want_setgid > 1 && initgroups(dp->run_as_user, dp->run_as_gid) < 0) + die("Cannot initialize groups: %m"); + if (dp->want_setuid && setresuid(dp->run_as_uid, dp->run_as_uid, dp->run_as_uid) < 0) + die("Cannot set UID to %d: %m", (int) dp->run_as_uid); +} + void daemon_init(struct daemon_params *dp) { daemon_resolve_ugid(dp); + if (dp->flags & DAEMON_FLAG_SIMULATE) + return; + if (dp->pid_file) { // Check that PID file path is absolute @@ -119,13 +130,14 @@ daemon_init(struct daemon_params *dp) void daemon_run(struct daemon_params *dp, void (*body)(struct daemon_params *dp)) { + if (dp->flags & DAEMON_FLAG_SIMULATE) + { + body(dp); + return; + } + // Switch GID and UID - if (dp->want_setgid && setresgid(dp->run_as_gid, dp->run_as_gid, dp->run_as_gid) < 0) - die("Cannot set GID to %d: %m", (int) dp->run_as_gid); - if (dp->want_setgid > 1 && initgroups(dp->run_as_user, dp->run_as_gid) < 0) - die("Cannot initialize groups: %m"); - if (dp->want_setuid && setresuid(dp->run_as_uid, dp->run_as_uid, dp->run_as_uid) < 0) - die("Cannot set UID to %d: %m", (int) dp->run_as_uid); + daemon_switch_ugid(dp); // Create a new session and close stdio setsid(); @@ -172,6 +184,9 @@ daemon_run(struct daemon_params *dp, void (*body)(struct daemon_params *dp)) void daemon_exit(struct daemon_params *dp) { + if (dp->flags & DAEMON_FLAG_SIMULATE) + return; + if (dp->pid_file) { if (unlink(dp->pid_file) < 0) @@ -180,171 +195,45 @@ daemon_exit(struct daemon_params *dp) } } -static enum daemon_control_status -daemon_control_err(struct daemon_control_params *dc, char *msg, ...) -{ - va_list args; - va_start(args, msg); - vsnprintf(dc->error_msg, DAEMON_ERR_LEN, msg, args); - va_end(args); - return DAEMON_STATUS_ERROR; -} - -static int -daemon_read_pid(struct daemon_control_params *dc) -{ - int pid_fd = open(dc->pid_file, O_RDONLY); - if (pid_fd < 0) - { - if (errno == ENOENT) - return 0; - daemon_control_err(dc, "Cannot open PID file `%s': %m", dc->pid_file); - return -1; - } - - if (flock(pid_fd, LOCK_EX | LOCK_NB) >= 0) - { - // The lock file is stale - close(pid_fd); - return 0; - } +#ifdef TEST - if (errno != EINTR && errno != EWOULDBLOCK) - { - daemon_control_err(dc, "Cannot lock PID file `%s': %m", dc->pid_file); - goto fail; - } +#include - char buf[16]; - int n = read(pid_fd, buf, sizeof(buf)); - if (n < 0) - { - daemon_control_err(dc, "Error reading `%s': %m", dc->pid_file); - goto fail; - } - if (n == (int) sizeof(buf)) - { - daemon_control_err(dc, "PID file `%s' is too long", dc->pid_file); - goto fail; - } - buf[n] = 0; - int pid = atoi(buf); - if (!pid) - { - daemon_control_err(dc, "PID file `%s' does not contain a valid PID", dc->pid_file); - goto fail; - } - close(pid_fd); - return pid; +static volatile sig_atomic_t terminate; -fail: - close(pid_fd); - return -1; +static void term_handler(int sig UNUSED) +{ + msg(L_INFO | L_SIGHANDLER, "SIGTERM received, terminating in a while"); + terminate = 1; } -enum daemon_control_status -daemon_control(struct daemon_control_params *dc) +static void hup_handler(int sig UNUSED) { - enum daemon_control_status st = DAEMON_STATUS_ERROR; + msg(L_INFO | L_SIGHANDLER, "SIGHUP received"); +} - int guard_fd = open(dc->guard_file, O_RDWR | O_CREAT, 0666); - if (guard_fd < 0) - return daemon_control_err(dc, "Cannot open guard file `%s': %m", dc->guard_file); - if (flock(guard_fd, LOCK_EX) < 0) - return daemon_control_err(dc, "Cannot lock guard file `%s': %m", dc->guard_file); +static void body(struct daemon_params *dp) +{ + log_fork(); + msg(L_INFO, "Daemon is running"); + msg(L_INFO, "uid=%d/%d gid=%d/%d", (int) getuid(), (int) geteuid(), (int) getgid(), (int) getegid()); - // Read the PID file - int pid = daemon_read_pid(dc); - if (pid < 0) - goto done; + struct sigaction sa_term = { .sa_handler = term_handler }; + struct sigaction sa_hup = { .sa_handler = hup_handler }; + if (sigaction(SIGTERM, &sa_term, NULL) < 0 || + sigaction(SIGHUP, &sa_hup, NULL) < 0) + ASSERT(0); - switch (dc->action) + while (!terminate) { - case DAEMON_CONTROL_CHECK: - if (pid) - st = DAEMON_STATUS_OK; - else - st = DAEMON_STATUS_NOT_RUNNING; - break; - case DAEMON_CONTROL_START: - if (pid) - st = DAEMON_STATUS_ALREADY_DONE; - else - { - pid_t pp = fork(); - if (pp < 0) - { - daemon_control_err(dc, "Cannot fork: %m"); - goto done; - } - if (pp) - { - close(guard_fd); - execvp(dc->argv[0], dc->argv); - fprintf(stderr, "Cannot execute `%s': %m\n", dc->argv[0]); - exit(DAEMON_STATUS_ERROR); - } - int stat; - int ec = waitpid(pp, &stat, 0); - if (ec < 0) - { - daemon_control_err(dc, "Cannot wait: %m"); - goto done; - } - if (WIFEXITED(stat) && WEXITSTATUS(stat) == DAEMON_STATUS_ERROR) - { - daemon_control_err(dc, "Cannot execute the daemon"); - goto done; - } - char ecmsg[EXIT_STATUS_MSG_SIZE]; - if (format_exit_status(ecmsg, stat)) - { - daemon_control_err(dc, "Daemon %s", ecmsg); - goto done; - } - pid = daemon_read_pid(dc); - if (!pid) - daemon_control_err(dc, "Daemon failed to write the PID file `%s'", dc->pid_file); - else - st = DAEMON_STATUS_OK; - } - break; - case DAEMON_CONTROL_STOP: - if (!pid) - return DAEMON_STATUS_ALREADY_DONE; - int sig = dc->signal ? : SIGTERM; - if (kill(pid, sig) < 0) + if (!sleep(60)) { - daemon_control_err(dc, "Cannot send signal %d: %m", dc->signal); - goto done; + msg(L_INFO, "Timeout elapsed, terminating in a while"); + break; } - // FIXME: Wait for the daemon to exit, possibly with a timeout - break; - case DAEMON_CONTROL_SIGNAL: - if (!pid) - return DAEMON_STATUS_NOT_RUNNING; - if (kill(pid, dc->signal) < 0) - daemon_control_err(dc, "Cannot send signal %d: %m", dc->signal); - else - st = DAEMON_STATUS_OK; - break; - default: - ASSERT(0); } -done: - close(guard_fd); - return st; -} - -#ifdef TEST - -static void body(struct daemon_params *dp) -{ - log_fork(); - msg(L_INFO, "Daemon is running"); - msg(L_INFO, "uid=%d/%d gid=%d/%d", (int) getuid(), (int) geteuid(), (int) getgid(), (int) getegid()); - sleep(60); + sleep(2); msg(L_INFO, "Daemon is shutting down"); daemon_exit(dp); }