Update copyrights
[dhcpcd-ui] / src / libdhcpcd / dhcpcd.c
index 150594d11e763987fcd3b33180863206cd3b24b9..c8bdd14fbfd8cb48cd54b610fbc3dc06c77a55ab 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * libdhcpcd
- * Copyright 2009-2014 Roy Marples <roy@marples.name>
+ * Copyright 2009-2015 Roy Marples <roy@marples.name>
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -37,7 +37,6 @@
 #include <ctype.h>
 #include <errno.h>
 #include <fcntl.h>
-#include <libintl.h>
 #include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -257,12 +256,132 @@ dhcpcd_get_value(const DHCPCD_IF *i, const char *var)
 }
 
 ssize_t
-dhcpcd_decode(char *dst, size_t dlen, const char *src)
+dhcpcd_encode_string_escape(char *dst, size_t len, const char *src, size_t slen)
 {
+       const char *end;
+       size_t bytes;
+       unsigned char c;
+
+       end = src + slen;
+       bytes = 0;
+       while (src < end) {
+               c = (unsigned char)*src++;
+               if ((c == '\\' || !isascii(c) || !isprint(c))) {
+                       if (c == '\\') {
+                               if (dst) {
+                                       if (len  == 0 || len == 1) {
+                                               errno = ENOSPC;
+                                               return -1;
+                                       }
+                                       *dst++ = '\\'; *dst++ = '\\';
+                                       len -= 2;
+                               }
+                               bytes += 2;
+                               continue;
+                       }
+                       if (dst) {
+                               if (len < 5) {
+                                       errno = ENOSPC;
+                                       return -1;
+                               }
+                               *dst++ = '\\';
+                               *dst++ = (char)(((c >> 6) & 03) + '0');
+                               *dst++ = (char)(((c >> 3) & 07) + '0');
+                               *dst++ = (char)(( c       & 07) + '0');
+                               len -= 4;
+                       }
+                       bytes += 4;
+               } else {
+                       if (dst) {
+                               if (len == 0) {
+                                       errno = ENOSPC;
+                                       return -1;
+                               }
+                               *dst++ = (char)c;
+                               len--;
+                       }
+                       bytes++;
+               }
+       }
+
+       if (dst) {
+               if (len == 0) {
+                       errno = ENOSPC;
+                       return -1;
+               }
+               *dst = '\0';
+       }
+
+       return (ssize_t)bytes;
+}
+
+ssize_t
+dhcpcd_decode_string_escape(char *dst, size_t dlen, const char *src)
+{
+       char c, esc;
+       int oct;
+       ssize_t bytes;
+
+       bytes = 0;
+       for (;;) {
+               c = *src++;
+               if (c == '\0')
+                       break;
+               if (dst && --dlen == 0) {
+                       errno = ENOSPC;
+                       return -1;
+               }
+               switch (c) {
+               case '\\':
+                       if (*src == '\0') {
+                               errno = EINVAL;
+                               return -1;
+                       }
+                       esc = *src++;
+                       switch (esc) {
+                       case '\\':
+                       case '0':
+                       case '1':
+                       case '3':
+                       case '4':
+                       case '5':
+                       case '6':
+                       case '7':
+                               oct = esc - '0';
+                               if (*src >= '0' && *src <='7')
+                                       oct = oct * 8 + (*src++ - '0');
+                               else {
+                                       errno = EINVAL;
+                                       return -1;
+                               }
+                               if (*src >= '0' && *src <='7')
+                                       oct = oct * 8 + (*src++ - '0');
+                               else {
+                                       errno = EINVAL;
+                                       return -1;
+                               }
+                               if (dst)
+                                       *dst++ = (char)oct;
+                       default:
+                               errno = EINVAL;
+                               return -1;
+                       }
+                       break;
+               default:
+                       if (dst)
+                               *dst++ = c;
+               }
+               bytes++;
+       }
 
-       assert(dst);
-       assert(src);
-       return strnunvis(dst, dlen, src);
+       if (dst) {
+               if (--dlen == 0) {
+                       errno = ENOSPC;
+                       return -1;
+               }
+               *dst = '\0';
+       }
+       return bytes;
 }
 
 ssize_t
@@ -302,31 +421,6 @@ dhcpcd_decode_hex(char *dst, size_t dlen, const char *src)
        return (ssize_t)bytes;
 }
 
