/** * slibc — Yet another C library * Copyright © 2015, 2016 Mattias Andrée (maandree@member.fsf.org) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include /** * Detach the process from the controlling terminal * and run in the background. * * The function shall change the working directory * to '/' to avoid block a mountpoint from being * unmounted. It shall also change direct stdin, * stdout, and stderr to '/dev/null'. It shall * then double-fork, and between the fork, become * a session leader, temporarily, so that the * it no longer has a controlling terminal. * * Note well, this function does not implement a * reliable or particularly correct mechanism for * daemonising a process. It shall not be used! * Note, the GNU implementation is slightly * different because of a bug. * * @etymology (Daemon)ise! * * @param nochdir The not change working directory to '/'. * @param noclose The not redirect stdin, stdout, and stderr to '/dev/null'. * @return Zero on success, -1 on error. * * @throws EACCES If `nochdir` is zero, and the user is denied access to '/'. * @throws Any error specified for open(3). * @throws Any error specified for dup2(3). * @throws Any error specified for fork(3). * @throws Any error specified for setsid(3). * * @since Always. */ int daemon(int nochdir, int noclose) { int fd = -1; int saved_errno; if (nochdir ? 0 : chdir("/")) return -1; if (noclose == 0) { if (fd = open("/dev/null", O_RDWR), fd < 0) return -1; if (dup2(fd, 0) < 0) goto fail; if (dup2(fd, 1) < 0) goto fail; if (dup2(fd, 2) < 0) goto fail; if (fd > 2) close(fd); } switch (fork()) { case 0: break; case -1: return -1; default: _exit(0); } if (setsid() < 0) return -1; switch (fork()) { case 0: break; case -1: return -1; default: _exit(0); } return 0; fail: saved_errno = errno; if (fd > 2) close (fd); errno = saved_errno; return -1; }