xref: /dflybsd-src/contrib/dhcpcd/src/script.c (revision b2927f2b6ddfb64c8f3a45f76e21fb8e0fcbe11a)
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 
777827cba2SAaron LI void
787827cba2SAaron LI if_printoptions(void)
797827cba2SAaron LI {
807827cba2SAaron LI 	const char * const *p;
817827cba2SAaron LI 
827827cba2SAaron LI 	for (p = if_params; *p; p++)
837827cba2SAaron LI 		printf(" -  %s\n", *p);
847827cba2SAaron LI }
857827cba2SAaron LI 
866e63cc1fSRoy Marples pid_t
87280986e4SRoy Marples script_exec(char *const *argv, char *const *env)
887827cba2SAaron LI {
89b9ccd228SRoy Marples 	pid_t pid = 0;
907827cba2SAaron LI 	posix_spawnattr_t attr;
917827cba2SAaron LI 	int r;
927827cba2SAaron LI #ifdef USE_SIGNALS
937827cba2SAaron LI 	size_t i;
947827cba2SAaron LI 	short flags;
957827cba2SAaron LI 	sigset_t defsigs;
967827cba2SAaron LI #else
977827cba2SAaron LI 	UNUSED(ctx);
987827cba2SAaron LI #endif
997827cba2SAaron LI 
1007827cba2SAaron LI 	/* posix_spawn is a safe way of executing another image
1017827cba2SAaron LI 	 * and changing signals back to how they should be. */
1027827cba2SAaron LI 	if (posix_spawnattr_init(&attr) == -1)
1037827cba2SAaron LI 		return -1;
1047827cba2SAaron LI #ifdef USE_SIGNALS
1057827cba2SAaron LI 	flags = POSIX_SPAWN_SETSIGMASK | POSIX_SPAWN_SETSIGDEF;
1067827cba2SAaron LI 	posix_spawnattr_setflags(&attr, flags);
1077827cba2SAaron LI 	sigemptyset(&defsigs);
108280986e4SRoy Marples 	posix_spawnattr_setsigmask(&attr, &defsigs);
1097827cba2SAaron LI 	for (i = 0; i < dhcpcd_signals_len; i++)
1107827cba2SAaron LI 		sigaddset(&defsigs, dhcpcd_signals[i]);
111d4fb1e02SRoy Marples 	for (i = 0; i < dhcpcd_signals_ignore_len; i++)
112d4fb1e02SRoy Marples 		sigaddset(&defsigs, dhcpcd_signals_ignore[i]);
1137827cba2SAaron LI 	posix_spawnattr_setsigdefault(&attr, &defsigs);
1147827cba2SAaron LI #endif
1157827cba2SAaron LI 	errno = 0;
1167827cba2SAaron LI 	r = posix_spawn(&pid, argv[0], NULL, &attr, argv, env);
1177827cba2SAaron LI 	posix_spawnattr_destroy(&attr);
1187827cba2SAaron LI 	if (r) {
1197827cba2SAaron LI 		errno = r;
1207827cba2SAaron LI 		return -1;
1217827cba2SAaron LI 	}
1227827cba2SAaron LI 	return pid;
1237827cba2SAaron LI }
1247827cba2SAaron LI 
1257827cba2SAaron LI #ifdef INET
1267827cba2SAaron LI static int
1278d36e1dfSRoy Marples append_config(FILE *fp, const char *prefix, const char *const *config)
1287827cba2SAaron LI {
1298d36e1dfSRoy Marples 	size_t i;
1307827cba2SAaron LI 
1317827cba2SAaron LI 	if (config == NULL)
1327827cba2SAaron LI 		return 0;
1337827cba2SAaron LI 
1348d36e1dfSRoy Marples 	/* Do we need to replace existing config rather than append? */
1357827cba2SAaron LI 	for (i = 0; config[i] != NULL; i++) {
1368d36e1dfSRoy Marples 		if (efprintf(fp, "%s_%s", prefix, config[i]) == -1)
1377827cba2SAaron LI 			return -1;
1387827cba2SAaron LI 	}
1398d36e1dfSRoy Marples 	return 1;
1407827cba2SAaron LI }
1417827cba2SAaron LI 
1428d36e1dfSRoy Marples #endif
1438d36e1dfSRoy Marples 
1447827cba2SAaron LI #define	PROTO_LINK	0
1457827cba2SAaron LI #define	PROTO_DHCP	1
1467827cba2SAaron LI #define	PROTO_IPV4LL	2
1477827cba2SAaron LI #define	PROTO_RA	3
1487827cba2SAaron LI #define	PROTO_DHCP6	4
1497827cba2SAaron LI #define	PROTO_STATIC6	5
1507827cba2SAaron LI static const char *protocols[] = {
1517827cba2SAaron LI 	"link",
1527827cba2SAaron LI 	"dhcp",
1537827cba2SAaron LI 	"ipv4ll",
1547827cba2SAaron LI 	"ra",
1557827cba2SAaron LI 	"dhcp6",
1567827cba2SAaron LI 	"static6"
1577827cba2SAaron LI };
1587827cba2SAaron LI 
1598d36e1dfSRoy Marples int
1608d36e1dfSRoy Marples efprintf(FILE *fp, const char *fmt, ...)
1617827cba2SAaron LI {
1628d36e1dfSRoy Marples 	va_list args;
1638d36e1dfSRoy Marples 	int r;
1648d36e1dfSRoy Marples 
1658d36e1dfSRoy Marples 	va_start(args, fmt);
1668d36e1dfSRoy Marples 	r = vfprintf(fp, fmt, args);
1678d36e1dfSRoy Marples 	va_end(args);
1688d36e1dfSRoy Marples 	if (r == -1)
1698d36e1dfSRoy Marples 		return -1;
1708d36e1dfSRoy Marples 	/* Write a trailing NULL so we can easily create env strings. */
1718d36e1dfSRoy Marples 	if (fputc('\0', fp) == EOF)
1728d36e1dfSRoy Marples 		return -1;
1738d36e1dfSRoy Marples 	return r;
1748d36e1dfSRoy Marples }
1758d36e1dfSRoy Marples 
1766e63cc1fSRoy Marples char **
177b9ccd228SRoy Marples script_buftoenv(struct dhcpcd_ctx *ctx, char *buf, size_t len)
178b9ccd228SRoy Marples {
179b9ccd228SRoy Marples 	char **env, **envp, *bufp, *endp;
180b9ccd228SRoy Marples 	size_t nenv;
181b9ccd228SRoy Marples 
182b9ccd228SRoy Marples 	/* Count the terminated env strings.
183b9ccd228SRoy Marples 	 * Assert that the terminations are correct. */
184b9ccd228SRoy Marples 	nenv = 0;
185b9ccd228SRoy Marples 	endp = buf + len;
186b9ccd228SRoy Marples 	for (bufp = buf; bufp < endp; bufp++) {
187b9ccd228SRoy Marples 		if (*bufp == '\0') {
188b9ccd228SRoy Marples #ifndef NDEBUG
189b9ccd228SRoy Marples 			if (bufp + 1 < endp)
190b9ccd228SRoy Marples 				assert(*(bufp + 1) != '\0');
191b9ccd228SRoy Marples #endif
192b9ccd228SRoy Marples 			nenv++;
193b9ccd228SRoy Marples 		}
194b9ccd228SRoy Marples 	}
195b9ccd228SRoy Marples 	assert(*(bufp - 1) == '\0');
196d4fb1e02SRoy Marples 	if (nenv == 0)
197d4fb1e02SRoy Marples 		return NULL;
198b9ccd228SRoy Marples 
199b9ccd228SRoy Marples 	if (ctx->script_envlen < nenv) {
200b9ccd228SRoy Marples 		env = reallocarray(ctx->script_env, nenv + 1, sizeof(*env));
201b9ccd228SRoy Marples 		if (env == NULL)
202b9ccd228SRoy Marples 			return NULL;
203b9ccd228SRoy Marples 		ctx->script_env = env;
204b9ccd228SRoy Marples 		ctx->script_envlen = nenv;
205b9ccd228SRoy Marples 	}
206b9ccd228SRoy Marples 
207b9ccd228SRoy Marples 	bufp = buf;
208b9ccd228SRoy Marples 	envp = ctx->script_env;
209b9ccd228SRoy Marples 	*envp++ = bufp++;
210b9ccd228SRoy Marples 	endp--; /* Avoid setting the last \0 to an invalid pointer */
211b9ccd228SRoy Marples 	for (; bufp < endp; bufp++) {
212b9ccd228SRoy Marples 		if (*bufp == '\0')
213b9ccd228SRoy Marples 			*envp++ = bufp + 1;
214b9ccd228SRoy Marples 	}
215b9ccd228SRoy Marples 	*envp = NULL;
216b9ccd228SRoy Marples 
217b9ccd228SRoy Marples 	return ctx->script_env;
218b9ccd228SRoy Marples }
219b9ccd228SRoy Marples 
2208d36e1dfSRoy Marples static long
2216e63cc1fSRoy Marples make_env(struct dhcpcd_ctx *ctx, const struct interface *ifp,
2226e63cc1fSRoy Marples     const char *reason)
2238d36e1dfSRoy Marples {
2248d36e1dfSRoy Marples 	FILE *fp;
2258d36e1dfSRoy Marples 	long buf_pos, i;
226b9ccd228SRoy Marples 	char *path;
2278d36e1dfSRoy Marples 	int protocol = PROTO_LINK;
2286e63cc1fSRoy Marples 	const struct if_options *ifo;
2297827cba2SAaron LI 	const struct interface *ifp2;
2307827cba2SAaron LI 	int af;
2317827cba2SAaron LI #ifdef INET
2327827cba2SAaron LI 	const struct dhcp_state *state;
2337827cba2SAaron LI #ifdef IPV4LL
2347827cba2SAaron LI 	const struct ipv4ll_state *istate;
2357827cba2SAaron LI #endif
2367827cba2SAaron LI #endif
2378d36e1dfSRoy Marples #ifdef DHCP6
2387827cba2SAaron LI 	const struct dhcp6_state *d6_state;
2397827cba2SAaron LI #endif
240d4fb1e02SRoy Marples 	bool is_stdin = ifp->name[0] == '\0';
2417827cba2SAaron LI 
2428d36e1dfSRoy Marples #ifdef HAVE_OPEN_MEMSTREAM
2438d36e1dfSRoy Marples 	if (ctx->script_fp == NULL) {
2448d36e1dfSRoy Marples 		fp = open_memstream(&ctx->script_buf, &ctx->script_buflen);
2458d36e1dfSRoy Marples 		if (fp == NULL)
2468d36e1dfSRoy Marples 			goto eexit;
2478d36e1dfSRoy Marples 		ctx->script_fp = fp;
2488d36e1dfSRoy Marples 	} else {
2498d36e1dfSRoy Marples 		fp = ctx->script_fp;
2508d36e1dfSRoy Marples 		rewind(fp);
2518d36e1dfSRoy Marples 	}
2528d36e1dfSRoy Marples #else
2538d36e1dfSRoy Marples 	char tmpfile[] = "/tmp/dhcpcd-script-env-XXXXXX";
2548d36e1dfSRoy Marples 	int tmpfd;
2558d36e1dfSRoy Marples 
2568d36e1dfSRoy Marples 	fp = NULL;
2578d36e1dfSRoy Marples 	tmpfd = mkstemp(tmpfile);
258d4fb1e02SRoy Marples 	if (tmpfd == -1) {
259d4fb1e02SRoy Marples 		logerr("%s: mkstemp", __func__);
260d4fb1e02SRoy Marples 		return -1;
261d4fb1e02SRoy Marples 	}
2628d36e1dfSRoy Marples 	unlink(tmpfile);
2638d36e1dfSRoy Marples 	fp = fdopen(tmpfd, "w+");
2648d36e1dfSRoy Marples 	if (fp == NULL) {
2658d36e1dfSRoy Marples 		close(tmpfd);
2668d36e1dfSRoy Marples 		goto eexit;
2678d36e1dfSRoy Marples 	}
2688d36e1dfSRoy Marples #endif
2698d36e1dfSRoy Marples 
270d4fb1e02SRoy Marples 	if (!(ifp->ctx->options & DHCPCD_DUMPLEASE)) {
2716e63cc1fSRoy Marples 		/* Needed for scripts */
2726e63cc1fSRoy Marples 		path = getenv("PATH");
273d4fb1e02SRoy Marples 		if (efprintf(fp, "PATH=%s",
274d4fb1e02SRoy Marples 		    path == NULL ? DEFAULT_PATH : path) == -1)
2756e63cc1fSRoy Marples 			goto eexit;
2766e63cc1fSRoy Marples 		if (efprintf(fp, "pid=%d", getpid()) == -1)
2776e63cc1fSRoy Marples 			goto eexit;
278d4fb1e02SRoy Marples 	}
279d4fb1e02SRoy Marples 	if (!is_stdin) {
280d4fb1e02SRoy Marples 		if (efprintf(fp, "reason=%s", reason) == -1)
2816e63cc1fSRoy Marples 			goto eexit;
2826e63cc1fSRoy Marples 	}
2836e63cc1fSRoy Marples 
2846e63cc1fSRoy Marples 	ifo = ifp->options;
2857827cba2SAaron LI #ifdef INET
2867827cba2SAaron LI 	state = D_STATE(ifp);
2877827cba2SAaron LI #ifdef IPV4LL
2887827cba2SAaron LI 	istate = IPV4LL_CSTATE(ifp);
2897827cba2SAaron LI #endif
2907827cba2SAaron LI #endif
2918d36e1dfSRoy Marples #ifdef DHCP6
2927827cba2SAaron LI 	d6_state = D6_CSTATE(ifp);
2937827cba2SAaron LI #endif
2947827cba2SAaron LI 	if (strcmp(reason, "TEST") == 0) {
2956e63cc1fSRoy Marples 		if (1 == 2) {
2966e63cc1fSRoy Marples 			/* This space left intentionally blank
2976e63cc1fSRoy Marples 			 * as all the below statements are optional. */
2986e63cc1fSRoy Marples 		}
2997827cba2SAaron LI #ifdef INET6
3008d36e1dfSRoy Marples #ifdef DHCP6
3017827cba2SAaron LI 		else if (d6_state && d6_state->new)
3027827cba2SAaron LI 			protocol = PROTO_DHCP6;
3038d36e1dfSRoy Marples #endif
3047827cba2SAaron LI 		else if (ipv6nd_hasra(ifp))
3057827cba2SAaron LI 			protocol = PROTO_RA;
3067827cba2SAaron LI #endif
3077827cba2SAaron LI #ifdef INET
3087827cba2SAaron LI #ifdef IPV4LL
3097827cba2SAaron LI 		else if (istate && istate->addr != NULL)
3107827cba2SAaron LI 			protocol = PROTO_IPV4LL;
3117827cba2SAaron LI #endif
3127827cba2SAaron LI 		else
3137827cba2SAaron LI 			protocol = PROTO_DHCP;
3147827cba2SAaron LI #endif
3157827cba2SAaron LI 	}
3167827cba2SAaron LI #ifdef INET6
3177827cba2SAaron LI 	else if (strcmp(reason, "STATIC6") == 0)
3187827cba2SAaron LI 		protocol = PROTO_STATIC6;
3198d36e1dfSRoy Marples #ifdef DHCP6
3207827cba2SAaron LI 	else if (reason[strlen(reason) - 1] == '6')
3217827cba2SAaron LI 		protocol = PROTO_DHCP6;
3228d36e1dfSRoy Marples #endif
3237827cba2SAaron LI 	else if (strcmp(reason, "ROUTERADVERT") == 0)
3247827cba2SAaron LI 		protocol = PROTO_RA;
3257827cba2SAaron LI #endif
3267827cba2SAaron LI 	else if (strcmp(reason, "PREINIT") == 0 ||
3277827cba2SAaron LI 	    strcmp(reason, "CARRIER") == 0 ||
3287827cba2SAaron LI 	    strcmp(reason, "NOCARRIER") == 0 ||
3297827cba2SAaron LI 	    strcmp(reason, "UNKNOWN") == 0 ||
3307827cba2SAaron LI 	    strcmp(reason, "DEPARTED") == 0 ||
3317827cba2SAaron LI 	    strcmp(reason, "STOPPED") == 0)
3327827cba2SAaron LI 		protocol = PROTO_LINK;
3337827cba2SAaron LI #ifdef INET
3347827cba2SAaron LI #ifdef IPV4LL
3357827cba2SAaron LI 	else if (strcmp(reason, "IPV4LL") == 0)
3367827cba2SAaron LI 		protocol = PROTO_IPV4LL;
3377827cba2SAaron LI #endif
3387827cba2SAaron LI 	else
3397827cba2SAaron LI 		protocol = PROTO_DHCP;
3407827cba2SAaron LI #endif
3417827cba2SAaron LI 
342d4fb1e02SRoy Marples 	if (!is_stdin) {
3438d36e1dfSRoy Marples 		if (efprintf(fp, "interface=%s", ifp->name) == -1)
3448d36e1dfSRoy Marples 			goto eexit;
345cc34ba0cSRoy Marples 		if (protocols[protocol] != NULL) {
346cc34ba0cSRoy Marples 			if (efprintf(fp, "protocol=%s",
347cc34ba0cSRoy Marples 			    protocols[protocol]) == -1)
348cc34ba0cSRoy Marples 				goto eexit;
349d4fb1e02SRoy Marples 		}
350cc34ba0cSRoy Marples 	}
351cc34ba0cSRoy Marples 	if (ifp->ctx->options & DHCPCD_DUMPLEASE && protocol != PROTO_LINK)
3527827cba2SAaron LI 		goto dumplease;
353*b2927f2bSRoy Marples 	if (efprintf(fp, "if_configured=%s",
354*b2927f2bSRoy Marples 	    ifo->options & DHCPCD_CONFIGURE ? "true" : "false") == -1)
355*b2927f2bSRoy Marples 		goto eexit;
3568d36e1dfSRoy Marples 	if (efprintf(fp, "ifcarrier=%s",
3577827cba2SAaron LI 	    ifp->carrier == LINK_UNKNOWN ? "unknown" :
3588d36e1dfSRoy Marples 	    ifp->carrier == LINK_UP ? "up" : "down") == -1)
3598d36e1dfSRoy Marples 		goto eexit;
3608d36e1dfSRoy Marples 	if (efprintf(fp, "ifmetric=%d", ifp->metric) == -1)
3618d36e1dfSRoy Marples 		goto eexit;
3628d36e1dfSRoy Marples 	if (efprintf(fp, "ifwireless=%d", ifp->wireless) == -1)
3638d36e1dfSRoy Marples 		goto eexit;
3648d36e1dfSRoy Marples 	if (efprintf(fp, "ifflags=%u", ifp->flags) == -1)
3658d36e1dfSRoy Marples 		goto eexit;
3668d36e1dfSRoy Marples 	if (efprintf(fp, "ifmtu=%d", if_getmtu(ifp)) == -1)
3678d36e1dfSRoy Marples 		goto eexit;
368cc34ba0cSRoy Marples 	if (ifp->wireless) {
369cc34ba0cSRoy Marples 		char pssid[IF_SSIDLEN * 4];
370cc34ba0cSRoy Marples 
371cc34ba0cSRoy Marples 		if (print_string(pssid, sizeof(pssid), OT_ESCSTRING,
372cc34ba0cSRoy Marples 		    ifp->ssid, ifp->ssid_len) != -1)
373cc34ba0cSRoy Marples 		{
374cc34ba0cSRoy Marples 			if (efprintf(fp, "ifssid=%s", pssid) == -1)
375cc34ba0cSRoy Marples 				goto eexit;
376cc34ba0cSRoy Marples 		}
377cc34ba0cSRoy Marples 	}
378cc34ba0cSRoy Marples 	if (*ifp->profile != '\0') {
379cc34ba0cSRoy Marples 		if (efprintf(fp, "profile=%s", ifp->profile) == -1)
380cc34ba0cSRoy Marples 			goto eexit;
381cc34ba0cSRoy Marples 	}
382cc34ba0cSRoy Marples 	if (ifp->ctx->options & DHCPCD_DUMPLEASE)
383cc34ba0cSRoy Marples 		goto dumplease;
3848d36e1dfSRoy Marples 
3858d36e1dfSRoy Marples 	if (fprintf(fp, "interface_order=") == -1)
3868d36e1dfSRoy Marples 		goto eexit;
3877827cba2SAaron LI 	TAILQ_FOREACH(ifp2, ifp->ctx->ifaces, next) {
3888d36e1dfSRoy Marples 		if (ifp2 != TAILQ_FIRST(ifp->ctx->ifaces)) {
3898d36e1dfSRoy Marples 			if (fputc(' ', fp) == EOF)
3908d36e1dfSRoy Marples 				return -1;
3917827cba2SAaron LI 		}
3928d36e1dfSRoy Marples 		if (fprintf(fp, "%s", ifp2->name) == -1)
3938d36e1dfSRoy Marples 			return -1;
3947827cba2SAaron LI 	}
3958d36e1dfSRoy Marples 	if (fputc('\0', fp) == EOF)
3968d36e1dfSRoy Marples 		return -1;
3978d36e1dfSRoy Marples 
3987827cba2SAaron LI 	if (strcmp(reason, "STOPPED") == 0) {
3998d36e1dfSRoy Marples 		if (efprintf(fp, "if_up=false") == -1)
4008d36e1dfSRoy Marples 			goto eexit;
4018d36e1dfSRoy Marples 		if (efprintf(fp, "if_down=%s",
4028d36e1dfSRoy Marples 		    ifo->options & DHCPCD_RELEASE ? "true" : "false") == -1)
4038d36e1dfSRoy Marples 			goto eexit;
4047827cba2SAaron LI 	} else if (strcmp(reason, "TEST") == 0 ||
4057827cba2SAaron LI 	    strcmp(reason, "PREINIT") == 0 ||
4067827cba2SAaron LI 	    strcmp(reason, "CARRIER") == 0 ||
4077827cba2SAaron LI 	    strcmp(reason, "UNKNOWN") == 0)
4087827cba2SAaron LI 	{
4098d36e1dfSRoy Marples 		if (efprintf(fp, "if_up=false") == -1)
4108d36e1dfSRoy Marples 			goto eexit;
4118d36e1dfSRoy Marples 		if (efprintf(fp, "if_down=false") == -1)
4128d36e1dfSRoy Marples 			goto eexit;
4137827cba2SAaron LI 	} else if (1 == 2 /* appease ifdefs */
4147827cba2SAaron LI #ifdef INET
4157827cba2SAaron LI 	    || (protocol == PROTO_DHCP && state && state->new)
4167827cba2SAaron LI #ifdef IPV4LL
4177827cba2SAaron LI 	    || (protocol == PROTO_IPV4LL && IPV4LL_STATE_RUNNING(ifp))
4187827cba2SAaron LI #endif
4197827cba2SAaron LI #endif
4207827cba2SAaron LI #ifdef INET6
4217827cba2SAaron LI 	    || (protocol == PROTO_STATIC6 && IPV6_STATE_RUNNING(ifp))
4228d36e1dfSRoy Marples #ifdef DHCP6
4237827cba2SAaron LI 	    || (protocol == PROTO_DHCP6 && d6_state && d6_state->new)
4248d36e1dfSRoy Marples #endif
4257827cba2SAaron LI 	    || (protocol == PROTO_RA && ipv6nd_hasra(ifp))
4267827cba2SAaron LI #endif
4277827cba2SAaron LI 	    )
4287827cba2SAaron LI 	{
4298d36e1dfSRoy Marples 		if (efprintf(fp, "if_up=true") == -1)
4308d36e1dfSRoy Marples 			goto eexit;
4318d36e1dfSRoy Marples 		if (efprintf(fp, "if_down=false") == -1)
4328d36e1dfSRoy Marples 			goto eexit;
4337827cba2SAaron LI 	} else {
4348d36e1dfSRoy Marples 		if (efprintf(fp, "if_up=false") == -1)
4358d36e1dfSRoy Marples 			goto eexit;
4368d36e1dfSRoy Marples 		if (efprintf(fp, "if_down=true") == -1)
4378d36e1dfSRoy Marples 			goto eexit;
4387827cba2SAaron LI 	}
4397827cba2SAaron LI 	if ((af = dhcpcd_ifafwaiting(ifp)) != AF_MAX) {
4408d36e1dfSRoy Marples 		if (efprintf(fp, "if_afwaiting=%d", af) == -1)
4418d36e1dfSRoy Marples 			goto eexit;
4427827cba2SAaron LI 	}
4437827cba2SAaron LI 	if ((af = dhcpcd_afwaiting(ifp->ctx)) != AF_MAX) {
4447827cba2SAaron LI 		TAILQ_FOREACH(ifp2, ifp->ctx->ifaces, next) {
4457827cba2SAaron LI 			if ((af = dhcpcd_ifafwaiting(ifp2)) != AF_MAX)
4467827cba2SAaron LI 				break;
4477827cba2SAaron LI 		}
4487827cba2SAaron LI 	}
4497827cba2SAaron LI 	if (af != AF_MAX) {
4508d36e1dfSRoy Marples 		if (efprintf(fp, "af_waiting=%d", af) == -1)
4518d36e1dfSRoy Marples 			goto eexit;
4527827cba2SAaron LI 	}
4537827cba2SAaron LI 	if (ifo->options & DHCPCD_DEBUG) {
4548d36e1dfSRoy Marples 		if (efprintf(fp, "syslog_debug=true") == -1)
4558d36e1dfSRoy Marples 			goto eexit;
4567827cba2SAaron LI 	}
4577827cba2SAaron LI #ifdef INET
4587827cba2SAaron LI 	if (protocol == PROTO_DHCP && state && state->old) {
4598d36e1dfSRoy Marples 		if (dhcp_env(fp, "old", ifp,
4608d36e1dfSRoy Marples 		    state->old, state->old_len) == -1)
4617827cba2SAaron LI 			goto eexit;
4628d36e1dfSRoy Marples 		if (append_config(fp, "old",
4637827cba2SAaron LI 		    (const char *const *)ifo->config) == -1)
4647827cba2SAaron LI 			goto eexit;
4657827cba2SAaron LI 	}
4667827cba2SAaron LI #endif
4678d36e1dfSRoy Marples #ifdef DHCP6
4687827cba2SAaron LI 	if (protocol == PROTO_DHCP6 && d6_state && d6_state->old) {
4698d36e1dfSRoy Marples 		if (dhcp6_env(fp, "old", ifp,
4708d36e1dfSRoy Marples 		    d6_state->old, d6_state->old_len) == -1)
4717827cba2SAaron LI 			goto eexit;
4727827cba2SAaron LI 	}
4737827cba2SAaron LI #endif
4747827cba2SAaron LI 
4757827cba2SAaron LI dumplease:
4767827cba2SAaron LI #ifdef INET
4777827cba2SAaron LI #ifdef IPV4LL
4786e63cc1fSRoy Marples 	if (protocol == PROTO_IPV4LL && istate) {
4798d36e1dfSRoy Marples 		if (ipv4ll_env(fp, istate->down ? "old" : "new", ifp) == -1)
4807827cba2SAaron LI 			goto eexit;
4817827cba2SAaron LI 	}
4827827cba2SAaron LI #endif
4837827cba2SAaron LI 	if (protocol == PROTO_DHCP && state && state->new) {
4848d36e1dfSRoy Marples 		if (dhcp_env(fp, "new", ifp,
4858d36e1dfSRoy Marples 		    state->new, state->new_len) == -1)
4867827cba2SAaron LI 			goto eexit;
4878d36e1dfSRoy Marples 		if (append_config(fp, "new",
4887827cba2SAaron LI 		    (const char *const *)ifo->config) == -1)
4897827cba2SAaron LI 			goto eexit;
4907827cba2SAaron LI 	}
4917827cba2SAaron LI #endif
4927827cba2SAaron LI #ifdef INET6
4937827cba2SAaron LI 	if (protocol == PROTO_STATIC6) {
4948d36e1dfSRoy Marples 		if (ipv6_env(fp, "new", ifp) == -1)
4957827cba2SAaron LI 			goto eexit;
4967827cba2SAaron LI 	}
4978d36e1dfSRoy Marples #ifdef DHCP6
4987827cba2SAaron LI 	if (protocol == PROTO_DHCP6 && D6_STATE_RUNNING(ifp)) {
4998d36e1dfSRoy Marples 		if (dhcp6_env(fp, "new", ifp,
5008d36e1dfSRoy Marples 		    d6_state->new, d6_state->new_len) == -1)
5017827cba2SAaron LI 			goto eexit;
5027827cba2SAaron LI 	}
5038d36e1dfSRoy Marples #endif
5047827cba2SAaron LI 	if (protocol == PROTO_RA) {
5058d36e1dfSRoy Marples 		if (ipv6nd_env(fp, ifp) == -1)
5067827cba2SAaron LI 			goto eexit;
5077827cba2SAaron LI 	}
5087827cba2SAaron LI #endif
5097827cba2SAaron LI 
5107827cba2SAaron LI 	/* Add our base environment */
5117827cba2SAaron LI 	if (ifo->environ) {
5128d36e1dfSRoy Marples 		for (i = 0; ifo->environ[i] != NULL; i++)
5138d36e1dfSRoy Marples 			if (efprintf(fp, "%s", ifo->environ[i]) == -1)
5147827cba2SAaron LI 				goto eexit;
5157827cba2SAaron LI 	}
5167827cba2SAaron LI 
5178d36e1dfSRoy Marples 	/* Convert buffer to argv */
5188d36e1dfSRoy Marples 	fflush(fp);
5198d36e1dfSRoy Marples 
5208d36e1dfSRoy Marples 	buf_pos = ftell(fp);
5218d36e1dfSRoy Marples 	if (buf_pos == -1) {
5228d36e1dfSRoy Marples 		logerr(__func__);
5238d36e1dfSRoy Marples 		goto eexit;
5248d36e1dfSRoy Marples 	}
5258d36e1dfSRoy Marples 
5268d36e1dfSRoy Marples #ifndef HAVE_OPEN_MEMSTREAM
5278d36e1dfSRoy Marples 	size_t buf_len = (size_t)buf_pos;
5288d36e1dfSRoy Marples 	if (ctx->script_buflen < buf_len) {
5298d36e1dfSRoy Marples 		char *buf = realloc(ctx->script_buf, buf_len);
5308d36e1dfSRoy Marples 		if (buf == NULL)
5318d36e1dfSRoy Marples 			goto eexit;
5328d36e1dfSRoy Marples 		ctx->script_buf = buf;
5338d36e1dfSRoy Marples 		ctx->script_buflen = buf_len;
5348d36e1dfSRoy Marples 	}
5358d36e1dfSRoy Marples 	rewind(fp);
5368d36e1dfSRoy Marples 	if (fread(ctx->script_buf, sizeof(char), buf_len, fp) != buf_len)
5378d36e1dfSRoy Marples 		goto eexit;
5388d36e1dfSRoy Marples 	fclose(fp);
5398d36e1dfSRoy Marples 	fp = NULL;
5408d36e1dfSRoy Marples #endif
5418d36e1dfSRoy Marples 
542d4fb1e02SRoy Marples 	if (is_stdin)
543d4fb1e02SRoy Marples 		return buf_pos;
544d4fb1e02SRoy Marples 
545b9ccd228SRoy Marples 	if (script_buftoenv(ctx, ctx->script_buf, (size_t)buf_pos) == NULL)
5468d36e1dfSRoy Marples 		goto eexit;
5478d36e1dfSRoy Marples 
5486e63cc1fSRoy Marples 	return buf_pos;
5497827cba2SAaron LI 
5507827cba2SAaron LI eexit:
5517827cba2SAaron LI 	logerr(__func__);
5528d36e1dfSRoy Marples #ifndef HAVE_OPEN_MEMSTREAM
5538d36e1dfSRoy Marples 	if (fp != NULL)
5548d36e1dfSRoy Marples 		fclose(fp);
5558d36e1dfSRoy Marples #endif
5567827cba2SAaron LI 	return -1;
5577827cba2SAaron LI }
5587827cba2SAaron LI 
5597827cba2SAaron LI static int
5608d36e1dfSRoy Marples send_interface1(struct fd_list *fd, const struct interface *ifp,
5617827cba2SAaron LI     const char *reason)
5627827cba2SAaron LI {
5638d36e1dfSRoy Marples 	struct dhcpcd_ctx *ctx = ifp->ctx;
5648d36e1dfSRoy Marples 	long len;
5657827cba2SAaron LI 
5666e63cc1fSRoy Marples 	len = make_env(ifp->ctx, ifp, reason);
5678d36e1dfSRoy Marples 	if (len == -1)
5687827cba2SAaron LI 		return -1;
5697f8103cdSRoy Marples 	return control_queue(fd, ctx->script_buf, (size_t)len);
5707827cba2SAaron LI }
5717827cba2SAaron LI 
5727827cba2SAaron LI int
5736e63cc1fSRoy Marples send_interface(struct fd_list *fd, const struct interface *ifp, int af)
5747827cba2SAaron LI {
5757827cba2SAaron LI 	int retval = 0;
5767827cba2SAaron LI #ifdef INET
5777827cba2SAaron LI 	const struct dhcp_state *d;
5787827cba2SAaron LI #endif
5798d36e1dfSRoy Marples #ifdef DHCP6
5807827cba2SAaron LI 	const struct dhcp6_state *d6;
5817827cba2SAaron LI #endif
5827827cba2SAaron LI 
5836e63cc1fSRoy Marples #ifndef AF_LINK
5846e63cc1fSRoy Marples #define	AF_LINK	AF_PACKET
5856e63cc1fSRoy Marples #endif
5866e63cc1fSRoy Marples 
5876e63cc1fSRoy Marples 	if (af == AF_UNSPEC || af == AF_LINK) {
5886e63cc1fSRoy Marples 		const char *reason;
5896e63cc1fSRoy Marples 
5907827cba2SAaron LI 		switch (ifp->carrier) {
5917827cba2SAaron LI 		case LINK_UP:
5927827cba2SAaron LI 			reason = "CARRIER";
5937827cba2SAaron LI 			break;
5947827cba2SAaron LI 		case LINK_DOWN:
5957827cba2SAaron LI 			reason = "NOCARRIER";
5967827cba2SAaron LI 			break;
5977827cba2SAaron LI 		default:
5987827cba2SAaron LI 			reason = "UNKNOWN";
5997827cba2SAaron LI 			break;
6007827cba2SAaron LI 		}
6016e63cc1fSRoy Marples 		if (fd != NULL) {
6027827cba2SAaron LI 			if (send_interface1(fd, ifp, reason) == -1)
6037827cba2SAaron LI 				retval = -1;
6046e63cc1fSRoy Marples 		} else
6056e63cc1fSRoy Marples 			retval++;
6066e63cc1fSRoy Marples 	}
6076e63cc1fSRoy Marples 
6087827cba2SAaron LI #ifdef INET
6096e63cc1fSRoy Marples 	if (af == AF_UNSPEC || af == AF_INET) {
6107827cba2SAaron LI 		if (D_STATE_RUNNING(ifp)) {
6117827cba2SAaron LI 			d = D_CSTATE(ifp);
6126e63cc1fSRoy Marples 			if (fd != NULL) {
6137827cba2SAaron LI 				if (send_interface1(fd, ifp, d->reason) == -1)
6147827cba2SAaron LI 					retval = -1;
6156e63cc1fSRoy Marples 			} else
6166e63cc1fSRoy Marples 				retval++;
6177827cba2SAaron LI 		}
6187827cba2SAaron LI #ifdef IPV4LL
6197827cba2SAaron LI 		if (IPV4LL_STATE_RUNNING(ifp)) {
6206e63cc1fSRoy Marples 			if (fd != NULL) {
6217827cba2SAaron LI 				if (send_interface1(fd, ifp, "IPV4LL") == -1)
6227827cba2SAaron LI 					retval = -1;
6236e63cc1fSRoy Marples 			} else
6246e63cc1fSRoy Marples 				retval++;
6257827cba2SAaron LI 		}
6267827cba2SAaron LI #endif
6276e63cc1fSRoy Marples 	}
6287827cba2SAaron LI #endif
6297827cba2SAaron LI 
6307827cba2SAaron LI #ifdef INET6
6316e63cc1fSRoy Marples 	if (af == AF_UNSPEC || af == AF_INET6) {
6327827cba2SAaron LI 		if (IPV6_STATE_RUNNING(ifp)) {
6336e63cc1fSRoy Marples 			if (fd != NULL) {
6347827cba2SAaron LI 				if (send_interface1(fd, ifp, "STATIC6") == -1)
6357827cba2SAaron LI 					retval = -1;
6366e63cc1fSRoy Marples 			} else
6376e63cc1fSRoy Marples 				retval++;
6387827cba2SAaron LI 		}
6397827cba2SAaron LI 		if (RS_STATE_RUNNING(ifp)) {
6406e63cc1fSRoy Marples 			if (fd != NULL) {
6416e63cc1fSRoy Marples 				if (send_interface1(fd, ifp,
6426e63cc1fSRoy Marples 				    "ROUTERADVERT") == -1)
6437827cba2SAaron LI 					retval = -1;
6446e63cc1fSRoy Marples 			} else
6456e63cc1fSRoy Marples 				retval++;
6467827cba2SAaron LI 		}
6478d36e1dfSRoy Marples #ifdef DHCP6
6487827cba2SAaron LI 		if (D6_STATE_RUNNING(ifp)) {
6497827cba2SAaron LI 			d6 = D6_CSTATE(ifp);
6506e63cc1fSRoy Marples 			if (fd != NULL) {
6517827cba2SAaron LI 				if (send_interface1(fd, ifp, d6->reason) == -1)
6527827cba2SAaron LI 					retval = -1;
6536e63cc1fSRoy Marples 			} else
6546e63cc1fSRoy Marples 				retval++;
6557827cba2SAaron LI 		}
6567827cba2SAaron LI #endif
6576e63cc1fSRoy Marples 	}
6588d36e1dfSRoy Marples #endif
6597827cba2SAaron LI 
6607827cba2SAaron LI 	return retval;
6617827cba2SAaron LI }
6627827cba2SAaron LI 
6636e63cc1fSRoy Marples static int
6646e63cc1fSRoy Marples script_run(struct dhcpcd_ctx *ctx, char **argv)
6657827cba2SAaron LI {
6667827cba2SAaron LI 	pid_t pid;
6677827cba2SAaron LI 	int status = 0;
6687827cba2SAaron LI 
669280986e4SRoy Marples 	pid = script_exec(argv, ctx->script_env);
6707827cba2SAaron LI 	if (pid == -1)
6717827cba2SAaron LI 		logerr("%s: %s", __func__, argv[0]);
6727827cba2SAaron LI 	else if (pid != 0) {
6737827cba2SAaron LI 		/* Wait for the script to finish */
6747827cba2SAaron LI 		while (waitpid(pid, &status, 0) == -1) {
6757827cba2SAaron LI 			if (errno != EINTR) {
6767827cba2SAaron LI 				logerr("%s: waitpid", __func__);
6777827cba2SAaron LI 				status = 0;
6787827cba2SAaron LI 				break;
6797827cba2SAaron LI 			}
6807827cba2SAaron LI 		}
6817827cba2SAaron LI 		if (WIFEXITED(status)) {
6827827cba2SAaron LI 			if (WEXITSTATUS(status))
6837827cba2SAaron LI 				logerrx("%s: %s: WEXITSTATUS %d",
6847827cba2SAaron LI 				    __func__, argv[0], WEXITSTATUS(status));
6857827cba2SAaron LI 		} else if (WIFSIGNALED(status))
6867827cba2SAaron LI 			logerrx("%s: %s: %s",
6877827cba2SAaron LI 			    __func__, argv[0], strsignal(WTERMSIG(status)));
6887827cba2SAaron LI 	}
6897827cba2SAaron LI 
6906e63cc1fSRoy Marples 	return WEXITSTATUS(status);
6916e63cc1fSRoy Marples }
6926e63cc1fSRoy Marples 
6936e63cc1fSRoy Marples int
694d4fb1e02SRoy Marples script_dump(const char *env, size_t len)
695d4fb1e02SRoy Marples {
696d4fb1e02SRoy Marples 	const char *ep = env + len;
697d4fb1e02SRoy Marples 
698d4fb1e02SRoy Marples 	if (len == 0)
699d4fb1e02SRoy Marples 		return 0;
700d4fb1e02SRoy Marples 
701d4fb1e02SRoy Marples 	if (*(ep - 1) != '\0') {
702d4fb1e02SRoy Marples 		errno = EINVAL;
703d4fb1e02SRoy Marples 		return -1;
704d4fb1e02SRoy Marples 	}
705d4fb1e02SRoy Marples 
706d4fb1e02SRoy Marples 	for (; env < ep; env += strlen(env) + 1) {
707d4fb1e02SRoy Marples 		if (strncmp(env, "new_", 4) == 0)
708d4fb1e02SRoy Marples 			env += 4;
709d4fb1e02SRoy Marples 		printf("%s\n", env);
710d4fb1e02SRoy Marples 	}
711d4fb1e02SRoy Marples 	return 0;
712d4fb1e02SRoy Marples }
713d4fb1e02SRoy Marples 
714d4fb1e02SRoy Marples int
7156e63cc1fSRoy Marples script_runreason(const struct interface *ifp, const char *reason)
7166e63cc1fSRoy Marples {
7176e63cc1fSRoy Marples 	struct dhcpcd_ctx *ctx = ifp->ctx;
7186e63cc1fSRoy Marples 	char *argv[2];
7196e63cc1fSRoy Marples 	int status = 0;
7206e63cc1fSRoy Marples 	struct fd_list *fd;
721d4fb1e02SRoy Marples 	long buflen;
7226e63cc1fSRoy Marples 
723d4fb1e02SRoy Marples 	if (ctx->script == NULL &&
7246e63cc1fSRoy Marples 	    TAILQ_FIRST(&ifp->ctx->control_fds) == NULL)
7256e63cc1fSRoy Marples 		return 0;
7266e63cc1fSRoy Marples 
7276e63cc1fSRoy Marples 	/* Make our env */
728d4fb1e02SRoy Marples 	if ((buflen = make_env(ifp->ctx, ifp, reason)) == -1) {
7296e63cc1fSRoy Marples 		logerr(__func__);
7306e63cc1fSRoy Marples 		return -1;
7316e63cc1fSRoy Marples 	}
7326e63cc1fSRoy Marples 
733d4fb1e02SRoy Marples 	if (strncmp(reason, "DUMP", 4) == 0)
734d4fb1e02SRoy Marples 		return script_dump(ctx->script_buf, (size_t)buflen);
735d4fb1e02SRoy Marples 
736d4fb1e02SRoy Marples 	if (ctx->script == NULL)
7376e63cc1fSRoy Marples 		goto send_listeners;
7386e63cc1fSRoy Marples 
739d4fb1e02SRoy Marples 	argv[0] = ctx->script;
7406e63cc1fSRoy Marples 	argv[1] = NULL;
741a0d9933aSRoy Marples 	logdebugx("%s: executing: %s %s", ifp->name, argv[0], reason);
7426e63cc1fSRoy Marples 
7436e63cc1fSRoy Marples #ifdef PRIVSEP
7446e63cc1fSRoy Marples 	if (ctx->options & DHCPCD_PRIVSEP) {
745d4fb1e02SRoy Marples 		if (ps_root_script(ctx,
7466e63cc1fSRoy Marples 		    ctx->script_buf, ctx->script_buflen) == -1)
7476e63cc1fSRoy Marples 			logerr(__func__);
7486e63cc1fSRoy Marples 		goto send_listeners;
7496e63cc1fSRoy Marples 	}
7506e63cc1fSRoy Marples #endif
7516e63cc1fSRoy Marples 
752d4fb1e02SRoy Marples 	script_run(ctx, argv);
7536e63cc1fSRoy Marples 
7547827cba2SAaron LI send_listeners:
7557827cba2SAaron LI 	/* Send to our listeners */
7567827cba2SAaron LI 	status = 0;
7578d36e1dfSRoy Marples 	TAILQ_FOREACH(fd, &ctx->control_fds, next) {
7587827cba2SAaron LI 		if (!(fd->flags & FD_LISTEN))
7597827cba2SAaron LI 			continue;
7607f8103cdSRoy Marples 		if (control_queue(fd, ctx->script_buf, ctx->script_buflen)== -1)
7617827cba2SAaron LI 			logerr("%s: control_queue", __func__);
7627827cba2SAaron LI 		else
7637827cba2SAaron LI 			status = 1;
7647827cba2SAaron LI 	}
7657827cba2SAaron LI 
7666e63cc1fSRoy Marples 	return status;
7677827cba2SAaron LI }
768