-ssize_t
-dhcpcd_encode(char *dst, size_t dlen, const char *src, size_t slen)
-{
-       char *d, c, v[5], *ve, *vp;
-       const char *send;
-
-       d = dst;
-       send = src + slen;
-       while (src < send) {
-               c = *src++;
-               ve = vis(v, c, VIS_OCTAL | VIS_CSTYLE, src != send ? *src : 0);
-               if (dlen < (size_t)(ve - v) + 1) {
-                       errno = ENOSPC;
-                       return -1;
-               }
-               dlen -= (size_t)(ve - v);
-               vp = v;
-               while (vp != ve)
-                       *d++ = *vp++;
-       }
-       *d = '\0';
-
-       return d - dst;
-}
-
 const char *
 dhcpcd_get_prefix_value(const DHCPCD_IF *i, const char *prefix, const char *var)
 {
@@ -416,6 +510,80 @@ dhcpcd_interfaces(DHCPCD_CONNECTION *con)
        return con->interfaces;
 }
 
+char **
+dhcpcd_interface_names(DHCPCD_CONNECTION *con, size_t *nnames)
+{
+       char **names;
+       size_t n;
+       DHCPCD_IF *i;
+
+       assert(con);
+       if (con->interfaces == NULL)
+               return NULL;
+
+       n = 0;
+       for (i = con->interfaces; i; i = i->next) {
+               if (strcmp(i->type, "link") == 0)
+                       n++;
+       }
+       names = malloc(sizeof(char *) * (n + 1));
+       if (names == NULL)
+               return NULL;
+       n = 0;
+       for (i = con->interfaces; i; i = i->next) {
+               if (strcmp(i->type, "link") == 0) {
+                       names[n] = strdup(i->ifname);
+                       if (names[n] == NULL) {
+                               dhcpcd_freev(names);
+                               return NULL;
+                       }
+                       n++;
+               }
+       }
+       names[n] = NULL;
+       if (nnames)
+               *nnames = n;
+
+       return names;
+}
+
+void
+dhcpcd_freev(char **argv)
+{
+       char **v;
+
+       if (argv) {
+               for (v = argv; *v; v++)
+                       free(*v);
+               free(argv);
+       }
+}
+
+static int
+dhcpcd_cmpstring(const void *p1, const void *p2)
+{
+       const char *s1, *s2;
+       int cmp;
+
+       s1 = *(char * const *)p1;
+       s2 = *(char * const *)p2;
+       if ((cmp = strcasecmp(s1, s2)) == 0)
+               cmp = strcmp(s1, s2);
+       return cmp;
+}
+
+char **
+dhcpcd_interface_names_sorted(DHCPCD_CONNECTION *con)
+{
+       char **names;
+       size_t nnames;
+
+       names = dhcpcd_interface_names(con, &nnames);
+       if (names)
+               qsort(names, nnames, sizeof(char *), dhcpcd_cmpstring);
+       return names;
+}
+
 DHCPCD_IF *
 dhcpcd_get_if(DHCPCD_CONNECTION *con, const char *ifname, const char *type)
 {
@@ -436,12 +604,18 @@ static DHCPCD_IF *
 dhcpcd_new_if(DHCPCD_CONNECTION *con, char *data, size_t len)
 {
        const char *ifname, *ifclass, *reason, *type, *order, *flags;
-       char *orderdup, *o, *p, *dbuf, *end, *dp, *eq;
+       char *orderdup, *o, *p;
        DHCPCD_IF *e, *i, *l, *n, *nl;
        int ti;
        bool addedi;
-       ssize_t dl, el;
-       size_t dbuflen, eql;
+
+#if 0
+       char *dp = data, *de = data + len;
+       while (dp < de) {
+               printf ("XX: %s\n", dp);
+               dp += strlen(dp) + 1;
+       }
+#endif
 
        ifname = get_value(data, len, "interface");
        if (ifname == NULL || *ifname == '\0') {
@@ -459,7 +633,9 @@ dhcpcd_new_if(DHCPCD_CONNECTION *con, char *data, size_t len)
                errno = ENOTSUP;
                return NULL;
        }
-       if (strcmp(reason, "RECONFIGURE") == 0) {
+       if (strcmp(reason, "RECONFIGURE") == 0 ||
+           strcmp(reason, "INFORM") == 0 || strcmp(reason, "INFORM6") == 0)
+       {
                errno = ENOTSUP;
                return NULL;
        }
@@ -512,44 +688,6 @@ dhcpcd_new_if(DHCPCD_CONNECTION *con, char *data, size_t len)
                        return NULL;
        }
 
-       /* Remove all shell encoding but keep our non graphic encoding */
-       end = data + len;
-       dp = data;
-       dbuflen = 128; /* allocate an initial buffer */
-       dbuf = malloc(dbuflen);
-       if (dbuf == NULL)
-               return NULL;
-       while (dp < end) {
-               eq = strchr(dp, '=');
-               if (eq == NULL || *++eq == '\0') {
-                       errno = EINVAL;
-                       return NULL;
-               }
-               eql = strlen(eq) + 1;
-               if (dbuflen < eql) {
-                       char *nbuf;
-
-                       nbuf = realloc(dbuf, eql);
-                       if (nbuf == NULL) {
-                               free(dbuf);
-                               return NULL;
-                       }
-                       dbuf = nbuf;
-                       dbuflen = eql;
-               }
-               if ((dl = dhcpcd_decode(dbuf, dbuflen, eq)) == -1 ||
-                   (el = dhcpcd_encode(eq, eql, dbuf, (size_t)dl)) == -1)
-               {
-                       free(dbuf);
-                       return NULL;
-               }
-               /* NUL pad the remainder so get_value can skip it */
-               if (eql - (size_t)el > 0)
-                       memset(eq + el, 0, eql - (size_t)el);
-               dp = eq + eql;
-       }
-       free(dbuf);
-
        orderdup = strdup(order);
        if (orderdup == NULL)
                return NULL;
@@ -594,15 +732,15 @@ dhcpcd_new_if(DHCPCD_CONNECTION *con, char *data, size_t len)
                i->flags = (unsigned int)strtoul(flags, NULL, 0);
        else
                i->flags = 0;
-       if (strcmp(reason, "CARRIER") == 0)
+       if (strcmp(reason, "CARRIER") == 0 ||
+           strcmp(reason, "DELEGATED6") == 0)
                i->up = true;
        else
                i->up = strtobool(dhcpcd_get_value(i, "if_up"));
        i->wireless = strtobool(dhcpcd_get_value(i, "ifwireless"));
-       if (strcmp(i->type, "link") == 0)
+       i->ssid = dhcpcd_get_value(i, "ifssid");
+       if (i->ssid == NULL && i->wireless)
                i->ssid = dhcpcd_get_value(i, i->up ? "new_ssid" : "old_ssid");
-       else
-               i->ssid = dhcpcd_get_value(i, "if_ssid");
 
        /* Sort! */
        n = nl = NULL;
@@ -980,8 +1118,20 @@ dhcpcd_if_message(DHCPCD_IF *i, bool *new_msg)
                if (i->wireless) {
                        showssid = true;
                        reason = _("Associated with");
-               } else
-                       reason = _("Cable plugged in");
+               } else {
+                       /* Don't report able in if we have addresses */
+                       const DHCPCD_IF *ci;
+
+                       for (ci = i->con->interfaces; ci; ci = ci->next) {
+                               if (ci != i &&
+                                   strcmp(i->ifname, ci->ifname) == 0 &&
+                                   ci->up)
+                                       break;
+                       }
+                       if (ci)
+                               return NULL;
+                       reason = _("Link is up, configuring");
+               }
        } else if (strcmp(i->reason, "NOCARRIER") == 0) {
                if (i->wireless) {
                        if (i->ssid) {
@@ -990,7 +1140,7 @@ dhcpcd_if_message(DHCPCD_IF *i, bool *new_msg)
                        } else
                                reason = _("Not associated");
                } else
-                       reason = _("Cable unplugged");
+                       reason = _("Link is down");
        } else if (strcmp(i->reason, "DEPARTED") == 0)
                reason = _("Departed");
        else if (strcmp(i->reason, "UNKNOWN") == 0)
