xref: /dflybsd-src/contrib/dhcpcd/src/script.c (revision 0aaf6155b4aaa728f5de058c78a7ee8f58d79b6b)
1d4fb1e02SRoy Marples /* SPDX-License-Identifier: BSD-2-Clause */
27827cba2SAaron LI /*
37827cba2SAaron LI  * dhcpcd - DHCP client daemon
46e63cc1fSRoy Marples  * Copyright (c) 2006-2020 Roy Marples <roy@marples.name>
57827cba2SAaron LI  * All rights reserved
67827cba2SAaron LI 
77827cba2SAaron LI  * Redistribution and use in source and binary forms, with or without
87827cba2SAaron LI  * modification, are permitted provided that the following conditions
97827cba2SAaron LI  * are met:
107827cba2SAaron LI  * 1. Redistributions of source code must retain the above copyright
117827cba2SAaron LI  *    notice, this list of conditions and the following disclaimer.
127827cba2SAaron LI  * 2. Redistributions in binary form must reproduce the above copyright
137827cba2SAaron LI  *    notice, this list of conditions and the following disclaimer in the
147827cba2SAaron LI  *    documentation and/or other materials provided with the distribution.
157827cba2SAaron LI  *
167827cba2SAaron LI  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
177827cba2SAaron LI  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
187827cba2SAaron LI  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
197827cba2SAaron LI  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
207827cba2SAaron LI  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
217827cba2SAaron LI  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
227827cba2SAaron LI  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
237827cba2SAaron LI  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
247827cba2SAaron LI  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
257827cba2SAaron LI  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
267827cba2SAaron LI  * SUCH DAMAGE.
277827cba2SAaron LI  */
287827cba2SAaron LI 
297827cba2SAaron LI #include <sys/stat.h>
307827cba2SAaron LI #include <sys/uio.h>
317827cba2SAaron LI #include <sys/wait.h>
327827cba2SAaron LI 
337827cba2SAaron LI #include <netinet/in.h>
347827cba2SAaron LI #include <arpa/inet.h>
357827cba2SAaron LI 
368d36e1dfSRoy Marples #include <assert.h>
377827cba2SAaron LI #include <ctype.h>
387827cba2SAaron LI #include <errno.h>
396e63cc1fSRoy Marples #include <pwd.h>
407827cba2SAaron LI #include <signal.h>
417827cba2SAaron LI #include <spawn.h>
428d36e1dfSRoy Marples #include <stdarg.h>
437827cba2SAaron LI #include <stdlib.h>
447827cba2SAaron LI #include <string.h>
457827cba2SAaron LI #include <unistd.h>
467827cba2SAaron LI 
477827cba2SAaron LI #include "config.h"
487827cba2SAaron LI #include "common.h"
497827cba2SAaron LI #include "dhcp.h"
507827cba2SAaron LI #include "dhcp6.h"
516e63cc1fSRoy Marples #include "eloop.h"
527827cba2SAaron LI #include "if.h"
537827cba2SAaron LI #include "if-options.h"
547827cba2SAaron LI #include "ipv4ll.h"
557827cba2SAaron LI #include "ipv6nd.h"
567827cba2SAaron LI #include "logerr.h"
576e63cc1fSRoy Marples #include "privsep.h"
587827cba2SAaron LI #include "script.h"
597827cba2SAaron LI 
608d36e1dfSRoy Marples #define DEFAULT_PATH	"/usr/bin:/usr/sbin:/bin:/sbin"
617827cba2SAaron LI 
627827cba2SAaron LI static const char * const if_params[] = {
637827cba2SAaron LI 	"interface",
647827cba2SAaron LI 	"protocol",
657827cba2SAaron LI 	"reason",
667827cba2SAaron LI 	"pid",
677827cba2SAaron LI 	"ifcarrier",
687827cba2SAaron LI 	"ifmetric",
697827cba2SAaron LI 	"ifwireless",
707827cba2SAaron LI 	"ifflags",
717827cba2SAaron LI 	"ssid",
727827cba2SAaron LI 	"profile",
737827cba2SAaron LI 	"interface_order",
747827cba2SAaron LI 	NULL
757827cba2SAaron LI };
767827cba2SAaron LI 
77*0aaf6155SRoy Marples static const char * true_str = "true";
78*0aaf6155SRoy Marples static const char * false_str = "false";
79*0aaf6155SRoy Marples 
807827cba2SAaron LI void
817827cba2SAaron LI if_printoptions(void)
827827cba2SAaron LI {
837827cba2SAaron LI 	const char * const *p;
847827cba2SAaron LI 
857827cba2SAaron LI 	for (p = if_params; *p; p++)
867827cba2SAaron LI 		printf(" -  %s\n", *p);
877827cba2SAaron LI }
887827cba2SAaron LI 
896e63cc1fSRoy Marples pid_t
90280986e4SRoy Marples script_exec(char *const *argv, char *const *env)
917827cba2SAaron LI {
92b9ccd228SRoy Marples 	pid_t pid = 0;
937827cba2SAaron LI 	posix_spawnattr_t attr;
947827cba2SAaron LI 	int r;
957827cba2SAaron LI #ifdef USE_SIGNALS
967827cba2SAaron LI 	size_t i;
977827cba2SAaron LI 	short flags;
987827cba2SAaron LI 	sigset_t defsigs;
997827cba2SAaron LI #else
1007827cba2SAaron LI 	UNUSED(ctx);
1017827cba2SAaron LI #endif
1027827cba2SAaron LI 
1037827cba2SAaron LI 	/* posix_spawn is a safe way of executing another image
1047827cba2SAaron LI 	 * and changing signals back to how they should be. */
1057827cba2SAaron LI 	if (posix_spawnattr_init(&attr) == -1)
1067827cba2SAaron LI 		return -1;
1077827cba2SAaron LI #ifdef USE_SIGNALS
1087827cba2SAaron LI 	flags = POSIX_SPAWN_SETSIGMASK | POSIX_SPAWN_SETSIGDEF;
1097827cba2SAaron LI 	posix_spawnattr_setflags(&attr, flags);
1107827cba2SAaron LI 	sigemptyset(&defsigs);
111280986e4SRoy Marples 	posix_spawnattr_setsigmask(&attr, &defsigs);
1127827cba2SAaron LI 	for (i = 0; i < dhcpcd_signals_len; i++)
1137827cba2SAaron LI 		sigaddset(&defsigs, dhcpcd_signals[i]);
114d4fb1e02SRoy Marples 	for (i = 0; i < dhcpcd_signals_ignore_len; i++)
115d4fb1e02SRoy Marples 		sigaddset(&defsigs, dhcpcd_signals_ignore[i]);
1167827cba2SAaron LI 	posix_spawnattr_setsigdefault(&attr, &defsigs);
1177827cba2SAaron LI #endif
1187827cba2SAaron LI 	errno = 0;
1197827cba2SAaron LI 	r = posix_spawn(&pid, argv[0], NULL, &attr, argv, env);
1207827cba2SAaron LI 	posix_spawnattr_destroy(&attr);
1217827cba2SAaron LI 	if (r) {
1227827cba2SAaron LI 		errno = r;
1237827cba2SAaron LI 		return -1;
1247827cba2SAaron LI 	}
1257827cba2SAaron LI 	return pid;
1267827cba2SAaron LI }
1277827cba2SAaron LI 
1287827cba2SAaron LI #ifdef INET
1297827cba2SAaron LI static int
1308d36e1dfSRoy Marples append_config(FILE *fp, const char *prefix, const char *const *config)
1317827cba2SAaron LI {
1328d36e1dfSRoy Marples 	size_t i;
1337827cba2SAaron LI 
1347827cba2SAaron LI 	if (config == NULL)
1357827cba2SAaron LI 		return 0;
1367827cba2SAaron LI 
1378d36e1dfSRoy Marples 	/* Do we need to replace existing config rather than append? */
1387827cba2SAaron LI 	for (i = 0; config[i] != NULL; i++) {
1398d36e1dfSRoy Marples 		if (efprintf(fp, "%s_%s", prefix, config[i]) == -1)
1407827cba2SAaron LI 			return -1;
1417827cba2SAaron LI 	}
1428d36e1dfSRoy Marples 	return 1;
1437827cba2SAaron LI }
1447827cba2SAaron LI 
1458d36e1dfSRoy Marples #endif
1468d36e1dfSRoy Marples 
1477827cba2SAaron LI #define	PROTO_LINK	0
1487827cba2SAaron LI #define	PROTO_DHCP	1
1497827cba2SAaron LI #define	PROTO_IPV4LL	2
1507827cba2SAaron LI #define	PROTO_RA	3
1517827cba2SAaron LI #define	PROTO_DHCP6	4
1527827cba2SAaron LI #define	PROTO_STATIC6	5
1537827cba2SAaron LI static const char *protocols[] = {
1547827cba2SAaron LI 	"link",
1557827cba2SAaron LI 	"dhcp",
1567827cba2SAaron LI 	"ipv4ll",
1577827cba2SAaron LI 	"ra",
1587827cba2SAaron LI 	"dhcp6",
1597827cba2SAaron LI 	"static6"
1607827cba2SAaron LI };
1617827cba2SAaron LI 
1628d36e1dfSRoy Marples int
1638d36e1dfSRoy Marples efprintf(FILE *fp, const char *fmt, ...)
1647827cba2SAaron LI {
1658d36e1dfSRoy Marples 	va_list args;
1668d36e1dfSRoy Marples 	int r;
1678d36e1dfSRoy Marples 
1688d36e1dfSRoy Marples 	va_start(args, fmt);
1698d36e1dfSRoy Marples 	r = vfprintf(fp, fmt, args);
1708d36e1dfSRoy Marples 	va_end(args);
1718d36e1dfSRoy Marples 	if (r == -1)
1728d36e1dfSRoy Marples 		return -1;
1738d36e1dfSRoy Marples 	/* Write a trailing NULL so we can easily create env strings. */
1748d36e1dfSRoy Marples 	if (fputc('\0', fp) == EOF)
1758d36e1dfSRoy Marples 		return -1;
1768d36e1dfSRoy Marples 	return r;
1778d36e1dfSRoy Marples }
1788d36e1dfSRoy Marples 
1796e63cc1fSRoy Marples char **
180b9ccd228SRoy Marples script_buftoenv(struct dhcpcd_ctx *ctx, char *buf, size_t len)
181b9ccd228SRoy Marples {
182b9ccd228SRoy Marples 	char **env, **envp, *bufp, *endp;
183b9ccd228SRoy Marples 	size_t nenv;
184b9ccd228SRoy Marples 
185b9ccd228SRoy Marples 	/* Count the terminated env strings.
186b9ccd228SRoy Marples 	 * Assert that the terminations are correct. */
187b9ccd228SRoy Marples 	nenv = 0;
188b9ccd228SRoy Marples 	endp = buf + len;
189b9ccd228SRoy Marples 	for (bufp = buf; bufp < endp; bufp++) {
190b9ccd228SRoy Marples 		if (*bufp == '\0') {
191b9ccd228SRoy Marples #ifndef NDEBUG
192b9ccd228SRoy Marples 			if (bufp + 1 < endp)
193b9ccd228SRoy Marples 				assert(*(bufp + 1) != '\0');
194b9ccd228SRoy Marples #endif
195b9ccd228SRoy Marples 			nenv++;
196b9ccd228SRoy Marples 		}
197b9ccd228SRoy Marples 	}
198b9ccd228SRoy Marples 	assert(*(bufp - 1) == '\0');
199d4fb1e02SRoy Marples 	if (nenv == 0)
200d4fb1e02SRoy Marples 		return NULL;
201b9ccd228SRoy Marples 
202b9ccd228SRoy Marples 	if (ctx->script_envlen < nenv) {
203b9ccd228SRoy Marples 		env = reallocarray(ctx->script_env, nenv + 1, sizeof(*env));
204b9ccd228SRoy Marples 		if (env == NULL)
205b9ccd228SRoy Marples 			return NULL;
206b9ccd228SRoy Marples 		ctx->script_env = env;
207b9ccd228SRoy Marples 		ctx->script_envlen = nenv;
208b9ccd228SRoy Marples 	}
209b9ccd228SRoy Marples 
210b9ccd228SRoy Marples 	bufp = buf;
211b9ccd228SRoy Marples 	envp = ctx->script_env;
212b9ccd228SRoy Marples 	*envp++ = bufp++;
213b9ccd228SRoy Marples 	endp--; /* Avoid setting the last \0 to an invalid pointer */
214b9ccd228SRoy Marples 	for (; bufp < endp; bufp++) {
215b9ccd228SRoy Marples 		if (*bufp == '\0')
216b9ccd228SRoy Marples 			*envp++ = bufp + 1;
217b9ccd228SRoy Marples 	}
218b9ccd228SRoy Marples 	*envp = NULL;
219b9ccd228SRoy Marples 
220b9ccd228SRoy Marples 	return ctx->script_env;
221b9ccd228SRoy Marples }
222b9ccd228SRoy Marples 
2238d36e1dfSRoy Marples static long
2246e63cc1fSRoy Marples make_env(struct dhcpcd_ctx *ctx, const struct interface *ifp,
2256e63cc1fSRoy Marples     const char *reason)
2268d36e1dfSRoy Marples {
2278d36e1dfSRoy Marples 	FILE *fp;
2288d36e1dfSRoy Marples 	long buf_pos, i;
229b9ccd228SRoy Marples 	char *path;
2308d36e1dfSRoy Marples 	int protocol = PROTO_LINK;
2316e63cc1fSRoy Marples 	const struct if_options *ifo;
2327827cba2SAaron LI 	const struct interface *ifp2;
2337827cba2SAaron LI 	int af;
234*0aaf6155SRoy Marples 	bool is_stdin = ifp->name[0] == '\0';
235*0aaf6155SRoy Marples 	const char *if_up, *if_down;
236*0aaf6155SRoy Marples 	rb_tree_t ifaces;
237*0aaf6155SRoy Marples 	struct rt *rt;
2387827cba2SAaron LI #ifdef INET
2397827cba2SAaron LI 	const struct dhcp_state *state;
2407827cba2SAaron LI #ifdef IPV4LL
2417827cba2SAaron LI 	const struct ipv4ll_state *istate;
2427827cba2SAaron LI #endif
2437827cba2SAaron LI #endif
2448d36e1dfSRoy Marples #ifdef DHCP6
2457827cba2SAaron LI 	const struct dhcp6_state *d6_state;
2467827cba2SAaron LI #endif
2477827cba2SAaron LI 
2488d36e1dfSRoy Marples #ifdef HAVE_OPEN_MEMSTREAM
2498d36e1dfSRoy Marples 	if (ctx->script_fp == NULL) {
2508d36e1dfSRoy Marples 		fp = open_memstream(&ctx->script_buf, &ctx->script_buflen);
2518d36e1dfSRoy Marples 		if (fp == NULL)
2528d36e1dfSRoy Marples 			goto eexit;
2538d36e1dfSRoy Marples 		ctx->script_fp = fp;
2548d36e1dfSRoy Marples 	} else {
2558d36e1dfSRoy Marples 		fp = ctx->script_fp;
2568d36e1dfSRoy Marples 		rewind(fp);
2578d36e1dfSRoy Marples 	}
2588d36e1dfSRoy Marples #else
2598d36e1dfSRoy Marples 	char tmpfile[] = "/tmp/dhcpcd-script-env-XXXXXX";
2608d36e1dfSRoy Marples 	int tmpfd;
2618d36e1dfSRoy Marples 
2628d36e1dfSRoy Marples 	fp = NULL;
2638d36e1dfSRoy Marples 	tmpfd = mkstemp(tmpfile);
264d4fb1e02SRoy Marples 	if (tmpfd == -1) {
265d4fb1e02SRoy Marples 		logerr("%s: mkstemp", __func__);
266d4fb1e02SRoy Marples 		return -1;
267d4fb1e02SRoy Marples 	}
2688d36e1dfSRoy Marples 	unlink(tmpfile);
2698d36e1dfSRoy Marples 	fp = fdopen(tmpfd, "w+");
2708d36e1dfSRoy Marples 	if (fp == NULL) {
2718d36e1dfSRoy Marples 		close(tmpfd);
2728d36e1dfSRoy Marples 		goto eexit;
2738d36e1dfSRoy Marples 	}
2748d36e1dfSRoy Marples #endif
2758d36e1dfSRoy Marples 
276d4fb1e02SRoy Marples 	if (!(ifp->ctx->options & DHCPCD_DUMPLEASE)) {
2776e63cc1fSRoy Marples 		/* Needed for scripts */
2786e63cc1fSRoy Marples 		path = getenv("PATH");
279d4fb1e02SRoy Marples 		if (efprintf(fp, "PATH=%s",
280d4fb1e02SRoy Marples 		    path == NULL ? DEFAULT_PATH : path) == -1)
2816e63cc1fSRoy Marples 			goto eexit;
2826e63cc1fSRoy Marples 		if (efprintf(fp, "pid=%d", getpid()) == -1)
2836e63cc1fSRoy Marples 			goto eexit;
284d4fb1e02SRoy Marples 	}
285*0aaf6155SRoy Marples 
286d4fb1e02SRoy Marples 	if (!is_stdin) {
287d4fb1e02SRoy Marples 		if (efprintf(fp, "reason=%s", reason) == -1)
2886e63cc1fSRoy Marples 			goto eexit;
2896e63cc1fSRoy Marples 	}
2906e63cc1fSRoy Marples 
2916e63cc1fSRoy Marples 	ifo = ifp->options;
2927827cba2SAaron LI #ifdef INET
2937827cba2SAaron LI 	state = D_STATE(ifp);
2947827cba2SAaron LI #ifdef IPV4LL
2957827cba2SAaron LI 	istate = IPV4LL_CSTATE(ifp);
2967827cba2SAaron LI #endif
2977827cba2SAaron LI #endif
2988d36e1dfSRoy Marples #ifdef DHCP6
2997827cba2SAaron LI 	d6_state = D6_CSTATE(ifp);
3007827cba2SAaron LI #endif
3017827cba2SAaron LI 	if (strcmp(reason, "TEST") == 0) {
3026e63cc1fSRoy Marples 		if (1 == 2) {
3036e63cc1fSRoy Marples 			/* This space left intentionally blank
3046e63cc1fSRoy Marples 			 * as all the below statements are optional. */
3056e63cc1fSRoy Marples 		}
3067827cba2SAaron LI #ifdef INET6
3078d36e1dfSRoy Marples #ifdef DHCP6
3087827cba2SAaron LI 		else if (d6_state && d6_state->new)
3097827cba2SAaron LI 			protocol = PROTO_DHCP6;
3108d36e1dfSRoy Marples #endif
3117827cba2SAaron LI 		else if (ipv6nd_hasra(ifp))
3127827cba2SAaron LI 			protocol = PROTO_RA;
3137827cba2SAaron LI #endif
3147827cba2SAaron LI #ifdef INET
3157827cba2SAaron LI #ifdef IPV4LL
3167827cba2SAaron LI 		else if (istate && istate->addr != NULL)
3177827cba2SAaron LI 			protocol = PROTO_IPV4LL;
3187827cba2SAaron LI #endif
3197827cba2SAaron LI 		else
3207827cba2SAaron LI 			protocol = PROTO_DHCP;
3217827cba2SAaron LI #endif
3227827cba2SAaron LI 	}
3237827cba2SAaron LI #ifdef INET6
3247827cba2SAaron LI 	else if (strcmp(reason, "STATIC6") == 0)
3257827cba2SAaron LI 		protocol = PROTO_STATIC6;
3268d36e1dfSRoy Marples #ifdef DHCP6
3277827cba2SAaron LI 	else if (reason[strlen(reason) - 1] == '6')
3287827cba2SAaron LI 		protocol = PROTO_DHCP6;
3298d36e1dfSRoy Marples #endif
3307827cba2SAaron LI 	else if (strcmp(reason, "ROUTERADVERT") == 0)
3317827cba2SAaron LI 		protocol = PROTO_RA;
3327827cba2SAaron LI #endif
3337827cba2SAaron LI 	else if (strcmp(reason, "PREINIT") == 0 ||
3347827cba2SAaron LI 	    strcmp(reason, "CARRIER") == 0 ||
3357827cba2SAaron LI 	    strcmp(reason, "NOCARRIER") == 0 ||
336*0aaf6155SRoy Marples 	    strcmp(reason, "NOCARRIER_ROAMING") == 0 ||
3377827cba2SAaron LI 	    strcmp(reason, "UNKNOWN") == 0 ||
3387827cba2SAaron LI 	    strcmp(reason, "DEPARTED") == 0 ||
3397827cba2SAaron LI 	    strcmp(reason, "STOPPED") == 0)
3407827cba2SAaron LI 		protocol = PROTO_LINK;
3417827cba2SAaron LI #ifdef INET
3427827cba2SAaron LI #ifdef IPV4LL
3437827cba2SAaron LI 	else if (strcmp(reason, "IPV4LL") == 0)
3447827cba2SAaron LI 		protocol = PROTO_IPV4LL;
3457827cba2SAaron LI #endif
3467827cba2SAaron LI 	else
3477827cba2SAaron LI 		protocol = PROTO_DHCP;
3487827cba2SAaron LI #endif
3497827cba2SAaron LI 
350d4fb1e02SRoy Marples 	if (!is_stdin) {
3518d36e1dfSRoy Marples 		if (efprintf(fp, "interface=%s", ifp->name) == -1)
3528d36e1dfSRoy Marples 			goto eexit;
353cc34ba0cSRoy Marples 		if (protocols[protocol] != NULL) {
354cc34ba0cSRoy Marples 			if (efprintf(fp, "protocol=%s",
355cc34ba0cSRoy Marples 			    protocols[protocol]) == -1)
356cc34ba0cSRoy Marples 				goto eexit;
357d4fb1e02SRoy Marples 		}
358cc34ba0cSRoy Marples 	}
359cc34ba0cSRoy Marples 	if (ifp->ctx->options & DHCPCD_DUMPLEASE && protocol != PROTO_LINK)
3607827cba2SAaron LI 		goto dumplease;
361b2927f2bSRoy Marples 	if (efprintf(fp, "if_configured=%s",
362b2927f2bSRoy Marples 	    ifo->options & DHCPCD_CONFIGURE ? "true" : "false") == -1)
363b2927f2bSRoy Marples 		goto eexit;
3648d36e1dfSRoy Marples 	if (efprintf(fp, "ifcarrier=%s",
3657827cba2SAaron LI 	    ifp->carrier == LINK_UNKNOWN ? "unknown" :
3668d36e1dfSRoy Marples 	    ifp->carrier == LINK_UP ? "up" : "down") == -1)
3678d36e1dfSRoy Marples 		goto eexit;
3688d36e1dfSRoy Marples 	if (efprintf(fp, "ifmetric=%d", ifp->metric) == -1)
3698d36e1dfSRoy Marples 		goto eexit;
3708d36e1dfSRoy Marples 	if (efprintf(fp, "ifwireless=%d", ifp->wireless) == -1)
3718d36e1dfSRoy Marples 		goto eexit;
3728d36e1dfSRoy Marples 	if (efprintf(fp, "ifflags=%u", ifp->flags) == -1)
3738d36e1dfSRoy Marples 		goto eexit;
3748d36e1dfSRoy Marples 	if (efprintf(fp, "ifmtu=%d", if_getmtu(ifp)) == -1)
3758d36e1dfSRoy Marples 		goto eexit;
376cc34ba0cSRoy Marples 	if (ifp->wireless) {
377cc34ba0cSRoy Marples 		char pssid[IF_SSIDLEN * 4];
378cc34ba0cSRoy Marples 
379cc34ba0cSRoy Marples 		if (print_string(pssid, sizeof(pssid), OT_ESCSTRING,
380cc34ba0cSRoy Marples 		    ifp->ssid, ifp->ssid_len) != -1)
381cc34ba0cSRoy Marples 		{
382cc34ba0cSRoy Marples 			if (efprintf(fp, "ifssid=%s", pssid) == -1)
383cc34ba0cSRoy Marples 				goto eexit;
384cc34ba0cSRoy Marples 		}
385cc34ba0cSRoy Marples 	}
386cc34ba0cSRoy Marples 	if (*ifp->profile != '\0') {
387cc34ba0cSRoy Marples 		if (efprintf(fp, "profile=%s", ifp->profile) == -1)
388cc34ba0cSRoy Marples 			goto eexit;
389cc34ba0cSRoy Marples 	}
390cc34ba0cSRoy Marples 	if (ifp->ctx->options & DHCPCD_DUMPLEASE)
391cc34ba0cSRoy Marples 		goto dumplease;
3928d36e1dfSRoy Marples 
393*0aaf6155SRoy Marples 	rb_tree_init(&ifaces, &rt_compare_proto_ops);
394*0aaf6155SRoy Marples 	TAILQ_FOREACH(ifp2, ifp->ctx->ifaces, next) {
395*0aaf6155SRoy Marples 		if (!ifp2->active)
396*0aaf6155SRoy Marples 			continue;
397*0aaf6155SRoy Marples 		rt = rt_new(UNCONST(ifp2));
398*0aaf6155SRoy Marples 		if (rt == NULL)
399*0aaf6155SRoy Marples 			goto eexit;
400*0aaf6155SRoy Marples 		if (rb_tree_insert_node(&ifaces, rt) != rt)
401*0aaf6155SRoy Marples 			goto eexit;
402*0aaf6155SRoy Marples 	}
4038d36e1dfSRoy Marples 	if (fprintf(fp, "interface_order=") == -1)
4048d36e1dfSRoy Marples 		goto eexit;
405*0aaf6155SRoy Marples 	RB_TREE_FOREACH(rt, &ifaces) {
406*0aaf6155SRoy Marples 		if (rt != RB_TREE_MIN(&ifaces) &&
407*0aaf6155SRoy Marples 		    fprintf(fp, "%s", " ") == -1)
408*0aaf6155SRoy Marples 			goto eexit;
409*0aaf6155SRoy Marples 		if (fprintf(fp, "%s", rt->rt_ifp->name) == -1)
410*0aaf6155SRoy Marples 			goto eexit;
4117827cba2SAaron LI 	}
412*0aaf6155SRoy Marples 	rt_headclear(&ifaces, AF_UNSPEC);
4138d36e1dfSRoy Marples 	if (fputc('\0', fp) == EOF)
414*0aaf6155SRoy Marples 		goto eexit;
4158d36e1dfSRoy Marples 
4167827cba2SAaron LI 	if (strcmp(reason, "STOPPED") == 0) {
417*0aaf6155SRoy Marples 		if_up = false_str;
418*0aaf6155SRoy Marples 		if_down = ifo->options & DHCPCD_RELEASE ? true_str : false_str;
4197827cba2SAaron LI 	} else if (strcmp(reason, "TEST") == 0 ||
4207827cba2SAaron LI 	    strcmp(reason, "PREINIT") == 0 ||
4217827cba2SAaron LI 	    strcmp(reason, "CARRIER") == 0 ||
4227827cba2SAaron LI 	    strcmp(reason, "UNKNOWN") == 0)
4237827cba2SAaron LI 	{
424*0aaf6155SRoy Marples 		if_up = false_str;
425*0aaf6155SRoy Marples 		if_down = false_str;
426*0aaf6155SRoy Marples 	} else if (strcmp(reason, "NOCARRIER") == 0) {
427*0aaf6155SRoy Marples 		if_up = false_str;
428*0aaf6155SRoy Marples 		if_down = true_str;
429*0aaf6155SRoy Marples 	} else if (strcmp(reason, "NOCARRIER_ROAMING") == 0) {
430*0aaf6155SRoy Marples 		if_up = true_str;
431*0aaf6155SRoy Marples 		if_down = false_str;
4327827cba2SAaron LI 	} else if (1 == 2 /* appease ifdefs */
4337827cba2SAaron LI #ifdef INET
4347827cba2SAaron LI 	    || (protocol == PROTO_DHCP && state && state->new)
4357827cba2SAaron LI #ifdef IPV4LL
4367827cba2SAaron LI 	    || (protocol == PROTO_IPV4LL && IPV4LL_STATE_RUNNING(ifp))
4377827cba2SAaron LI #endif
4387827cba2SAaron LI #endif
4397827cba2SAaron LI #ifdef INET6
4407827cba2SAaron LI 	    || (protocol == PROTO_STATIC6 && IPV6_STATE_RUNNING(ifp))
4418d36e1dfSRoy Marples #ifdef DHCP6
4427827cba2SAaron LI 	    || (protocol == PROTO_DHCP6 && d6_state && d6_state->new)
4438d36e1dfSRoy Marples #endif
4447827cba2SAaron LI 	    || (protocol == PROTO_RA && ipv6nd_hasra(ifp))
4457827cba2SAaron LI #endif
4467827cba2SAaron LI 	    )
4477827cba2SAaron LI 	{
448*0aaf6155SRoy Marples 		if_up = true_str;
449*0aaf6155SRoy Marples 		if_down = false_str;
4507827cba2SAaron LI 	} else {
451*0aaf6155SRoy Marples 		if_up = false_str;
452*0aaf6155SRoy Marples 		if_down = true_str;
4537827cba2SAaron LI 	}
454*0aaf6155SRoy Marples 	if (efprintf(fp, "if_up=%s", if_up) == -1)
455*0aaf6155SRoy Marples 		goto eexit;
456*0aaf6155SRoy Marples 	if (efprintf(fp, "if_down=%s", if_down) == -1)
457*0aaf6155SRoy Marples 		goto eexit;
458*0aaf6155SRoy Marples 
4597827cba2SAaron LI 	if ((af = dhcpcd_ifafwaiting(ifp)) != AF_MAX) {
4608d36e1dfSRoy Marples 		if (efprintf(fp, "if_afwaiting=%d", af) == -1)
4618d36e1dfSRoy Marples 			goto eexit;
4627827cba2SAaron LI 	}
4637827cba2SAaron LI 	if ((af = dhcpcd_afwaiting(ifp->ctx)) != AF_MAX) {
4647827cba2SAaron LI 		TAILQ_FOREACH(ifp2, ifp->ctx->ifaces, next) {
4657827cba2SAaron LI 			if ((af = dhcpcd_ifafwaiting(ifp2)) != AF_MAX)
4667827cba2SAaron LI 				break;
4677827cba2SAaron LI 		}
4687827cba2SAaron LI 	}
4697827cba2SAaron LI 	if (af != AF_MAX) {
4708d36e1dfSRoy Marples 		if (efprintf(fp, "af_waiting=%d", af) == -1)
4718d36e1dfSRoy Marples 			goto eexit;
4727827cba2SAaron LI 	}
4737827cba2SAaron LI 	if (ifo->options & DHCPCD_DEBUG) {
4748d36e1dfSRoy Marples 		if (efprintf(fp, "syslog_debug=true") == -1)
4758d36e1dfSRoy Marples 			goto eexit;
4767827cba2SAaron LI 	}
4777827cba2SAaron LI #ifdef INET
4787827cba2SAaron LI 	if (protocol == PROTO_DHCP && state && state->old) {
4798d36e1dfSRoy Marples 		if (dhcp_env(fp, "old", ifp,
4808d36e1dfSRoy Marples 		    state->old, state->old_len) == -1)
4817827cba2SAaron LI 			goto eexit;
4828d36e1dfSRoy Marples 		if (append_config(fp, "old",
4837827cba2SAaron LI 		    (const char *const *)ifo->config) == -1)
4847827cba2SAaron LI 			goto eexit;
4857827cba2SAaron LI 	}
4867827cba2SAaron LI #endif
4878d36e1dfSRoy Marples #ifdef DHCP6
4887827cba2SAaron LI 	if (protocol == PROTO_DHCP6 && d6_state && d6_state->old) {
4898d36e1dfSRoy Marples 		if (dhcp6_env(fp, "old", ifp,
4908d36e1dfSRoy Marples 		    d6_state->old, d6_state->old_len) == -1)
4917827cba2SAaron LI 			goto eexit;
4927827cba2SAaron LI 	}
4937827cba2SAaron LI #endif
4947827cba2SAaron LI 
4957827cba2SAaron LI dumplease:
4967827cba2SAaron LI #ifdef INET
4977827cba2SAaron LI #ifdef IPV4LL
4986e63cc1fSRoy Marples 	if (protocol == PROTO_IPV4LL && istate) {
4998d36e1dfSRoy Marples 		if (ipv4ll_env(fp, istate->down ? "old" : "new", ifp) == -1)
5007827cba2SAaron LI 			goto eexit;
5017827cba2SAaron LI 	}
5027827cba2SAaron LI #endif
5037827cba2SAaron LI 	if (protocol == PROTO_DHCP && state && state->new) {
5048d36e1dfSRoy Marples 		if (dhcp_env(fp, "new", ifp,
5058d36e1dfSRoy Marples 		    state->new, state->new_len) == -1)
5067827cba2SAaron LI 			goto eexit;
5078d36e1dfSRoy Marples 		if (append_config(fp, "new",
5087827cba2SAaron LI 		    (const char *const *)ifo->config) == -1)
5097827cba2SAaron LI 			goto eexit;
5107827cba2SAaron LI 	}
5117827cba2SAaron LI #endif
5127827cba2SAaron LI #ifdef INET6
5137827cba2SAaron LI 	if (protocol == PROTO_STATIC6) {
5148d36e1dfSRoy Marples 		if (ipv6_env(fp, "new", ifp) == -1)
5157827cba2SAaron LI 			goto eexit;
5167827cba2SAaron LI 	}
5178d36e1dfSRoy Marples #ifdef DHCP6
5187827cba2SAaron LI 	if (protocol == PROTO_DHCP6 && D6_STATE_RUNNING(ifp)) {
5198d36e1dfSRoy Marples 		if (dhcp6_env(fp, "new", ifp,
5208d36e1dfSRoy Marples 		    d6_state->new, d6_state->new_len) == -1)
5217827cba2SAaron LI 			goto eexit;
5227827cba2SAaron LI 	}
5238d36e1dfSRoy Marples #endif
5247827cba2SAaron LI 	if (protocol == PROTO_RA) {
5258d36e1dfSRoy Marples 		if (ipv6nd_env(fp, ifp) == -1)
5267827cba2SAaron LI 			goto eexit;
5277827cba2SAaron LI 	}
5287827cba2SAaron LI #endif
5297827cba2SAaron LI 
5307827cba2SAaron LI 	/* Add our base environment */
5317827cba2SAaron LI 	if (ifo->environ) {
5328d36e1dfSRoy Marples 		for (i = 0; ifo->environ[i] != NULL; i++)
5338d36e1dfSRoy Marples 			if (efprintf(fp, "%s", ifo->environ[i]) == -1)
5347827cba2SAaron LI 				goto eexit;
5357827cba2SAaron LI 	}
5367827cba2SAaron LI 
5378d36e1dfSRoy Marples 	/* Convert buffer to argv */
5388d36e1dfSRoy Marples 	fflush(fp);
5398d36e1dfSRoy Marples 
5408d36e1dfSRoy Marples 	buf_pos = ftell(fp);
5418d36e1dfSRoy Marples 	if (buf_pos == -1) {
5428d36e1dfSRoy Marples 		logerr(__func__);
5438d36e1dfSRoy Marples 		goto eexit;
5448d36e1dfSRoy Marples 	}
5458d36e1dfSRoy Marples 
5468d36e1dfSRoy Marples #ifndef HAVE_OPEN_MEMSTREAM
5478d36e1dfSRoy Marples 	size_t buf_len = (size_t)buf_pos;
5488d36e1dfSRoy Marples 	if (ctx->script_buflen < buf_len) {
5498d36e1dfSRoy Marples 		char *buf = realloc(ctx->script_buf, buf_len);
5508d36e1dfSRoy Marples 		if (buf == NULL)
5518d36e1dfSRoy Marples 			goto eexit;
5528d36e1dfSRoy Marples 		ctx->script_buf = buf;
5538d36e1dfSRoy Marples 		ctx->script_buflen = buf_len;
5548d36e1dfSRoy Marples 	}
5558d36e1dfSRoy Marples 	rewind(fp);
5568d36e1dfSRoy Marples 	if (fread(ctx->script_buf, sizeof(char), buf_len, fp) != buf_len)
5578d36e1dfSRoy Marples 		goto eexit;
5588d36e1dfSRoy Marples 	fclose(fp);
5598d36e1dfSRoy Marples 	fp = NULL;
5608d36e1dfSRoy Marples #endif
5618d36e1dfSRoy Marples 
562d4fb1e02SRoy Marples 	if (is_stdin)
563d4fb1e02SRoy Marples 		return buf_pos;
564d4fb1e02SRoy Marples 
565b9ccd228SRoy Marples 	if (script_buftoenv(ctx, ctx->script_buf, (size_t)buf_pos) == NULL)
5668d36e1dfSRoy Marples 		goto eexit;
5678d36e1dfSRoy Marples 
5686e63cc1fSRoy Marples 	return buf_pos;
5697827cba2SAaron LI 
5707827cba2SAaron LI eexit:
5717827cba2SAaron LI 	logerr(__func__);
5728d36e1dfSRoy Marples #ifndef HAVE_OPEN_MEMSTREAM
5738d36e1dfSRoy Marples 	if (fp != NULL)
5748d36e1dfSRoy Marples 		fclose(fp);
5758d36e1dfSRoy Marples #endif
5767827cba2SAaron LI 	return -1;
5777827cba2SAaron LI }
5787827cba2SAaron LI 
5797827cba2SAaron LI static int
5808d36e1dfSRoy Marples send_interface1(struct fd_list *fd, const struct interface *ifp,
5817827cba2SAaron LI     const char *reason)
5827827cba2SAaron LI {
5838d36e1dfSRoy Marples 	struct dhcpcd_ctx *ctx = ifp->ctx;
5848d36e1dfSRoy Marples 	long len;
5857827cba2SAaron LI 
5866e63cc1fSRoy Marples 	len = make_env(ifp->ctx, ifp, reason);
5878d36e1dfSRoy Marples 	if (len == -1)
5887827cba2SAaron LI 		return -1;
5897f8103cdSRoy Marples 	return control_queue(fd, ctx->script_buf, (size_t)len);
5907827cba2SAaron LI }
5917827cba2SAaron LI 
5927827cba2SAaron LI int
5936e63cc1fSRoy Marples send_interface(struct fd_list *fd, const struct interface *ifp, int af)
5947827cba2SAaron LI {
5957827cba2SAaron LI 	int retval = 0;
5967827cba2SAaron LI #ifdef INET
5977827cba2SAaron LI 	const struct dhcp_state *d;
5987827cba2SAaron LI #endif
5998d36e1dfSRoy Marples #ifdef DHCP6
6007827cba2SAaron LI 	const struct dhcp6_state *d6;
6017827cba2SAaron LI #endif
6027827cba2SAaron LI 
6036e63cc1fSRoy Marples #ifndef AF_LINK
6046e63cc1fSRoy Marples #define	AF_LINK	AF_PACKET
6056e63cc1fSRoy Marples #endif
6066e63cc1fSRoy Marples 
6076e63cc1fSRoy Marples 	if (af == AF_UNSPEC || af == AF_LINK) {
6086e63cc1fSRoy Marples 		const char *reason;
6096e63cc1fSRoy Marples 
6107827cba2SAaron LI 		switch (ifp->carrier) {
6117827cba2SAaron LI 		case LINK_UP:
6127827cba2SAaron LI 			reason = "CARRIER";
6137827cba2SAaron LI 			break;
6147827cba2SAaron LI 		case LINK_DOWN:
6157827cba2SAaron LI 			reason = "NOCARRIER";
6167827cba2SAaron LI 			break;
6177827cba2SAaron LI 		default:
6187827cba2SAaron LI 			reason = "UNKNOWN";
6197827cba2SAaron LI 			break;
6207827cba2SAaron LI 		}
6216e63cc1fSRoy Marples 		if (fd != NULL) {
6227827cba2SAaron LI 			if (send_interface1(fd, ifp, reason) == -1)
6237827cba2SAaron LI 				retval = -1;
6246e63cc1fSRoy Marples 		} else
6256e63cc1fSRoy Marples 			retval++;
6266e63cc1fSRoy Marples 	}
6276e63cc1fSRoy Marples 
6287827cba2SAaron LI #ifdef INET
6296e63cc1fSRoy Marples 	if (af == AF_UNSPEC || af == AF_INET) {
6307827cba2SAaron LI 		if (D_STATE_RUNNING(ifp)) {
6317827cba2SAaron LI 			d = D_CSTATE(ifp);
6326e63cc1fSRoy Marples 			if (fd != NULL) {
6337827cba2SAaron LI 				if (send_interface1(fd, ifp, d->reason) == -1)
6347827cba2SAaron LI 					retval = -1;
6356e63cc1fSRoy Marples 			} else
6366e63cc1fSRoy Marples 				retval++;
6377827cba2SAaron LI 		}
6387827cba2SAaron LI #ifdef IPV4LL
6397827cba2SAaron LI 		if (IPV4LL_STATE_RUNNING(ifp)) {
6406e63cc1fSRoy Marples 			if (fd != NULL) {
6417827cba2SAaron LI 				if (send_interface1(fd, ifp, "IPV4LL") == -1)
6427827cba2SAaron LI 					retval = -1;
6436e63cc1fSRoy Marples 			} else
6446e63cc1fSRoy Marples 				retval++;
6457827cba2SAaron LI 		}
6467827cba2SAaron LI #endif
6476e63cc1fSRoy Marples 	}
6487827cba2SAaron LI #endif
6497827cba2SAaron LI 
6507827cba2SAaron LI #ifdef INET6
6516e63cc1fSRoy Marples 	if (af == AF_UNSPEC || af == AF_INET6) {
6527827cba2SAaron LI 		if (IPV6_STATE_RUNNING(ifp)) {
6536e63cc1fSRoy Marples 			if (fd != NULL) {
6547827cba2SAaron LI 				if (send_interface1(fd, ifp, "STATIC6") == -1)
6557827cba2SAaron LI 					retval = -1;
6566e63cc1fSRoy Marples 			} else
6576e63cc1fSRoy Marples 				retval++;
6587827cba2SAaron LI 		}
6597827cba2SAaron LI 		if (RS_STATE_RUNNING(ifp)) {
6606e63cc1fSRoy Marples 			if (fd != NULL) {
6616e63cc1fSRoy Marples 				if (send_interface1(fd, ifp,
6626e63cc1fSRoy Marples 				    "ROUTERADVERT") == -1)
6637827cba2SAaron LI 					retval = -1;
6646e63cc1fSRoy Marples 			} else
6656e63cc1fSRoy Marples 				retval++;
6667827cba2SAaron LI 		}
6678d36e1dfSRoy Marples #ifdef DHCP6
6687827cba2SAaron LI 		if (D6_STATE_RUNNING(ifp)) {
6697827cba2SAaron LI 			d6 = D6_CSTATE(ifp);
6706e63cc1fSRoy Marples 			if (fd != NULL) {
6717827cba2SAaron LI 				if (send_interface1(fd, ifp, d6->reason) == -1)
6727827cba2SAaron LI 					retval = -1;
6736e63cc1fSRoy Marples 			} else
6746e63cc1fSRoy Marples 				retval++;
6757827cba2SAaron LI 		}
6767827cba2SAaron LI #endif
6776e63cc1fSRoy Marples 	}
6788d36e1dfSRoy Marples #endif
6797827cba2SAaron LI 
6807827cba2SAaron LI 	return retval;
6817827cba2SAaron LI }
6827827cba2SAaron LI 
6836e63cc1fSRoy Marples static int
6846e63cc1fSRoy Marples script_run(struct dhcpcd_ctx *ctx, char **argv)
6857827cba2SAaron LI {
6867827cba2SAaron LI 	pid_t pid;
6877827cba2SAaron LI 	int status = 0;
6887827cba2SAaron LI 
689280986e4SRoy Marples 	pid = script_exec(argv, ctx->script_env);
6907827cba2SAaron LI 	if (pid == -1)
6917827cba2SAaron LI 		logerr("%s: %s", __func__, argv[0]);
6927827cba2SAaron LI 	else if (pid != 0) {
6937827cba2SAaron LI 		/* Wait for the script to finish */
6947827cba2SAaron LI 		while (waitpid(pid, &status, 0) == -1) {
6957827cba2SAaron LI 			if (errno != EINTR) {
6967827cba2SAaron LI 				logerr("%s: waitpid", __func__);
6977827cba2SAaron LI 				status = 0;
6987827cba2SAaron LI 				break;
6997827cba2SAaron LI 			}
7007827cba2SAaron LI 		}
7017827cba2SAaron LI 		if (WIFEXITED(status)) {
7027827cba2SAaron LI 			if (WEXITSTATUS(status))
7037827cba2SAaron LI 				logerrx("%s: %s: WEXITSTATUS %d",
7047827cba2SAaron LI 				    __func__, argv[0], WEXITSTATUS(status));
7057827cba2SAaron LI 		} else if (WIFSIGNALED(status))
7067827cba2SAaron LI 			logerrx("%s: %s: %s",
7077827cba2SAaron LI 			    __func__, argv[0], strsignal(WTERMSIG(status)));
7087827cba2SAaron LI 	}
7097827cba2SAaron LI 
7106e63cc1fSRoy Marples 	return WEXITSTATUS(status);
7116e63cc1fSRoy Marples }
7126e63cc1fSRoy Marples 
7136e63cc1fSRoy Marples int
714d4fb1e02SRoy Marples script_dump(const char *env, size_t len)
715d4fb1e02SRoy Marples {
716d4fb1e02SRoy Marples 	const char *ep = env + len;
717d4fb1e02SRoy Marples 
718d4fb1e02SRoy Marples 	if (len == 0)
719d4fb1e02SRoy Marples 		return 0;
720d4fb1e02SRoy Marples 
721d4fb1e02SRoy Marples 	if (*(ep - 1) != '\0') {
722d4fb1e02SRoy Marples 		errno = EINVAL;
723d4fb1e02SRoy Marples 		return -1;
724d4fb1e02SRoy Marples 	}
725d4fb1e02SRoy Marples 
726d4fb1e02SRoy Marples 	for (; env < ep; env += strlen(env) + 1) {
727d4fb1e02SRoy Marples 		if (strncmp(env, "new_", 4) == 0)
728d4fb1e02SRoy Marples 			env += 4;
729d4fb1e02SRoy Marples 		printf("%s\n", env);
730d4fb1e02SRoy Marples 	}
731d4fb1e02SRoy Marples 	return 0;
732d4fb1e02SRoy Marples }
733d4fb1e02SRoy Marples 
734d4fb1e02SRoy Marples int
7356e63cc1fSRoy Marples script_runreason(const struct interface *ifp, const char *reason)
7366e63cc1fSRoy Marples {
7376e63cc1fSRoy Marples 	struct dhcpcd_ctx *ctx = ifp->ctx;
7386e63cc1fSRoy Marples 	char *argv[2];
7396e63cc1fSRoy Marples 	int status = 0;
7406e63cc1fSRoy Marples 	struct fd_list *fd;
741d4fb1e02SRoy Marples 	long buflen;
7426e63cc1fSRoy Marples 
743d4fb1e02SRoy Marples 	if (ctx->script == NULL &&
7446e63cc1fSRoy Marples 	    TAILQ_FIRST(&ifp->ctx->control_fds) == NULL)
7456e63cc1fSRoy Marples 		return 0;
7466e63cc1fSRoy Marples 
7476e63cc1fSRoy Marples 	/* Make our env */
748d4fb1e02SRoy Marples 	if ((buflen = make_env(ifp->ctx, ifp, reason)) == -1) {
7496e63cc1fSRoy Marples 		logerr(__func__);
7506e63cc1fSRoy Marples 		return -1;
7516e63cc1fSRoy Marples 	}
7526e63cc1fSRoy Marples 
753d4fb1e02SRoy Marples 	if (strncmp(reason, "DUMP", 4) == 0)
754d4fb1e02SRoy Marples 		return script_dump(ctx->script_buf, (size_t)buflen);
755d4fb1e02SRoy Marples 
756d4fb1e02SRoy Marples 	if (ctx->script == NULL)
7576e63cc1fSRoy Marples 		goto send_listeners;
7586e63cc1fSRoy Marples 
759d4fb1e02SRoy Marples 	argv[0] = ctx->script;
7606e63cc1fSRoy Marples 	argv[1] = NULL;
761a0d9933aSRoy Marples 	logdebugx("%s: executing: %s %s", ifp->name, argv[0], reason);
7626e63cc1fSRoy Marples 
7636e63cc1fSRoy Marples #ifdef PRIVSEP
7646e63cc1fSRoy Marples 	if (ctx->options & DHCPCD_PRIVSEP) {
765d4fb1e02SRoy Marples 		if (ps_root_script(ctx,
7666e63cc1fSRoy Marples 		    ctx->script_buf, ctx->script_buflen) == -1)
7676e63cc1fSRoy Marples 			logerr(__func__);
7686e63cc1fSRoy Marples 		goto send_listeners;
7696e63cc1fSRoy Marples 	}
7706e63cc1fSRoy Marples #endif
7716e63cc1fSRoy Marples 
772d4fb1e02SRoy Marples 	script_run(ctx, argv);
7736e63cc1fSRoy Marples 
7747827cba2SAaron LI send_listeners:
7757827cba2SAaron LI 	/* Send to our listeners */
7767827cba2SAaron LI 	status = 0;
7778d36e1dfSRoy Marples 	TAILQ_FOREACH(fd, &ctx->control_fds, next) {
7787827cba2SAaron LI 		if (!(fd->flags & FD_LISTEN))
7797827cba2SAaron LI 			continue;
7807f8103cdSRoy Marples 		if (control_queue(fd, ctx->script_buf, ctx->script_buflen)== -1)
7817827cba2SAaron LI 			logerr("%s: control_queue", __func__);
7827827cba2SAaron LI 		else
7837827cba2SAaron LI 			status = 1;
7847827cba2SAaron LI 	}
7857827cba2SAaron LI 
7866e63cc1fSRoy Marples 	return status;
7877827cba2SAaron LI }
788