CLOSEFROM=
RBTREE=
CONSTTIME_MEMEQUAL=
+OPEN_MEMSTREAM=
STRLCPY=
UDEV=
OS=
echo "#include \"compat/arc4random_uniform.h\"" >>$CONFIG_H
fi
-
-if [ -z "$STRLCPY" ]; then
- printf "Testing for strlcpy ... "
- cat <<EOF >_strlcpy.c
-#include <string.h>
+if [ -z "$OPEN_MEMSTREAM" ]; then
+ printf "Testing for open_memstream ... "
+ cat <<EOF >_open_memstream.c
+#include <stdio.h>
int main(void) {
- const char s1[] = "foo";
- char s2[10];
- strlcpy(s2, s1, sizeof(s2));
+ open_memstream(NULL, NULL);
return 0;
}
EOF
- if $XCC _strlcpy.c -o _strlcpy 2>&3; then
- STRLCPY=yes
+ if $XCC _open_memstream.c -o _open_memstream 2>&3; then
+ OPEN_MEMSTREAM=yes
else
- STRLCPY=no
+ OPEN_MEMSTREAM=no
fi
- echo "$STRLCPY"
- rm -f _strlcpy.c _strlcpy
+ echo "$OPEN_MEMSTREAM"
+ rm -f _open_memstream.c _open_memstream
fi
-if [ "$STRLCPY" = no ]; then
- echo "COMPAT_SRCS+= compat/strlcpy.c" >>$CONFIG_MK
- echo "#include \"compat/strlcpy.h\"" >>$CONFIG_H
+if [ "$OPEN_MEMSTREAM" = yes ]; then
+ echo "#define HAVE_OPEN_MEMSTREAM" >>$CONFIG_H
fi
if [ -z "$PIDFILE_LOCK" ]; then
echo "#define HAVE_SETPROCTITLE" >>$CONFIG_H
fi
+if [ -z "$STRLCPY" ]; then
+ printf "Testing for strlcpy ... "
+ cat <<EOF >_strlcpy.c
+#include <string.h>
+int main(void) {
+ const char s1[] = "foo";
+ char s2[10];
+ strlcpy(s2, s1, sizeof(s2));
+ return 0;
+}
+EOF
+ if $XCC _strlcpy.c -o _strlcpy 2>&3; then
+ STRLCPY=yes
+ else
+ STRLCPY=no
+ fi
+ echo "$STRLCPY"
+ rm -f _strlcpy.c _strlcpy
+fi
+if [ "$STRLCPY" = no ]; then
+ echo "COMPAT_SRCS+= compat/strlcpy.c" >>$CONFIG_MK
+ echo "#include \"compat/strlcpy.h\"" >>$CONFIG_H
+fi
+
if [ -z "$STRTOI" ]; then
printf "Testing for strtoi ... "
cat <<EOF >_strtoi.c
#include <errno.h>
#include <stdlib.h>
+#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <inttypes.h>
#include <stddef.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
/* Most route(4) messages are less than 256 bytes. */
#define IOVEC_BUFSIZ 256
-ssize_t
-setvar(char **e, const char *prefix, const char *var, const char *value)
-{
- size_t len = strlen(var) + strlen(value) + 3;
-
- if (prefix)
- len += strlen(prefix) + 1;
- if ((*e = malloc(len)) == NULL) {
- logerr(__func__);
- return -1;
- }
- if (prefix)
- snprintf(*e, len, "%s_%s=%s", prefix, var, value);
- else
- snprintf(*e, len, "%s=%s", var, value);
- return (ssize_t)len;
-}
-
-ssize_t
-setvard(char **e, const char *prefix, const char *var, size_t value)
-{
-
- char buffer[32];
-
- snprintf(buffer, sizeof(buffer), "%zu", value);
- return setvar(e, prefix, var, buffer);
-}
-
-ssize_t
-addvar(char ***e, const char *prefix, const char *var, const char *value)
-{
- ssize_t len;
-
- len = setvar(*e, prefix, var, value);
- if (len != -1)
- (*e)++;
- return (ssize_t)len;
-}
-
-ssize_t
-addvard(char ***e, const char *prefix, const char *var, size_t value)
-{
- char buffer[32];
-
- snprintf(buffer, sizeof(buffer), "%zu", value);
- return addvar(e, prefix, var, buffer);
-}
-
const char *
hwaddr_ntoa(const void *hwaddr, size_t hwlen, char *buf, size_t buflen)
{
extern int clock_monotonic;
int get_monotonic(struct timespec *);
-ssize_t setvar(char **, const char *, const char *, const char *);
-ssize_t setvard(char **, const char *, const char *, size_t);
-ssize_t addvar(char ***, const char *, const char *, const char *);
-ssize_t addvard(char ***, const char *, const char *, size_t);
-
const char *hwaddr_ntoa(const void *, size_t, char *, size_t);
size_t hwaddr_aton(uint8_t *, const char *);
size_t read_hwaddr_aton(uint8_t **, const char *);
#include <string.h>
#include <unistd.h>
-#include <arpa/nameser.h> /* after normal includes for sunos */
-
#include "config.h"
#include "common.h"
#include "if.h"
#include "ipv6.h"
#include "logerr.h"
-
-/* Support very old arpa/nameser.h as found in OpenBSD */
-#ifndef NS_MAXDNAME
-#define NS_MAXCDNAME MAXCDNAME
-#define NS_MAXDNAME MAXDNAME
-#define NS_MAXLABEL MAXLABEL
-#endif
+#include "script.h"
const char *
dhcp_get_hostname(char *buf, size_t buf_len, const struct if_options *ifo)
return (ssize_t)sz;
}
-/* It's possible for DHCPv4 to contain an IPv6 address */
-static ssize_t
-ipv6_printaddr(char *s, size_t sl, const uint8_t *d, const char *ifname)
-{
- char buf[INET6_ADDRSTRLEN];
- const char *p;
- size_t l;
-
- p = inet_ntop(AF_INET6, d, buf, sizeof(buf));
- if (p == NULL)
- return -1;
-
- l = strlen(p);
- if (d[0] == 0xfe && (d[1] & 0xc0) == 0x80)
- l += 1 + strlen(ifname);
-
- if (s == NULL)
- return (ssize_t)l;
-
- if (sl < l) {
- errno = ENOMEM;
- return -1;
- }
-
- s += strlcpy(s, p, sl);
- if (d[0] == 0xfe && (d[1] & 0xc0) == 0x80) {
- *s++ = '%';
- s += strlcpy(s, ifname, sl);
- }
- *s = '\0';
- return (ssize_t)l;
-}
-
static ssize_t
-print_option(char *s, size_t len, const struct dhcp_opt *opt,
+print_option(FILE *fp, const char *prefix, const struct dhcp_opt *opt,
+ int vname,
const uint8_t *data, size_t dl, const char *ifname)
{
const uint8_t *e, *t;
struct in_addr addr;
ssize_t bytes = 0, sl;
size_t l;
-#ifdef INET
- char *tmp;
-#endif
+
+ /* Ensure a valid length */
+ dl = (size_t)dhcp_optlen(opt, dl);
+ if ((ssize_t)dl == -1)
+ return 0;
+
+ if (fprintf(fp, "%s", prefix) == -1)
+ return -1;
+ if (vname) {
+ if (fprintf(fp, "_%s", opt->var) == -1)
+ return -1;
+ }
+ if (fputc('=', fp) == EOF)
+ return -1;
+ if (dl == 0)
+ return 1;
if (opt->type & OT_RFC1035) {
- sl = decode_rfc1035(s, len, data, dl);
+ char domain[NS_MAXDNAME];
+
+ sl = decode_rfc1035(domain, sizeof(domain), data, dl);
if (sl == 0 || sl == -1)
return sl;
- if (s != NULL) {
- if (valid_domainname(s, opt->type) == -1)
- return -1;
- }
- return sl;
+ if (valid_domainname(domain, opt->type) == -1)
+ return -1;
+ return efprintf(fp, "%s", domain);
}
#ifdef INET
- if (opt->type & OT_RFC3361) {
- if ((tmp = decode_rfc3361(data, dl)) == NULL)
- return -1;
- l = strlen(tmp);
- sl = print_string(s, len, opt->type, (uint8_t *)tmp, l);
- free(tmp);
- return sl;
- }
+ if (opt->type & OT_RFC3361)
+ return print_rfc3361(fp, data, dl);
if (opt->type & OT_RFC3442)
- return decode_rfc3442(s, len, data, dl);
+ return print_rfc3442(fp, data, dl);
#endif
- if (opt->type & OT_STRING)
- return print_string(s, len, opt->type, data, dl);
+ if (opt->type & OT_STRING) {
+ char buf[1024];
- if (opt->type & OT_FLAG) {
- if (s) {
- *s++ = '1';
- *s = '\0';
- }
- return 1;
+ if (print_string(buf, sizeof(buf), opt->type, data, dl) == -1)
+ return -1;
+ return efprintf(fp, "%s", buf);
}
+ if (opt->type & OT_FLAG)
+ return efprintf(fp, "1");
+
if (opt->type & OT_BITFLAG) {
/* bitflags are a string, MSB first, such as ABCDEFGH
* where A is 10000000, B is 01000000, etc. */
opt->bitflags[l] != '0' &&
*data & (1 << sl))
{
- if (s)
- *s++ = opt->bitflags[l];
- bytes++;
+ if (fputc(opt->bitflags[l], fp) == EOF)
+ return -1;
}
}
- if (s)
- *s = '\0';
- return bytes;
- }
-
- if (!s) {
- if (opt->type & OT_UINT8)
- l = 3;
- else if (opt->type & OT_INT8)
- l = 4;
- else if (opt->type & OT_UINT16) {
- l = 5;
- dl /= 2;
- } else if (opt->type & OT_INT16) {
- l = 6;
- dl /= 2;
- } else if (opt->type & OT_UINT32) {
- l = 10;
- dl /= 4;
- } else if (opt->type & OT_INT32) {
- l = 11;
- dl /= 4;
- } else if (opt->type & OT_ADDRIPV4) {
- l = 16;
- dl /= 4;
- } else if (opt->type & OT_ADDRIPV6) {
- e = data + dl;
- l = 0;
- while (data < e) {
- if (l)
- l++; /* space */
- sl = ipv6_printaddr(NULL, 0, data, ifname);
- if (sl == -1)
- return l == 0 ? -1 : (ssize_t)l;
- l += (size_t)sl;
- data += 16;
- }
- return (ssize_t)l;
- } else {
- errno = EINVAL;
+ if (fputc('\0', fp) == EOF)
return -1;
- }
- return (ssize_t)(l * dl);
+ return 1;
}
t = data;
e = data + dl;
while (data < e) {
if (data != t) {
- *s++ = ' ';
- bytes++;
- len--;
+ if (fputc(' ', fp) == EOF)
+ return -1;
}
if (opt->type & OT_UINT8) {
- sl = snprintf(s, len, "%u", *data);
+ if (fprintf(fp, "%u", *data) == -1)
+ return -1;
data++;
} else if (opt->type & OT_INT8) {
- sl = snprintf(s, len, "%d", *data);
+ if (fprintf(fp, "%d", *data) == -1)
+ return -1;
data++;
} else if (opt->type & OT_UINT16) {
memcpy(&u16, data, sizeof(u16));
u16 = ntohs(u16);
- sl = snprintf(s, len, "%u", u16);
+ if (fprintf(fp, "%u", u16) == -1)
+ return -1;
data += sizeof(u16);
} else if (opt->type & OT_INT16) {
memcpy(&u16, data, sizeof(u16));
s16 = (int16_t)ntohs(u16);
- sl = snprintf(s, len, "%d", s16);
+ if (fprintf(fp, "%d", s16) == -1)
+ return -1;
data += sizeof(u16);
} else if (opt->type & OT_UINT32) {
memcpy(&u32, data, sizeof(u32));
u32 = ntohl(u32);
- sl = snprintf(s, len, "%u", u32);
+ if (fprintf(fp, "%u", u32) == -1)
+ return -1;
data += sizeof(u32);
} else if (opt->type & OT_INT32) {
memcpy(&u32, data, sizeof(u32));
s32 = (int32_t)ntohl(u32);
- sl = snprintf(s, len, "%d", s32);
+ if (fprintf(fp, "%d", s32) == -1)
+ return -1;
data += sizeof(u32);
} else if (opt->type & OT_ADDRIPV4) {
memcpy(&addr.s_addr, data, sizeof(addr.s_addr));
- sl = snprintf(s, len, "%s", inet_ntoa(addr));
+ if (fprintf(fp, "%s", inet_ntoa(addr)) == -1)
+ return -1;
data += sizeof(addr.s_addr);
} else if (opt->type & OT_ADDRIPV6) {
- sl = ipv6_printaddr(s, len, data, ifname);
+ char buf[INET6_ADDRSTRLEN];
+
+ if (inet_ntop(AF_INET6, data, buf, sizeof(buf)) == NULL)
+ return -1;
+ if (fprintf(fp, "%s", buf) == -1)
+ return -1;
+ if (data[0] == 0xfe && (data[1] & 0xc0) == 0x80) {
+ if (fprintf(fp,"%%%s", ifname) == -1)
+ return -1;
+ }
data += 16;
} else {
errno = EINVAL;
return -1;
}
- if (sl == -1)
- return bytes == 0 ? -1 : bytes;
- len -= (size_t)sl;
- bytes += sl;
- s += sl;
}
- return bytes;
+ if (fputc('\0', fp) == EOF)
+ return -1;
+ return 1;
}
int
ifp->name, ssid);
}
-static size_t
-dhcp_envoption1(char **env, const char *prefix,
- const struct dhcp_opt *opt, int vname, const uint8_t *od, size_t ol,
- const char *ifname)
-{
- ssize_t len;
- size_t e;
- char *v, *val;
- int r;
-
- /* Ensure a valid length */
- ol = (size_t)dhcp_optlen(opt, ol);
- if ((ssize_t)ol == -1)
- return 0;
-
- len = print_option(NULL, 0, opt, od, ol, ifname);
- if (len < 0)
- return 0;
- if (vname)
- e = strlen(opt->var) + 1;
- else
- e = 0;
- if (prefix)
- e += strlen(prefix);
- e += (size_t)len + 2;
- if (env == NULL)
- return e;
- v = val = *env = malloc(e);
- if (v == NULL)
- return 0;
- if (vname)
- r = snprintf(val, e, "%s_%s=", prefix, opt->var);
- else
- r = snprintf(val, e, "%s=", prefix);
- if (r != -1 && len != 0) {
- v += r;
- if (print_option(v, (size_t)len + 1, opt, od, ol, ifname) == -1)
- r = -1;
- }
- if (r == -1) {
- free(val);
- return 0;
- }
- return e;
-}
-
-size_t
-dhcp_envoption(struct dhcpcd_ctx *ctx, char **env, const char *prefix,
+void
+dhcp_envoption(struct dhcpcd_ctx *ctx, FILE *fp, const char *prefix,
const char *ifname, struct dhcp_opt *opt,
const uint8_t *(*dgetopt)(struct dhcpcd_ctx *,
size_t *, unsigned int *, size_t *,
const uint8_t *, size_t, struct dhcp_opt **),
const uint8_t *od, size_t ol)
{
- size_t e, i, n, eos, eol;
+ size_t i, eos, eol;
ssize_t eo;
unsigned int eoc;
const uint8_t *eod;
/* If no embedded or encapsulated options, it's easy */
if (opt->embopts_len == 0 && opt->encopts_len == 0) {
- if (!(opt->type & OT_RESERVED)) {
- if (dhcp_envoption1(env == NULL ? NULL : &env[0],
- prefix, opt, 1, od, ol, ifname))
- return 1;
- else
- logerr("%s: %s %d",
- ifname, __func__, opt->option);
- }
- return 0;
+ if (opt->type & OT_RESERVED)
+ return;
+ if (print_option(fp, prefix, opt, 1, od, ol, ifname) == -1)
+ logerr("%s: %s %d", ifname, __func__, opt->option);
+ return;
}
/* Create a new prefix based on the option */
- if (env) {
- if (opt->type & OT_INDEX) {
- if (opt->index > 999) {
- errno = ENOBUFS;
- logerr(__func__);
- return 0;
- }
- }
- e = strlen(prefix) + strlen(opt->var) + 2 +
- (opt->type & OT_INDEX ? 3 : 0);
- pfx = malloc(e);
- if (pfx == NULL) {
- logerr(__func__);
- return 0;
- }
- if (opt->type & OT_INDEX)
- snprintf(pfx, e, "%s_%s%d", prefix,
- opt->var, ++opt->index);
- else
- snprintf(pfx, e, "%s_%s", prefix, opt->var);
- } else
- pfx = NULL;
+ if (opt->type & OT_INDEX) {
+ if (asprintf(&pfx, "%s_%s%d",
+ prefix, opt->var, ++opt->index) == -1)
+ pfx = NULL;
+ } else {
+ if (asprintf(&pfx, "%s_%s", prefix, opt->var) == -1)
+ pfx = NULL;
+ }
+ if (pfx == NULL) {
+ logerr(__func__);
+ return;
+ }
/* Embedded options are always processed first as that
* is a fixed layout */
- n = 0;
for (i = 0, eopt = opt->embopts; i < opt->embopts_len; i++, eopt++) {
eo = dhcp_optlen(eopt, ol);
if (eo == -1) {
- if (env == NULL)
- logerrx("%s: %s %d.%d/%zu: "
- "malformed embedded option",
- ifname, __func__, opt->option,
- eopt->option, i);
+ logerrx("%s: %s %d.%d/%zu: "
+ "malformed embedded option",
+ ifname, __func__, opt->option,
+ eopt->option, i);
goto out;
}
if (eo == 0) {
* This may not be an error as some options like
* DHCP FQDN in RFC4702 have a string as the last
* option which is optional. */
- if (env == NULL &&
- (ol != 0 || !(eopt->type & OT_OPTIONAL)))
- logerrx("%s: %s %d.%d/%zu: missing embedded option",
+ if (ol != 0 || !(eopt->type & OT_OPTIONAL))
+ logerrx("%s: %s %d.%d/%zu: "
+ "missing embedded option",
ifname, __func__, opt->option,
eopt->option, i);
goto out;
* This avoids new_fqdn_fqdn which would be silly. */
if (!(eopt->type & OT_RESERVED)) {
ov = strcmp(opt->var, eopt->var);
- if (dhcp_envoption1(env == NULL ? NULL : &env[n],
- pfx, eopt, ov, od, (size_t)eo, ifname))
- n++;
- else if (env == NULL)
+ if (print_option(fp, pfx, eopt, ov, od, (size_t)eo,
+ ifname) == -1)
logerr("%s: %s %d.%d/%zu",
ifname, __func__,
opt->option, eopt->option, i);
i < opt->encopts_len;
i++, eopt++)
{
- if (eopt->option == eoc) {
- if (eopt->type & OT_OPTION) {
- if (oopt == NULL)
- /* Report error? */
- continue;
- }
- n += dhcp_envoption(ctx,
- env == NULL ? NULL : &env[n], pfx,
- ifname,
- eopt->type & OT_OPTION ? oopt:eopt,
- dgetopt, eod, eol);
- break;
+ if (eopt->option != eoc)
+ continue;
+ if (eopt->type & OT_OPTION) {
+ if (oopt == NULL)
+ /* Report error? */
+ continue;
}
+ dhcp_envoption(ctx, fp, pfx, ifname,
+ eopt->type & OT_OPTION ? oopt:eopt,
+ dgetopt, eod, eol);
}
od += eos + eol;
ol -= eos + eol;
}
out:
- if (env)
- free(pfx);
-
- /* Return number of options found */
- return n;
+ free(pfx);
}
void
size_t sz;
void *buf;
ssize_t len;
-
+
if (fstat(fd, &st) != 0)
goto out;
if (!S_ISREG(st.st_mode)) {
#include <stdint.h>
+#include <arpa/nameser.h> /* after normal includes for sunos */
+
#include "common.h"
#include "dhcpcd.h"
+/* Support very old arpa/nameser.h as found in OpenBSD */
+#ifndef NS_MAXDNAME
+#define NS_MAXCDNAME MAXCDNAME
+#define NS_MAXDNAME MAXDNAME
+#define NS_MAXLABEL MAXLABEL
+#endif
+
/* Max MTU - defines dhcp option length */
#define IP_UDP_SIZE 28
#define MTU_MAX 1500 - IP_UDP_SIZE
ssize_t print_string(char *, size_t, int, const uint8_t *, size_t);
int dhcp_set_leasefile(char *, size_t, int, const struct interface *);
-size_t dhcp_envoption(struct dhcpcd_ctx *,
- char **, const char *, const char *, struct dhcp_opt *,
+void dhcp_envoption(struct dhcpcd_ctx *,
+ FILE *, const char *, const char *, struct dhcp_opt *,
const uint8_t *(*dgetopt)(struct dhcpcd_ctx *,
size_t *, unsigned int *, size_t *,
const uint8_t *, size_t, struct dhcp_opt **),
#include <inttypes.h>
#include <stdbool.h>
#include <stddef.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
}
ssize_t
-decode_rfc3442(char *out, size_t len, const uint8_t *p, size_t pl)
+print_rfc3442(FILE *fp, const uint8_t *data, size_t data_len)
{
- const uint8_t *e;
- size_t bytes = 0, ocets;
- int b;
+ const uint8_t *p = data, *e;
+ size_t ocets;
uint8_t cidr;
struct in_addr addr;
- char *o = out;
/* Minimum is 5 -first is CIDR and a router length of 4 */
- if (pl < 5) {
+ if (data_len < 5) {
errno = EINVAL;
return -1;
}
- e = p + pl;
+ e = p + data_len;
while (p < e) {
+ if (p != data) {
+ if (fputc(' ', fp) == EOF)
+ return -1;
+ }
cidr = *p++;
if (cidr > 32) {
errno = EINVAL;
errno = ERANGE;
return -1;
}
- if (!out) {
- p += 4 + ocets;
- bytes += ((4 * 4) * 2) + 4;
- continue;
- }
- if ((((4 * 4) * 2) + 4) > len) {
- errno = ENOBUFS;
- return -1;
- }
- if (o != out) {
- *o++ = ' ';
- len--;
- }
/* If we have ocets then we have a destination and netmask */
+ addr.s_addr = 0;
if (ocets > 0) {
- addr.s_addr = 0;
memcpy(&addr.s_addr, p, ocets);
- b = snprintf(o, len, "%s/%d", inet_ntoa(addr), cidr);
p += ocets;
- } else
- b = snprintf(o, len, "0.0.0.0/0");
- o += b;
- len -= (size_t)b;
+ }
+ if (fprintf(fp, "%s/%d", inet_ntoa(addr), cidr) == -1)
+ return -1;
/* Finally, snag the router */
memcpy(&addr.s_addr, p, 4);
p += 4;
- b = snprintf(o, len, " %s", inet_ntoa(addr));
- o += b;
- len -= (size_t)b;
+ if (fprintf(fp, " %s", inet_ntoa(addr)) == -1)
+ return -1;
}
- if (out)
- return o - out;
- return (ssize_t)bytes;
+ if (fputc('\0', fp) == EOF)
+ return -1;
+ return 1;
}
static int
return n;
}
-char *
-decode_rfc3361(const uint8_t *data, size_t dl)
+ssize_t
+print_rfc3361(FILE *fp, const uint8_t *data, size_t dl)
{
uint8_t enc;
- size_t l;
- ssize_t r;
- char *sip = NULL;
+ char sip[NS_MAXDNAME];
struct in_addr addr;
- char *p;
if (dl < 2) {
errno = EINVAL;
dl--;
switch (enc) {
case 0:
- if ((r = decode_rfc1035(NULL, 0, data, dl)) > 0) {
- l = (size_t)r + 1;
- sip = malloc(l);
- if (sip == NULL)
- return 0;
- decode_rfc1035(sip, l, data, dl);
- }
+ if (decode_rfc1035(sip, sizeof(sip), data, dl) == -1)
+ return -1;
+ if (efprintf(fp, "%s", sip) == -1)
+ return -1;
break;
case 1:
if (dl == 0 || dl % 4 != 0) {
break;
}
addr.s_addr = INADDR_BROADCAST;
- l = ((dl / sizeof(addr.s_addr)) * ((4 * 4) + 1)) + 1;
- sip = p = malloc(l);
- if (sip == NULL)
- return 0;
- while (dl != 0) {
+ for (;
+ dl != 0;
+ data += sizeof(addr.s_addr), dl -= sizeof(addr.s_addr))
+ {
memcpy(&addr.s_addr, data, sizeof(addr.s_addr));
- data += sizeof(addr.s_addr);
- p += snprintf(p, l - (size_t)(p - sip),
- "%s ", inet_ntoa(addr));
- dl -= sizeof(addr.s_addr);
+ if (fprintf(fp, "%s", inet_ntoa(addr)) == -1)
+ return -1;
+ if (dl != 0) {
+ if (fputc(' ', fp) == EOF)
+ return -1;
+ }
}
- *--p = '\0';
+ if (fputc('\0', fp) == EOF)
+ return -1;
break;
default:
errno = EINVAL;
return 0;
}
- return sip;
+ return 1;
}
static char *
}
ssize_t
-dhcp_env(char **env, const char *prefix,
- const struct bootp *bootp, size_t bootp_len,
- const struct interface *ifp)
+dhcp_env(FILE *fenv, const char *prefix, const struct interface *ifp,
+ const struct bootp *bootp, size_t bootp_len)
{
const struct if_options *ifo;
const uint8_t *p;
struct in_addr brd;
struct dhcp_opt *opt, *vo;
size_t e, i, pl;
- char **ep;
- char cidr[4], safe[(BOOTP_FILE_LEN * 4) + 1];
+ char safe[(BOOTP_FILE_LEN * 4) + 1];
uint8_t overl = 0;
uint32_t en;
DHO_OPTSOVERLOADED) == -1)
overl = 0;
- if (env == NULL) {
- if (bootp->yiaddr || bootp->ciaddr)
- e += 5;
- if (*bootp->file && !(overl & 1))
- e++;
- if (*bootp->sname && !(overl & 2))
- e++;
- for (i = 0, opt = ifp->ctx->dhcp_opts;
- i < ifp->ctx->dhcp_opts_len;
- i++, opt++)
- {
- if (has_option_mask(ifo->nomask, opt->option))
- continue;
- if (dhcp_getoverride(ifo, opt->option))
- continue;
- p = get_option(ifp->ctx, bootp, bootp_len,
- opt->option, &pl);
- if (!p)
- continue;
- e += dhcp_envoption(ifp->ctx, NULL, NULL, ifp->name,
- opt, dhcp_getoption, p, pl);
- }
- for (i = 0, opt = ifo->dhcp_override;
- i < ifo->dhcp_override_len;
- i++, opt++)
- {
- if (has_option_mask(ifo->nomask, opt->option))
- continue;
- p = get_option(ifp->ctx, bootp, bootp_len,
- opt->option, &pl);
- if (!p)
- continue;
- e += dhcp_envoption(ifp->ctx, NULL, NULL, ifp->name,
- opt, dhcp_getoption, p, pl);
- }
- return (ssize_t)e;
- }
-
- ep = env;
if (bootp->yiaddr || bootp->ciaddr) {
/* Set some useful variables that we derive from the DHCP
* message but are not necessarily in the options */
addr.s_addr = bootp->yiaddr ? bootp->yiaddr : bootp->ciaddr;
- addvar(&ep, prefix, "ip_address", inet_ntoa(addr));
+ if (efprintf(fenv, "%s_ip_address=%s",
+ prefix, inet_ntoa(addr)) == -1)
+ return -1;
if (get_option_addr(ifp->ctx, &net,
- bootp, bootp_len, DHO_SUBNETMASK) == -1)
- {
+ bootp, bootp_len, DHO_SUBNETMASK) == -1) {
net.s_addr = ipv4_getnetmask(addr.s_addr);
- addvar(&ep, prefix,
- "subnet_mask", inet_ntoa(net));
+ if (efprintf(fenv, "%s_subnet_mask=%s",
+ prefix, inet_ntoa(net)) == -1)
+ return -1;
}
- snprintf(cidr, sizeof(cidr), "%d", inet_ntocidr(net));
- addvar(&ep, prefix, "subnet_cidr", cidr);
+ if (efprintf(fenv, "%s_subnet_cidr=%d",
+ prefix, inet_ntocidr(net))== -1)
+ return -1;
if (get_option_addr(ifp->ctx, &brd,
bootp, bootp_len, DHO_BROADCAST) == -1)
{
brd.s_addr = addr.s_addr | ~net.s_addr;
- addvar(&ep, prefix,
- "broadcast_address", inet_ntoa(brd));
+ if (efprintf(fenv, "%s_broadcast_address=%s",
+ prefix, inet_ntoa(brd)) == -1)
+ return -1;
}
addr.s_addr = bootp->yiaddr & net.s_addr;
- addvar(&ep, prefix,
- "network_number", inet_ntoa(addr));
+ if (efprintf(fenv, "%s_network_number=%s",
+ prefix, inet_ntoa(addr)) == -1)
+ return -1;
}
if (*bootp->file && !(overl & 1)) {
print_string(safe, sizeof(safe), OT_STRING,
bootp->file, sizeof(bootp->file));
- addvar(&ep, prefix, "filename", safe);
+ if (efprintf(fenv, "%s_filename=%s", prefix, safe) == -1)
+ return -1;
}
if (*bootp->sname && !(overl & 2)) {
print_string(safe, sizeof(safe), OT_STRING | OT_DOMAIN,
bootp->sname, sizeof(bootp->sname));
- addvar(&ep, prefix, "server_name", safe);
+ if (efprintf(fenv, "%s_server_name=%s", prefix, safe) == -1)
+ return -1;
}
/* Zero our indexes */
- if (env) {
- for (i = 0, opt = ifp->ctx->dhcp_opts;
- i < ifp->ctx->dhcp_opts_len;
- i++, opt++)
- dhcp_zero_index(opt);
- for (i = 0, opt = ifp->options->dhcp_override;
- i < ifp->options->dhcp_override_len;
- i++, opt++)
- dhcp_zero_index(opt);
- for (i = 0, opt = ifp->ctx->vivso;
- i < ifp->ctx->vivso_len;
- i++, opt++)
- dhcp_zero_index(opt);
- }
+ for (i = 0, opt = ifp->ctx->dhcp_opts;
+ i < ifp->ctx->dhcp_opts_len;
+ i++, opt++)
+ dhcp_zero_index(opt);
+ for (i = 0, opt = ifp->options->dhcp_override;
+ i < ifp->options->dhcp_override_len;
+ i++, opt++)
+ dhcp_zero_index(opt);
+ for (i = 0, opt = ifp->ctx->vivso;
+ i < ifp->ctx->vivso_len;
+ i++, opt++)
+ dhcp_zero_index(opt);
for (i = 0, opt = ifp->ctx->dhcp_opts;
i < ifp->ctx->dhcp_opts_len;
p = get_option(ifp->ctx, bootp, bootp_len, opt->option, &pl);
if (p == NULL)
continue;
- ep += dhcp_envoption(ifp->ctx, ep, prefix, ifp->name,
+ dhcp_envoption(ifp->ctx, fenv, prefix, ifp->name,
opt, dhcp_getoption, p, pl);
if (opt->option != DHO_VIVSO || pl <= (int)sizeof(uint32_t))
/* Skip over en + total size */
p += sizeof(en) + 1;
pl -= sizeof(en) + 1;
- ep += dhcp_envoption(ifp->ctx, ep, prefix, ifp->name,
+ dhcp_envoption(ifp->ctx, fenv, prefix, ifp->name,
vo, dhcp_getoption, p, pl);
}
p = get_option(ifp->ctx, bootp, bootp_len, opt->option, &pl);
if (p == NULL)
continue;
- ep += dhcp_envoption(ifp->ctx, ep, prefix, ifp->name,
+ dhcp_envoption(ifp->ctx, fenv, prefix, ifp->name,
opt, dhcp_getoption, p, pl);
}
- return ep - env;
+ return 1;
}
static void
#include "dhcpcd.h"
#include "if-options.h"
-char *decode_rfc3361(const uint8_t *, size_t);
-ssize_t decode_rfc3442(char *, size_t, const uint8_t *p, size_t);
+ssize_t print_rfc3361(FILE *, const uint8_t *, size_t);
+ssize_t print_rfc3442(FILE *, const uint8_t *, size_t);
void dhcp_printoptions(const struct dhcpcd_ctx *,
const struct dhcp_opt *, size_t);
uint16_t dhcp_get_mtu(const struct interface *);
int dhcp_get_routes(rb_tree_t *, struct interface *);
-ssize_t dhcp_env(char **, const char *, const struct bootp *, size_t,
- const struct interface *);
+ssize_t dhcp_env(FILE *, const char *, const struct interface *,
+ const struct bootp *, size_t);
void dhcp_handleifa(int, struct ipv4_addr *, pid_t pid);
void dhcp_drop(struct interface *, const char *);
}
ssize_t
-dhcp6_env(char **env, const char *prefix, const struct interface *ifp,
+dhcp6_env(FILE *fp, const char *prefix, const struct interface *ifp,
const struct dhcp6_message *m, size_t len)
{
const struct if_options *ifo;
#ifndef SMALL
const struct dhcp6_state *state;
const struct ipv6_addr *ap;
- char *v, *val;
#endif
n = 0;
ctx = ifp->ctx;
/* Zero our indexes */
- if (env) {
- for (i = 0, opt = ctx->dhcp6_opts;
- i < ctx->dhcp6_opts_len;
- i++, opt++)
- dhcp_zero_index(opt);
- for (i = 0, opt = ifp->options->dhcp6_override;
- i < ifp->options->dhcp6_override_len;
- i++, opt++)
- dhcp_zero_index(opt);
- for (i = 0, opt = ctx->vivso;
- i < ctx->vivso_len;
- i++, opt++)
- dhcp_zero_index(opt);
- i = strlen(prefix) + strlen("_dhcp6") + 1;
- pfx = malloc(i);
- if (pfx == NULL) {
- logerr(__func__);
- return -1;
- }
- snprintf(pfx, i, "%s_dhcp6", prefix);
- } else
- pfx = NULL;
+ for (i = 0, opt = ctx->dhcp6_opts;
+ i < ctx->dhcp6_opts_len;
+ i++, opt++)
+ dhcp_zero_index(opt);
+ for (i = 0, opt = ifp->options->dhcp6_override;
+ i < ifp->options->dhcp6_override_len;
+ i++, opt++)
+ dhcp_zero_index(opt);
+ for (i = 0, opt = ctx->vivso;
+ i < ctx->vivso_len;
+ i++, opt++)
+ dhcp_zero_index(opt);
+ if (asprintf(&pfx, "%s_dhcp6", prefix) == -1)
+ return -1;
/* Unlike DHCP, DHCPv6 options *may* occur more than once.
* There is also no provision for option concatenation unlike DHCP. */
opt = NULL;
}
if (opt) {
- n += dhcp_envoption(ifp->ctx,
- env == NULL ? NULL : &env[n],
- pfx, ifp->name,
+ dhcp_envoption(ifp->ctx,
+ fp, pfx, ifp->name,
opt, dhcp6_getoption, p, o.len);
}
if (vo) {
- n += dhcp_envoption(ifp->ctx,
- env == NULL ? NULL : &env[n],
- pfx, ifp->name,
+ dhcp_envoption(ifp->ctx,
+ fp, pfx, ifp->name,
vo, dhcp6_getoption,
p + sizeof(en),
o.len - sizeof(en));
#ifndef SMALL
/* Needed for Delegated Prefixes */
state = D6_CSTATE(ifp);
- i = 0;
TAILQ_FOREACH(ap, &state->addrs, next) {
- if (ap->delegating_prefix) {
- i += strlen(ap->saddr) + 1;
- }
+ if (ap->delegating_prefix)
+ break;
}
- if (env && i) {
- i += strlen(prefix) + strlen("_delegated_dhcp6_prefix=");
- v = val = env[n] = malloc(i);
- if (v == NULL) {
- logerr(__func__);
- return -1;
- }
- v += snprintf(val, i, "%s_delegated_dhcp6_prefix=", prefix);
- TAILQ_FOREACH(ap, &state->addrs, next) {
- if (ap->delegating_prefix) {
- /* Can't use stpcpy(3) due to "security" */
- const char *sap = ap->saddr;
-
- do
- *v++ = *sap;
- while (*++sap != '\0');
- *v++ = ' ';
- }
+ if (ap == NULL)
+ return 1;
+ if (fprintf(fp, "%s_delegated_dhcp6_prefix=", prefix) == -1)
+ return -1;
+ TAILQ_FOREACH(ap, &state->addrs, next) {
+ if (ap->delegating_prefix == NULL)
+ continue;
+ if (ap != TAILQ_FIRST(&state->addrs)) {
+ if (fputc(' ', fp) == EOF)
+ return -1;
}
- *--v = '\0';
+ if (fprintf(fp, "%s", ap->saddr) == -1)
+ return -1;
}
- if (i)
- n++;
+ if (fputc('\0', fp) == EOF)
+ return -1;
#endif
- return (ssize_t)n;
+ return 1;
}
int
int dhcp6_start(struct interface *, enum DH6S);
void dhcp6_reboot(struct interface *);
void dhcp6_renew(struct interface *);
-ssize_t dhcp6_env(char **, const char *, const struct interface *,
+ssize_t dhcp6_env(FILE *, const char *, const struct interface *,
const struct dhcp6_message *, size_t);
void dhcp6_free(struct interface *);
void dhcp6_handleifa(int, struct ipv6_addr *, pid_t);
if (ctx.options & DHCPCD_FORKED)
_exit(i); /* so atexit won't remove our pidfile */
#endif
+#ifdef HAVE_OPEN_MEMSTREAM
+ if (ctx.script_fp)
+ fclose(ctx.script_fp);
+#endif
+ free(ctx.script_buf);
+ free(ctx.script_env);
return i;
}
#endif
struct eloop *eloop;
+#ifdef HAVE_OPEN_MEMSTREAM
+ FILE *script_fp;
+#endif
+ char *script_buf;
+ size_t script_buflen;
+ char **script_env;
+ size_t script_envlen;
+
int control_fd;
int control_unpriv_fd;
struct fd_list_head control_fds;
#include <ctype.h>
#include <errno.h>
#include <stdbool.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#include <errno.h>
#include <stdbool.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
}
ssize_t
-ipv4ll_env(char **env, const char *prefix, const struct interface *ifp)
+ipv4ll_env(FILE *fp, const char *prefix, const struct interface *ifp)
{
const struct ipv4ll_state *state;
const char *pf = prefix == NULL ? "" : "_";
if ((state = IPV4LL_CSTATE(ifp)) == NULL || state->addr == NULL)
return 0;
- if (env == NULL)
- return 5;
-
/* Emulate a DHCP environment */
- if (asprintf(&env[0], "%s%sip_address=%s",
+ if (efprintf(fp, "%s%sip_address=%s",
prefix, pf, inet_ntoa(state->addr->addr)) == -1)
return -1;
- if (asprintf(&env[1], "%s%ssubnet_mask=%s",
+ if (efprintf(fp, "%s%ssubnet_mask=%s",
prefix, pf, inet_ntoa(state->addr->mask)) == -1)
return -1;
- if (asprintf(&env[2], "%s%ssubnet_cidr=%d",
+ if (efprintf(fp, "%s%ssubnet_cidr=%d",
prefix, pf, inet_ntocidr(state->addr->mask)) == -1)
return -1;
- if (asprintf(&env[3], "%s%sbroadcast_address=%s",
+ if (efprintf(fp, "%s%sbroadcast_address=%s",
prefix, pf, inet_ntoa(state->addr->brd)) == -1)
return -1;
netnum.s_addr = state->addr->addr.s_addr & state->addr->mask.s_addr;
- if (asprintf(&env[4], "%s%snetwork_number=%s",
+ if (efprintf(fp, "%s%snetwork_number=%s",
prefix, pf, inet_ntoa(netnum)) == -1)
return -1;
return 5;
int ipv4ll_subnetroute(rb_tree_t *, struct interface *);
int ipv4ll_defaultroute(rb_tree_t *,struct interface *);
-ssize_t ipv4ll_env(char **, const char *, const struct interface *);
+ssize_t ipv4ll_env(FILE *, const char *, const struct interface *);
void ipv4ll_start(void *);
void ipv4ll_claimed(void *);
void ipv4ll_handle_failure(void *);
}
ssize_t
-ipv6_env(char **env, const char *prefix, const struct interface *ifp)
+ipv6_env(FILE *fp, const char *prefix, const struct interface *ifp)
{
- char **ep;
- ssize_t n;
struct ipv6_addr *ia;
- ep = env;
- n = 0;
ia = ipv6_iffindaddr(UNCONST(ifp), &ifp->options->req_addr6,
IN6_IFF_NOTUSEABLE);
- if (ia) {
- if (env)
- addvar(&ep, prefix, "ip6_address", ia->saddr);
- n++;
- }
-
- return n;
+ if (ia == NULL)
+ return 0;
+ if (efprintf(fp, "%s_ip6_address=%s", prefix, ia->saddr) == -1)
+ return -1;
+ return 1;
}
int
int ipv6_start(struct interface *);
int ipv6_staticdadcompleted(const struct interface *);
int ipv6_startstatic(struct interface *);
-ssize_t ipv6_env(char **, const char *, const struct interface *);
+ssize_t ipv6_env(FILE *, const char *, const struct interface *);
void ipv6_ctxfree(struct dhcpcd_ctx *);
bool inet6_getroutes(struct dhcpcd_ctx *, rb_tree_t *);
#endif /* INET6 */
}
ssize_t
-ipv6nd_env(char **env, const char *prefix, const struct interface *ifp)
+ipv6nd_env(FILE *fp, const struct interface *ifp)
{
size_t i, j, n, len, olen;
struct ra *rap;
- char ndprefix[32], abuf[24];
+ char ndprefix[32];
struct dhcp_opt *opt;
uint8_t *p;
struct nd_opt_hdr ndo;
if (rap->iface != ifp)
continue;
i++;
- if (prefix != NULL)
- snprintf(ndprefix, sizeof(ndprefix),
- "%s_nd%zu", prefix, i);
- else
- snprintf(ndprefix, sizeof(ndprefix),
- "nd%zu", i);
- if (env)
- setvar(&env[n], ndprefix, "from", rap->sfrom);
- n++;
- if (env)
- setvard(&env[n], ndprefix, "acquired",
- (size_t)rap->acquired.tv_sec);
- n++;
- if (env)
- setvard(&env[n], ndprefix, "now", (size_t)now.tv_sec);
- n++;
+ snprintf(ndprefix, sizeof(ndprefix), "nd%zu", i);
+ if (efprintf(fp, "%s_from=%s", ndprefix, rap->sfrom) == -1)
+ return -1;
+ if (efprintf(fp, "%s_acquired=%ld", ndprefix,
+ rap->acquired.tv_sec) == -1)
+ return -1;
+ if (efprintf(fp, "%s_now=%ld", ndprefix, now.tv_sec) == -1)
+ return -1;
/* Zero our indexes */
- if (env) {
- for (j = 0, opt = rap->iface->ctx->nd_opts;
- j < rap->iface->ctx->nd_opts_len;
- j++, opt++)
- dhcp_zero_index(opt);
- for (j = 0, opt = rap->iface->options->nd_override;
- j < rap->iface->options->nd_override_len;
- j++, opt++)
- dhcp_zero_index(opt);
- }
+ for (j = 0, opt = rap->iface->ctx->nd_opts;
+ j < rap->iface->ctx->nd_opts_len;
+ j++, opt++)
+ dhcp_zero_index(opt);
+ for (j = 0, opt = rap->iface->options->nd_override;
+ j < rap->iface->options->nd_override_len;
+ j++, opt++)
+ dhcp_zero_index(opt);
/* Unlike DHCP, ND6 options *may* occur more than once.
* There is also no provision for option concatenation
if (j == rap->iface->ctx->nd_opts_len)
opt = NULL;
}
- if (opt) {
- n += dhcp_envoption(rap->iface->ctx,
- env == NULL ? NULL : &env[n],
- ndprefix, rap->iface->name,
- opt, ipv6nd_getoption,
- p + sizeof(ndo), olen - sizeof(ndo));
- }
+ if (opt == NULL)
+ continue;
+ dhcp_envoption(rap->iface->ctx, fp,
+ ndprefix, rap->iface->name,
+ opt, ipv6nd_getoption,
+ p + sizeof(ndo), olen - sizeof(ndo));
}
/* We need to output the addresses we actually made
!(ia->flags & IPV6_AF_ADDED) ||
ia->prefix_vltime == 0)
continue;
- j++;
- if (env) {
- snprintf(abuf, sizeof(abuf), "addr%zu", j);
- setvar(&env[n], ndprefix, abuf, ia->saddr);
- }
- n++;
+ if (efprintf(fp, "%s_addr%zu=%s",
+ ndprefix, j++, ia->saddr) == -1)
+ return -1;
}
}
- return (ssize_t)n;
+ return 1;
}
void
void ipv6nd_printoptions(const struct dhcpcd_ctx *,
const struct dhcp_opt *, size_t);
void ipv6nd_startrs(struct interface *);
-ssize_t ipv6nd_env(char **, const char *, const struct interface *);
+ssize_t ipv6nd_env(FILE *, const struct interface *);
const struct ipv6_addr *ipv6nd_iffindaddr(const struct interface *ifp,
const struct in6_addr *addr, unsigned int flags);
struct ipv6_addr *ipv6nd_findaddr(struct dhcpcd_ctx *,
#include <errno.h>
#include <signal.h>
#include <spawn.h>
+#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define RC_SVCNAME "RC_SVCNAME"
#endif
-#define DEFAULT_PATH "PATH=/usr/bin:/usr/sbin:/bin:/sbin"
+#define DEFAULT_PATH "/usr/bin:/usr/sbin:/bin:/sbin"
static const char * const if_params[] = {
"interface",
}
#ifdef INET
-static char *
-make_var(const char *prefix, const char *var)
-{
- size_t len;
- char *v;
-
- len = strlen(prefix) + strlen(var) + 2;
- if ((v = malloc(len)) == NULL) {
- logerr(__func__);
- return NULL;
- }
- snprintf(v, len, "%s_%s", prefix, var);
- return v;
-}
-
-
static int
-append_config(char ***env, size_t *len,
- const char *prefix, const char *const *config)
+append_config(FILE *fp, const char *prefix, const char *const *config)
{
- size_t i, j, e1;
- char **ne, *eq, **nep, *p;
- int ret;
+ size_t i;
if (config == NULL)
return 0;
- ne = *env;
- ret = 0;
+ /* Do we need to replace existing config rather than append? */
for (i = 0; config[i] != NULL; i++) {
- eq = strchr(config[i], '=');
- e1 = (size_t)(eq - config[i] + 1);
- for (j = 0; j < *len; j++) {
- if (strncmp(ne[j], prefix, strlen(prefix)) == 0 &&
- ne[j][strlen(prefix)] == '_' &&
- strncmp(ne[j] + strlen(prefix) + 1,
- config[i], e1) == 0)
- {
- p = make_var(prefix, config[i]);
- if (p == NULL) {
- ret = -1;
- break;
- }
- free(ne[j]);
- ne[j] = p;
- break;
- }
- }
- if (j == *len) {
- j++;
- p = make_var(prefix, config[i]);
- if (p == NULL) {
- ret = -1;
- break;
- }
- nep = realloc(ne, sizeof(char *) * (j + 1));
- if (nep == NULL) {
- logerr(__func__);
- free(p);
- ret = -1;
- break;
- }
- ne = nep;
- ne[j - 1] = p;
- *len = j;
- }
+ if (efprintf(fp, "%s_%s", prefix, config[i]) == -1)
+ return -1;
}
- *env = ne;
- return ret;
+ return 1;
}
-#endif
-static ssize_t
-arraytostr(const char *const *argv, char **s)
-{
- const char *const *ap;
- char *p;
- size_t len, l;
-
- if (*argv == NULL)
- return 0;
- len = 0;
- ap = argv;
- while (*ap)
- len += strlen(*ap++) + 1;
- *s = p = malloc(len);
- if (p == NULL)
- return -1;
- ap = argv;
- while (*ap) {
- l = strlen(*ap) + 1;
- memcpy(p, *ap, l);
- p += l;
- ap++;
- }
- return (ssize_t)len;
-}
+#endif
#define PROTO_LINK 0
#define PROTO_DHCP 1
"static6"
};
+int
+efprintf(FILE *fp, const char *fmt, ...)
+{
+ va_list args;
+ int r;
+
+ va_start(args, fmt);
+ r = vfprintf(fp, fmt, args);
+ va_end(args);
+ if (r == -1)
+ return -1;
+ /* Write a trailing NULL so we can easily create env strings. */
+ if (fputc('\0', fp) == EOF)
+ return -1;
+ return r;
+}
+
static ssize_t
-make_env(const struct interface *ifp, const char *reason, char ***argv)
+make_env(const struct interface *ifp, const char *reason)
{
- int protocol, r;
- char **env, **nenv, *p;
- size_t e, elen, l;
-#if defined(INET) || defined(INET6)
- ssize_t n;
-#endif
+ struct dhcpcd_ctx *ctx = ifp->ctx;
+ FILE *fp;
+ char **env, **envp, *buf, *bufp, *endp, *path;
+ size_t nenv;
+ long buf_pos, i;
+ int protocol;
const struct if_options *ifo = ifp->options;
const struct interface *ifp2;
int af;
const struct dhcp6_state *d6_state;
#endif
+#ifdef HAVE_OPEN_MEMSTREAM
+ if (ctx->script_fp == NULL) {
+ fp = open_memstream(&ctx->script_buf, &ctx->script_buflen);
+ if (fp == NULL)
+ goto eexit;
+ ctx->script_fp = fp;
+ } else {
+ fp = ctx->script_fp;
+ rewind(fp);
+ }
+#else
+ char tmpfile[] = "/tmp/dhcpcd-script-env-XXXXXX";
+ int tmpfd;
+
+ fp = NULL;
+ tmpfd = mkstemp(tmpfile);
+ if (tmpfd == -1)
+ goto eexit;
+ unlink(tmpfile);
+ fp = fopen(tmpfile, "w+");
+ close(tmpfd);
+ if (fp == NULL)
+ goto eexit;
+#endif
+
#ifdef INET
state = D_STATE(ifp);
#ifdef IPV4LL
protocol = PROTO_DHCP;
#endif
- /* When dumping the lease, we only want to report interface and
- reason - the other interface variables are meaningless */
- if (ifp->ctx->options & DHCPCD_DUMPLEASE)
- elen = 2;
- else
- elen = 11;
+ /* Needed for scripts */
+ path = getenv("PATH");
+ if (efprintf(fp, "PATH=%s", path == NULL ? DEFAULT_PATH:path) == -1)
+ goto eexit;
-#define EMALLOC(i, l) if ((env[(i)] = malloc((l))) == NULL) goto eexit;
- /* Make our env + space for profile, wireless and debug */
- env = calloc(1, sizeof(char *) * (elen + 5 + 1));
- if (env == NULL)
+ if (efprintf(fp, "interface=%s", ifp->name) == -1)
+ goto eexit;
+ if (efprintf(fp, "reason=%s", reason) == -1)
goto eexit;
- e = strlen("interface") + strlen(ifp->name) + 2;
- EMALLOC(0, e);
- snprintf(env[0], e, "interface=%s", ifp->name);
- e = strlen("reason") + strlen(reason) + 2;
- EMALLOC(1, e);
- snprintf(env[1], e, "reason=%s", reason);
if (ifp->ctx->options & DHCPCD_DUMPLEASE)
goto dumplease;
- e = 20;
- EMALLOC(2, e);
- snprintf(env[2], e, "pid=%d", getpid());
- EMALLOC(3, e);
- snprintf(env[3], e, "ifcarrier=%s",
+ if (efprintf(fp, "pid=%d", getpid()) == -1)
+ goto eexit;
+ if (efprintf(fp, "ifcarrier=%s",
ifp->carrier == LINK_UNKNOWN ? "unknown" :
- ifp->carrier == LINK_UP ? "up" : "down");
- EMALLOC(4, e);
- snprintf(env[4], e, "ifmetric=%d", ifp->metric);
- EMALLOC(5, e);
- snprintf(env[5], e, "ifwireless=%d", ifp->wireless);
- EMALLOC(6, e);
- snprintf(env[6], e, "ifflags=%u", ifp->flags);
- EMALLOC(7, e);
- snprintf(env[7], e, "ifmtu=%d", if_getmtu(ifp));
- l = e = strlen("interface_order=");
- TAILQ_FOREACH(ifp2, ifp->ctx->ifaces, next) {
- e += strlen(ifp2->name) + 1;
- }
- EMALLOC(8, e);
- p = env[8];
- strlcpy(p, "interface_order=", e);
- e -= l;
- p += l;
+ ifp->carrier == LINK_UP ? "up" : "down") == -1)
+ goto eexit;
+ if (efprintf(fp, "ifmetric=%d", ifp->metric) == -1)
+ goto eexit;
+ if (efprintf(fp, "ifwireless=%d", ifp->wireless) == -1)
+ goto eexit;
+ if (efprintf(fp, "ifflags=%u", ifp->flags) == -1)
+ goto eexit;
+ if (efprintf(fp, "ifmtu=%d", if_getmtu(ifp)) == -1)
+ goto eexit;
+
+ if (fprintf(fp, "interface_order=") == -1)
+ goto eexit;
TAILQ_FOREACH(ifp2, ifp->ctx->ifaces, next) {
- l = strlcpy(p, ifp2->name, e);
- p += l;
- e -= l;
- *p++ = ' ';
- e--;
+ if (ifp2 != TAILQ_FIRST(ifp->ctx->ifaces)) {
+ if (fputc(' ', fp) == EOF)
+ return -1;
+ }
+ if (fprintf(fp, "%s", ifp2->name) == -1)
+ return -1;
}
- *--p = '\0';
+ if (fputc('\0', fp) == EOF)
+ return -1;
+
if (strcmp(reason, "STOPPED") == 0) {
- env[9] = strdup("if_up=false");
- if (ifo->options & DHCPCD_RELEASE)
- env[10] = strdup("if_down=true");
- else
- env[10] = strdup("if_down=false");
+ if (efprintf(fp, "if_up=false") == -1)
+ goto eexit;
+ if (efprintf(fp, "if_down=%s",
+ ifo->options & DHCPCD_RELEASE ? "true" : "false") == -1)
+ goto eexit;
} else if (strcmp(reason, "TEST") == 0 ||
strcmp(reason, "PREINIT") == 0 ||
strcmp(reason, "CARRIER") == 0 ||
strcmp(reason, "UNKNOWN") == 0)
{
- env[9] = strdup("if_up=false");
- env[10] = strdup("if_down=false");
+ if (efprintf(fp, "if_up=false") == -1)
+ goto eexit;
+ if (efprintf(fp, "if_down=false") == -1)
+ goto eexit;
} else if (1 == 2 /* appease ifdefs */
#ifdef INET
|| (protocol == PROTO_DHCP && state && state->new)
#endif
)
{
- env[9] = strdup("if_up=true");
- env[10] = strdup("if_down=false");
+ if (efprintf(fp, "if_up=true") == -1)
+ goto eexit;
+ if (efprintf(fp, "if_down=false") == -1)
+ goto eexit;
} else {
- env[9] = strdup("if_up=false");
- env[10] = strdup("if_down=true");
+ if (efprintf(fp, "if_up=false") == -1)
+ goto eexit;
+ if (efprintf(fp, "if_down=true") == -1)
+ goto eexit;
}
- if (env[9] == NULL || env[10] == NULL)
- goto eexit;
if (protocols[protocol] != NULL) {
- r = asprintf(&env[elen], "protocol=%s", protocols[protocol]);
- if (r == -1)
+ if (efprintf(fp, "protocol=%s", protocols[protocol]) == -1)
goto eexit;
- elen++;
}
if ((af = dhcpcd_ifafwaiting(ifp)) != AF_MAX) {
- e = 20;
- EMALLOC(elen, e);
- snprintf(env[elen++], e, "if_afwaiting=%d", af);
+ if (efprintf(fp, "if_afwaiting=%d", af) == -1)
+ goto eexit;
}
if ((af = dhcpcd_afwaiting(ifp->ctx)) != AF_MAX) {
TAILQ_FOREACH(ifp2, ifp->ctx->ifaces, next) {
}
}
if (af != AF_MAX) {
- e = 20;
- EMALLOC(elen, e);
- snprintf(env[elen++], e, "af_waiting=%d", af);
+ if (efprintf(fp, "af_waiting=%d", af) == -1)
+ goto eexit;
}
if (ifo->options & DHCPCD_DEBUG) {
- e = strlen("syslog_debug=true") + 1;
- EMALLOC(elen, e);
- snprintf(env[elen++], e, "syslog_debug=true");
+ if (efprintf(fp, "syslog_debug=true") == -1)
+ goto eexit;
}
if (*ifp->profile) {
- e = strlen("profile=") + strlen(ifp->profile) + 1;
- EMALLOC(elen, e);
- snprintf(env[elen++], e, "profile=%s", ifp->profile);
+ if (efprintf(fp, "profile=%s", ifp->profile) == -1)
+ goto eexit;
}
+#if 0
if (ifp->wireless) {
static const char *pfx = "ifssid=";
size_t pfx_len;
elen++;
}
}
+#endif
#ifdef INET
if (protocol == PROTO_DHCP && state && state->old) {
- n = dhcp_env(NULL, NULL, state->old, state->old_len, ifp);
- if (n == -1)
+ if (dhcp_env(fp, "old", ifp,
+ state->old, state->old_len) == -1)
goto eexit;
- if (n > 0) {
- nenv = realloc(env, sizeof(char *) *
- (elen + (size_t)n + 1));
- if (nenv == NULL)
- goto eexit;
- env = nenv;
- n = dhcp_env(env + elen, "old",
- state->old, state->old_len, ifp);
- if (n == -1)
- goto eexit;
- elen += (size_t)n;
- }
- if (append_config(&env, &elen, "old",
+ if (append_config(fp, "old",
(const char *const *)ifo->config) == -1)
goto eexit;
}
#endif
#ifdef DHCP6
if (protocol == PROTO_DHCP6 && d6_state && d6_state->old) {
- n = dhcp6_env(NULL, NULL, ifp,
- d6_state->old, d6_state->old_len);
- if (n > 0) {
- nenv = realloc(env, sizeof(char *) *
- (elen + (size_t)n + 1));
- if (nenv == NULL)
- goto eexit;
- env = nenv;
- n = dhcp6_env(env + elen, "old", ifp,
- d6_state->old, d6_state->old_len);
- if (n == -1)
- goto eexit;
- elen += (size_t)n;
- }
+ if (dhcp6_env(fp, "old", ifp,
+ d6_state->old, d6_state->old_len) == -1)
+ goto eexit;
}
#endif
#ifdef INET
#ifdef IPV4LL
if (protocol == PROTO_IPV4LL) {
- n = ipv4ll_env(NULL, NULL, ifp);
- if (n > 0) {
- nenv = realloc(env, sizeof(char *) *
- (elen + (size_t)n + 1));
- if (nenv == NULL)
- goto eexit;
- env = nenv;
- if ((n = ipv4ll_env(env + elen,
- istate->down ? "old" : "new", ifp)) == -1)
- goto eexit;
- elen += (size_t)n;
- }
+ if (ipv4ll_env(fp, istate->down ? "old" : "new", ifp) == -1)
+ goto eexit;
}
#endif
if (protocol == PROTO_DHCP && state && state->new) {
- n = dhcp_env(NULL, NULL, state->new, state->new_len, ifp);
- if (n > 0) {
- nenv = realloc(env, sizeof(char *) *
- (elen + (size_t)n + 1));
- if (nenv == NULL)
- goto eexit;
- env = nenv;
- n = dhcp_env(env + elen, "new",
- state->new, state->new_len, ifp);
- if (n == -1)
- goto eexit;
- elen += (size_t)n;
- }
- if (append_config(&env, &elen, "new",
+ if (dhcp_env(fp, "new", ifp,
+ state->new, state->new_len) == -1)
+ goto eexit;
+ if (append_config(fp, "new",
(const char *const *)ifo->config) == -1)
goto eexit;
}
#endif
#ifdef INET6
if (protocol == PROTO_STATIC6) {
- n = ipv6_env(NULL, NULL, ifp);
- if (n > 0) {
- nenv = realloc(env, sizeof(char *) *
- (elen + (size_t)n + 1));
- if (nenv == NULL)
- goto eexit;
- env = nenv;
- n = ipv6_env(env + elen, "new", ifp);
- if (n == -1)
- goto eexit;
- elen += (size_t)n;
- }
+ if (ipv6_env(fp, "new", ifp) == -1)
+ goto eexit;
}
#ifdef DHCP6
if (protocol == PROTO_DHCP6 && D6_STATE_RUNNING(ifp)) {
- n = dhcp6_env(NULL, NULL, ifp,
- d6_state->new, d6_state->new_len);
- if (n > 0) {
- nenv = realloc(env, sizeof(char *) *
- (elen + (size_t)n + 1));
- if (nenv == NULL)
- goto eexit;
- env = nenv;
- n = dhcp6_env(env + elen, "new", ifp,
- d6_state->new, d6_state->new_len);
- if (n == -1)
- goto eexit;
- elen += (size_t)n;
- }
+ if (dhcp6_env(fp, "new", ifp,
+ d6_state->new, d6_state->new_len) == -1)
+ goto eexit;
}
#endif
if (protocol == PROTO_RA) {
- n = ipv6nd_env(NULL, NULL, ifp);
- if (n > 0) {
- nenv = realloc(env, sizeof(char *) *
- (elen + (size_t)n + 1));
- if (nenv == NULL)
- goto eexit;
- env = nenv;
- n = ipv6nd_env(env + elen, NULL, ifp);
- if (n == -1)
- goto eexit;
- elen += (size_t)n;
- }
+ if (ipv6nd_env(fp, ifp) == -1)
+ goto eexit;
}
#endif
/* Add our base environment */
if (ifo->environ) {
- e = 0;
- while (ifo->environ[e++])
- ;
- nenv = realloc(env, sizeof(char *) * (elen + e + 1));
- if (nenv == NULL)
- goto eexit;
- env = nenv;
- e = 0;
- while (ifo->environ[e]) {
- env[elen + e] = strdup(ifo->environ[e]);
- if (env[elen + e] == NULL)
+ for (i = 0; ifo->environ[i] != NULL; i++)
+ if (efprintf(fp, "%s", ifo->environ[i]) == -1)
goto eexit;
- e++;
- }
- elen += e;
}
- env[elen] = NULL;
- *argv = env;
- return (ssize_t)elen;
+ /* Convert buffer to argv */
+ fflush(fp);
+
+ buf_pos = ftell(fp);
+ if (buf_pos == -1) {
+ logerr(__func__);
+ goto eexit;
+ }
+#ifdef HAVE_OPEN_MEMSTREAM
+ buf = ctx->script_buf;
+#else
+ size_t buf_len = (size_t)buf_pos;
+ if (ctx->script_buflen < buf_len) {
+ buf = realloc(ctx->script_buf, buf_len);
+ if (buf == NULL)
+ goto eexit;
+ ctx->script_buf = buf;
+ ctx->script_buflen = buf_len;
+ }
+ buf = ctx->script_buf;
+ rewind(fp);
+ if (fread(buf, sizeof(char), buf_len, fp) != buf_len)
+ goto eexit;
+ fclose(fp);
+ fp = NULL;
+#endif
+
+ nenv = 0;
+ endp = buf + buf_pos;
+ for (bufp = buf; bufp < endp; bufp++) {
+ if (*bufp == '\0')
+ nenv++;
+ }
+ if (ctx->script_envlen < nenv) {
+ env = reallocarray(ctx->script_env, nenv, sizeof(*env));
+ if (env == NULL)
+ goto eexit;
+ ctx->script_env = env;
+ ctx->script_envlen = nenv;
+ }
+ bufp = buf;
+ envp = ctx->script_env;
+ *envp++ = bufp++;
+ envp--; /* Avoid setting the last \0 to an invalid pointer */
+ for (; bufp < endp; bufp++) {
+ if (*bufp == '\0')
+ *envp++ = bufp + 1;
+ }
+ *envp = NULL;
+
+ return (ssize_t)nenv;
eexit:
logerr(__func__);
- if (env) {
- nenv = env;
- while (*nenv)
- free(*nenv++);
- free(env);
- }
+#ifndef HAVE_OPEN_MEMSTREAM
+ if (fp != NULL)
+ fclose(fp);
+#endif
return -1;
}
static int
-send_interface1(struct fd_list *fd, const struct interface *iface,
+send_interface1(struct fd_list *fd, const struct interface *ifp,
const char *reason)
{
- char **env, **ep, *s;
- size_t elen;
- int retval;
+ struct dhcpcd_ctx *ctx = ifp->ctx;
- if (make_env(iface, reason, &env) == -1)
+ if (make_env(ifp, reason) == -1)
return -1;
- s = NULL;
- elen = (size_t)arraytostr((const char *const *)env, &s);
- if ((ssize_t)elen == -1) {
- free(s);
- retval = -1;
- } else
- retval = control_queue(fd, s, elen, 1);
- ep = env;
- while (*ep)
- free(*ep++);
- free(env);
- return retval;
+ return control_queue(fd, ctx->script_buf, ctx->script_buflen, 1);
}
int
int
script_runreason(const struct interface *ifp, const char *reason)
{
+ struct dhcpcd_ctx *ctx = ifp->ctx;
char *argv[2];
- char **env = NULL, **ep;
- char *svcname, *path, *bigenv;
- size_t e, elen = 0;
pid_t pid;
int status = 0;
struct fd_list *fd;
return 0;
/* Make our env */
- elen = (size_t)make_env(ifp, reason, &env);
- if (elen == (size_t)-1) {
+ if (make_env(ifp, reason) == -1) {
logerr(__func__);
return -1;
}
argv[1] = NULL;
logdebugx("%s: executing `%s' %s", ifp->name, argv[0], reason);
- /* Resize for PATH and RC_SVCNAME */
- svcname = getenv(RC_SVCNAME);
- ep = reallocarray(env, elen + 2 + (svcname ? 1 : 0), sizeof(char *));
- if (ep == NULL) {
- elen = 0;
- goto out;
- }
- env = ep;
- /* Add path to it */
- path = getenv("PATH");
- if (path) {
- e = strlen("PATH") + strlen(path) + 2;
- env[elen] = malloc(e);
- if (env[elen] == NULL) {
- elen = 0;
- goto out;
- }
- snprintf(env[elen], e, "PATH=%s", path);
- } else {
- env[elen] = strdup(DEFAULT_PATH);
- if (env[elen] == NULL) {
- elen = 0;
- goto out;
- }
- }
- if (svcname) {
- e = strlen(RC_SVCNAME) + strlen(svcname) + 2;
- env[++elen] = malloc(e);
- if (env[elen] == NULL) {
- elen = 0;
- goto out;
- }
- snprintf(env[elen], e, "%s=%s", RC_SVCNAME, svcname);
- }
- env[++elen] = NULL;
-
- pid = exec_script(ifp->ctx, argv, env);
+ pid = exec_script(ctx, argv, ctx->script_env);
if (pid == -1)
logerr("%s: %s", __func__, argv[0]);
else if (pid != 0) {
send_listeners:
/* Send to our listeners */
- bigenv = NULL;
status = 0;
- TAILQ_FOREACH(fd, &ifp->ctx->control_fds, next) {
+ TAILQ_FOREACH(fd, &ctx->control_fds, next) {
if (!(fd->flags & FD_LISTEN))
continue;
- if (bigenv == NULL) {
- elen = (size_t)arraytostr((const char *const *)env,
- &bigenv);
- if ((ssize_t)elen == -1) {
- logerr("%s: arraytostr", ifp->name);
- break;
- }
- }
- if (control_queue(fd, bigenv, elen, 1) == -1)
+ if (control_queue(fd, ctx->script_buf, ctx->script_buflen, 1)
+ == -1)
logerr("%s: control_queue", __func__);
else
status = 1;
}
- if (!status)
- free(bigenv);
-out:
- /* Cleanup */
- ep = env;
- while (*ep)
- free(*ep++);
- free(env);
- if (elen == 0) {
- logerr(__func__);
- return -1;
- }
return WEXITSTATUS(status);
}
#include "control.h"
+__printflike(2, 3) int efprintf(FILE *, const char *, ...);
void if_printoptions(void);
int send_interface(struct fd_list *, const struct interface *);
int script_runreason(const struct interface *, const char *);