1 /* $NetBSD: rumpuser_daemonize.c,v 1.7 2014/11/04 19:05:17 pooka Exp $ */
2
3 /*
4 * Copyright (c) 2010 Antti Kantee. All Rights Reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28 #include "rumpuser_port.h"
29
30 #if !defined(lint)
31 __RCSID("$NetBSD: rumpuser_daemonize.c,v 1.7 2014/11/04 19:05:17 pooka Exp $");
32 #endif /* !lint */
33
34 #include <sys/types.h>
35 #include <sys/socket.h>
36
37 #include <errno.h>
38 #include <fcntl.h>
39 #include <stdint.h>
40 #include <stdio.h>
41 #include <unistd.h>
42
43 #include "rumpuser_int.h"
44
45 #if defined(HAVE_PATHS_H)
46 #include <paths.h>
47 #else
48 #define _PATH_DEVNULL "/dev/null"
49 #endif
50
51 static int isdaemonizing;
52 static int daemonpipe[2];
53
54 #include <rump/rumpuser.h>
55
56 int
rumpuser_daemonize_begin(void)57 rumpuser_daemonize_begin(void)
58 {
59 ssize_t n;
60 int error;
61 int rv;
62
63 if (isdaemonizing) {
64 rv = EINPROGRESS;
65 goto out;
66 }
67 isdaemonizing = 1;
68
69 /*
70 * For daemons we need to fork. However, since we can't fork
71 * after rump_init (which creates threads), do it now. Add
72 * a little pipe trickery to make sure we don't exit until the
73 * service is fully inited (i.e. interlocked daemonization).
74 * Actually, use sucketpair since that allows to easily steer
75 * clear of the dreaded sigpipe.
76 *
77 * Note: We do *NOT* host chdir("/"). It's up to the caller to
78 * take care of that or not.
79 */
80 if (socketpair(PF_LOCAL, SOCK_STREAM, 0, daemonpipe) == -1) {
81 rv = errno;
82 goto out;
83 }
84
85 switch (fork()) {
86 case 0:
87 if (setsid() == -1) {
88 rumpuser_daemonize_done(errno);
89 }
90 rv = 0;
91 break;
92 case -1:
93 rv = errno;
94 break;
95 default:
96 close(daemonpipe[1]);
97 n = recv(daemonpipe[0], &error, sizeof(error), MSG_NOSIGNAL);
98 if (n == -1)
99 error = errno;
100 else if (n != sizeof(error))
101 error = ESRCH;
102 _exit(error);
103 /*NOTREACHED*/
104 }
105
106 out:
107 ET(rv);
108 }
109
110 int
rumpuser_daemonize_done(int error)111 rumpuser_daemonize_done(int error)
112 {
113 ssize_t n;
114 int fd, rv = 0;
115
116 if (!isdaemonizing) {
117 rv = ENOENT;
118 goto outout;
119 }
120
121 if (error == 0) {
122 fd = open(_PATH_DEVNULL, O_RDWR);
123 if (fd == -1) {
124 error = errno;
125 goto out;
126 }
127 dup2(fd, STDIN_FILENO);
128 dup2(fd, STDOUT_FILENO);
129 dup2(fd, STDERR_FILENO);
130 if (fd > STDERR_FILENO)
131 close(fd);
132 }
133
134 out:
135 n = send(daemonpipe[1], &error, sizeof(error), MSG_NOSIGNAL);
136 if (n != sizeof(error)) {
137 rv = EPIPE;
138 } else if (n == -1) {
139 rv = errno;
140 } else {
141 close(daemonpipe[0]);
142 close(daemonpipe[1]);
143 }
144
145 outout:
146 ET(rv);
147 }
148