156893Sfenner/* $NetBSD: rumpuser_daemonize.c,v 1.10 2024/04/04 21:19:25 riastradh Exp $ */ 256893Sfenner 356893Sfenner/* 456893Sfenner * Copyright (c) 2010 Antti Kantee. All Rights Reserved. 556893Sfenner * 656893Sfenner * Redistribution and use in source and binary forms, with or without 756893Sfenner * modification, are permitted provided that the following conditions 856893Sfenner * are met: 956893Sfenner * 1. Redistributions of source code must retain the above copyright 1056893Sfenner * notice, this list of conditions and the following disclaimer. 1156893Sfenner * 2. Redistributions in binary form must reproduce the above copyright 1256893Sfenner * notice, this list of conditions and the following disclaimer in the 1356893Sfenner * documentation and/or other materials provided with the distribution. 1456893Sfenner * 1556893Sfenner * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 1656893Sfenner * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 1756893Sfenner * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 1856893Sfenner * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1956893Sfenner * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2056893Sfenner * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 2156893Sfenner * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2256893Sfenner * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2356893Sfenner * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2456893Sfenner * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2556893Sfenner * SUCH DAMAGE. 2656893Sfenner */ 2756893Sfenner 2856893Sfenner#include "rumpuser_port.h" 2956893Sfenner 3056893Sfenner#if !defined(lint) 3156893Sfenner__RCSID("$NetBSD: rumpuser_daemonize.c,v 1.10 2024/04/04 21:19:25 riastradh Exp $"); 3256893Sfenner#endif /* !lint */ 3356893Sfenner 3456893Sfenner#include <sys/types.h> 3556893Sfenner#include <sys/socket.h> 3656893Sfenner 3756893Sfenner#include <errno.h> 3856893Sfenner#include <fcntl.h> 3956893Sfenner#include <stdint.h> 4056893Sfenner#include <stdio.h> 4156893Sfenner#include <unistd.h> 4256893Sfenner 4356893Sfenner#include "rumpuser_int.h" 44127668Sbms 45190207Srpaulo#if defined(HAVE_PATHS_H) 4656893Sfenner#include <paths.h> 47127668Sbms#else 4856893Sfenner#define _PATH_DEVNULL "/dev/null" 4956893Sfenner#endif 5056893Sfenner 5156893Sfennerstatic int isdaemonizing; 52127668Sbmsstatic int daemonpipe[2]; 5356893Sfenner 5456893Sfenner#include <rump/rumpuser.h> 5556893Sfenner 5656893Sfennerstatic int 5756893Sfenneropenstdoutstderr(void) 58127668Sbms{ 5956893Sfenner char path[PATH_MAX]; 60162017Ssam int fd; 6156893Sfenner 62162017Ssam if (getenv_r("RUMP_STDOUT", path, sizeof(path)) == 0) { 63162017Ssam if ((fd = open(path, O_WRONLY|O_CREAT)) == -1) 64162017Ssam return -1; 65162017Ssam dup2(fd, STDOUT_FILENO); 66162017Ssam (void)close(fd); 67162017Ssam } 68162017Ssam if (getenv_r("RUMP_STDERR", path, sizeof(path)) == 0) { 69162017Ssam if ((fd = open(path, O_WRONLY|O_CREAT)) == -1) 70162017Ssam return -1; 71162017Ssam dup2(fd, STDERR_FILENO); 72162017Ssam (void)close(fd); 73162017Ssam } 74162017Ssam return 0; 75162017Ssam} 76162017Ssam 77162017Ssamint 78162017Ssamrumpuser_daemonize_begin(void) 79162017Ssam{ 8056893Sfenner ssize_t n; 8156893Sfenner int error; 8256893Sfenner int rv; 8356893Sfenner 84127668Sbms if (isdaemonizing) { 8556893Sfenner rv = EINPROGRESS; 8656893Sfenner goto out; 8756893Sfenner } 8856893Sfenner isdaemonizing = 1; 8956893Sfenner 9056893Sfenner /* 9156893Sfenner * For daemons we need to fork. However, since we can't fork 92162017Ssam * after rump_init (which creates threads), do it now. Add 93162017Ssam * a little pipe trickery to make sure we don't exit until the 94162017Ssam * service is fully inited (i.e. interlocked daemonization). 95162017Ssam * Actually, use socketpair since that allows to easily steer 96162017Ssam * clear of the dreaded sigpipe. 97162017Ssam * 98162017Ssam * Note: We do *NOT* host chdir("/"). It's up to the caller to 99127668Sbms * take care of that or not. 100162017Ssam */ 101162017Ssam if (socketpair(PF_LOCAL, SOCK_STREAM, 0, daemonpipe) == -1) { 102162017Ssam rv = errno; 103127668Sbms goto out; 104127668Sbms } 105127668Sbms 10656893Sfenner if (openstdoutstderr() == -1) { 10756893Sfenner rv = errno; 10856893Sfenner (void)close(daemonpipe[0]); 109162017Ssam (void)close(daemonpipe[1]); 110162017Ssam goto out; 111162017Ssam } 112162017Ssam 11356893Sfenner switch (fork()) { 11456893Sfenner case 0: 11556893Sfenner if (setsid() == -1) { 11656893Sfenner rumpuser_daemonize_done(errno); 117162017Ssam } 118162017Ssam rv = 0; 119162017Ssam break; 12056893Sfenner case -1: 12156893Sfenner rv = errno; 12256893Sfenner break; 12356893Sfenner default: 124162017Ssam close(daemonpipe[1]); 125162017Ssam n = recv(daemonpipe[0], &error, sizeof(error), MSG_NOSIGNAL); 12656893Sfenner if (n == -1) 127162017Ssam error = errno; 12856893Sfenner else if (n != sizeof(error)) 129127668Sbms error = ESRCH; 13056893Sfenner _exit(error); 13156893Sfenner /*NOTREACHED*/ 13256893Sfenner } 13356893Sfenner 134146773Ssam out: 13556893Sfenner ET(rv); 13656893Sfenner} 13756893Sfenner 13856893Sfennerint 13956893Sfennerrumpuser_daemonize_done(int error) 14056893Sfenner{ 14156893Sfenner ssize_t n; 14256893Sfenner int fd, rv = 0; 14356893Sfenner 144127668Sbms if (!isdaemonizing) { 14556893Sfenner rv = ENOENT; 14656893Sfenner goto outout; 14756893Sfenner } 14856893Sfenner 14956893Sfenner if (error == 0) { 15056893Sfenner fd = open(_PATH_DEVNULL, O_RDWR); 15156893Sfenner if (fd == -1) { 152127668Sbms error = errno; 15356893Sfenner goto out; 15456893Sfenner } 15556893Sfenner dup2(fd, STDIN_FILENO); 15656893Sfenner if (getenv("RUMP_STDOUT") == NULL) 15756893Sfenner dup2(fd, STDOUT_FILENO); 15856893Sfenner if (getenv("RUMP_STDERR") == NULL) 15956893Sfenner dup2(fd, STDERR_FILENO); 16056893Sfenner if (fd > STDERR_FILENO) 161146773Ssam close(fd); 16256893Sfenner } 163127668Sbms 16456893Sfenner fflush(stdout); 16556893Sfenner fflush(stderr); 16656893Sfenner 16756893Sfenner out: 16856893Sfenner n = send(daemonpipe[1], &error, sizeof(error), MSG_NOSIGNAL); 16956893Sfenner if (n != sizeof(error)) { 170162017Ssam rv = EPIPE; 17156893Sfenner } else if (n == -1) { 172162017Ssam rv = errno; 173162017Ssam } else { 17456893Sfenner close(daemonpipe[0]); 17556893Sfenner close(daemonpipe[1]); 17656893Sfenner } 177162017Ssam 17856893Sfenner outout: 179162017Ssam ET(rv); 180162017Ssam} 18156893Sfenner