It is natural for ip(8) tool to access /proc/net/dev for various information and there at least two places implementing same iteration over lines in this file: iptunnel.c and ip6tunnel.c.
To unify interface and avoid code duplication introduce helper that reads line from /proc/net/dev, passes it to given callback function that may return following three states to control do_each_proc_net_dev() behaviour: o PND_ERROR - stop reading lines and return -1 o PND_OK - stop reading lines and return 0 o PND_NEXT - continue by reading next line. Signed-off-by: Serhey Popovych <serhe.popov...@gmail.com> --- include/utils.h | 10 ++++++++++ lib/utils.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/include/utils.h b/include/utils.h index 0394268..819b0ca 100644 --- a/include/utils.h +++ b/include/utils.h @@ -285,6 +285,16 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req, int do_each_netns(int (*func)(char *nsname, void *arg), void *arg, bool show_label); +typedef enum { + PND_ERROR = -1, + PND_OK = 0, + PND_NEXT = 1 +} pnd_result_t; + +typedef pnd_result_t (pnd_func_t)(char *name, char *stats, void *arg); + +int do_each_proc_net_dev(pnd_func_t f, void *arg); + char *int_to_str(int val, char *buf); int get_guid(__u64 *guid, const char *arg); int get_real_family(int rtm_type, int rtm_family); diff --git a/lib/utils.c b/lib/utils.c index 8e15625..4f142d8 100644 --- a/lib/utils.c +++ b/lib/utils.c @@ -1375,6 +1375,57 @@ int do_each_netns(int (*func)(char *nsname, void *arg), void *arg, return netns_foreach(on_netns, &nsf); } +int do_each_proc_net_dev(pnd_func_t f, void *arg) +{ + static const char pnd[] = "/proc/net/dev"; + char buf[512]; + int err = -1; + FILE *fp; + + fp = fopen(pnd, "r"); + if (!fp) { + perror("fopen"); + return -1; + } + + /* skip two lines at the begenning of the file */ + if (!fgets(buf, sizeof(buf), fp) || + !fgets(buf, sizeof(buf), fp)) { + perror("fgets"); + goto end; + } + + while (fgets(buf, sizeof(buf), fp)) { + char *stats, *name = NULL; + pnd_result_t result; + + buf[sizeof(buf) - 1] = '\0'; + stats = strchr(buf, ':'); + if (stats) { + *stats++ = '\0'; + if (!check_ifname(buf)) + name = buf; + } + if (!name) { + fprintf(stderr, + "Wrong format for \"%s\". Giving up.\n", pnd); + goto end; + } + + result = f(name, stats, arg); + if (result == PND_NEXT) + continue; + if (result == PND_OK) + break; + goto end; + } + if (feof(fp)) + err = 0; +end: + fclose(fp); + return err; +} + char *int_to_str(int val, char *buf) { sprintf(buf, "%d", val); -- 1.7.10.4