Conky: Dynamic interface names

Created on 17 May 2016  Â·  14Comments  Â·  Source: brndnmtthws/conky

Please provide a way to get interface names dynamically.
With new systemd persistent naming it is quite hard to predict all possible interface names on multiple machines. Some other way of referring to interface is needed. For example, by number in sorted list of all currently available interfaces.

enhancement

All 14 comments

@su8 ${gw_iface iface1}, ${gw_iface iface2}, ${gw_iface iface3}...?

@lasers Don't have multiple interfaces on my machine, but I wrote some simple implementation.

diff --git a/src/core.cc b/src/core.cc
index 960d3fdd..42d95120 100644
--- a/src/core.cc
+++ b/src/core.cc
@@ -1434,12 +1434,13 @@ struct text_object *construct_text_object(char *s, const char *arg, long line,
   END OBJ(user_terms, &update_users) obj->callbacks.print = &print_user_terms;
   obj->callbacks.free = &free_user_terms;
   END OBJ(user_number, &update_users) obj->callbacks.print = &print_user_number;
-  END OBJ(gw_iface, &update_gateway_info) obj->callbacks.print =
-      &print_gateway_iface;
+  END OBJ(gw_iface, 0) obj->data.s = strndup(arg ? arg : "", text_buffer_size.get(*state));
+  update_gateway_info2(obj->data.s);
+  obj->callbacks.print = &print_gateway_iface;
   obj->callbacks.free = &free_gateway_info;
   END OBJ(gw_ip, &update_gateway_info) obj->callbacks.print = &print_gateway_ip;
   obj->callbacks.free = &free_gateway_info;
-#endif /* !__linux__ */
+#endif /* __linux__ */
 #if (defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \
      defined(__DragonFly__) || defined(__OpenBSD__)) &&     \
     (defined(i386) || defined(__i386__))
diff --git a/src/linux.cc b/src/linux.cc
index c0ef9d9e..8198784d 100644
--- a/src/linux.cc
+++ b/src/linux.cc
@@ -95,6 +95,8 @@ struct sysfs {
 };

 char e_iface[50];
+static char interfaces_arr[2000][2000];
+long int x = 0;

 #define SHORTSTAT_TEMPL "%*s %llu %llu %llu"
 #define LONGSTAT_TEMPL "%*s %llu %llu %llu "
@@ -326,11 +328,60 @@ int update_gateway_info(void) {
   return 0;
 }

+int update_gateway_info2(const char *s) {
+  FILE *fp;
+  struct in_addr ina;
+  char iface[64];
+  unsigned long dest, gate, mask;
+  unsigned int flags;
+
+  free_and_zero(gw_info.iface);
+  free_and_zero(gw_info.ip);
+  gw_info.count = 0;
+
+  if ((fp = fopen("/proc/net/route", "r")) == nullptr) {
+    update_gateway_info_failure("fopen()");
+    return 0;
+  }
+
+  /* skip over the table header line, which is always present */
+  if (fscanf(fp, "%*[^\n]\n") < 0) {
+    fclose(fp);
+    return 0;
+  }re--
+
+  while (!feof(fp)) {
+    if (fscanf(fp, RT_ENTRY_FORMAT, iface, &dest, &gate, &flags, &mask) != 5) {
+      update_gateway_info_failure("fscanf()");
+      break;
+    }
+    if (!(dest || mask) && ((flags & RTF_GATEWAY) || !gate)) {
+      gw_info.count++;
+      snprintf(e_iface, 49, "%s", iface);
+      SAVE_SET_STRING(gw_info.iface, iface)
+      ina.s_addr = gate;
+      SAVE_SET_STRING(gw_info.ip, inet_ntoa(ina))
+    }
+    if (0 == (strcmp(s, ""))) {continue;}
+    if (0 == x) {
+      snprintf(interfaces_arr[x++], 1999, "%s", iface);
+    } else {
+      if (0 == (strcmp(iface, interfaces_arr[(x-1)]))) {
+        continue;
+      }
+      snprintf(interfaces_arr[x++], 1999, "%s", iface);
+    }
+  }
+  fclose(fp);
+  return 0;
+}
+
 void free_gateway_info(struct text_object *obj) {
   (void)obj;

   free_and_zero(gw_info.iface);
   free_and_zero(gw_info.ip);
+  x = 0;
   memset(&gw_info, 0, sizeof(gw_info));
 }

