1*561072c7Sriastradh /* $NetBSD: rumpuser_daemonize.c,v 1.10 2024/04/04 21:19:25 riastradh Exp $ */
27332ad15Spooka
37332ad15Spooka /*
47332ad15Spooka * Copyright (c) 2010 Antti Kantee. All Rights Reserved.
57332ad15Spooka *
67332ad15Spooka * Redistribution and use in source and binary forms, with or without
77332ad15Spooka * modification, are permitted provided that the following conditions
87332ad15Spooka * are met:
97332ad15Spooka * 1. Redistributions of source code must retain the above copyright
107332ad15Spooka * notice, this list of conditions and the following disclaimer.
117332ad15Spooka * 2. Redistributions in binary form must reproduce the above copyright
127332ad15Spooka * notice, this list of conditions and the following disclaimer in the
137332ad15Spooka * documentation and/or other materials provided with the distribution.
147332ad15Spooka *
157332ad15Spooka * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
167332ad15Spooka * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
177332ad15Spooka * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
187332ad15Spooka * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
197332ad15Spooka * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
207332ad15Spooka * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
217332ad15Spooka * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
227332ad15Spooka * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
237332ad15Spooka * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
247332ad15Spooka * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
257332ad15Spooka * SUCH DAMAGE.
267332ad15Spooka */
277332ad15Spooka
283b3ffd70Spooka #include "rumpuser_port.h"
293b3ffd70Spooka
307332ad15Spooka #if !defined(lint)
31*561072c7Sriastradh __RCSID("$NetBSD: rumpuser_daemonize.c,v 1.10 2024/04/04 21:19:25 riastradh Exp $");
327332ad15Spooka #endif /* !lint */
337332ad15Spooka
347332ad15Spooka #include <sys/types.h>
357332ad15Spooka #include <sys/socket.h>
367332ad15Spooka
377332ad15Spooka #include <errno.h>
387332ad15Spooka #include <fcntl.h>
39059f8df6Spooka #include <stdint.h>
407332ad15Spooka #include <stdio.h>
417332ad15Spooka #include <unistd.h>
427332ad15Spooka
43be085dcdSpooka #include "rumpuser_int.h"
44be085dcdSpooka
4523dfcd74Spooka #if defined(HAVE_PATHS_H)
4665306217Spooka #include <paths.h>
4723dfcd74Spooka #else
4823dfcd74Spooka #define _PATH_DEVNULL "/dev/null"
4965306217Spooka #endif
5065306217Spooka
517332ad15Spooka static int isdaemonizing;
527332ad15Spooka static int daemonpipe[2];
537332ad15Spooka
547332ad15Spooka #include <rump/rumpuser.h>
557332ad15Spooka
563f290931Sriastradh static int
openstdoutstderr(void)573f290931Sriastradh openstdoutstderr(void)
583f290931Sriastradh {
593f290931Sriastradh char path[PATH_MAX];
603f290931Sriastradh int fd;
613f290931Sriastradh
623f290931Sriastradh if (getenv_r("RUMP_STDOUT", path, sizeof(path)) == 0) {
633f290931Sriastradh if ((fd = open(path, O_WRONLY|O_CREAT)) == -1)
643f290931Sriastradh return -1;
653f290931Sriastradh dup2(fd, STDOUT_FILENO);
663f290931Sriastradh (void)close(fd);
673f290931Sriastradh }
683f290931Sriastradh if (getenv_r("RUMP_STDERR", path, sizeof(path)) == 0) {
693f290931Sriastradh if ((fd = open(path, O_WRONLY|O_CREAT)) == -1)
703f290931Sriastradh return -1;
713f290931Sriastradh dup2(fd, STDERR_FILENO);
723f290931Sriastradh (void)close(fd);
733f290931Sriastradh }
743f290931Sriastradh return 0;
753f290931Sriastradh }
763f290931Sriastradh
777332ad15Spooka int
rumpuser_daemonize_begin(void)787332ad15Spooka rumpuser_daemonize_begin(void)
797332ad15Spooka {
807332ad15Spooka ssize_t n;
817332ad15Spooka int error;
82be085dcdSpooka int rv;
837332ad15Spooka
84be085dcdSpooka if (isdaemonizing) {
85be085dcdSpooka rv = EINPROGRESS;
86be085dcdSpooka goto out;
87be085dcdSpooka }
887332ad15Spooka isdaemonizing = 1;
897332ad15Spooka
907332ad15Spooka /*
917332ad15Spooka * For daemons we need to fork. However, since we can't fork
927332ad15Spooka * after rump_init (which creates threads), do it now. Add
937332ad15Spooka * a little pipe trickery to make sure we don't exit until the
947332ad15Spooka * service is fully inited (i.e. interlocked daemonization).
95506971ffSandvar * Actually, use socketpair since that allows to easily steer
967332ad15Spooka * clear of the dreaded sigpipe.
977332ad15Spooka *
987332ad15Spooka * Note: We do *NOT* host chdir("/"). It's up to the caller to
997332ad15Spooka * take care of that or not.
1007332ad15Spooka */
1017332ad15Spooka if (socketpair(PF_LOCAL, SOCK_STREAM, 0, daemonpipe) == -1) {
102be085dcdSpooka rv = errno;
103be085dcdSpooka goto out;
1047332ad15Spooka }
1057332ad15Spooka
1063f290931Sriastradh if (openstdoutstderr() == -1) {
1073f290931Sriastradh rv = errno;
1083f290931Sriastradh (void)close(daemonpipe[0]);
1093f290931Sriastradh (void)close(daemonpipe[1]);
1103f290931Sriastradh goto out;
1113f290931Sriastradh }
1123f290931Sriastradh
1137332ad15Spooka switch (fork()) {
1147332ad15Spooka case 0:
1157332ad15Spooka if (setsid() == -1) {
1167332ad15Spooka rumpuser_daemonize_done(errno);
1177332ad15Spooka }
118be085dcdSpooka rv = 0;
119be085dcdSpooka break;
1207332ad15Spooka case -1:
121be085dcdSpooka rv = errno;
122be085dcdSpooka break;
1237332ad15Spooka default:
1247332ad15Spooka close(daemonpipe[1]);
1257332ad15Spooka n = recv(daemonpipe[0], &error, sizeof(error), MSG_NOSIGNAL);
1267332ad15Spooka if (n == -1)
1277332ad15Spooka error = errno;
1287332ad15Spooka else if (n != sizeof(error))
1297332ad15Spooka error = ESRCH;
1307332ad15Spooka _exit(error);
1313b79c0ebSpooka /*NOTREACHED*/
1327332ad15Spooka }
133be085dcdSpooka
134be085dcdSpooka out:
135be085dcdSpooka ET(rv);
1367332ad15Spooka }
1377332ad15Spooka
1387332ad15Spooka int
rumpuser_daemonize_done(int error)1397332ad15Spooka rumpuser_daemonize_done(int error)
1407332ad15Spooka {
1417332ad15Spooka ssize_t n;
142be085dcdSpooka int fd, rv = 0;
1437332ad15Spooka
144be085dcdSpooka if (!isdaemonizing) {
145be085dcdSpooka rv = ENOENT;
146be085dcdSpooka goto outout;
147be085dcdSpooka }
1487332ad15Spooka
1497332ad15Spooka if (error == 0) {
1507332ad15Spooka fd = open(_PATH_DEVNULL, O_RDWR);
1517332ad15Spooka if (fd == -1) {
1527332ad15Spooka error = errno;
1537332ad15Spooka goto out;
1547332ad15Spooka }
1557332ad15Spooka dup2(fd, STDIN_FILENO);
1563f290931Sriastradh if (getenv("RUMP_STDOUT") == NULL)
1577332ad15Spooka dup2(fd, STDOUT_FILENO);
1583f290931Sriastradh if (getenv("RUMP_STDERR") == NULL)
1597332ad15Spooka dup2(fd, STDERR_FILENO);
1607332ad15Spooka if (fd > STDERR_FILENO)
1617332ad15Spooka close(fd);
1627332ad15Spooka }
1637332ad15Spooka
164*561072c7Sriastradh fflush(stdout);
165*561072c7Sriastradh fflush(stderr);
166*561072c7Sriastradh
1677332ad15Spooka out:
1687332ad15Spooka n = send(daemonpipe[1], &error, sizeof(error), MSG_NOSIGNAL);
169be085dcdSpooka if (n != sizeof(error)) {
170be085dcdSpooka rv = EPIPE;
171be085dcdSpooka } else if (n == -1) {
172be085dcdSpooka rv = errno;
173be085dcdSpooka } else {
1747332ad15Spooka close(daemonpipe[0]);
1757332ad15Spooka close(daemonpipe[1]);
176be085dcdSpooka }
1777332ad15Spooka
178be085dcdSpooka outout:
179be085dcdSpooka ET(rv);
1807332ad15Spooka }
181