]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
script: Write variables to a FILE
authorRoy Marples <roy@marples.name>
Tue, 18 Jun 2019 10:33:53 +0000 (11:33 +0100)
committerRoy Marples <roy@marples.name>
Tue, 18 Jun 2019 10:33:53 +0000 (11:33 +0100)
Each variable is NULL terminated inside the file just like the
control stream which saves us from having to flatten it when
writing to the control stream.
Once written, create env pointers to the start of each string
just after the NULL terminator.

This also means that we just need to free two buffers when
dhcpcd exits (FILE buffer and env buffer) rather than each variable
individually.

If open_memstream(3) is not supported by libc then dhcpcd will
write to a file in /tmp instead.

22 files changed:
configure
src/arp.c
src/auth.c
src/common.c
src/common.h
src/dhcp-common.c
src/dhcp-common.h
src/dhcp.c
src/dhcp.h
src/dhcp6.c
src/dhcp6.h
src/dhcpcd.c
src/dhcpcd.h
src/ipv4.c
src/ipv4ll.c
src/ipv4ll.h
src/ipv6.c
src/ipv6.h
src/ipv6nd.c
src/ipv6nd.h
src/script.c
src/script.h

index 4a4920e28b6eb50743b025819d31b54d0c434382..79201c04819661497803808202714ee4424e212d 100755 (executable)
--- a/configure
+++ b/configure
@@ -15,6 +15,7 @@ ARC4RANDOM=
 CLOSEFROM=
 RBTREE=
 CONSTTIME_MEMEQUAL=
+OPEN_MEMSTREAM=
 STRLCPY=
 UDEV=
 OS=
@@ -741,29 +742,25 @@ if [ "$ARC4RANDOM_UNIFORM" = no ]; then
        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
@@ -824,6 +821,30 @@ if [ "$SETPROCTITLE" = yes ]; 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
index 59d82e9fb6b3d7aed842447eea7b41a85bcfae0e..f48bc91c429d1115de3d5a8492cbb18f67ead8de 100644 (file)
--- a/src/arp.c
+++ b/src/arp.c
@@ -36,6 +36,7 @@
 
 #include <errno.h>
 #include <stdlib.h>
+#include <stdio.h>
 #include <string.h>
 #include <unistd.h>
 
index cd774150309bf24237529260effacf280579c234..0e4c9f4d9a23926305807c9d96983f0b821ee822 100644 (file)
@@ -30,6 +30,7 @@
 #include <fcntl.h>
 #include <inttypes.h>
 #include <stddef.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <time.h>
index 0214af2c22293a5de5c012c94670a81fc63975c9..d6d5b4749f92b98ce1266fe80a42aad85e3af46a 100644 (file)
 /* 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)
 {
index 1022e6ff25ab88707a000cf37bbf3ea105ae1c33..3e63ab77aff14f51d10afa7ed69e1e86bc96973b 100644 (file)
@@ -193,11 +193,6 @@ void get_line_free(void);
 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 *);
index c562ada7543bdf97090e31122a8085f57b245c97..6d66ebefb8a96053e77429a1c02a2bb4064a2e11 100644 (file)
@@ -36,8 +36,6 @@
 #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)
@@ -624,41 +616,9 @@ dhcp_optlen(const struct dhcp_opt *opt, size_t dl)
        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;
@@ -669,46 +629,53 @@ print_option(char *s, size_t len, const struct dhcp_opt *opt,
        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. */
