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