]> git.sur5r.net Git - i3/i3status/commitdiff
Parse uevent file to detect network device type (#153)
authorCihangir Akturk <cakturk@gmail.com>
Mon, 22 Aug 2016 17:23:59 +0000 (20:23 +0300)
committerMichael Stapelberg <stapelberg@users.noreply.github.com>
Mon, 22 Aug 2016 17:23:59 +0000 (10:23 -0700)
Currently i3status differentiates wireless and wired devices based
on the existence of wireless directory inside the device's sysfs
directory. This approach seems to cause 3g modems to be incorrectly
identified as the first ethernet device.

This commit solves this problem by using DEVTYPE variable from
uevent file.

Signed-off-by: Cihangir Akturk <cakturk@gmail.com>
include/i3status.h
src/first_network_device.c

index b4cf83f8354b0fdfcebd769f6482177e77523c7f..4d2d0f10ee6ae8ff259a1a8c640686df534fddd3 100644 (file)
@@ -202,7 +202,8 @@ void set_timezone(const char *tz);
 /* src/first_network_device.c */
 typedef enum {
     NET_TYPE_WIRELESS = 0,
-    NET_TYPE_ETHERNET = 1
+    NET_TYPE_ETHERNET = 1,
+    NET_TYPE_OTHER = 2
 } net_type_t;
 const char *first_eth_interface(const net_type_t type);
 
index 06d8b4a03471af2800cd341438ef6882b094ff93..541aabb4d69daa2cf032b07d7445efb00a71aa3b 100644 (file)
@@ -6,11 +6,58 @@
 
 #include "i3status.h"
 
+static bool sysfs_devtype(char *dest, size_t n, const char *ifnam) {
+    FILE *fp;
+    char buf[1024];
+
+    snprintf(buf, sizeof(buf), "/sys/class/net/%s/uevent", ifnam);
+    if ((fp = fopen(buf, "r")) == NULL)
+        return false;
+
+    dest[0] = '\0';
+
+    while (fgets(buf, sizeof(buf), fp)) {
+        size_t slen;
+        char *s;
+
+        slen = strlen(buf);
+        /* Line is too long to fit in the buffer */
+        if (buf[slen - 1] != '\n' && !feof(fp))
+            break;
+        if ((s = strchr(buf, '='))) {
+            if (strncmp(buf, "DEVTYPE", s - buf))
+                continue;
+            buf[slen - 1] = '\0';
+            strncpy(dest, ++s, n);
+            break;
+        }
+    }
+    fclose(fp);
+    return true;
+}
+
+static net_type_t iface_type(const char *ifname) {
+    char devtype[32];
+
+    if (!sysfs_devtype(devtype, sizeof(devtype), ifname))
+        return NET_TYPE_OTHER;
+
+    if (!devtype[0])
+        return NET_TYPE_ETHERNET;
+
+    if (strcmp(devtype, "wlan") == 0)
+        return NET_TYPE_WIRELESS;
+
+    if (strcmp(devtype, "wwan") == 0)
+        return NET_TYPE_OTHER;
+
+    return NET_TYPE_OTHER;
+}
+
 const char *first_eth_interface(const net_type_t type) {
     static char *interface = NULL;
     struct ifaddrs *ifaddr, *addrp;
-    struct stat stbuf;
-    static char path[1024];
+    net_type_t iftype;
 
     getifaddrs(&ifaddr);
 
@@ -32,10 +79,8 @@ const char *first_eth_interface(const net_type_t type) {
             addrp->ifa_addr->sa_family != AF_INET6)
             continue;
         // Skip this interface if it is a wireless interface.
-        snprintf(path, sizeof(path), "/sys/class/net/%s/wireless", addrp->ifa_name);
-        const bool is_wireless = (stat(path, &stbuf) == 0);
-        if ((is_wireless && type == NET_TYPE_ETHERNET) ||
-            (!is_wireless && type == NET_TYPE_WIRELESS))
+        iftype = iface_type(addrp->ifa_name);
+        if (iftype != type)
             continue;
         interface = strdup(addrp->ifa_name);
         break;