/* * Copyright (C) 2017 Aaron M. D. Jones * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE ARE DISCLAIMED. * * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "acopm-common.h" #include /* errno */ #include /* open(), O_* */ #include /* strerror() */ #include /* chdir(), exit(), fork(), pipe(), setsid() */ #include /* event_reinit(), struct event_base */ #include "daemon.h" /* decls for own functions */ #include "vars.h" /* extern struct event_base *ev_base */ #include "utils/log.h" /* acopm_log_*() */ static bool acopm_do_daemon = false; static inline bool acopm_attr_inline acopm_daemon_child(const int pipefd) { bool result = false; const unsigned char buf = 0x01; const int nullfd = open("/dev/null", O_RDWR | O_NOCTTY); if (nullfd == -1) { (void) acopm_log_error("%s: open: %s", __func__, strerror(errno)); goto end; } if (event_reinit(ev_base) == -1) { (void) acopm_log_error("%s: event_reinit: %s", __func__, strerror(errno)); goto end; } if (chdir("/") == -1) { (void) acopm_log_error("%s: chdir: %s", __func__, strerror(errno)); goto end; } for (int x = 0; x < 3; x++) if (x != nullfd) (void) dup2(nullfd, x); if (nullfd >= 3) (void) close(nullfd); if (setsid() == -1) { (void) acopm_log_error("%s: setsid: %s", __func__, strerror(errno)); goto end; } if (write(pipefd, &buf, sizeof buf) == -1) { (void) acopm_log_warning("%s: write: %s", __func__, strerror(errno)); (void) acopm_log_warning("%s: our parent may think we died!", __func__); } result = true; end: (void) close(pipefd); return result; } void acopm_daemon_set(void) { acopm_do_daemon = true; } bool acopm_daemonise(void) { if (! acopm_do_daemon) return true; (void) acopm_log_flush(); int pipefd[2]; if (pipe(pipefd) == -1) { (void) acopm_log_error("%s: pipe: %s", __func__, strerror(errno)); return false; } const pid_t ret = fork(); if (ret == -1) { (void) acopm_log_error("%s: fork: %s", __func__, strerror(errno)); return false; } else if (ret == 0) { (void) close(pipefd[0]); return acopm_daemon_child(pipefd[1]); } else { unsigned char buf = 0x00; (void) close(pipefd[1]); if (read(pipefd[0], &buf, sizeof buf) <= 0) exit(EXIT_FAILURE); exit(EXIT_SUCCESS); } }