xref: /netbsd-src/lib/librumpuser/rumpuser_daemonize.c (revision 561072c7c1874035652bf4084d6cb47b85da0e92)
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