// SPDX-License-Identifier: GPL-3.0-or-later
#include "libnetdata/libnetdata.h"
#include "libnetdata/required_dummies.h"
#ifdef HAVE_SETNS
#ifndef _GNU_SOURCE
#define _GNU_SOURCE /* See feature_test_macros(7) */
#endif
#include <sched.h>
#endif
char environment_variable2[FILENAME_MAX + 50] = "";
char environment_variable3[FILENAME_MAX + 50] = "";
char *environment[] = {
"PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin",
environment_variable2,
environment_variable3,
NULL
};
struct iface {
const char *device;
uint32_t hash;
unsigned int ifindex;
unsigned int iflink;
struct iface *next;
};
unsigned int calc_num_ifaces(struct iface *root) {
unsigned int num = 0;
for (struct iface *h = root; h; h = h->next) {
num++;
}
return num;
}
unsigned int read_iface_iflink(const char *prefix, const char *iface) {
if(!prefix) prefix = "";
char filename[FILENAME_MAX + 1];
snprintfz(filename, FILENAME_MAX, "%s/sys/class/net/%s/iflink", prefix, iface);
unsigned long long iflink = 0;
int ret = read_single_number_file(filename, &iflink);
if(ret) collector_error("Cannot read '%s'.", filename);
return (unsigned int)iflink;
}
unsigned int read_iface_ifindex(const char *prefix, const char *iface) {
if(!prefix) prefix = "";
char filename[FILENAME_MAX + 1];
snprintfz(filename, FILENAME_MAX, "%s/sys/class/net/%s/ifindex", prefix, iface);
unsigned long long ifindex = 0;
int ret = read_single_number_file(filename, &ifindex);
if(ret) collector_error("Cannot read '%s'.", filename);
return (unsigned int)ifindex;
}
struct iface *read_proc_net_dev(const char *scope __maybe_unused, const char *prefix) {
if(!prefix) prefix = "";
procfile *ff = NULL;
char filename[FILENAME_MAX + 1];
snprintfz(filename, FILENAME_MAX, "%s%s", prefix, (*prefix)?"/proc/1/net/dev":"/proc/net/dev");
#ifdef NETDATA_INTERNAL_CHECKS
collector_info("parsing '%s'", filename);
#endif
ff = procfile_open(filename, " \t,:|", PROCFILE_FLAG_DEFAULT);
if(unlikely(!ff)) {
collector_error("Cannot open file '%s'", filename);
return NULL;
}
ff = procfile_readall(ff);
if(unlikely(!ff)) {
collector_error("Cannot read file '%s'", filename);
return NULL;
}
size_t lines = procfile_lines(ff), l;
struct iface *root = NULL;
for(l = 2; l < lines ;l++) {
if (unlikely(procfile_linewords(ff, l) < 1)) continue;
struct iface *t = callocz(1, sizeof(struct iface));
t->device = strdupz(procfile_lineword(ff, l, 0));
t->hash = simple_hash(t->device);
t->ifindex = read_iface_ifindex(prefix, t->device);
t->iflink = read_iface_iflink(prefix, t->device);
t->next = root;
root = t;
#ifdef NETDATA_INTERNAL_CHECKS
collector_info("added %s interface '%s', ifindex %u, iflink %u", scope, t->device, t->ifindex, t->iflink);
#endif
}
procfile_close(ff);
return root;
}
void free_iface(struct iface *iface) {
freez((void *)iface->device);
freez(iface);
}
void free_host_ifaces(struct iface *iface) {
while(iface) {
struct iface *t = iface->next;
free_iface(iface);
iface = t;
}
}
int iface_is_eligible(struct iface *iface) {
if(iface->iflink != iface->ifindex)
return 1;
return 0;
}
int eligible_ifaces(struct iface *root) {
int eligible = 0;
struct iface *t;
for(t = root; t ; t = t->next)
if(iface_is_eligible(t))
eligible++;
return eligible;
}
static void continue_as_child(void) {
pid_t child = fork();
int status;
pid_t ret;
if (child < 0)
collector_error("fork() failed");
/* Only the child returns */
if (child == 0)
return;
for (;;) {
ret = waitpid(child, &status,