]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - contrib/ntp/libntp/work_fork.c
MFC r338126: MFV r338092: ntp 4.2.8p12.
[FreeBSD/stable/10.git] / contrib / ntp / libntp / work_fork.c
1 /*
2  * work_fork.c - fork implementation for blocking worker child.
3  */
4 #include <config.h>
5 #include "ntp_workimpl.h"
6
7 #ifdef WORK_FORK
8 #include <stdio.h>
9 #include <ctype.h>
10 #include <signal.h>
11 #include <sys/wait.h>
12
13 #include "iosignal.h"
14 #include "ntp_stdlib.h"
15 #include "ntp_malloc.h"
16 #include "ntp_syslog.h"
17 #include "ntpd.h"
18 #include "ntp_io.h"
19 #include "ntp_assert.h"
20 #include "ntp_unixtime.h"
21 #include "ntp_worker.h"
22
23 /* === variables === */
24         int                     worker_process;
25         addremove_io_fd_func    addremove_io_fd;
26 static  volatile int            worker_sighup_received;
27 int     saved_argc = 0;
28 char    **saved_argv;
29
30 /* === function prototypes === */
31 static  void            fork_blocking_child(blocking_child *);
32 static  RETSIGTYPE      worker_sighup(int);
33 static  void            send_worker_home_atexit(void);
34 static  void            cleanup_after_child(blocking_child *);
35
36 /* === I/O helpers === */
37 /* Since we have signals enabled, there's a good chance that blocking IO
38  * via pipe suffers from EINTR -- and this goes for both directions.
39  * The next two wrappers will loop until either all the data is written
40  * or read, plus handling the EOF condition on read. They may return
41  * zero if no data was transferred at all, and effectively every return
42  * value that differs from the given transfer length signifies an error
43  * condition.
44  */
45
46 static size_t
47 netread(
48         int             fd,
49         void *          vb,
50         size_t          l
51         )
52 {
53         char *          b = vb;
54         ssize_t         r;
55
56         while (l) {
57                 r = read(fd, b, l);
58                 if (r > 0) {
59                         l -= r;
60                         b += r;
61                 } else if (r == 0 || errno != EINTR) {
62                         l = 0;
63                 }
64         }
65         return (size_t)(b - (char *)vb);
66 }
67
68
69 static size_t
70 netwrite(
71         int             fd,
72         const void *    vb,
73         size_t          l
74         )
75 {
76         const char *    b = vb;
77         ssize_t         w;
78
79         while (l) {
80                 w = write(fd, b, l);
81                 if (w > 0) {
82                         l -= w;
83                         b += w;
84                 } else if (errno != EINTR) {
85                         l = 0;
86                 }
87         }
88         return (size_t)(b - (const char *)vb);
89 }
90
91
92 int set_user_group_ids(void);
93
94 /* === functions === */
95 /*
96  * exit_worker()
97  *
98  * On some systems _exit() is preferred to exit() for forked children.
99  * For example, http://netbsd.gw.com/cgi-bin/man-cgi?fork++NetBSD-5.0
100  * recommends _exit() to avoid double-flushing C runtime stream buffers
101  * and also to avoid calling the parent's atexit() routines in the
102  * child.  On those systems WORKER_CHILD_EXIT is _exit.  Since _exit
103  * bypasses CRT cleanup, fflush() files we know might have output
104  * buffered.
105  */
106 void
107 exit_worker(
108         int     exitcode
109         )
110 {
111         if (syslog_file != NULL)
112                 fflush(syslog_file);
113         fflush(stdout);
114         fflush(stderr);
115         WORKER_CHILD_EXIT (exitcode);   /* space before ( required */
116 }
117
118
119 static RETSIGTYPE
120 worker_sighup(
121         int sig
122         )
123 {
124         if (SIGHUP == sig)
125                 worker_sighup_received = 1;
126 }
127
128
129 int
130 worker_sleep(
131         blocking_child *        c,
132         time_t                  seconds
133         )
134 {
135         u_int sleep_remain;
136
137         sleep_remain = (u_int)seconds;
138         do {
139                 if (!worker_sighup_received)
140                         sleep_remain = sleep(sleep_remain);
141                 if (worker_sighup_received) {
142                         TRACE(1, ("worker SIGHUP with %us left to sleep",
143                                   sleep_remain));
144                         worker_sighup_received = 0;
145                         return -1;
146                 }
147         } while (sleep_remain);
148
149         return 0;
150 }
151
152
153 void
154 interrupt_worker_sleep(void)
155 {
156         u_int                   idx;
157         blocking_child *        c;
158         int                     rc;
159
160         for (idx = 0; idx < blocking_children_alloc; idx++) {
161                 c = blocking_children[idx];
162
163                 if (NULL == c || c->reusable == TRUE)
164                         continue;
165
166                 rc = kill(c->pid, SIGHUP);
167                 if (rc < 0)
168                         msyslog(LOG_ERR,
169                                 "Unable to signal HUP to wake child pid %d: %m",
170                                 c->pid);
171         }
172 }
173
174
175 /*
176  * harvest_child_status() runs in the parent.
177  *
178  * Note the error handling -- this is an interaction with SIGCHLD.
179  * SIG_IGN on SIGCHLD on some OSes means do not wait but reap
180  * automatically. Since we're not really interested in the result code,
181  * we simply ignore the error.
182  */
183 static void
184 harvest_child_status(
185         blocking_child *        c
186         )
187 {
188         if (c->pid) {
189                 /* Wait on the child so it can finish terminating */
190                 if (waitpid(c->pid, NULL, 0) == c->pid)
191                         TRACE(4, ("harvested child %d\n", c->pid));
192                 else if (errno != ECHILD)
193                         msyslog(LOG_ERR, "error waiting on child %d: %m", c->pid);
194                 c->pid = 0;
195         }
196 }
197
198 /*
199  * req_child_exit() runs in the parent.
200  */
201 int
202 req_child_exit(
203         blocking_child *        c
204         )
205 {
206         if (-1 != c->req_write_pipe) {
207                 close(c->req_write_pipe);
208                 c->req_write_pipe = -1;
209                 return 0;
210         }
211         /* Closing the pipe forces the child to exit */
212         harvest_child_status(c);
213         return -1;
214 }
215
216
217 /*
218  * cleanup_after_child() runs in parent.
219  */
220 static void
221 cleanup_after_child(
222         blocking_child *        c
223         )
224 {
225         harvest_child_status(c);
226         if (-1 != c->resp_read_pipe) {
227                 (*addremove_io_fd)(c->resp_read_pipe, c->ispipe, TRUE);
228                 close(c->resp_read_pipe);
229                 c->resp_read_pipe = -1;
230         }
231         c->resp_read_ctx = NULL;
232         DEBUG_INSIST(-1 == c->req_read_pipe);
233         DEBUG_INSIST(-1 == c->resp_write_pipe);
234         c->reusable = TRUE;
235 }
236
237
238 static void
239 send_worker_home_atexit(void)
240 {
241         u_int                   idx;
242         blocking_child *        c;
243
244         if (worker_process)
245                 return;
246
247         for (idx = 0; idx < blocking_children_alloc; idx++) {
248                 c = blocking_children[idx];
249                 if (NULL == c)
250                         continue;
251                 req_child_exit(c);
252         }
253 }
254
255
256 int
257 send_blocking_req_internal(
258         blocking_child *        c,
259         blocking_pipe_header *  hdr,
260         void *                  data
261         )
262 {
263         size_t  octets;
264         size_t  rc;
265
266         DEBUG_REQUIRE(hdr != NULL);
267         DEBUG_REQUIRE(data != NULL);
268         DEBUG_REQUIRE(BLOCKING_REQ_MAGIC == hdr->magic_sig);
269
270         if (-1 == c->req_write_pipe) {
271                 fork_blocking_child(c);
272                 DEBUG_INSIST(-1 != c->req_write_pipe);
273         }
274
275         octets = sizeof(*hdr);
276         rc = netwrite(c->req_write_pipe, hdr, octets);
277
278         if (rc == octets) {
279                 octets = hdr->octets - sizeof(*hdr);
280                 rc = netwrite(c->req_write_pipe, data, octets);
281                 if (rc == octets)
282                         return 0;
283         }
284
285         msyslog(LOG_ERR,
286                 "send_blocking_req_internal: short write (%zu of %zu), %m",
287                 rc, octets);
288
289         /* Fatal error.  Clean up the child process.  */
290         req_child_exit(c);
291         exit(1);        /* otherwise would be return -1 */
292 }
293
294
295 blocking_pipe_header *
296 receive_blocking_req_internal(
297         blocking_child *        c
298         )
299 {
300         blocking_pipe_header    hdr;
301         blocking_pipe_header *  req;
302         size_t                  rc;
303         size_t                  octets;
304
305         DEBUG_REQUIRE(-1 != c->req_read_pipe);
306
307         req = NULL;
308         rc = netread(c->req_read_pipe, &hdr, sizeof(hdr));
309
310         if (0 == rc) {
311                 TRACE(4, ("parent closed request pipe, child %d terminating\n",
312                           c->pid));
313         } else if (rc != sizeof(hdr)) {
314                 msyslog(LOG_ERR,
315                         "receive_blocking_req_internal: short header read (%zu of %zu), %m",
316                         rc, sizeof(hdr));
317         } else {
318                 INSIST(sizeof(hdr) < hdr.octets && hdr.octets < 4 * 1024);
319                 req = emalloc(hdr.octets);
320                 memcpy(req, &hdr, sizeof(*req));
321                 octets = hdr.octets - sizeof(hdr);
322                 rc = netread(c->req_read_pipe, (char *)(req + 1),
323                              octets);
324
325                 if (rc != octets)
326                         msyslog(LOG_ERR,
327                                 "receive_blocking_req_internal: short read (%zu of %zu), %m",
328                                 rc, octets);
329                 else if (BLOCKING_REQ_MAGIC != req->magic_sig)
330                         msyslog(LOG_ERR,
331                                 "receive_blocking_req_internal: packet header mismatch (0x%x)",
332                                 req->magic_sig);
333                 else
334                         return req;
335         }
336
337         if (req != NULL)
338                 free(req);
339
340         return NULL;
341 }
342
343
344 int
345 send_blocking_resp_internal(
346         blocking_child *        c,
347         blocking_pipe_header *  resp
348         )
349 {
350         size_t  octets;
351         size_t  rc;
352
353         DEBUG_REQUIRE(-1 != c->resp_write_pipe);
354
355         octets = resp->octets;
356         rc = netwrite(c->resp_write_pipe, resp, octets);
357         free(resp);
358
359         if (octets == rc)
360                 return 0;
361
362         TRACE(1, ("send_blocking_resp_internal: short write (%zu of %zu), %m\n",
363                   rc, octets));
364         return -1;
365 }
366
367
368 blocking_pipe_header *
369 receive_blocking_resp_internal(
370         blocking_child *        c
371         )
372 {
373         blocking_pipe_header    hdr;
374         blocking_pipe_header *  resp;
375         size_t                  rc;
376         size_t                  octets;
377
378         DEBUG_REQUIRE(c->resp_read_pipe != -1);
379
380         resp = NULL;
381         rc = netread(c->resp_read_pipe, &hdr, sizeof(hdr));
382
383         if (0 == rc) {
384                 /* this is the normal child exited indication */
385         } else if (rc != sizeof(hdr)) {
386                 TRACE(1, ("receive_blocking_resp_internal: short header read (%zu of %zu), %m\n",
387                           rc, sizeof(hdr)));
388         } else if (BLOCKING_RESP_MAGIC != hdr.magic_sig) {
389                 TRACE(1, ("receive_blocking_resp_internal: header mismatch (0x%x)\n",
390                           hdr.magic_sig));
391         } else {
392                 INSIST(sizeof(hdr) < hdr.octets &&
393                        hdr.octets < 16 * 1024);
394                 resp = emalloc(hdr.octets);
395                 memcpy(resp, &hdr, sizeof(*resp));
396                 octets = hdr.octets - sizeof(hdr);
397                 rc = netread(c->resp_read_pipe, (char *)(resp + 1),
398                              octets);
399
400                 if (rc != octets)
401                         TRACE(1, ("receive_blocking_resp_internal: short read (%zu of %zu), %m\n",
402                                   rc, octets));
403                 else
404                         return resp;
405         }
406
407         cleanup_after_child(c);
408         
409         if (resp != NULL)
410                 free(resp);
411         
412         return NULL;
413 }
414
415
416 #if defined(HAVE_DROPROOT) && defined(WORK_FORK)
417 void
418 fork_deferred_worker(void)
419 {
420         u_int                   idx;
421         blocking_child *        c;
422
423         REQUIRE(droproot && root_dropped);
424
425         for (idx = 0; idx < blocking_children_alloc; idx++) {
426                 c = blocking_children[idx];
427                 if (NULL == c)
428                         continue;
429                 if (-1 != c->req_write_pipe && 0 == c->pid)
430                         fork_blocking_child(c);
431         }
432 }
433 #endif
434
435
436 static void
437 fork_blocking_child(
438         blocking_child *        c
439         )
440 {
441         static int      atexit_installed;
442         static int      blocking_pipes[4] = { -1, -1, -1, -1 };
443         int             rc;
444         int             was_pipe;
445         int             is_pipe;
446         int             saved_errno = 0;
447         int             childpid;
448         int             keep_fd;
449         int             fd;
450
451         /*
452          * parent and child communicate via a pair of pipes.
453          * 
454          * 0 child read request
455          * 1 parent write request
456          * 2 parent read response
457          * 3 child write response
458          */
459         if (-1 == c->req_write_pipe) {
460                 rc = pipe_socketpair(&blocking_pipes[0], &was_pipe);
461                 if (0 != rc) {
462                         saved_errno = errno;
463                 } else {
464                         rc = pipe_socketpair(&blocking_pipes[2], &is_pipe);
465                         if (0 != rc) {
466                                 saved_errno = errno;
467                                 close(blocking_pipes[0]);
468                                 close(blocking_pipes[1]);
469                         } else {
470                                 INSIST(was_pipe == is_pipe);
471                         }
472                 }
473                 if (0 != rc) {
474                         errno = saved_errno;
475                         msyslog(LOG_ERR, "unable to create worker pipes: %m");
476                         exit(1);
477                 }
478
479                 /*
480                  * Move the descriptors the parent will keep open out of the
481                  * low descriptors preferred by C runtime buffered FILE *.
482                  */
483                 c->req_write_pipe = move_fd(blocking_pipes[1]);
484                 c->resp_read_pipe = move_fd(blocking_pipes[2]);
485                 /*
486                  * wake any worker child on orderly shutdown of the
487                  * daemon so that it can notice the broken pipes and
488                  * go away promptly.
489                  */
490                 if (!atexit_installed) {
491                         atexit(&send_worker_home_atexit);
492                         atexit_installed = TRUE;
493                 }
494         }
495
496 #if defined(HAVE_DROPROOT) && !defined(NEED_EARLY_FORK)
497         /* defer the fork until after root is dropped */
498         if (droproot && !root_dropped)
499                 return;
500 #endif
501         if (syslog_file != NULL)
502                 fflush(syslog_file);
503         fflush(stdout);
504         fflush(stderr);
505
506         /* [BUG 3050] setting SIGCHLD to SIG_IGN likely causes unwanted
507          * or undefined effects. We don't do it and leave SIGCHLD alone.
508          */
509         /* signal_no_reset(SIGCHLD, SIG_IGN); */
510
511         childpid = fork();
512         if (-1 == childpid) {
513                 msyslog(LOG_ERR, "unable to fork worker: %m");
514                 exit(1);
515         }
516
517         if (childpid) {
518                 /* this is the parent */
519                 TRACE(1, ("forked worker child (pid %d)\n", childpid));
520                 c->pid = childpid;
521                 c->ispipe = is_pipe;
522
523                 /* close the child's pipe descriptors. */
524                 close(blocking_pipes[0]);
525                 close(blocking_pipes[3]);
526
527                 memset(blocking_pipes, -1, sizeof(blocking_pipes));
528
529                 /* wire into I/O loop */
530                 (*addremove_io_fd)(c->resp_read_pipe, is_pipe, FALSE);
531
532                 return;         /* parent returns */
533         }
534
535         /*
536          * The parent gets the child pid as the return value of fork().
537          * The child must work for it.
538          */
539         c->pid = getpid();
540         worker_process = TRUE;
541
542         /*
543          * Change the process name of the child to avoid confusion
544          * about ntpd trunning twice.
545          */
546         if (saved_argc != 0) {
547                 int argcc;
548                 int argvlen = 0;
549                 /* Clear argv */
550                 for (argcc = 0; argcc < saved_argc; argcc++) {
551                         int l = strlen(saved_argv[argcc]);
552                         argvlen += l + 1;
553                         memset(saved_argv[argcc], 0, l);
554                 }
555                 strlcpy(saved_argv[0], "ntpd: asynchronous dns resolver", argvlen);
556         }
557
558         /*
559          * In the child, close all files except stdin, stdout, stderr,
560          * and the two child ends of the pipes.
561          */
562         DEBUG_INSIST(-1 == c->req_read_pipe);
563         DEBUG_INSIST(-1 == c->resp_write_pipe);
564         c->req_read_pipe = blocking_pipes[0];
565         c->resp_write_pipe = blocking_pipes[3];
566
567         kill_asyncio(0);
568         closelog();
569         if (syslog_file != NULL) {
570                 fclose(syslog_file);
571                 syslog_file = NULL;
572                 syslogit = TRUE;
573         }
574         keep_fd = max(c->req_read_pipe, c->resp_write_pipe);
575         for (fd = 3; fd < keep_fd; fd++)
576                 if (fd != c->req_read_pipe && 
577                     fd != c->resp_write_pipe)
578                         close(fd);
579         close_all_beyond(keep_fd);
580         /*
581          * We get signals from refclock serial I/O on NetBSD in the
582          * worker if we do not reset SIGIO's handler to the default.
583          * It is not conditionalized for NetBSD alone because on
584          * systems where it is not needed, it is harmless, and that
585          * allows us to handle unknown others with NetBSD behavior.
586          * [Bug 1386]
587          */
588 #if defined(USE_SIGIO)
589         signal_no_reset(SIGIO, SIG_DFL);
590 #elif defined(USE_SIGPOLL)
591         signal_no_reset(SIGPOLL, SIG_DFL);
592 #endif
593         signal_no_reset(SIGHUP, worker_sighup);
594         init_logging("ntp_intres", 0, FALSE);
595         setup_logfile(NULL);
596
597         (void) set_user_group_ids();
598
599         /*
600          * And now back to the portable code
601          */
602         exit_worker(blocking_child_common(c));
603 }
604
605
606 void worker_global_lock(int inOrOut)
607 {
608         (void)inOrOut;
609 }
610
611 #else   /* !WORK_FORK follows */
612 char work_fork_nonempty_compilation_unit;
613 #endif