xref: /freebsd/contrib/ntp/libntp/work_fork.c (revision 2aaf9152a852aba9eb2036b95f4948ee77988826)
12b15cb3dSCy Schubert /*
22b15cb3dSCy Schubert  * work_fork.c - fork implementation for blocking worker child.
32b15cb3dSCy Schubert  */
42b15cb3dSCy Schubert #include <config.h>
52b15cb3dSCy Schubert #include "ntp_workimpl.h"
62b15cb3dSCy Schubert 
72b15cb3dSCy Schubert #ifdef WORK_FORK
82b15cb3dSCy Schubert #include <stdio.h>
92b15cb3dSCy Schubert #include <ctype.h>
102b15cb3dSCy Schubert #include <signal.h>
11276da39aSCy Schubert #include <sys/wait.h>
122b15cb3dSCy Schubert 
132b15cb3dSCy Schubert #include "iosignal.h"
142b15cb3dSCy Schubert #include "ntp_stdlib.h"
152b15cb3dSCy Schubert #include "ntp_malloc.h"
162b15cb3dSCy Schubert #include "ntp_syslog.h"
172b15cb3dSCy Schubert #include "ntpd.h"
182b15cb3dSCy Schubert #include "ntp_io.h"
192b15cb3dSCy Schubert #include "ntp_assert.h"
202b15cb3dSCy Schubert #include "ntp_unixtime.h"
212b15cb3dSCy Schubert #include "ntp_worker.h"
222b15cb3dSCy Schubert 
232b15cb3dSCy Schubert /* === variables === */
242b15cb3dSCy Schubert 	int			worker_process;
252b15cb3dSCy Schubert 	addremove_io_fd_func	addremove_io_fd;
262b15cb3dSCy Schubert static	volatile int		worker_sighup_received;
27f0574f5cSXin LI int	saved_argc = 0;
28f0574f5cSXin LI char	**saved_argv;
292b15cb3dSCy Schubert 
302b15cb3dSCy Schubert /* === function prototypes === */
312b15cb3dSCy Schubert static	void		fork_blocking_child(blocking_child *);
322b15cb3dSCy Schubert static	RETSIGTYPE	worker_sighup(int);
332b15cb3dSCy Schubert static	void		send_worker_home_atexit(void);
342b15cb3dSCy Schubert static	void		cleanup_after_child(blocking_child *);
352b15cb3dSCy Schubert 
36f0574f5cSXin LI /* === I/O helpers === */
37f0574f5cSXin LI /* Since we have signals enabled, there's a good chance that blocking IO
38f0574f5cSXin LI  * via pipe suffers from EINTR -- and this goes for both directions.
39f0574f5cSXin LI  * The next two wrappers will loop until either all the data is written
40f0574f5cSXin LI  * or read, plus handling the EOF condition on read. They may return
41f0574f5cSXin LI  * zero if no data was transferred at all, and effectively every return
42f0574f5cSXin LI  * value that differs from the given transfer length signifies an error
43f0574f5cSXin LI  * condition.
44f0574f5cSXin LI  */
45f0574f5cSXin LI 
46f0574f5cSXin LI static size_t
netread(int fd,void * vb,size_t l)47f0574f5cSXin LI netread(
48f0574f5cSXin LI 	int		fd,
49f0574f5cSXin LI 	void *		vb,
50f0574f5cSXin LI 	size_t		l
51f0574f5cSXin LI 	)
52f0574f5cSXin LI {
53f0574f5cSXin LI 	char *		b = vb;
54f0574f5cSXin LI 	ssize_t		r;
55f0574f5cSXin LI 
56f0574f5cSXin LI 	while (l) {
57f0574f5cSXin LI 		r = read(fd, b, l);
58f0574f5cSXin LI 		if (r > 0) {
59f0574f5cSXin LI 			l -= r;
60f0574f5cSXin LI 			b += r;
61f0574f5cSXin LI 		} else if (r == 0 || errno != EINTR) {
62f0574f5cSXin LI 			l = 0;
63f0574f5cSXin LI 		}
64f0574f5cSXin LI 	}
65f0574f5cSXin LI 	return (size_t)(b - (char *)vb);
66f0574f5cSXin LI }
67f0574f5cSXin LI 
68f0574f5cSXin LI 
69f0574f5cSXin LI static size_t
netwrite(int fd,const void * vb,size_t l)70f0574f5cSXin LI netwrite(
71f0574f5cSXin LI 	int		fd,
72f0574f5cSXin LI 	const void *	vb,
73f0574f5cSXin LI 	size_t		l
74f0574f5cSXin LI 	)
75f0574f5cSXin LI {
76f0574f5cSXin LI 	const char *	b = vb;
77f0574f5cSXin LI 	ssize_t		w;
78f0574f5cSXin LI 
79f0574f5cSXin LI 	while (l) {
80f0574f5cSXin LI 		w = write(fd, b, l);
81f0574f5cSXin LI 		if (w > 0) {
82f0574f5cSXin LI 			l -= w;
83f0574f5cSXin LI 			b += w;
84f0574f5cSXin LI 		} else if (errno != EINTR) {
85f0574f5cSXin LI 			l = 0;
86f0574f5cSXin LI 		}
87f0574f5cSXin LI 	}
88f0574f5cSXin LI 	return (size_t)(b - (const char *)vb);
89f0574f5cSXin LI }
90f0574f5cSXin LI 
91f0574f5cSXin LI 
92*052d159aSCy Schubert #if defined(HAVE_DROPROOT)
93*052d159aSCy Schubert extern int set_user_group_ids(void);
94*052d159aSCy Schubert #endif
954e1ef62aSXin LI 
962b15cb3dSCy Schubert /* === functions === */
972b15cb3dSCy Schubert /*
982b15cb3dSCy Schubert  * exit_worker()
992b15cb3dSCy Schubert  *
1002b15cb3dSCy Schubert  * On some systems _exit() is preferred to exit() for forked children.
1012b15cb3dSCy Schubert  * For example, http://netbsd.gw.com/cgi-bin/man-cgi?fork++NetBSD-5.0
1022b15cb3dSCy Schubert  * recommends _exit() to avoid double-flushing C runtime stream buffers
1032b15cb3dSCy Schubert  * and also to avoid calling the parent's atexit() routines in the
1042b15cb3dSCy Schubert  * child.  On those systems WORKER_CHILD_EXIT is _exit.  Since _exit
1052b15cb3dSCy Schubert  * bypasses CRT cleanup, fflush() files we know might have output
1062b15cb3dSCy Schubert  * buffered.
1072b15cb3dSCy Schubert  */
1082b15cb3dSCy Schubert void
exit_worker(int exitcode)1092b15cb3dSCy Schubert exit_worker(
1102b15cb3dSCy Schubert 	int	exitcode
1112b15cb3dSCy Schubert 	)
1122b15cb3dSCy Schubert {
1132b15cb3dSCy Schubert 	if (syslog_file != NULL)
1142b15cb3dSCy Schubert 		fflush(syslog_file);
1152b15cb3dSCy Schubert 	fflush(stdout);
1162b15cb3dSCy Schubert 	fflush(stderr);
1172b15cb3dSCy Schubert 	WORKER_CHILD_EXIT (exitcode);	/* space before ( required */
1182b15cb3dSCy Schubert }
1192b15cb3dSCy Schubert 
1202b15cb3dSCy Schubert 
1212b15cb3dSCy Schubert static RETSIGTYPE
worker_sighup(int sig)1222b15cb3dSCy Schubert worker_sighup(
1232b15cb3dSCy Schubert 	int sig
1242b15cb3dSCy Schubert 	)
1252b15cb3dSCy Schubert {
1262b15cb3dSCy Schubert 	if (SIGHUP == sig)
1272b15cb3dSCy Schubert 		worker_sighup_received = 1;
1282b15cb3dSCy Schubert }
1292b15cb3dSCy Schubert 
1302b15cb3dSCy Schubert 
1312b15cb3dSCy Schubert int
worker_sleep(blocking_child * c,time_t seconds)1322b15cb3dSCy Schubert worker_sleep(
1332b15cb3dSCy Schubert 	blocking_child *	c,
1342b15cb3dSCy Schubert 	time_t			seconds
1352b15cb3dSCy Schubert 	)
1362b15cb3dSCy Schubert {
1372b15cb3dSCy Schubert 	u_int sleep_remain;
1382b15cb3dSCy Schubert 
1392b15cb3dSCy Schubert 	sleep_remain = (u_int)seconds;
1402b15cb3dSCy Schubert 	do {
1412b15cb3dSCy Schubert 		if (!worker_sighup_received)
1422b15cb3dSCy Schubert 			sleep_remain = sleep(sleep_remain);
1432b15cb3dSCy Schubert 		if (worker_sighup_received) {
1442b15cb3dSCy Schubert 			TRACE(1, ("worker SIGHUP with %us left to sleep",
1452b15cb3dSCy Schubert 				  sleep_remain));
1462b15cb3dSCy Schubert 			worker_sighup_received = 0;
1472b15cb3dSCy Schubert 			return -1;
1482b15cb3dSCy Schubert 		}
1492b15cb3dSCy Schubert 	} while (sleep_remain);
1502b15cb3dSCy Schubert 
1512b15cb3dSCy Schubert 	return 0;
1522b15cb3dSCy Schubert }
1532b15cb3dSCy Schubert 
1542b15cb3dSCy Schubert 
1552b15cb3dSCy Schubert void
interrupt_worker_sleep(void)1562b15cb3dSCy Schubert interrupt_worker_sleep(void)
1572b15cb3dSCy Schubert {
1582b15cb3dSCy Schubert 	u_int			idx;
1592b15cb3dSCy Schubert 	blocking_child *	c;
1602b15cb3dSCy Schubert 	int			rc;
1612b15cb3dSCy Schubert 
1622b15cb3dSCy Schubert 	for (idx = 0; idx < blocking_children_alloc; idx++) {
1632b15cb3dSCy Schubert 		c = blocking_children[idx];
1642b15cb3dSCy Schubert 
1652b15cb3dSCy Schubert 		if (NULL == c || c->reusable == TRUE)
1662b15cb3dSCy Schubert 			continue;
1672b15cb3dSCy Schubert 
1682b15cb3dSCy Schubert 		rc = kill(c->pid, SIGHUP);
1692b15cb3dSCy Schubert 		if (rc < 0)
1702b15cb3dSCy Schubert 			msyslog(LOG_ERR,
1712b15cb3dSCy Schubert 				"Unable to signal HUP to wake child pid %d: %m",
1722b15cb3dSCy Schubert 				c->pid);
1732b15cb3dSCy Schubert 	}
1742b15cb3dSCy Schubert }
1752b15cb3dSCy Schubert 
1762b15cb3dSCy Schubert 
1772b15cb3dSCy Schubert /*
178276da39aSCy Schubert  * harvest_child_status() runs in the parent.
179f391d6bcSXin LI  *
180f391d6bcSXin LI  * Note the error handling -- this is an interaction with SIGCHLD.
181f391d6bcSXin LI  * SIG_IGN on SIGCHLD on some OSes means do not wait but reap
182f391d6bcSXin LI  * automatically. Since we're not really interested in the result code,
183f391d6bcSXin LI  * we simply ignore the error.
184276da39aSCy Schubert  */
185276da39aSCy Schubert static void
harvest_child_status(blocking_child * c)186276da39aSCy Schubert harvest_child_status(
187276da39aSCy Schubert 	blocking_child *	c
188276da39aSCy Schubert 	)
189276da39aSCy Schubert {
190f391d6bcSXin LI 	if (c->pid) {
191276da39aSCy Schubert 		/* Wait on the child so it can finish terminating */
192276da39aSCy Schubert 		if (waitpid(c->pid, NULL, 0) == c->pid)
193276da39aSCy Schubert 			TRACE(4, ("harvested child %d\n", c->pid));
194f391d6bcSXin LI 		else if (errno != ECHILD)
195f391d6bcSXin LI 			msyslog(LOG_ERR, "error waiting on child %d: %m", c->pid);
196f391d6bcSXin LI 		c->pid = 0;
197276da39aSCy Schubert 	}
198276da39aSCy Schubert }
199276da39aSCy Schubert 
200276da39aSCy Schubert /*
2012b15cb3dSCy Schubert  * req_child_exit() runs in the parent.
2022b15cb3dSCy Schubert  */
2032b15cb3dSCy Schubert int
req_child_exit(blocking_child * c)2042b15cb3dSCy Schubert req_child_exit(
2052b15cb3dSCy Schubert 	blocking_child *	c
2062b15cb3dSCy Schubert 	)
2072b15cb3dSCy Schubert {
2082b15cb3dSCy Schubert 	if (-1 != c->req_write_pipe) {
2092b15cb3dSCy Schubert 		close(c->req_write_pipe);
2102b15cb3dSCy Schubert 		c->req_write_pipe = -1;
2112b15cb3dSCy Schubert 		return 0;
2122b15cb3dSCy Schubert 	}
213276da39aSCy Schubert 	/* Closing the pipe forces the child to exit */
214276da39aSCy Schubert 	harvest_child_status(c);
2152b15cb3dSCy Schubert 	return -1;
2162b15cb3dSCy Schubert }
2172b15cb3dSCy Schubert 
2182b15cb3dSCy Schubert 
2192b15cb3dSCy Schubert /*
2202b15cb3dSCy Schubert  * cleanup_after_child() runs in parent.
2212b15cb3dSCy Schubert  */
2222b15cb3dSCy Schubert static void
cleanup_after_child(blocking_child * c)2232b15cb3dSCy Schubert cleanup_after_child(
2242b15cb3dSCy Schubert 	blocking_child *	c
2252b15cb3dSCy Schubert 	)
2262b15cb3dSCy Schubert {
227276da39aSCy Schubert 	harvest_child_status(c);
2282b15cb3dSCy Schubert 	if (-1 != c->resp_read_pipe) {
2292b15cb3dSCy Schubert 		(*addremove_io_fd)(c->resp_read_pipe, c->ispipe, TRUE);
2302b15cb3dSCy Schubert 		close(c->resp_read_pipe);
2312b15cb3dSCy Schubert 		c->resp_read_pipe = -1;
2322b15cb3dSCy Schubert 	}
2332b15cb3dSCy Schubert 	c->resp_read_ctx = NULL;
2342b15cb3dSCy Schubert 	DEBUG_INSIST(-1 == c->req_read_pipe);
2352b15cb3dSCy Schubert 	DEBUG_INSIST(-1 == c->resp_write_pipe);
2362b15cb3dSCy Schubert 	c->reusable = TRUE;
2372b15cb3dSCy Schubert }
2382b15cb3dSCy Schubert 
2392b15cb3dSCy Schubert 
2402b15cb3dSCy Schubert static void
send_worker_home_atexit(void)2412b15cb3dSCy Schubert send_worker_home_atexit(void)
2422b15cb3dSCy Schubert {
2432b15cb3dSCy Schubert 	u_int			idx;
2442b15cb3dSCy Schubert 	blocking_child *	c;
2452b15cb3dSCy Schubert 
2462b15cb3dSCy Schubert 	if (worker_process)
2472b15cb3dSCy Schubert 		return;
2482b15cb3dSCy Schubert 
2492b15cb3dSCy Schubert 	for (idx = 0; idx < blocking_children_alloc; idx++) {
2502b15cb3dSCy Schubert 		c = blocking_children[idx];
2512b15cb3dSCy Schubert 		if (NULL == c)
2522b15cb3dSCy Schubert 			continue;
2532b15cb3dSCy Schubert 		req_child_exit(c);
2542b15cb3dSCy Schubert 	}
2552b15cb3dSCy Schubert }
2562b15cb3dSCy Schubert 
2572b15cb3dSCy Schubert 
2582b15cb3dSCy Schubert int
send_blocking_req_internal(blocking_child * c,blocking_pipe_header * hdr,void * data)2592b15cb3dSCy Schubert send_blocking_req_internal(
2602b15cb3dSCy Schubert 	blocking_child *	c,
2612b15cb3dSCy Schubert 	blocking_pipe_header *	hdr,
2622b15cb3dSCy Schubert 	void *			data
2632b15cb3dSCy Schubert 	)
2642b15cb3dSCy Schubert {
265f0574f5cSXin LI 	size_t	octets;
266f0574f5cSXin LI 	size_t	rc;
2672b15cb3dSCy Schubert 
2682b15cb3dSCy Schubert 	DEBUG_REQUIRE(hdr != NULL);
2692b15cb3dSCy Schubert 	DEBUG_REQUIRE(data != NULL);
2702b15cb3dSCy Schubert 	DEBUG_REQUIRE(BLOCKING_REQ_MAGIC == hdr->magic_sig);
2712b15cb3dSCy Schubert 
2722b15cb3dSCy Schubert 	if (-1 == c->req_write_pipe) {
2732b15cb3dSCy Schubert 		fork_blocking_child(c);
2742b15cb3dSCy Schubert 		DEBUG_INSIST(-1 != c->req_write_pipe);
2752b15cb3dSCy Schubert 	}
2762b15cb3dSCy Schubert 
2772b15cb3dSCy Schubert 	octets = sizeof(*hdr);
278f0574f5cSXin LI 	rc = netwrite(c->req_write_pipe, hdr, octets);
2792b15cb3dSCy Schubert 
2802b15cb3dSCy Schubert 	if (rc == octets) {
2812b15cb3dSCy Schubert 		octets = hdr->octets - sizeof(*hdr);
282f0574f5cSXin LI 		rc = netwrite(c->req_write_pipe, data, octets);
2832b15cb3dSCy Schubert 		if (rc == octets)
2842b15cb3dSCy Schubert 			return 0;
2852b15cb3dSCy Schubert 	}
2862b15cb3dSCy Schubert 
2872b15cb3dSCy Schubert 	msyslog(LOG_ERR,
288f0574f5cSXin LI 		"send_blocking_req_internal: short write (%zu of %zu), %m",
2892b15cb3dSCy Schubert 		rc, octets);
2902b15cb3dSCy Schubert 
291276da39aSCy Schubert 	/* Fatal error.  Clean up the child process.  */
292276da39aSCy Schubert 	req_child_exit(c);
2932b15cb3dSCy Schubert 	exit(1);	/* otherwise would be return -1 */
2942b15cb3dSCy Schubert }
2952b15cb3dSCy Schubert 
2962b15cb3dSCy Schubert 
2972b15cb3dSCy Schubert blocking_pipe_header *
receive_blocking_req_internal(blocking_child * c)2982b15cb3dSCy Schubert receive_blocking_req_internal(
2992b15cb3dSCy Schubert 	blocking_child *	c
3002b15cb3dSCy Schubert 	)
3012b15cb3dSCy Schubert {
3022b15cb3dSCy Schubert 	blocking_pipe_header	hdr;
3032b15cb3dSCy Schubert 	blocking_pipe_header *	req;
304f0574f5cSXin LI 	size_t			rc;
305f0574f5cSXin LI 	size_t			octets;
3062b15cb3dSCy Schubert 
3072b15cb3dSCy Schubert 	DEBUG_REQUIRE(-1 != c->req_read_pipe);
3082b15cb3dSCy Schubert 
3092b15cb3dSCy Schubert 	req = NULL;
310f0574f5cSXin LI 	rc = netread(c->req_read_pipe, &hdr, sizeof(hdr));
3112b15cb3dSCy Schubert 
312f0574f5cSXin LI 	if (0 == rc) {
3132b15cb3dSCy Schubert 		TRACE(4, ("parent closed request pipe, child %d terminating\n",
3142b15cb3dSCy Schubert 			  c->pid));
3152b15cb3dSCy Schubert 	} else if (rc != sizeof(hdr)) {
3162b15cb3dSCy Schubert 		msyslog(LOG_ERR,
317f0574f5cSXin LI 			"receive_blocking_req_internal: short header read (%zu of %zu), %m",
318f0574f5cSXin LI 			rc, sizeof(hdr));
3192b15cb3dSCy Schubert 	} else {
3202b15cb3dSCy Schubert 		INSIST(sizeof(hdr) < hdr.octets && hdr.octets < 4 * 1024);
3212b15cb3dSCy Schubert 		req = emalloc(hdr.octets);
3222b15cb3dSCy Schubert 		memcpy(req, &hdr, sizeof(*req));
3232b15cb3dSCy Schubert 		octets = hdr.octets - sizeof(hdr);
324f0574f5cSXin LI 		rc = netread(c->req_read_pipe, (char *)(req + 1),
3252b15cb3dSCy Schubert 			     octets);
3262b15cb3dSCy Schubert 
327f0574f5cSXin LI 		if (rc != octets)
3282b15cb3dSCy Schubert 			msyslog(LOG_ERR,
329f0574f5cSXin LI 				"receive_blocking_req_internal: short read (%zu of %zu), %m",
3302b15cb3dSCy Schubert 				rc, octets);
3312b15cb3dSCy Schubert 		else if (BLOCKING_REQ_MAGIC != req->magic_sig)
3322b15cb3dSCy Schubert 			msyslog(LOG_ERR,
3332b15cb3dSCy Schubert 				"receive_blocking_req_internal: packet header mismatch (0x%x)",
3342b15cb3dSCy Schubert 				req->magic_sig);
3352b15cb3dSCy Schubert 		else
3362b15cb3dSCy Schubert 			return req;
3372b15cb3dSCy Schubert 	}
3382b15cb3dSCy Schubert 
3392b15cb3dSCy Schubert 	if (req != NULL)
3402b15cb3dSCy Schubert 		free(req);
3412b15cb3dSCy Schubert 
3422b15cb3dSCy Schubert 	return NULL;
3432b15cb3dSCy Schubert }
3442b15cb3dSCy Schubert 
3452b15cb3dSCy Schubert 
3462b15cb3dSCy Schubert int
send_blocking_resp_internal(blocking_child * c,blocking_pipe_header * resp)3472b15cb3dSCy Schubert send_blocking_resp_internal(
3482b15cb3dSCy Schubert 	blocking_child *	c,
3492b15cb3dSCy Schubert 	blocking_pipe_header *	resp
3502b15cb3dSCy Schubert 	)
3512b15cb3dSCy Schubert {
352f0574f5cSXin LI 	size_t	octets;
353f0574f5cSXin LI 	size_t	rc;
3542b15cb3dSCy Schubert 
3552b15cb3dSCy Schubert 	DEBUG_REQUIRE(-1 != c->resp_write_pipe);
3562b15cb3dSCy Schubert 
3572b15cb3dSCy Schubert 	octets = resp->octets;
358f0574f5cSXin LI 	rc = netwrite(c->resp_write_pipe, resp, octets);
3592b15cb3dSCy Schubert 	free(resp);
3602b15cb3dSCy Schubert 
3612b15cb3dSCy Schubert 	if (octets == rc)
3622b15cb3dSCy Schubert 		return 0;
3632b15cb3dSCy Schubert 
364f0574f5cSXin LI 	TRACE(1, ("send_blocking_resp_internal: short write (%zu of %zu), %m\n",
3652b15cb3dSCy Schubert 		  rc, octets));
3662b15cb3dSCy Schubert 	return -1;
3672b15cb3dSCy Schubert }
3682b15cb3dSCy Schubert 
3692b15cb3dSCy Schubert 
3702b15cb3dSCy Schubert blocking_pipe_header *
receive_blocking_resp_internal(blocking_child * c)3712b15cb3dSCy Schubert receive_blocking_resp_internal(
3722b15cb3dSCy Schubert 	blocking_child *	c
3732b15cb3dSCy Schubert 	)
3742b15cb3dSCy Schubert {
3752b15cb3dSCy Schubert 	blocking_pipe_header	hdr;
3762b15cb3dSCy Schubert 	blocking_pipe_header *	resp;
377f0574f5cSXin LI 	size_t			rc;
378f0574f5cSXin LI 	size_t			octets;
3792b15cb3dSCy Schubert 
3802b15cb3dSCy Schubert 	DEBUG_REQUIRE(c->resp_read_pipe != -1);
3812b15cb3dSCy Schubert 
3822b15cb3dSCy Schubert 	resp = NULL;
383f0574f5cSXin LI 	rc = netread(c->resp_read_pipe, &hdr, sizeof(hdr));
3842b15cb3dSCy Schubert 
385f0574f5cSXin LI 	if (0 == rc) {
3862b15cb3dSCy Schubert 		/* this is the normal child exited indication */
3872b15cb3dSCy Schubert 	} else if (rc != sizeof(hdr)) {
388f0574f5cSXin LI 		TRACE(1, ("receive_blocking_resp_internal: short header read (%zu of %zu), %m\n",
389f0574f5cSXin LI 			  rc, sizeof(hdr)));
3902b15cb3dSCy Schubert 	} else if (BLOCKING_RESP_MAGIC != hdr.magic_sig) {
3912b15cb3dSCy Schubert 		TRACE(1, ("receive_blocking_resp_internal: header mismatch (0x%x)\n",
3922b15cb3dSCy Schubert 			  hdr.magic_sig));
3932b15cb3dSCy Schubert 	} else {
3942b15cb3dSCy Schubert 		INSIST(sizeof(hdr) < hdr.octets &&
3952b15cb3dSCy Schubert 		       hdr.octets < 16 * 1024);
3962b15cb3dSCy Schubert 		resp = emalloc(hdr.octets);
3972b15cb3dSCy Schubert 		memcpy(resp, &hdr, sizeof(*resp));
3982b15cb3dSCy Schubert 		octets = hdr.octets - sizeof(hdr);
399f0574f5cSXin LI 		rc = netread(c->resp_read_pipe, (char *)(resp + 1),
4002b15cb3dSCy Schubert 			     octets);
4012b15cb3dSCy Schubert 
402f0574f5cSXin LI 		if (rc != octets)
403f0574f5cSXin LI 			TRACE(1, ("receive_blocking_resp_internal: short read (%zu of %zu), %m\n",
4042b15cb3dSCy Schubert 				  rc, octets));
4052b15cb3dSCy Schubert 		else
4062b15cb3dSCy Schubert 			return resp;
4072b15cb3dSCy Schubert 	}
4082b15cb3dSCy Schubert 
4092b15cb3dSCy Schubert 	cleanup_after_child(c);
4102b15cb3dSCy Schubert 
4112b15cb3dSCy Schubert 	if (resp != NULL)
4122b15cb3dSCy Schubert 		free(resp);
4132b15cb3dSCy Schubert 
4142b15cb3dSCy Schubert 	return NULL;
4152b15cb3dSCy Schubert }
4162b15cb3dSCy Schubert 
4172b15cb3dSCy Schubert 
4182b15cb3dSCy Schubert #if defined(HAVE_DROPROOT) && defined(WORK_FORK)
4192b15cb3dSCy Schubert void
fork_deferred_worker(void)4202b15cb3dSCy Schubert fork_deferred_worker(void)
4212b15cb3dSCy Schubert {
4222b15cb3dSCy Schubert 	u_int			idx;
4232b15cb3dSCy Schubert 	blocking_child *	c;
4242b15cb3dSCy Schubert 
4252b15cb3dSCy Schubert 	REQUIRE(droproot && root_dropped);
4262b15cb3dSCy Schubert 
4272b15cb3dSCy Schubert 	for (idx = 0; idx < blocking_children_alloc; idx++) {
4282b15cb3dSCy Schubert 		c = blocking_children[idx];
4292b15cb3dSCy Schubert 		if (NULL == c)
4302b15cb3dSCy Schubert 			continue;
4312b15cb3dSCy Schubert 		if (-1 != c->req_write_pipe && 0 == c->pid)
4322b15cb3dSCy Schubert 			fork_blocking_child(c);
4332b15cb3dSCy Schubert 	}
4342b15cb3dSCy Schubert }
4352b15cb3dSCy Schubert #endif
4362b15cb3dSCy Schubert 
4372b15cb3dSCy Schubert 
4382b15cb3dSCy Schubert static void
fork_blocking_child(blocking_child * c)4392b15cb3dSCy Schubert fork_blocking_child(
4402b15cb3dSCy Schubert 	blocking_child *	c
4412b15cb3dSCy Schubert 	)
4422b15cb3dSCy Schubert {
4432b15cb3dSCy Schubert 	static int	atexit_installed;
4442b15cb3dSCy Schubert 	static int	blocking_pipes[4] = { -1, -1, -1, -1 };
4452b15cb3dSCy Schubert 	int		rc;
4462b15cb3dSCy Schubert 	int		was_pipe;
4472b15cb3dSCy Schubert 	int		is_pipe;
448a25439b6SCy Schubert 	int		saved_errno = 0;
4492b15cb3dSCy Schubert 	int		childpid;
4502b15cb3dSCy Schubert 	int		keep_fd;
4512b15cb3dSCy Schubert 	int		fd;
4522b15cb3dSCy Schubert 
4532b15cb3dSCy Schubert 	/*
4542b15cb3dSCy Schubert 	 * parent and child communicate via a pair of pipes.
4552b15cb3dSCy Schubert 	 *
4562b15cb3dSCy Schubert 	 * 0 child read request
4572b15cb3dSCy Schubert 	 * 1 parent write request
4582b15cb3dSCy Schubert 	 * 2 parent read response
4592b15cb3dSCy Schubert 	 * 3 child write response
4602b15cb3dSCy Schubert 	 */
4612b15cb3dSCy Schubert 	if (-1 == c->req_write_pipe) {
4622b15cb3dSCy Schubert 		rc = pipe_socketpair(&blocking_pipes[0], &was_pipe);
4632b15cb3dSCy Schubert 		if (0 != rc) {
4642b15cb3dSCy Schubert 			saved_errno = errno;
4652b15cb3dSCy Schubert 		} else {
4662b15cb3dSCy Schubert 			rc = pipe_socketpair(&blocking_pipes[2], &is_pipe);
4672b15cb3dSCy Schubert 			if (0 != rc) {
4682b15cb3dSCy Schubert 				saved_errno = errno;
4692b15cb3dSCy Schubert 				close(blocking_pipes[0]);
4702b15cb3dSCy Schubert 				close(blocking_pipes[1]);
4712b15cb3dSCy Schubert 			} else {
4722b15cb3dSCy Schubert 				INSIST(was_pipe == is_pipe);
4732b15cb3dSCy Schubert 			}
4742b15cb3dSCy Schubert 		}
4752b15cb3dSCy Schubert 		if (0 != rc) {
4762b15cb3dSCy Schubert 			errno = saved_errno;
4772b15cb3dSCy Schubert 			msyslog(LOG_ERR, "unable to create worker pipes: %m");
4782b15cb3dSCy Schubert 			exit(1);
4792b15cb3dSCy Schubert 		}
4802b15cb3dSCy Schubert 
4812b15cb3dSCy Schubert 		/*
4822b15cb3dSCy Schubert 		 * Move the descriptors the parent will keep open out of the
4832b15cb3dSCy Schubert 		 * low descriptors preferred by C runtime buffered FILE *.
4842b15cb3dSCy Schubert 		 */
4852b15cb3dSCy Schubert 		c->req_write_pipe = move_fd(blocking_pipes[1]);
4862b15cb3dSCy Schubert 		c->resp_read_pipe = move_fd(blocking_pipes[2]);
4872b15cb3dSCy Schubert 		/*
4882b15cb3dSCy Schubert 		 * wake any worker child on orderly shutdown of the
4892b15cb3dSCy Schubert 		 * daemon so that it can notice the broken pipes and
4902b15cb3dSCy Schubert 		 * go away promptly.
4912b15cb3dSCy Schubert 		 */
4922b15cb3dSCy Schubert 		if (!atexit_installed) {
4932b15cb3dSCy Schubert 			atexit(&send_worker_home_atexit);
4942b15cb3dSCy Schubert 			atexit_installed = TRUE;
4952b15cb3dSCy Schubert 		}
4962b15cb3dSCy Schubert 	}
4972b15cb3dSCy Schubert 
4984990d495SXin LI #if defined(HAVE_DROPROOT) && !defined(NEED_EARLY_FORK)
4992b15cb3dSCy Schubert 	/* defer the fork until after root is dropped */
5002b15cb3dSCy Schubert 	if (droproot && !root_dropped)
5012b15cb3dSCy Schubert 		return;
5022b15cb3dSCy Schubert #endif
5032b15cb3dSCy Schubert 	if (syslog_file != NULL)
5042b15cb3dSCy Schubert 		fflush(syslog_file);
5052b15cb3dSCy Schubert 	fflush(stdout);
5062b15cb3dSCy Schubert 	fflush(stderr);
5072b15cb3dSCy Schubert 
508f391d6bcSXin LI 	/* [BUG 3050] setting SIGCHLD to SIG_IGN likely causes unwanted
509f391d6bcSXin LI 	 * or undefined effects. We don't do it and leave SIGCHLD alone.
510f391d6bcSXin LI 	 */
511f391d6bcSXin LI 	/* signal_no_reset(SIGCHLD, SIG_IGN); */
5122b15cb3dSCy Schubert 
5132b15cb3dSCy Schubert 	childpid = fork();
5142b15cb3dSCy Schubert 	if (-1 == childpid) {
5152b15cb3dSCy Schubert 		msyslog(LOG_ERR, "unable to fork worker: %m");
5162b15cb3dSCy Schubert 		exit(1);
5172b15cb3dSCy Schubert 	}
5182b15cb3dSCy Schubert 
5192b15cb3dSCy Schubert 	if (childpid) {
5202b15cb3dSCy Schubert 		/* this is the parent */
5212b15cb3dSCy Schubert 		TRACE(1, ("forked worker child (pid %d)\n", childpid));
5222b15cb3dSCy Schubert 		c->pid = childpid;
5232b15cb3dSCy Schubert 		c->ispipe = is_pipe;
5242b15cb3dSCy Schubert 
5252b15cb3dSCy Schubert 		/* close the child's pipe descriptors. */
5262b15cb3dSCy Schubert 		close(blocking_pipes[0]);
5272b15cb3dSCy Schubert 		close(blocking_pipes[3]);
5282b15cb3dSCy Schubert 
5292b15cb3dSCy Schubert 		memset(blocking_pipes, -1, sizeof(blocking_pipes));
5302b15cb3dSCy Schubert 
5312b15cb3dSCy Schubert 		/* wire into I/O loop */
5322b15cb3dSCy Schubert 		(*addremove_io_fd)(c->resp_read_pipe, is_pipe, FALSE);
5332b15cb3dSCy Schubert 
5342b15cb3dSCy Schubert 		return;		/* parent returns */
5352b15cb3dSCy Schubert 	}
5362b15cb3dSCy Schubert 
5372b15cb3dSCy Schubert 	/*
5382b15cb3dSCy Schubert 	 * The parent gets the child pid as the return value of fork().
5392b15cb3dSCy Schubert 	 * The child must work for it.
5402b15cb3dSCy Schubert 	 */
5412b15cb3dSCy Schubert 	c->pid = getpid();
5422b15cb3dSCy Schubert 	worker_process = TRUE;
5432b15cb3dSCy Schubert 
5442b15cb3dSCy Schubert 	/*
545f0574f5cSXin LI 	 * Change the process name of the child to avoid confusion
546f0574f5cSXin LI 	 * about ntpd trunning twice.
547f0574f5cSXin LI 	 */
548f0574f5cSXin LI 	if (saved_argc != 0) {
549f0574f5cSXin LI 		int argcc;
550f0574f5cSXin LI 		int argvlen = 0;
551f0574f5cSXin LI 		/* Clear argv */
552f0574f5cSXin LI 		for (argcc = 0; argcc < saved_argc; argcc++) {
553f0574f5cSXin LI 			int l = strlen(saved_argv[argcc]);
554f0574f5cSXin LI 			argvlen += l + 1;
555f0574f5cSXin LI 			memset(saved_argv[argcc], 0, l);
556f0574f5cSXin LI 		}
557f0574f5cSXin LI 		strlcpy(saved_argv[0], "ntpd: asynchronous dns resolver", argvlen);
558f0574f5cSXin LI 	}
559f0574f5cSXin LI 
560f0574f5cSXin LI 	/*
5612b15cb3dSCy Schubert 	 * In the child, close all files except stdin, stdout, stderr,
5622b15cb3dSCy Schubert 	 * and the two child ends of the pipes.
5632b15cb3dSCy Schubert 	 */
5642b15cb3dSCy Schubert 	DEBUG_INSIST(-1 == c->req_read_pipe);
5652b15cb3dSCy Schubert 	DEBUG_INSIST(-1 == c->resp_write_pipe);
5662b15cb3dSCy Schubert 	c->req_read_pipe = blocking_pipes[0];
5672b15cb3dSCy Schubert 	c->resp_write_pipe = blocking_pipes[3];
5682b15cb3dSCy Schubert 
5692b15cb3dSCy Schubert 	kill_asyncio(0);
5702b15cb3dSCy Schubert 	closelog();
5712b15cb3dSCy Schubert 	if (syslog_file != NULL) {
5722b15cb3dSCy Schubert 		fclose(syslog_file);
5732b15cb3dSCy Schubert 		syslog_file = NULL;
5742b15cb3dSCy Schubert 		syslogit = TRUE;
5752b15cb3dSCy Schubert 	}
5762b15cb3dSCy Schubert 	keep_fd = max(c->req_read_pipe, c->resp_write_pipe);
5772b15cb3dSCy Schubert 	for (fd = 3; fd < keep_fd; fd++)
5782b15cb3dSCy Schubert 		if (fd != c->req_read_pipe &&
5792b15cb3dSCy Schubert 		    fd != c->resp_write_pipe)
5802b15cb3dSCy Schubert 			close(fd);
5812b15cb3dSCy Schubert 	close_all_beyond(keep_fd);
5822b15cb3dSCy Schubert 	/*
5832b15cb3dSCy Schubert 	 * We get signals from refclock serial I/O on NetBSD in the
5842b15cb3dSCy Schubert 	 * worker if we do not reset SIGIO's handler to the default.
5852b15cb3dSCy Schubert 	 * It is not conditionalized for NetBSD alone because on
5862b15cb3dSCy Schubert 	 * systems where it is not needed, it is harmless, and that
5872b15cb3dSCy Schubert 	 * allows us to handle unknown others with NetBSD behavior.
5882b15cb3dSCy Schubert 	 * [Bug 1386]
5892b15cb3dSCy Schubert 	 */
5902b15cb3dSCy Schubert #if defined(USE_SIGIO)
5912b15cb3dSCy Schubert 	signal_no_reset(SIGIO, SIG_DFL);
5922b15cb3dSCy Schubert #elif defined(USE_SIGPOLL)
5932b15cb3dSCy Schubert 	signal_no_reset(SIGPOLL, SIG_DFL);
5942b15cb3dSCy Schubert #endif
5952b15cb3dSCy Schubert 	signal_no_reset(SIGHUP, worker_sighup);
5962b15cb3dSCy Schubert 	init_logging("ntp_intres", 0, FALSE);
5972b15cb3dSCy Schubert 	setup_logfile(NULL);
5982b15cb3dSCy Schubert 
599*052d159aSCy Schubert #ifdef HAVE_DROPROOT
6004e1ef62aSXin LI 	(void) set_user_group_ids();
601*052d159aSCy Schubert #endif
6024e1ef62aSXin LI 
6032b15cb3dSCy Schubert 	/*
6042b15cb3dSCy Schubert 	 * And now back to the portable code
6052b15cb3dSCy Schubert 	 */
6062b15cb3dSCy Schubert 	exit_worker(blocking_child_common(c));
6072b15cb3dSCy Schubert }
6082b15cb3dSCy Schubert 
6092b15cb3dSCy Schubert 
worker_global_lock(int inOrOut)6104990d495SXin LI void worker_global_lock(int inOrOut)
6114990d495SXin LI {
6124990d495SXin LI 	(void)inOrOut;
6134990d495SXin LI }
6144990d495SXin LI 
6152b15cb3dSCy Schubert #else	/* !WORK_FORK follows */
6162b15cb3dSCy Schubert char work_fork_nonempty_compilation_unit;
6172b15cb3dSCy Schubert #endif
618