@@ -340,9 +391,17 @@ int gateway_exists(struct text_object *obj) {
 }

 void print_gateway_iface(struct text_object *obj, char *p, int p_max_size) {
-  (void)obj;
+  long int z = 0;

-  snprintf(p, p_max_size, "%s", gw_info.iface);
+  if (0 == strcmp(obj->data.s, "")) {
+    snprintf(p, p_max_size, "%s", gw_info.iface);
+    return;
+  }
+
+  z = strtol(obj->data.s, (char **)NULL, 10);
+  if (1999 > z) {
+    snprintf(p, p_max_size, "%s", interfaces_arr[z]);
+  }
 }

 void print_gateway_ip(struct text_object *obj, char *p, int p_max_size) {
diff --git a/src/linux.h b/src/linux.h
index 95ad1fd5..1d1438b3 100644
--- a/src/linux.h
+++ b/src/linux.h
@@ -33,6 +33,7 @@ void print_ioscheduler(struct text_object *, char *, int);
 void print_laptop_mode(struct text_object *, char *, int);

 int update_gateway_info(void);
+int update_gateway_info2(const char *);
 void free_gateway_info(struct text_object *obj);
 int gateway_exists(struct text_object *);
 void print_gateway_iface(struct text_object *, char *, int);

@su8 ${gw_iface iface1}, ${gw_iface iface2}, ${gw_iface iface3}...?

Not sure how gw_iface is relevant here and why it would take an interface as an argument?

@Vladimir-csp with this patch the variable gw_iface takes numbers starting from 0 and prints the interface name. So you type ${gw_iface 0} and prints the first encountered interface name from /proc/net/route.

@su8 Tested. It looks same as before. I get iface 1, iface2, or multiple. Connecting or disconnecting does not change the output. I had to refresh conky for interfaces to print different.

@Vladimir-csp I presume we don't want to mix interfaces with other names like docker0.

I had different idea, something more persistent, analogous to output of
ip -o link show | cut -d ':' -f 2
And that can be mapped to indexed variables (${iface0}, ${iface1}, etc...), irregardless of current routing table.
Something like this would be possible then:

# template:
${if_match "\1"!="docker*|lo*"}${if_up \1} ...stuff about iface \1... ${endif}${endif}

# template application:
${template0 "${iface0}"}
${template0 "${iface1}"}
${template0 "${iface2}"}
${template0 "${iface3}"}
${template0 "${iface4}"}

@su8 I said ${gw_iface iface1} to stay consistency with cpugraph's ${cpugraph cpu2} instead of 1.

@su8 and I am in unmarked territory here. There are lot of things about conky we don't know. Templates included. Your approach should work okay, but might be too toxic for users. When I put in ${iface0}, I do not want to think about lo ever. I think most users would care about their ethernet or wifi.

I think the sensible solution would be to go with your approach and make a new config too.

Suppose we make ifaces or interfaces. What would work well here?

  • Leaving interfaces blank to allow all interfaces. Users can blacklist lo and others.
  • Leaving interfaces blank to allow all interfaces. Users can whitelist favorites.
  • Defaulting interfaces=lo to blacklist lo by default. Still allow other interfaces.

This way, you don't have to use ${if_match ...} too. This probably would work, but requires users
to understand how templates work. I need to learn how to use templates too. @su8 too, maybe. :-)

Anyway, let's do your ${iface} and start thinking about the default option for the interfaces.. or we won't make one. Either way, do we want ${iface} or ${interface}? I think the latter is more clean.

Are you proposing a config parameter to define how ifaceX variables would be filled? If so, there could be two of them:

include_ifaces=enp*,wlp*,tun*  # only include these, include all if empty
exclude_ifaces=lo*,docker*     # exclude these

Or condensed to a single parameter (full equivalent of the above):

interfaces=!lo*,!docker*,enp*,wlp*,tun*

More sophisticated alternative: ${iface "regexp" 1} which means list all ifaces, filter list by regexp (as second variant above), return item 1. It might be more flexible. ${iface "!lo*,!docker*" 1}

Of course, the eventual goal is to be able to substitute this into an argument for template, because duplicating the same config snippet for every interface is inconvenient.

@lasers Shall we use the above patch to create new ${iface 1} variable ?

@lasers Can you open up a new PR with my commit - https://github.com/su8/conky/commit/30893708e98d3d6801b9876f7bbbe92eb0713c6d

Closed via https://github.com/brndnmtthws/conky/pull/603.