@@ -722,109 +689,80 @@ print_option(char *s, size_t len, const struct dhcp_opt *opt,
                            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
@@ -859,61 +797,15 @@ dhcp_set_leasefile(char *leasefile, size_t len, int family,
            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;
@@ -923,52 +815,36 @@ dhcp_envoption(struct dhcpcd_ctx *ctx, char **env, const char *prefix,
 
        /* 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) {
@@ -977,9 +853,9 @@ dhcp_envoption(struct dhcpcd_ctx *ctx, char **env, const char *prefix,
                         * 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;
@@ -989,10 +865,8 @@ dhcp_envoption(struct dhcpcd_ctx *ctx, char **env, const char *prefix,
                 * 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);
@@ -1023,19 +897,16 @@ dhcp_envoption(struct dhcpcd_ctx *ctx, char **env, const char *prefix,
                            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;
@@ -1043,11 +914,7 @@ dhcp_envoption(struct dhcpcd_ctx *ctx, char **env, const char *prefix,
        }
 
 out:
-       if (env)
-               free(pfx);
-
-       /* Return number of options found */
-       return n;
+       free(pfx);
 }
 
 void
@@ -1070,7 +937,7 @@ dhcp_read_lease_fd(int fd, void **lease)
        size_t sz;
        void *buf;
        ssize_t len;
-       
+
        if (fstat(fd, &st) != 0)
                goto out;
        if (!S_ISREG(st.st_mode)) {
index a4de7420b0a3079a3c3acfb6e6f17319d086e713..109f20171743185104fa190b18a744b024e54279 100644 (file)
 
 #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
@@ -111,8 +120,8 @@ ssize_t decode_rfc1035(char *, size_t, const uint8_t *, size_t);
 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 **),
index 25a9e72cd9c94601f306164c40ff3688b858be37..fc0c549027beb4a2d62148ede6f353220168e075 100644 (file)
@@ -47,6 +47,7 @@
 #include <inttypes.h>
 #include <stdbool.h>
 #include <stddef.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
@@ -340,23 +341,25 @@ get_option_uint8(struct dhcpcd_ctx *ctx,
 }
 
 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;
@@ -367,41 +370,25 @@ decode_rfc3442(char *out, size_t len, const uint8_t *p, size_t pl)
                        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
@@ -474,15 +461,12 @@ decode_rfc3442_rt(rb_tree_t *routes, struct interface *ifp,
        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;
@@ -493,13 +477,10 @@ decode_rfc3361(const uint8_t *data, size_t dl)
        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) {
@@ -507,25 +488,27 @@ decode_rfc3361(const uint8_t *data, size_t dl)
                        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 *
@@ -1302,9 +1285,8 @@ dhcp_getoption(struct dhcpcd_ctx *ctx,
 }
 
 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;
@@ -1313,8 +1295,7 @@ dhcp_env(char **env, const char *prefix,
        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;
 
@@ -1324,97 +1305,63 @@ dhcp_env(char **env, const char *prefix,
            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;
@@ -1427,7 +1374,7 @@ dhcp_env(char **env, const char *prefix,
                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))
@@ -1440,7 +1387,7 @@ dhcp_env(char **env, const char *prefix,
                /* 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);
        }
 
@@ -1453,11 +1400,11 @@ dhcp_env(char **env, const char *prefix,
                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
index 245d20a4134d529e495f5b3707b4c63e94659176..e7bb1131906d476bc4c3857168e6090ab30cd82c 100644 (file)
@@ -245,15 +245,15 @@ struct dhcp_state {
 #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 *);
index aba6d42b5c9e322a4c5e9515b73e5f21bc86da16..6ebb591a1020ad3f07b38e1ce0be906c3a85770a 100644 (file)
@@ -3952,7 +3952,7 @@ dhcp6_handleifa(int cmd, struct ipv6_addr *ia, pid_t pid)
 }
 
 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;
@@ -3966,7 +3966,6 @@ dhcp6_env(char **env, const char *prefix, const struct interface *ifp,
 #ifndef SMALL
        const struct dhcp6_state *state;
        const struct ipv6_addr *ap;
-       char *v, *val;
 #endif
 
        n = 0;
@@ -3984,28 +3983,20 @@ dhcp6_env(char **env, const char *prefix, const struct interface *ifp,
        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. */
@@ -4051,15 +4042,13 @@ dhcp6_env(char **env, const char *prefix, const struct interface *ifp,
                                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));
@@ -4071,38 +4060,29 @@ delegated:
 #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
index 8853d7f8a2d6dbc111967841024bc56d0e3d8821..4e08eb68cba6a8e8d3716d14816dd185e29be007 100644 (file)
@@ -228,7 +228,7 @@ size_t dhcp6_find_delegates(struct interface *);
 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);
index fc5003531a7c14e382e101327f72c7909357a9d8..7737c83ea5561a2fc9d829a094a5d90513361e4e 100644 (file)
@@ -2133,5 +2133,11 @@ exit1:
        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;
 }
index 7ce3cad303959b9d766cf8061c67bdd0cb39d0fb..4ce1c15e8e8207e80a433af19c9dc5627b1ef759 100644 (file)
@@ -156,6 +156,14 @@ struct dhcpcd_ctx {
 #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;
index 5f138b5c9af10337cd6d1baf566ef5dab0902ab7..91188cc839d0195e69655adb1cfb95ab71a8e9cf 100644 (file)
@@ -38,6 +38,7 @@
 #include <ctype.h>
 #include <errno.h>
 #include <stdbool.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
index 8a1cc914a416095d14575d8335234a6064ac2cfe..2f7a3f8b433a51becb5cd5911d2af46e7265c60b 100644 (file)
@@ -30,6 +30,7 @@
 #include <assert.h>
 #include <errno.h>
 #include <stdbool.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
@@ -137,7 +138,7 @@ ipv4ll_defaultroute(rb_tree_t *routes, struct interface *ifp)
 }
 
 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 ? "" : "_";
@@ -147,24 +148,21 @@ ipv4ll_env(char **env, const char *prefix, const struct interface *ifp)
        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;
index 5fefa42928d9963dc4382b0eea53c62c4ef3ba9d..d7fb0c326f06086ef3ff42c464142aa90dc34a04 100644 (file)
@@ -59,7 +59,7 @@ struct ipv4ll_state {
 
 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 *);
index 8288cb40ce7e4512b33e2558c4eff61c6d4e2d3b..0128617372ed2af35015f1a96bb37682fd2cf5b6 100644 (file)
@@ -1540,23 +1540,17 @@ ipv6_staticdadcallback(void *arg)
 }
 
 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
index 38382993609e99867ad0181f3d7b50599280e26f..152361b1ed33ffa417099f67d25e837b96a6f759 100644 (file)
@@ -287,7 +287,7 @@ void ipv6_addtempaddrs(struct interface *, const struct timespec *);
 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 */
index 5ece711e5d5c201ff0467df262ec162d9cb90b48..b879c1712c0e4dea7c2a5d268b275eb989292689 100644 (file)
@@ -1384,11 +1384,11 @@ ipv6nd_getoption(struct dhcpcd_ctx *ctx,
 }
 
 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;
@@ -1401,34 +1401,24 @@ ipv6nd_env(char **env, const char *prefix, const struct interface *ifp)
                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
@@ -1461,13 +1451,12 @@ ipv6nd_env(char **env, const char *prefix, const struct interface *ifp)
                                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
@@ -1481,15 +1470,12 @@ ipv6nd_env(char **env, const char *prefix, const struct interface *ifp)
                            !(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
index 2727e51446a47b731e38b564a8933d1334971688..555ef2feb38ae3badf541ff18be76993c84f83de 100644 (file)
@@ -95,7 +95,7 @@ struct rs_state {
 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 *,
index 451b0308059e14b90d16c68f307cd3459cf2e4ab..1952a04f347ddd1882a4bb587bc2a1d630bbedc2 100644 (file)
@@ -36,6 +36,7 @@
 #include <errno.h>
 #include <signal.h>
 #include <spawn.h>
+#include <stdarg.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
@@ -56,7 +57,7 @@
 #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",
@@ -120,103 +121,23 @@ exec_script(const struct dhcpcd_ctx *ctx, char *const *argv, char *const *env)
 }
 
 #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
@@ -233,15 +154,32 @@ static const char *protocols[] = {
        "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;
@@ -255,6 +193,31 @@ make_env(const struct interface *ifp, const char *reason, char ***argv)
        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
@@ -309,71 +272,60 @@ make_env(const struct interface *ifp, const char *reason, char ***argv)
                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)
@@ -390,24 +342,23 @@ make_env(const struct interface *ifp, const char *reason, char ***argv)
 #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) {
@@ -416,20 +367,18 @@ make_env(const struct interface *ifp, const char *reason, char ***argv)
                }
        }
        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;
@@ -447,44 +396,22 @@ make_env(const struct interface *ifp, const char *reason, char ***argv)
                        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
 
@@ -492,144 +419,114 @@ dumplease:
 #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
@@ -696,10 +593,8 @@ send_interface(struct fd_list *fd, const struct interface *ifp)
 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;
@@ -709,8 +604,7 @@ script_runreason(const struct interface *ifp, const char *reason)
                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;
        }
@@ -722,43 +616,7 @@ script_runreason(const struct interface *ifp, const char *reason)
        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) {
@@ -781,36 +639,16 @@ script_runreason(const struct interface *ifp, const char *reason)
 
 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);
 }
index 6b7a593b64c999c0a4632a9b2145154a12e2c341..4408eeb41562efb05c367d7c1df7c538f0022c4e 100644 (file)
@@ -30,6 +30,7 @@
 
 #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 *);