@@ -1001,9 +1151,12 @@ dhcpcd_if_message(DHCPCD_IF *i, bool *new_msg)
                reason = _("Waiting for 3rd Party configuration");
 
        if (reason == NULL) {
-               if (i->up)
-                       reason = _("Configured");
-               else if (strcmp(i->type, "ra") == 0)
+               if (i->up) {
+                       if (strcmp(i->reason, "DELEGATED6") == 0)
+                               reason = _("Delegated");
+                       else
+                               reason = _("Configured");
+               } else if (strcmp(i->type, "ra") == 0)
                        reason = "Expired RA";
                else
                        reason = i->reason;
@@ -1012,11 +1165,16 @@ dhcpcd_if_message(DHCPCD_IF *i, bool *new_msg)
        pfx = i->up ? "new_" : "old_";
        if ((ip = dhcpcd_get_prefix_value(i, pfx, "ip_address")))
                iplen = dhcpcd_get_prefix_value(i, pfx, "subnet_cidr");
+       else if ((ip = dhcpcd_get_value(i, "ra1_addr")))
+               iplen = NULL;
        else if ((ip = dhcpcd_get_value(i, "ra1_prefix")))
                iplen = NULL;
        else if ((ip = dhcpcd_get_prefix_value(i, pfx,
            "dhcp6_ia_na1_ia_addr1")))
                iplen = "128";
+       else if ((ip = dhcpcd_get_prefix_value(i, pfx,
+           "delegated_dhcp6_prefix")))
+               iplen = NULL;
        else {
                ip = NULL;
                iplen = NULL;