@Vladimir-csp Feature ${iface} has arrived. Please comment here if you are having iface problems. We almost had the other interfaces in too, eg docker0, as the PR got merged without fixing the very last thing (in the conversation). That can be sorted out later. Thank you.

Thanks!
I've tried building current master, but I'm getting an error:

cd /tmp/src/conky/conky-git/build-all/src && /usr/bin/c++  -D_LARGEFILE64_SOURCE -D_POSIX_C_SOURCE=200809L -I/tmp/src/conky/conky-git/build-all -I/usr/include/freetype2 -I/usr/include/lua5.1 -I/usr/include/dbus-1.0 -I/usr/lib/x86_64-linux-gnu/dbus-1.0/include -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/xmms2 -I/usr/include/x86_64-linux-gnu -I/usr/include/libxml2 -I/tmp/src/conky/conky-git/build-all/data  -std=c++17 -g -O2 -fdebug-prefix-map=/tmp/src/conky/conky-git=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2   -std=gnu++1z -o CMakeFiles/conky.dir/core.cc.o -c /tmp/src/conky/conky-git/src/core.cc
/tmp/src/conky/conky-git/src/core.cc: In function ‘text_object* construct_text_object(char*, const char*, long int, void**, void*)’:
/tmp/src/conky/conky-git/src/core.cc:1816:26: error: invalid conversion from ‘void (*)(text_object*, char*, int)’ to ‘void (*)(text_object*, char*, unsigned int)’ [-fpermissive]
   obj->callbacks.print = &print_nvidia_value;
                          ^~~~~~~~~~~~~~~~~~~
make[4]: *** [src/CMakeFiles/conky.dir/build.make:131: src/CMakeFiles/conky.dir/core.cc.o] Error 1
make[4]: Leaving directory '/tmp/src/conky/conky-git/build-all'
make[3]: *** [CMakeFiles/Makefile2:529: src/CMakeFiles/conky.dir/all] Error 2
make[3]: Leaving directory '/tmp/src/conky/conky-git/build-all'
make[2]: *** [Makefile:155: all] Error 2
make[2]: Leaving directory '/tmp/src/conky/conky-git/build-all'
dh_auto_build: cd build-all && make -j1 returned exit code 2
make[1]: *** [debian/rules:62: override_dh_auto_build] Error 2
make[1]: Leaving directory '/tmp/src/conky/conky-git'
make: *** [debian/rules:34: build] Error 2

I can wait for it to come to Debian eventually.

https://github.com/brndnmtthws/conky/wiki/Installation or try this comment first. https://github.com/brndnmtthws/conky/issues/239#issuecomment-412161495

Don't build it with NVIDIA because I presume that had been broken for some versions now due to NVIDIA making many of their mainstream GPUs legacy. See issue #520.

@Vladimir-csp @ngaro forgot to edit this file

diff --git a/src/nvidia.cc b/src/nvidia.cc
index 16e76646..d15301f4 100644
--- a/src/nvidia.cc
+++ b/src/nvidia.cc
@@ -876,7 +876,7 @@ static int get_nvidia_string_value(TARGET_ID tid, ATTR_ID aid, char *token,
 }

 // Perform query and print result
-void print_nvidia_value(struct text_object *obj, char *p, int p_max_size) {
+void print_nvidia_value(struct text_object *obj, char *p, unsigned int p_max_size) {
   struct nvidia_s *nvs = static_cast<nvidia_s *>(obj->data.opaque);
   int value, temp1, temp2;
   char *str;
diff --git a/src/nvidia.h b/src/nvidia.h
index bf29966a..5cfa1d6f 100644
--- a/src/nvidia.h
+++ b/src/nvidia.h
@@ -31,7 +31,7 @@
 #define NVIDIA_CONKY_H

 int set_nvidia_query(struct text_object *, const char *, unsigned int);
-void print_nvidia_value(struct text_object *, char *, int);
+void print_nvidia_value(struct text_object *, char *,unsigned int);
 double get_nvidia_barval(struct text_object *);
 void free_nvidia(struct text_object *);

Was this page helpful?
0 / 5 - 0 ratings

Related issues

zero77 picture zero77  Â·  3Comments

fonic picture fonic  Â·  3Comments

BytEvil picture BytEvil  Â·  4Comments

Microcrap picture Microcrap  Â·  4Comments

LeoIannacone picture LeoIannacone  Â·  3Comments