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