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