summaryrefslogtreecommitdiffstats
path: root/contrib/ntp/libntp/work_fork.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/ntp/libntp/work_fork.c')
-rw-r--r--contrib/ntp/libntp/work_fork.c165
1 files changed, 108 insertions, 57 deletions
diff --git a/contrib/ntp/libntp/work_fork.c b/contrib/ntp/libntp/work_fork.c
index 8223fdd..2aa2d5c 100644
--- a/contrib/ntp/libntp/work_fork.c
+++ b/contrib/ntp/libntp/work_fork.c
@@ -24,6 +24,8 @@
int worker_process;
addremove_io_fd_func addremove_io_fd;
static volatile int worker_sighup_received;
+int saved_argc = 0;
+char **saved_argv;
/* === function prototypes === */
static void fork_blocking_child(blocking_child *);
@@ -31,6 +33,62 @@ static RETSIGTYPE worker_sighup(int);
static void send_worker_home_atexit(void);
static void cleanup_after_child(blocking_child *);
+/* === I/O helpers === */
+/* Since we have signals enabled, there's a good chance that blocking IO
+ * via pipe suffers from EINTR -- and this goes for both directions.
+ * The next two wrappers will loop until either all the data is written
+ * or read, plus handling the EOF condition on read. They may return
+ * zero if no data was transferred at all, and effectively every return
+ * value that differs from the given transfer length signifies an error
+ * condition.
+ */
+
+static size_t
+netread(
+ int fd,
+ void * vb,
+ size_t l
+ )
+{
+ char * b = vb;
+ ssize_t r;
+
+ while (l) {
+ r = read(fd, b, l);
+ if (r > 0) {
+ l -= r;
+ b += r;
+ } else if (r == 0 || errno != EINTR) {
+ l = 0;
+ }
+ }
+ return (size_t)(b - (char *)vb);
+}
+
+
+static size_t
+netwrite(
+ int fd,
+ const void * vb,
+ size_t l
+ )
+{
+ const char * b = vb;
+ ssize_t w;
+
+ while (l) {
+ w = write(fd, b, l);
+ if (w > 0) {
+ l -= w;
+ b += w;
+ } else if (errno != EINTR) {
+ l = 0;
+ }
+ }
+ return (size_t)(b - (const char *)vb);
+}
+
+
/* === functions === */
/*
* exit_worker()
@@ -200,8 +258,8 @@ send_blocking_req_internal(
void * data
)
{
- int octets;
- int rc;
+ size_t octets;
+ size_t rc;
DEBUG_REQUIRE(hdr != NULL);
DEBUG_REQUIRE(data != NULL);
@@ -213,23 +271,18 @@ send_blocking_req_internal(
}
octets = sizeof(*hdr);
- rc = write(c->req_write_pipe, hdr, octets);
+ rc = netwrite(c->req_write_pipe, hdr, octets);
if (rc == octets) {
octets = hdr->octets - sizeof(*hdr);
- rc = write(c->req_write_pipe, data, octets);
-
+ rc = netwrite(c->req_write_pipe, data, octets);
if (rc == octets)
return 0;
}
- if (rc < 0)
- msyslog(LOG_ERR,
- "send_blocking_req_internal: pipe write: %m");
- else
- msyslog(LOG_ERR,
- "send_blocking_req_internal: short write %d of %d",
- rc, octets);
+ msyslog(LOG_ERR,
+ "send_blocking_req_internal: short write (%zu of %zu), %m",
+ rc, octets);
/* Fatal error. Clean up the child process. */
req_child_exit(c);
@@ -244,41 +297,32 @@ receive_blocking_req_internal(
{
blocking_pipe_header hdr;
blocking_pipe_header * req;
- int rc;
- long octets;
+ size_t rc;
+ size_t octets;
DEBUG_REQUIRE(-1 != c->req_read_pipe);
req = NULL;
+ rc = netread(c->req_read_pipe, &hdr, sizeof(hdr));
- do {
- rc = read(c->req_read_pipe, &hdr, sizeof(hdr));
- } while (rc < 0 && EINTR == errno);
-
- if (rc < 0) {
- msyslog(LOG_ERR,
- "receive_blocking_req_internal: pipe read %m");
- } else if (0 == rc) {
+ if (0 == rc) {
TRACE(4, ("parent closed request pipe, child %d terminating\n",
c->pid));
} else if (rc != sizeof(hdr)) {
msyslog(LOG_ERR,
- "receive_blocking_req_internal: short header read %d of %lu",
- rc, (u_long)sizeof(hdr));
+ "receive_blocking_req_internal: short header read (%zu of %zu), %m",
+ rc, sizeof(hdr));
} else {
INSIST(sizeof(hdr) < hdr.octets && hdr.octets < 4 * 1024);
req = emalloc(hdr.octets);
memcpy(req, &hdr, sizeof(*req));
octets = hdr.octets - sizeof(hdr);
- rc = read(c->req_read_pipe, (char *)req + sizeof(*req),
- octets);
+ rc = netread(c->req_read_pipe, (char *)(req + 1),
+ octets);
- if (rc < 0)
- msyslog(LOG_ERR,
- "receive_blocking_req_internal: pipe data read %m");
- else if (rc != octets)
+ if (rc != octets)
msyslog(LOG_ERR,
- "receive_blocking_req_internal: short read %d of %ld",
+ "receive_blocking_req_internal: short read (%zu of %zu), %m",
rc, octets);
else if (BLOCKING_REQ_MAGIC != req->magic_sig)
msyslog(LOG_ERR,
@@ -301,24 +345,20 @@ send_blocking_resp_internal(
blocking_pipe_header * resp
)
{
- long octets;
- int rc;
+ size_t octets;
+ size_t rc;
DEBUG_REQUIRE(-1 != c->resp_write_pipe);
octets = resp->octets;
- rc = write(c->resp_write_pipe, resp, octets);
+ rc = netwrite(c->resp_write_pipe, resp, octets);
free(resp);
if (octets == rc)
return 0;
- if (rc < 0)
- TRACE(1, ("send_blocking_resp_internal: pipe write %m\n"));
- else
- TRACE(1, ("send_blocking_resp_internal: short write %d of %ld\n",
- rc, octets));
-
+ TRACE(1, ("send_blocking_resp_internal: short write (%zu of %zu), %m\n",
+ rc, octets));
return -1;
}
@@ -330,21 +370,19 @@ receive_blocking_resp_internal(
{
blocking_pipe_header hdr;
blocking_pipe_header * resp;
- int rc;
- long octets;
+ size_t rc;
+ size_t octets;
DEBUG_REQUIRE(c->resp_read_pipe != -1);
resp = NULL;
- rc = read(c->resp_read_pipe, &hdr, sizeof(hdr));
+ rc = netread(c->resp_read_pipe, &hdr, sizeof(hdr));
- if (rc < 0) {
- TRACE(1, ("receive_blocking_resp_internal: pipe read %m\n"));
- } else if (0 == rc) {
+ if (0 == rc) {
/* this is the normal child exited indication */
} else if (rc != sizeof(hdr)) {
- TRACE(1, ("receive_blocking_resp_internal: short header read %d of %lu\n",
- rc, (u_long)sizeof(hdr)));
+ TRACE(1, ("receive_blocking_resp_internal: short header read (%zu of %zu), %m\n",
+ rc, sizeof(hdr)));
} else if (BLOCKING_RESP_MAGIC != hdr.magic_sig) {
TRACE(1, ("receive_blocking_resp_internal: header mismatch (0x%x)\n",
hdr.magic_sig));
@@ -354,24 +392,21 @@ receive_blocking_resp_internal(
resp = emalloc(hdr.octets);
memcpy(resp, &hdr, sizeof(*resp));
octets = hdr.octets - sizeof(hdr);
- rc = read(c->resp_read_pipe,
- (char *)resp + sizeof(*resp),
- octets);
+ rc = netread(c->resp_read_pipe, (char *)(resp + 1),
+ octets);
- if (rc < 0)
- TRACE(1, ("receive_blocking_resp_internal: pipe data read %m\n"));
- else if (rc < octets)
- TRACE(1, ("receive_blocking_resp_internal: short read %d of %ld\n",
+ if (rc != octets)
+ TRACE(1, ("receive_blocking_resp_internal: short read (%zu of %zu), %m\n",
rc, octets));
else
return resp;
}
cleanup_after_child(c);
-
+
if (resp != NULL)
free(resp);
-
+
return NULL;
}
@@ -503,6 +538,22 @@ fork_blocking_child(
worker_process = TRUE;
/*
+ * Change the process name of the child to avoid confusion
+ * about ntpd trunning twice.
+ */
+ if (saved_argc != 0) {
+ int argcc;
+ int argvlen = 0;
+ /* Clear argv */
+ for (argcc = 0; argcc < saved_argc; argcc++) {
+ int l = strlen(saved_argv[argcc]);
+ argvlen += l + 1;
+ memset(saved_argv[argcc], 0, l);
+ }
+ strlcpy(saved_argv[0], "ntpd: asynchronous dns resolver", argvlen);
+ }
+
+ /*
* In the child, close all files except stdin, stdout, stderr,
* and the two child ends of the pipes.
*/
OpenPOWER on IntegriCloud