1290001Sglebius/*
2290001Sglebius * work_fork.c - fork implementation for blocking worker child.
3290001Sglebius */
4290001Sglebius#include <config.h>
5290001Sglebius#include "ntp_workimpl.h"
6290001Sglebius
7290001Sglebius#ifdef WORK_FORK
8290001Sglebius#include <stdio.h>
9290001Sglebius#include <ctype.h>
10290001Sglebius#include <signal.h>
11290001Sglebius#include <sys/wait.h>
12290001Sglebius
13290001Sglebius#include "iosignal.h"
14290001Sglebius#include "ntp_stdlib.h"
15290001Sglebius#include "ntp_malloc.h"
16290001Sglebius#include "ntp_syslog.h"
17290001Sglebius#include "ntpd.h"
18290001Sglebius#include "ntp_io.h"
19290001Sglebius#include "ntp_assert.h"
20290001Sglebius#include "ntp_unixtime.h"
21290001Sglebius#include "ntp_worker.h"
22290001Sglebius
23290001Sglebius/* === variables === */
24290001Sglebius	int			worker_process;
25290001Sglebius	addremove_io_fd_func	addremove_io_fd;
26290001Sglebiusstatic	volatile int		worker_sighup_received;
27290001Sglebius
28290001Sglebius/* === function prototypes === */
29290001Sglebiusstatic	void		fork_blocking_child(blocking_child *);
30290001Sglebiusstatic	RETSIGTYPE	worker_sighup(int);
31290001Sglebiusstatic	void		send_worker_home_atexit(void);
32290001Sglebiusstatic	void		cleanup_after_child(blocking_child *);
33290001Sglebius
34290001Sglebius/* === functions === */
35290001Sglebius/*
36290001Sglebius * exit_worker()
37290001Sglebius *
38290001Sglebius * On some systems _exit() is preferred to exit() for forked children.
39290001Sglebius * For example, http://netbsd.gw.com/cgi-bin/man-cgi?fork++NetBSD-5.0
40290001Sglebius * recommends _exit() to avoid double-flushing C runtime stream buffers
41290001Sglebius * and also to avoid calling the parent's atexit() routines in the
42290001Sglebius * child.  On those systems WORKER_CHILD_EXIT is _exit.  Since _exit
43290001Sglebius * bypasses CRT cleanup, fflush() files we know might have output
44290001Sglebius * buffered.
45290001Sglebius */
46290001Sglebiusvoid
47290001Sglebiusexit_worker(
48290001Sglebius	int	exitcode
49290001Sglebius	)
50290001Sglebius{
51290001Sglebius	if (syslog_file != NULL)
52290001Sglebius		fflush(syslog_file);
53290001Sglebius	fflush(stdout);
54290001Sglebius	fflush(stderr);
55290001Sglebius	WORKER_CHILD_EXIT (exitcode);	/* space before ( required */
56290001Sglebius}
57290001Sglebius
58290001Sglebius
59290001Sglebiusstatic RETSIGTYPE
60290001Sglebiusworker_sighup(
61290001Sglebius	int sig
62290001Sglebius	)
63290001Sglebius{
64290001Sglebius	if (SIGHUP == sig)
65290001Sglebius		worker_sighup_received = 1;
66290001Sglebius}
67290001Sglebius
68290001Sglebius
69290001Sglebiusint
70290001Sglebiusworker_sleep(
71290001Sglebius	blocking_child *	c,
72290001Sglebius	time_t			seconds
73290001Sglebius	)
74290001Sglebius{
75290001Sglebius	u_int sleep_remain;
76290001Sglebius
77290001Sglebius	sleep_remain = (u_int)seconds;
78290001Sglebius	do {
79290001Sglebius		if (!worker_sighup_received)
80290001Sglebius			sleep_remain = sleep(sleep_remain);
81290001Sglebius		if (worker_sighup_received) {
82290001Sglebius			TRACE(1, ("worker SIGHUP with %us left to sleep",
83290001Sglebius				  sleep_remain));
84290001Sglebius			worker_sighup_received = 0;
85290001Sglebius			return -1;
86290001Sglebius		}
87290001Sglebius	} while (sleep_remain);
88290001Sglebius
89290001Sglebius	return 0;
90290001Sglebius}
91290001Sglebius
92290001Sglebius
93290001Sglebiusvoid
94290001Sglebiusinterrupt_worker_sleep(void)
95290001Sglebius{
96290001Sglebius	u_int			idx;
97290001Sglebius	blocking_child *	c;
98290001Sglebius	int			rc;
99290001Sglebius
100290001Sglebius	for (idx = 0; idx < blocking_children_alloc; idx++) {
101290001Sglebius		c = blocking_children[idx];
102290001Sglebius
103290001Sglebius		if (NULL == c || c->reusable == TRUE)
104290001Sglebius			continue;
105290001Sglebius
106290001Sglebius		rc = kill(c->pid, SIGHUP);
107290001Sglebius		if (rc < 0)
108290001Sglebius			msyslog(LOG_ERR,
109290001Sglebius				"Unable to signal HUP to wake child pid %d: %m",
110290001Sglebius				c->pid);
111290001Sglebius	}
112290001Sglebius}
113290001Sglebius
114290001Sglebius
115290001Sglebius/*
116290001Sglebius * harvest_child_status() runs in the parent.
117310419Sdelphij *
118310419Sdelphij * Note the error handling -- this is an interaction with SIGCHLD.
119310419Sdelphij * SIG_IGN on SIGCHLD on some OSes means do not wait but reap
120310419Sdelphij * automatically. Since we're not really interested in the result code,
121310419Sdelphij * we simply ignore the error.
122290001Sglebius */
123290001Sglebiusstatic void
124290001Sglebiusharvest_child_status(
125290001Sglebius	blocking_child *	c
126290001Sglebius	)
127290001Sglebius{
128310419Sdelphij	if (c->pid) {
129290001Sglebius		/* Wait on the child so it can finish terminating */
130290001Sglebius		if (waitpid(c->pid, NULL, 0) == c->pid)
131290001Sglebius			TRACE(4, ("harvested child %d\n", c->pid));
132310419Sdelphij		else if (errno != ECHILD)
133310419Sdelphij			msyslog(LOG_ERR, "error waiting on child %d: %m", c->pid);
134310419Sdelphij		c->pid = 0;
135290001Sglebius	}
136290001Sglebius}
137290001Sglebius
138290001Sglebius/*
139290001Sglebius * req_child_exit() runs in the parent.
140290001Sglebius */
141290001Sglebiusint
142290001Sglebiusreq_child_exit(
143290001Sglebius	blocking_child *	c
144290001Sglebius	)
145290001Sglebius{
146290001Sglebius	if (-1 != c->req_write_pipe) {
147290001Sglebius		close(c->req_write_pipe);
148290001Sglebius		c->req_write_pipe = -1;
149290001Sglebius		return 0;
150290001Sglebius	}
151290001Sglebius	/* Closing the pipe forces the child to exit */
152290001Sglebius	harvest_child_status(c);
153290001Sglebius	return -1;
154290001Sglebius}
155290001Sglebius
156290001Sglebius
157290001Sglebius/*
158290001Sglebius * cleanup_after_child() runs in parent.
159290001Sglebius */
160290001Sglebiusstatic void
161290001Sglebiuscleanup_after_child(
162290001Sglebius	blocking_child *	c
163290001Sglebius	)
164290001Sglebius{
165290001Sglebius	harvest_child_status(c);
166290001Sglebius	if (-1 != c->resp_read_pipe) {
167290001Sglebius		(*addremove_io_fd)(c->resp_read_pipe, c->ispipe, TRUE);
168290001Sglebius		close(c->resp_read_pipe);
169290001Sglebius		c->resp_read_pipe = -1;
170290001Sglebius	}
171290001Sglebius	c->resp_read_ctx = NULL;
172290001Sglebius	DEBUG_INSIST(-1 == c->req_read_pipe);
173290001Sglebius	DEBUG_INSIST(-1 == c->resp_write_pipe);
174290001Sglebius	c->reusable = TRUE;
175290001Sglebius}
176290001Sglebius
177290001Sglebius
178290001Sglebiusstatic void
179290001Sglebiussend_worker_home_atexit(void)
180290001Sglebius{
181290001Sglebius	u_int			idx;
182290001Sglebius	blocking_child *	c;
183290001Sglebius
184290001Sglebius	if (worker_process)
185290001Sglebius		return;
186290001Sglebius
187290001Sglebius	for (idx = 0; idx < blocking_children_alloc; idx++) {
188290001Sglebius		c = blocking_children[idx];
189290001Sglebius		if (NULL == c)
190290001Sglebius			continue;
191290001Sglebius		req_child_exit(c);
192290001Sglebius	}
193290001Sglebius}
194290001Sglebius
195290001Sglebius
196290001Sglebiusint
197290001Sglebiussend_blocking_req_internal(
198290001Sglebius	blocking_child *	c,
199290001Sglebius	blocking_pipe_header *	hdr,
200290001Sglebius	void *			data
201290001Sglebius	)
202290001Sglebius{
203290001Sglebius	int octets;
204290001Sglebius	int rc;
205290001Sglebius
206290001Sglebius	DEBUG_REQUIRE(hdr != NULL);
207290001Sglebius	DEBUG_REQUIRE(data != NULL);
208290001Sglebius	DEBUG_REQUIRE(BLOCKING_REQ_MAGIC == hdr->magic_sig);
209290001Sglebius
210290001Sglebius	if (-1 == c->req_write_pipe) {
211290001Sglebius		fork_blocking_child(c);
212290001Sglebius		DEBUG_INSIST(-1 != c->req_write_pipe);
213290001Sglebius	}
214290001Sglebius
215290001Sglebius	octets = sizeof(*hdr);
216290001Sglebius	rc = write(c->req_write_pipe, hdr, octets);
217290001Sglebius
218290001Sglebius	if (rc == octets) {
219290001Sglebius		octets = hdr->octets - sizeof(*hdr);
220290001Sglebius		rc = write(c->req_write_pipe, data, octets);
221290001Sglebius
222290001Sglebius		if (rc == octets)
223290001Sglebius			return 0;
224290001Sglebius	}
225290001Sglebius
226290001Sglebius	if (rc < 0)
227290001Sglebius		msyslog(LOG_ERR,
228290001Sglebius			"send_blocking_req_internal: pipe write: %m");
229290001Sglebius	else
230290001Sglebius		msyslog(LOG_ERR,
231290001Sglebius			"send_blocking_req_internal: short write %d of %d",
232290001Sglebius			rc, octets);
233290001Sglebius
234290001Sglebius	/* Fatal error.  Clean up the child process.  */
235290001Sglebius	req_child_exit(c);
236290001Sglebius	exit(1);	/* otherwise would be return -1 */
237290001Sglebius}
238290001Sglebius
239290001Sglebius
240290001Sglebiusblocking_pipe_header *
241290001Sglebiusreceive_blocking_req_internal(
242290001Sglebius	blocking_child *	c
243290001Sglebius	)
244290001Sglebius{
245290001Sglebius	blocking_pipe_header	hdr;
246290001Sglebius	blocking_pipe_header *	req;
247290001Sglebius	int			rc;
248290001Sglebius	long			octets;
249290001Sglebius
250290001Sglebius	DEBUG_REQUIRE(-1 != c->req_read_pipe);
251290001Sglebius
252290001Sglebius	req = NULL;
253290001Sglebius
254290001Sglebius	do {
255290001Sglebius		rc = read(c->req_read_pipe, &hdr, sizeof(hdr));
256290001Sglebius	} while (rc < 0 && EINTR == errno);
257290001Sglebius
258290001Sglebius	if (rc < 0) {
259290001Sglebius		msyslog(LOG_ERR,
260290001Sglebius			"receive_blocking_req_internal: pipe read %m");
261290001Sglebius	} else if (0 == rc) {
262290001Sglebius		TRACE(4, ("parent closed request pipe, child %d terminating\n",
263290001Sglebius			  c->pid));
264290001Sglebius	} else if (rc != sizeof(hdr)) {
265290001Sglebius		msyslog(LOG_ERR,
266290001Sglebius			"receive_blocking_req_internal: short header read %d of %lu",
267290001Sglebius			rc, (u_long)sizeof(hdr));
268290001Sglebius	} else {
269290001Sglebius		INSIST(sizeof(hdr) < hdr.octets && hdr.octets < 4 * 1024);
270290001Sglebius		req = emalloc(hdr.octets);
271290001Sglebius		memcpy(req, &hdr, sizeof(*req));
272290001Sglebius		octets = hdr.octets - sizeof(hdr);
273290001Sglebius		rc = read(c->req_read_pipe, (char *)req + sizeof(*req),
274290001Sglebius			  octets);
275290001Sglebius
276290001Sglebius		if (rc < 0)
277290001Sglebius			msyslog(LOG_ERR,
278290001Sglebius				"receive_blocking_req_internal: pipe data read %m");
279290001Sglebius		else if (rc != octets)
280290001Sglebius			msyslog(LOG_ERR,
281290001Sglebius				"receive_blocking_req_internal: short read %d of %ld",
282290001Sglebius				rc, octets);
283290001Sglebius		else if (BLOCKING_REQ_MAGIC != req->magic_sig)
284290001Sglebius			msyslog(LOG_ERR,
285290001Sglebius				"receive_blocking_req_internal: packet header mismatch (0x%x)",
286290001Sglebius				req->magic_sig);
287290001Sglebius		else
288290001Sglebius			return req;
289290001Sglebius	}
290290001Sglebius
291290001Sglebius	if (req != NULL)
292290001Sglebius		free(req);
293290001Sglebius
294290001Sglebius	return NULL;
295290001Sglebius}
296290001Sglebius
297290001Sglebius
298290001Sglebiusint
299290001Sglebiussend_blocking_resp_internal(
300290001Sglebius	blocking_child *	c,
301290001Sglebius	blocking_pipe_header *	resp
302290001Sglebius	)
303290001Sglebius{
304290001Sglebius	long	octets;
305290001Sglebius	int	rc;
306290001Sglebius
307290001Sglebius	DEBUG_REQUIRE(-1 != c->resp_write_pipe);
308290001Sglebius
309290001Sglebius	octets = resp->octets;
310290001Sglebius	rc = write(c->resp_write_pipe, resp, octets);
311290001Sglebius	free(resp);
312290001Sglebius
313290001Sglebius	if (octets == rc)
314290001Sglebius		return 0;
315290001Sglebius
316290001Sglebius	if (rc < 0)
317290001Sglebius		TRACE(1, ("send_blocking_resp_internal: pipe write %m\n"));
318290001Sglebius	else
319290001Sglebius		TRACE(1, ("send_blocking_resp_internal: short write %d of %ld\n",
320290001Sglebius			  rc, octets));
321290001Sglebius
322290001Sglebius	return -1;
323290001Sglebius}
324290001Sglebius
325290001Sglebius
326290001Sglebiusblocking_pipe_header *
327290001Sglebiusreceive_blocking_resp_internal(
328290001Sglebius	blocking_child *	c
329290001Sglebius	)
330290001Sglebius{
331290001Sglebius	blocking_pipe_header	hdr;
332290001Sglebius	blocking_pipe_header *	resp;
333290001Sglebius	int			rc;
334290001Sglebius	long			octets;
335290001Sglebius
336290001Sglebius	DEBUG_REQUIRE(c->resp_read_pipe != -1);
337290001Sglebius
338290001Sglebius	resp = NULL;
339290001Sglebius	rc = read(c->resp_read_pipe, &hdr, sizeof(hdr));
340290001Sglebius
341290001Sglebius	if (rc < 0) {
342290001Sglebius		TRACE(1, ("receive_blocking_resp_internal: pipe read %m\n"));
343290001Sglebius	} else if (0 == rc) {
344290001Sglebius		/* this is the normal child exited indication */
345290001Sglebius	} else if (rc != sizeof(hdr)) {
346290001Sglebius		TRACE(1, ("receive_blocking_resp_internal: short header read %d of %lu\n",
347290001Sglebius			  rc, (u_long)sizeof(hdr)));
348290001Sglebius	} else if (BLOCKING_RESP_MAGIC != hdr.magic_sig) {
349290001Sglebius		TRACE(1, ("receive_blocking_resp_internal: header mismatch (0x%x)\n",
350290001Sglebius			  hdr.magic_sig));
351290001Sglebius	} else {
352290001Sglebius		INSIST(sizeof(hdr) < hdr.octets &&
353290001Sglebius		       hdr.octets < 16 * 1024);
354290001Sglebius		resp = emalloc(hdr.octets);
355290001Sglebius		memcpy(resp, &hdr, sizeof(*resp));
356290001Sglebius		octets = hdr.octets - sizeof(hdr);
357290001Sglebius		rc = read(c->resp_read_pipe,
358290001Sglebius			  (char *)resp + sizeof(*resp),
359290001Sglebius			  octets);
360290001Sglebius
361290001Sglebius		if (rc < 0)
362290001Sglebius			TRACE(1, ("receive_blocking_resp_internal: pipe data read %m\n"));
363290001Sglebius		else if (rc < octets)
364290001Sglebius			TRACE(1, ("receive_blocking_resp_internal: short read %d of %ld\n",
365290001Sglebius				  rc, octets));
366290001Sglebius		else
367290001Sglebius			return resp;
368290001Sglebius	}
369290001Sglebius
370290001Sglebius	cleanup_after_child(c);
371290001Sglebius
372290001Sglebius	if (resp != NULL)
373290001Sglebius		free(resp);
374290001Sglebius
375290001Sglebius	return NULL;
376290001Sglebius}
377290001Sglebius
378290001Sglebius
379290001Sglebius#if defined(HAVE_DROPROOT) && defined(WORK_FORK)
380290001Sglebiusvoid
381290001Sglebiusfork_deferred_worker(void)
382290001Sglebius{
383290001Sglebius	u_int			idx;
384290001Sglebius	blocking_child *	c;
385290001Sglebius
386290001Sglebius	REQUIRE(droproot && root_dropped);
387290001Sglebius
388290001Sglebius	for (idx = 0; idx < blocking_children_alloc; idx++) {
389290001Sglebius		c = blocking_children[idx];
390290001Sglebius		if (NULL == c)
391290001Sglebius			continue;
392290001Sglebius		if (-1 != c->req_write_pipe && 0 == c->pid)
393290001Sglebius			fork_blocking_child(c);
394290001Sglebius	}
395290001Sglebius}
396290001Sglebius#endif
397290001Sglebius
398290001Sglebius
399290001Sglebiusstatic void
400290001Sglebiusfork_blocking_child(
401290001Sglebius	blocking_child *	c
402290001Sglebius	)
403290001Sglebius{
404290001Sglebius	static int	atexit_installed;
405290001Sglebius	static int	blocking_pipes[4] = { -1, -1, -1, -1 };
406290001Sglebius	int		rc;
407290001Sglebius	int		was_pipe;
408290001Sglebius	int		is_pipe;
409290001Sglebius	int		saved_errno = 0;
410290001Sglebius	int		childpid;
411290001Sglebius	int		keep_fd;
412290001Sglebius	int		fd;
413290001Sglebius
414290001Sglebius	/*
415290001Sglebius	 * parent and child communicate via a pair of pipes.
416290001Sglebius	 *
417290001Sglebius	 * 0 child read request
418290001Sglebius	 * 1 parent write request
419290001Sglebius	 * 2 parent read response
420290001Sglebius	 * 3 child write response
421290001Sglebius	 */
422290001Sglebius	if (-1 == c->req_write_pipe) {
423290001Sglebius		rc = pipe_socketpair(&blocking_pipes[0], &was_pipe);
424290001Sglebius		if (0 != rc) {
425290001Sglebius			saved_errno = errno;
426290001Sglebius		} else {
427290001Sglebius			rc = pipe_socketpair(&blocking_pipes[2], &is_pipe);
428290001Sglebius			if (0 != rc) {
429290001Sglebius				saved_errno = errno;
430290001Sglebius				close(blocking_pipes[0]);
431290001Sglebius				close(blocking_pipes[1]);
432290001Sglebius			} else {
433290001Sglebius				INSIST(was_pipe == is_pipe);
434290001Sglebius			}
435290001Sglebius		}
436290001Sglebius		if (0 != rc) {
437290001Sglebius			errno = saved_errno;
438290001Sglebius			msyslog(LOG_ERR, "unable to create worker pipes: %m");
439290001Sglebius			exit(1);
440290001Sglebius		}
441290001Sglebius
442290001Sglebius		/*
443290001Sglebius		 * Move the descriptors the parent will keep open out of the
444290001Sglebius		 * low descriptors preferred by C runtime buffered FILE *.
445290001Sglebius		 */
446290001Sglebius		c->req_write_pipe = move_fd(blocking_pipes[1]);
447290001Sglebius		c->resp_read_pipe = move_fd(blocking_pipes[2]);
448290001Sglebius		/*
449290001Sglebius		 * wake any worker child on orderly shutdown of the
450290001Sglebius		 * daemon so that it can notice the broken pipes and
451290001Sglebius		 * go away promptly.
452290001Sglebius		 */
453290001Sglebius		if (!atexit_installed) {
454290001Sglebius			atexit(&send_worker_home_atexit);
455290001Sglebius			atexit_installed = TRUE;
456290001Sglebius		}
457290001Sglebius	}
458290001Sglebius
459298770Sdelphij#if defined(HAVE_DROPROOT) && !defined(NEED_EARLY_FORK)
460290001Sglebius	/* defer the fork until after root is dropped */
461290001Sglebius	if (droproot && !root_dropped)
462290001Sglebius		return;
463290001Sglebius#endif
464290001Sglebius	if (syslog_file != NULL)
465290001Sglebius		fflush(syslog_file);
466290001Sglebius	fflush(stdout);
467290001Sglebius	fflush(stderr);
468290001Sglebius
469310419Sdelphij	/* [BUG 3050] setting SIGCHLD to SIG_IGN likely causes unwanted
470310419Sdelphij	 * or undefined effects. We don't do it and leave SIGCHLD alone.
471310419Sdelphij	 */
472310419Sdelphij	/* signal_no_reset(SIGCHLD, SIG_IGN); */
473290001Sglebius
474290001Sglebius	childpid = fork();
475290001Sglebius	if (-1 == childpid) {
476290001Sglebius		msyslog(LOG_ERR, "unable to fork worker: %m");
477290001Sglebius		exit(1);
478290001Sglebius	}
479290001Sglebius
480290001Sglebius	if (childpid) {
481290001Sglebius		/* this is the parent */
482290001Sglebius		TRACE(1, ("forked worker child (pid %d)\n", childpid));
483290001Sglebius		c->pid = childpid;
484290001Sglebius		c->ispipe = is_pipe;
485290001Sglebius
486290001Sglebius		/* close the child's pipe descriptors. */
487290001Sglebius		close(blocking_pipes[0]);
488290001Sglebius		close(blocking_pipes[3]);
489290001Sglebius
490290001Sglebius		memset(blocking_pipes, -1, sizeof(blocking_pipes));
491290001Sglebius
492290001Sglebius		/* wire into I/O loop */
493290001Sglebius		(*addremove_io_fd)(c->resp_read_pipe, is_pipe, FALSE);
494290001Sglebius
495290001Sglebius		return;		/* parent returns */
496290001Sglebius	}
497290001Sglebius
498290001Sglebius	/*
499290001Sglebius	 * The parent gets the child pid as the return value of fork().
500290001Sglebius	 * The child must work for it.
501290001Sglebius	 */
502290001Sglebius	c->pid = getpid();
503290001Sglebius	worker_process = TRUE;
504290001Sglebius
505290001Sglebius	/*
506290001Sglebius	 * In the child, close all files except stdin, stdout, stderr,
507290001Sglebius	 * and the two child ends of the pipes.
508290001Sglebius	 */
509290001Sglebius	DEBUG_INSIST(-1 == c->req_read_pipe);
510290001Sglebius	DEBUG_INSIST(-1 == c->resp_write_pipe);
511290001Sglebius	c->req_read_pipe = blocking_pipes[0];
512290001Sglebius	c->resp_write_pipe = blocking_pipes[3];
513290001Sglebius
514290001Sglebius	kill_asyncio(0);
515290001Sglebius	closelog();
516290001Sglebius	if (syslog_file != NULL) {
517290001Sglebius		fclose(syslog_file);
518290001Sglebius		syslog_file = NULL;
519290001Sglebius		syslogit = TRUE;
520290001Sglebius	}
521290001Sglebius	keep_fd = max(c->req_read_pipe, c->resp_write_pipe);
522290001Sglebius	for (fd = 3; fd < keep_fd; fd++)
523290001Sglebius		if (fd != c->req_read_pipe &&
524290001Sglebius		    fd != c->resp_write_pipe)
525290001Sglebius			close(fd);
526290001Sglebius	close_all_beyond(keep_fd);
527290001Sglebius	/*
528290001Sglebius	 * We get signals from refclock serial I/O on NetBSD in the
529290001Sglebius	 * worker if we do not reset SIGIO's handler to the default.
530290001Sglebius	 * It is not conditionalized for NetBSD alone because on
531290001Sglebius	 * systems where it is not needed, it is harmless, and that
532290001Sglebius	 * allows us to handle unknown others with NetBSD behavior.
533290001Sglebius	 * [Bug 1386]
534290001Sglebius	 */
535290001Sglebius#if defined(USE_SIGIO)
536290001Sglebius	signal_no_reset(SIGIO, SIG_DFL);
537290001Sglebius#elif defined(USE_SIGPOLL)
538290001Sglebius	signal_no_reset(SIGPOLL, SIG_DFL);
539290001Sglebius#endif
540290001Sglebius	signal_no_reset(SIGHUP, worker_sighup);
541290001Sglebius	init_logging("ntp_intres", 0, FALSE);
542290001Sglebius	setup_logfile(NULL);
543290001Sglebius
544290001Sglebius	/*
545290001Sglebius	 * And now back to the portable code
546290001Sglebius	 */
547290001Sglebius	exit_worker(blocking_child_common(c));
548290001Sglebius}
549290001Sglebius
550290001Sglebius
551298770Sdelphijvoid worker_global_lock(int inOrOut)
552298770Sdelphij{
553298770Sdelphij	(void)inOrOut;
554298770Sdelphij}
555298770Sdelphij
556290001Sglebius#else	/* !WORK_FORK follows */
557290001Sglebiuschar work_fork_nonempty_compilation_unit;
558290001Sglebius#endif
559