1 /*
2  * dhcpcd - DHCP client daemon
3  * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
4  * 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 AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE 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
21  * OR 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 <sys/stat.h>
29 #include <sys/uio.h>
30 #include <sys/wait.h>
31 
32 #include <netinet/in.h>
33 #include <arpa/inet.h>
34 
35 #include <ctype.h>
36 #include <errno.h>
37 #include <signal.h>
38 /* We can't include spawn.h here because it may not exist.
39  * config.h will pull it in, or our compat one. */
40 #include <stdlib.h>
41 #include <string.h>
42 #include <unistd.h>
43 
44 #include "config.h"
45 #include "common.h"
46 #include "dhcp.h"
47 #include "dhcp6.h"
48 #include "if.h"
49 #include "if-options.h"
50 #include "ipv6nd.h"
51 #include "script.h"
52 
53 #ifdef HAVE_SPAWN_H
54 #include <spawn.h>
55 #else
56 #include "compat/posix_spawn.h"
57 #endif
58 
59 /* Allow the OS to define another script env var name */
60 #ifndef RC_SVCNAME
61 #define RC_SVCNAME "RC_SVCNAME"
62 #endif
63 
64 #define DEFAULT_PATH	"PATH=/usr/bin:/usr/sbin:/bin:/sbin"
65 
66 static const char * const if_params[] = {
67 	"interface",
68 	"reason",
69 	"pid",
70 	"ifcarrier",
71 	"ifmetric",
72 	"ifwireless",
73 	"ifflags",
74 	"ssid",
75 	"profile",
76 	"interface_order",
77 	NULL
78 };
79 
80 void
if_printoptions(void)81 if_printoptions(void)
82 {
83 	const char * const *p;
84 
85 	for (p = if_params; *p; p++)
86 		printf(" -  %s\n", *p);
87 }
88 
89 static int
exec_script(const struct dhcpcd_ctx * ctx,char * const * argv,char * const * env)90 exec_script(const struct dhcpcd_ctx *ctx, char *const *argv, char *const *env)
91 {
92 	pid_t pid;
93 	posix_spawnattr_t attr;
94 	int i;
95 #ifdef USE_SIGNALS
96 	short flags;
97 	sigset_t defsigs;
98 #else
99 	UNUSED(ctx);
100 #endif
101 
102 	/* posix_spawn is a safe way of executing another image
103 	 * and changing signals back to how they should be. */
104 	if (posix_spawnattr_init(&attr) == -1)
105 		return -1;
106 #ifdef USE_SIGNALS
107 	flags = POSIX_SPAWN_SETSIGMASK | POSIX_SPAWN_SETSIGDEF;
108 	posix_spawnattr_setflags(&attr, flags);
109 	sigemptyset(&defsigs);
110 	for (i = 0; dhcpcd_handlesigs[i]; i++)
111 		sigaddset(&defsigs, dhcpcd_handlesigs[i]);
112 	posix_spawnattr_setsigdefault(&attr, &defsigs);
113 	posix_spawnattr_setsigmask(&attr, &ctx->sigset);
114 #endif
115 	errno = 0;
116 	i = posix_spawn(&pid, argv[0], NULL, &attr, argv, env);
117 	if (i) {
118 		errno = i;
119 		return -1;
120 	}
121 	return pid;
122 }
123 
124 #ifdef INET
125 static char *
make_var(struct dhcpcd_ctx * ctx,const char * prefix,const char * var)126 make_var(struct dhcpcd_ctx *ctx, const char *prefix, const char *var)
127 {
128 	size_t len;
129 	char *v;
130 
131 	len = strlen(prefix) + strlen(var) + 2;
132 	v = malloc(len);
133 	if (v == NULL) {
134 		logger(ctx, LOG_ERR, "%s: %m", __func__);
135 		return NULL;
136 	}
137 	snprintf(v, len, "%s_%s", prefix, var);
138 	return v;
139 }
140 
141 
142 static int
append_config(struct dhcpcd_ctx * ctx,char *** env,size_t * len,const char * prefix,const char * const * config)143 append_config(struct dhcpcd_ctx *ctx, char ***env, size_t *len,
144     const char *prefix, const char *const *config)
145 {
146 	size_t i, j, e1;
147 	char **ne, *eq, **nep, *p;
148 	int ret;
149 
150 	if (config == NULL)
151 		return 0;
152 
153 	ne = *env;
154 	ret = 0;
155 	for (i = 0; config[i] != NULL; i++) {
156 		eq = strchr(config[i], '=');
157 		e1 = (size_t)(eq - config[i] + 1);
158 		for (j = 0; j < *len; j++) {
159 			if (strncmp(ne[j] + strlen(prefix) + 1,
160 				config[i], e1) == 0)
161 			{
162 				p = make_var(ctx, prefix, config[i]);
163 				if (p == NULL) {
164 					ret = -1;
165 					break;
166 				}
167 				free(ne[j]);
168 				ne[j] = p;
169 				break;
170 			}
171 		}
172 		if (j == *len) {
173 			j++;
174 			p = make_var(ctx, prefix, config[i]);
175 			if (p == NULL) {
176 				ret = -1;
177 				break;
178 			}
179 			nep = realloc(ne, sizeof(char *) * (j + 1));
180 			if (nep == NULL) {
181 				logger(ctx, LOG_ERR, "%s: %m", __func__);
182 				free(p);
183 				ret = -1;
184 				break;
185 			}
186 			ne = nep;
187 			ne[j - 1] = p;
188 			*len = j;
189 		}
190 	}
191 	*env = ne;
192 	return ret;
193 }
194 #endif
195 
196 static ssize_t
arraytostr(const char * const * argv,char ** s)197 arraytostr(const char *const *argv, char **s)
198 {
199 	const char *const *ap;
200 	char *p;
201 	size_t len, l;
202 
203 	if (*argv == NULL)
204 		return 0;
205 	len = 0;
206 	ap = argv;
207 	while (*ap)
208 		len += strlen(*ap++) + 1;
209 	*s = p = malloc(len);
210 	if (p == NULL)
211 		return -1;
212 	ap = argv;
213 	while (*ap) {
214 		l = strlen(*ap) + 1;
215 		memcpy(p, *ap, l);
216 		p += l;
217 		ap++;
218 	}
219 	return (ssize_t)len;
220 }
221 
222 static ssize_t
make_env(const struct interface * ifp,const char * reason,char *** argv)223 make_env(const struct interface *ifp, const char *reason, char ***argv)
224 {
225 	char **env, **nenv, *p;
226 	size_t e, elen, l;
227 #if defined(INET) || defined(INET6)
228 	ssize_t n;
229 #endif
230 	const struct if_options *ifo = ifp->options;
231 	const struct interface *ifp2;
232 #ifdef INET
233 	int dhcp;
234 	const struct dhcp_state *state;
235 #endif
236 #ifdef INET6
237 	const struct dhcp6_state *d6_state;
238 	int dhcp6, ra;
239 #endif
240 
241 #ifdef INET
242 	dhcp = 0;
243 	state = D_STATE(ifp);
244 #endif
245 #ifdef INET6
246 	dhcp6 = ra = 0;
247 	d6_state = D6_CSTATE(ifp);
248 #endif
249 	if (strcmp(reason, "TEST") == 0) {
250 		if (1 == 2) {}
251 #ifdef INET6
252 		else if (d6_state && d6_state->new)
253 			dhcp6 = 1;
254 		else if (ipv6nd_hasra(ifp))
255 			ra = 1;
256 #endif
257 #ifdef INET
258 		else
259 			dhcp = 1;
260 #endif
261 	}
262 #ifdef INET6
263 	else if (reason[strlen(reason) - 1] == '6')
264 		dhcp6 = 1;
265 	else if (strcmp(reason, "ROUTERADVERT") == 0)
266 		ra = 1;
267 #endif
268 	else if (strcmp(reason, "PREINIT") == 0 ||
269 	    strcmp(reason, "CARRIER") == 0 ||
270 	    strcmp(reason, "NOCARRIER") == 0 ||
271 	    strcmp(reason, "UNKNOWN") == 0 ||
272 	    strcmp(reason, "DEPARTED") == 0 ||
273 	    strcmp(reason, "STOPPED") == 0)
274 	{
275 		/* This space left intentionally blank */
276 	}
277 #ifdef INET
278 	else
279 		dhcp = 1;
280 #endif
281 
282 	/* When dumping the lease, we only want to report interface and
283 	   reason - the other interface variables are meaningless */
284 	if (ifp->ctx->options & DHCPCD_DUMPLEASE)
285 		elen = 2;
286 	else
287 		elen = 13;
288 
289 #define EMALLOC(i, l) if ((env[(i)] = malloc((l))) == NULL) goto eexit;
290 	/* Make our env + space for profile, wireless and debug */
291 	env = calloc(1, sizeof(char *) * (elen + 3 + 1));
292 	if (env == NULL)
293 		goto eexit;
294 	e = strlen("interface") + strlen(ifp->name) + 2;
295 	EMALLOC(0, e);
296 	snprintf(env[0], e, "interface=%s", ifp->name);
297 	e = strlen("reason") + strlen(reason) + 2;
298 	EMALLOC(1, e);
299 	snprintf(env[1], e, "reason=%s", reason);
300 	if (ifp->ctx->options & DHCPCD_DUMPLEASE)
301 		goto dumplease;
302 	e = 20;
303 	EMALLOC(2, e);
304 	snprintf(env[2], e, "pid=%d", getpid());
305 	EMALLOC(3, e);
306 	snprintf(env[3], e, "ifcarrier=%s",
307 	    ifp->carrier == LINK_UNKNOWN ? "unknown" :
308 	    ifp->carrier == LINK_UP ? "up" : "down");
309 	EMALLOC(4, e);
310 	snprintf(env[4], e, "ifmetric=%d", ifp->metric);
311 	EMALLOC(5, e);
312 	snprintf(env[5], e, "ifwireless=%d", ifp->wireless);
313 	EMALLOC(6, e);
314 	snprintf(env[6], e, "ifflags=%u", ifp->flags);
315 	EMALLOC(7, e);
316 	snprintf(env[7], e, "ifmtu=%d", if_getmtu(ifp->name));
317 	l = e = strlen("interface_order=");
318 	TAILQ_FOREACH(ifp2, ifp->ctx->ifaces, next) {
319 		if (!(ifp2->options->options & DHCPCD_PFXDLGONLY))
320 			e += strlen(ifp2->name) + 1;
321 	}
322 	EMALLOC(8, e);
323 	p = env[8];
324 	strlcpy(p, "interface_order=", e);
325 	e -= l;
326 	p += l;
327 	TAILQ_FOREACH(ifp2, ifp->ctx->ifaces, next) {
328 		if (!(ifp2->options->options & DHCPCD_PFXDLGONLY)) {
329 			l = strlcpy(p, ifp2->name, e);
330 			p += l;
331 			e -= l;
332 			*p++ = ' ';
333 			e--;
334 		}
335 	}
336 	*--p = '\0';
337 	if (strcmp(reason, "STOPPED") == 0) {
338 		env[9] = strdup("if_up=false");
339 		if (ifo->options & DHCPCD_RELEASE)
340 			env[10] = strdup("if_down=true");
341 		else
342 			env[10] = strdup("if_down=false");
343 	} else if (strcmp(reason, "TEST") == 0 ||
344 	    strcmp(reason, "PREINIT") == 0 ||
345 	    strcmp(reason, "CARRIER") == 0 ||
346 	    strcmp(reason, "UNKNOWN") == 0)
347 	{
348 		env[9] = strdup("if_up=false");
349 		env[10] = strdup("if_down=false");
350 	} else if (1 == 2 /* appease ifdefs */
351 #ifdef INET
352 	    || (dhcp && state && state->new)
353 #endif
354 #ifdef INET6
355 	    || (dhcp6 && d6_state && d6_state->new)
356 	    || (ra && ipv6nd_hasra(ifp))
357 #endif
358 	    )
359 	{
360 		env[9] = strdup("if_up=true");
361 		env[10] = strdup("if_down=false");
362 	} else {
363 		env[9] = strdup("if_up=false");
364 		env[10] = strdup("if_down=true");
365 	}
366 	if (env[9] == NULL || env[10] == NULL)
367 		goto eexit;
368 	if (dhcpcd_oneup(ifp->ctx))
369 		env[11] = strdup("if_oneup=true");
370 	else
371 		env[11] = strdup("if_oneup=false");
372 	if (env[11] == NULL)
373 		goto eexit;
374 	if (dhcpcd_ipwaited(ifp->ctx))
375 		env[12] = strdup("if_ipwaited=true");
376 	else
377 		env[12] = strdup("if_ipwaited=false");
378 	if (env[12] == NULL)
379 		goto eexit;
380 	if (ifo->options & DHCPCD_DEBUG) {
381 		e = strlen("syslog_debug=true") + 1;
382 		EMALLOC(elen, e);
383 		snprintf(env[elen++], e, "syslog_debug=true");
384 	}
385 	if (*ifp->profile) {
386 		e = strlen("profile=") + strlen(ifp->profile) + 1;
387 		EMALLOC(elen, e);
388 		snprintf(env[elen++], e, "profile=%s", ifp->profile);
389 	}
390 	if (ifp->wireless) {
391 		static const char *pfx = "ifssid=";
392 		size_t pfx_len;
393 		ssize_t psl;
394 
395 		pfx_len = strlen(pfx);
396 		psl = print_string(NULL, 0, ESCSTRING,
397 		    (const uint8_t *)ifp->ssid, ifp->ssid_len);
398 		if (psl != -1) {
399 			EMALLOC(elen, pfx_len + (size_t)psl + 1);
400 			memcpy(env[elen], pfx, pfx_len);
401 			print_string(env[elen] + pfx_len, (size_t)psl + 1,
402 			    ESCSTRING,
403 			    (const uint8_t *)ifp->ssid, ifp->ssid_len);
404 			elen++;
405 		}
406 	}
407 #ifdef INET
408 	if (dhcp && state && state->old) {
409 		n = dhcp_env(NULL, NULL, state->old, ifp);
410 		if (n == -1)
411 			goto eexit;
412 		if (n > 0) {
413 			nenv = realloc(env, sizeof(char *) *
414 			    (elen + (size_t)n + 1));
415 			if (nenv == NULL)
416 				goto eexit;
417 			env = nenv;
418 			n = dhcp_env(env + elen, "old", state->old, ifp);
419 			if (n == -1)
420 				goto eexit;
421 			elen += (size_t)n;
422 		}
423 		if (append_config(ifp->ctx, &env, &elen, "old",
424 		    (const char *const *)ifo->config) == -1)
425 			goto eexit;
426 	}
427 #endif
428 #ifdef INET6
429 	if (dhcp6 && d6_state && ifo->options & DHCPCD_PFXDLGONLY) {
430 		nenv = realloc(env, sizeof(char *) * (elen + 2));
431 		if (nenv == NULL)
432 			goto eexit;
433 		env = nenv;
434 		env[elen] = strdup("ifclass=pd");
435 		if (env[elen] == NULL)
436 			goto eexit;
437 		elen++;
438 	}
439 	if (dhcp6 && d6_state && d6_state->old) {
440 		n = dhcp6_env(NULL, NULL, ifp,
441 		    d6_state->old, d6_state->old_len);
442 		if (n > 0) {
443 			nenv = realloc(env, sizeof(char *) *
444 			    (elen + (size_t)n + 1));
445 			if (nenv == NULL)
446 				goto eexit;
447 			env = nenv;
448 			n = dhcp6_env(env + elen, "old", ifp,
449 			    d6_state->old, d6_state->old_len);
450 			if (n == -1)
451 				goto eexit;
452 			elen += (size_t)n;
453 		}
454 	}
455 #endif
456 
457 dumplease:
458 #ifdef INET
459 	if (dhcp && state && state->new) {
460 		n = dhcp_env(NULL, NULL, state->new, ifp);
461 		if (n > 0) {
462 			nenv = realloc(env, sizeof(char *) *
463 			    (elen + (size_t)n + 1));
464 			if (nenv == NULL)
465 				goto eexit;
466 			env = nenv;
467 			n = dhcp_env(env + elen, "new",
468 			    state->new, ifp);
469 			if (n == -1)
470 				goto eexit;
471 			elen += (size_t)n;
472 		}
473 		if (append_config(ifp->ctx, &env, &elen, "new",
474 		    (const char *const *)ifo->config) == -1)
475 			goto eexit;
476 	}
477 #endif
478 #ifdef INET6
479 	if (dhcp6 && D6_STATE_RUNNING(ifp)) {
480 		n = dhcp6_env(NULL, NULL, ifp,
481 		    d6_state->new, d6_state->new_len);
482 		if (n > 0) {
483 			nenv = realloc(env, sizeof(char *) *
484 			    (elen + (size_t)n + 1));
485 			if (nenv == NULL)
486 				goto eexit;
487 			env = nenv;
488 			n = dhcp6_env(env + elen, "new", ifp,
489 			    d6_state->new, d6_state->new_len);
490 			if (n == -1)
491 				goto eexit;
492 			elen += (size_t)n;
493 		}
494 	}
495 	if (ra) {
496 		n = ipv6nd_env(NULL, NULL, ifp);
497 		if (n > 0) {
498 			nenv = realloc(env, sizeof(char *) *
499 			    (elen + (size_t)n + 1));
500 			if (nenv == NULL)
501 				goto eexit;
502 			env = nenv;
503 			n = ipv6nd_env(env + elen, NULL, ifp);
504 			if (n == -1)
505 				goto eexit;
506 			elen += (size_t)n;
507 		}
508 	}
509 #endif
510 
511 	/* Add our base environment */
512 	if (ifo->environ) {
513 		e = 0;
514 		while (ifo->environ[e++])
515 			;
516 		nenv = realloc(env, sizeof(char *) * (elen + e + 1));
517 		if (nenv == NULL)
518 			goto eexit;
519 		env = nenv;
520 		e = 0;
521 		while (ifo->environ[e]) {
522 			env[elen + e] = strdup(ifo->environ[e]);
523 			if (env[elen + e] == NULL)
524 				goto eexit;
525 			e++;
526 		}
527 		elen += e;
528 	}
529 	env[elen] = NULL;
530 
531 	*argv = env;
532 	return (ssize_t)elen;
533 
534 eexit:
535 	logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
536 	if (env) {
537 		nenv = env;
538 		while (*nenv)
539 			free(*nenv++);
540 		free(env);
541 	}
542 	return -1;
543 }
544 
545 static int
send_interface1(struct fd_list * fd,const struct interface * iface,const char * reason)546 send_interface1(struct fd_list *fd, const struct interface *iface,
547     const char *reason)
548 {
549 	char **env, **ep, *s;
550 	size_t elen;
551 	int retval;
552 
553 	if (make_env(iface, reason, &env) == -1)
554 		return -1;
555 	s = NULL;
556 	elen = (size_t)arraytostr((const char *const *)env, &s);
557 	if ((ssize_t)elen == -1) {
558 		free(s);
559 		return -1;
560 	}
561 	retval = control_queue(fd, s, elen, 1);
562 	ep = env;
563 	while (*ep)
564 		free(*ep++);
565 	free(env);
566 	return retval;
567 }
568 
569 int
send_interface(struct fd_list * fd,const struct interface * ifp)570 send_interface(struct fd_list *fd, const struct interface *ifp)
571 {
572 	const char *reason;
573 	int retval = 0;
574 #ifdef INET
575 	const struct dhcp_state *d;
576 #endif
577 #ifdef INET6
578 	const struct dhcp6_state *d6;
579 #endif
580 
581 	switch (ifp->carrier) {
582 	case LINK_UP:
583 		reason = "CARRIER";
584 		break;
585 	case LINK_DOWN:
586 		reason = "NOCARRIER";
587 		break;
588 	default:
589 		reason = "UNKNOWN";
590 		break;
591 	}
592 	if (send_interface1(fd, ifp, reason) == -1)
593 		retval = -1;
594 #ifdef INET
595 	if (D_STATE_RUNNING(ifp)) {
596 		d = D_CSTATE(ifp);
597 		if (send_interface1(fd, ifp, d->reason) == -1)
598 			retval = -1;
599 	}
600 #endif
601 
602 #ifdef INET6
603 	if (RS_STATE_RUNNING(ifp)) {
604 		if (send_interface1(fd, ifp, "ROUTERADVERT") == -1)
605 			retval = -1;
606 	}
607 	if (D6_STATE_RUNNING(ifp)) {
608 		d6 = D6_CSTATE(ifp);
609 		if (send_interface1(fd, ifp, d6->reason) == -1)
610 			retval = -1;
611 	}
612 #endif
613 
614 	return retval;
615 }
616 
617 int
script_runreason(const struct interface * ifp,const char * reason)618 script_runreason(const struct interface *ifp, const char *reason)
619 {
620 	char *argv[2];
621 	char **env = NULL, **ep;
622 	char *svcname, *path, *bigenv;
623 	size_t e, elen = 0;
624 	pid_t pid;
625 	int status = 0;
626 	struct fd_list *fd;
627 
628 	if (ifp->options->script &&
629 	    (ifp->options->script[0] == '\0' ||
630 	    strcmp(ifp->options->script, "/dev/null") == 0))
631 		return 0;
632 
633 	argv[0] = ifp->options->script ? ifp->options->script : UNCONST(SCRIPT);
634 	argv[1] = NULL;
635 	logger(ifp->ctx, LOG_DEBUG, "%s: executing `%s' %s",
636 	    ifp->name, argv[0], reason);
637 
638 	/* Make our env */
639 	elen = (size_t)make_env(ifp, reason, &env);
640 	if (elen == (size_t)-1) {
641 		logger(ifp->ctx, LOG_ERR, "%s: make_env: %m", ifp->name);
642 		return -1;
643 	}
644 	/* Resize for PATH and RC_SVCNAME */
645 	svcname = getenv(RC_SVCNAME);
646 	ep = realloc(env, sizeof(char *) * (elen + 2 + (svcname ? 1 : 0)));
647 	if (ep == NULL) {
648 		elen = 0;
649 		goto out;
650 	}
651 	env = ep;
652 	/* Add path to it */
653 	path = getenv("PATH");
654 	if (path) {
655 		e = strlen("PATH") + strlen(path) + 2;
656 		env[elen] = malloc(e);
657 		if (env[elen] == NULL) {
658 			elen = 0;
659 			goto out;
660 		}
661 		snprintf(env[elen], e, "PATH=%s", path);
662 	} else {
663 		env[elen] = strdup(DEFAULT_PATH);
664 		if (env[elen] == NULL) {
665 			elen = 0;
666 			goto out;
667 		}
668 	}
669 	if (svcname) {
670 		e = strlen(RC_SVCNAME) + strlen(svcname) + 2;
671 		env[++elen] = malloc(e);
672 		if (env[elen] == NULL) {
673 			elen = 0;
674 			goto out;
675 		}
676 		snprintf(env[elen], e, "%s=%s", RC_SVCNAME, svcname);
677 	}
678 	env[++elen] = NULL;
679 
680 	pid = exec_script(ifp->ctx, argv, env);
681 	if (pid == -1)
682 		logger(ifp->ctx, LOG_ERR, "%s: %s: %m", __func__, argv[0]);
683 	else if (pid != 0) {
684 		/* Wait for the script to finish */
685 		while (waitpid(pid, &status, 0) == -1) {
686 			if (errno != EINTR) {
687 				logger(ifp->ctx, LOG_ERR, "waitpid: %m");
688 				status = 0;
689 				break;
690 			}
691 		}
692 		if (WIFEXITED(status)) {
693 			if (WEXITSTATUS(status))
694 				logger(ifp->ctx, LOG_ERR,
695 				    "%s: %s: WEXITSTATUS %d",
696 				    __func__, argv[0], WEXITSTATUS(status));
697 		} else if (WIFSIGNALED(status))
698 			logger(ifp->ctx, LOG_ERR, "%s: %s: %s",
699 			    __func__, argv[0], strsignal(WTERMSIG(status)));
700 	}
701 
702 	/* Send to our listeners */
703 	bigenv = NULL;
704 	status = 0;
705 	TAILQ_FOREACH(fd, &ifp->ctx->control_fds, next) {
706 		if (!(fd->flags & FD_LISTEN))
707 			continue;
708 		if (bigenv == NULL) {
709 			elen = (size_t)arraytostr((const char *const *)env,
710 			    &bigenv);
711 			if ((ssize_t)elen == -1) {
712 				logger(ifp->ctx, LOG_ERR, "%s: arraytostr: %m",
713 				    ifp->name);
714 				    break;
715 			}
716 		}
717 		if (control_queue(fd, bigenv, elen, 1) == -1)
718 			logger(ifp->ctx, LOG_ERR,
719 			    "%s: control_queue: %m", __func__);
720 		else
721 			status = 1;
722 	}
723 	if (!status)
724 		free(bigenv);
725 
726 out:
727 	/* Cleanup */
728 	ep = env;
729 	while (*ep)
730 		free(*ep++);
731 	free(env);
732 	if (elen == 0)
733 		return -1;
734 	return WEXITSTATUS(status);
735 }
736