Skip to content

Commit

Permalink
Add network interfaces
Browse files Browse the repository at this point in the history
  • Loading branch information
everdrone committed Jun 29, 2021
1 parent bffc50b commit eff08b1
Show file tree
Hide file tree
Showing 21 changed files with 280 additions and 39 deletions.
1 change: 1 addition & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ jnfo_SOURCES = \
include/filesystem.h \
include/formatter.h \
include/gpu.h \
include/inet.h \
include/mem.h \
include/parse_size.h \
include/power.h \
Expand Down
2 changes: 1 addition & 1 deletion configure.ac
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
AC_INIT([jnfo], [1.0.1], [])
AC_INIT([jnfo], [1.1], [])
AM_INIT_AUTOMAKE([-Wall foreign subdir-objects])

AX_CXX_COMPILE_STDCXX_17
Expand Down
8 changes: 7 additions & 1 deletion debian/changelog
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
jnfo (1.1-1) unstable; urgency=low

* Add network interfaces

-- Giorgio Tropiano <[email protected]> Tue, 29 Jun 2021 13:18:00 +0200

jnfo (1.0.1-1) unstable; urgency=medium

* Add filesystem statistics

-- Giorgio Tropiano <[email protected]> Sun, 13 Jun 2021 13:25:54 +0200
-- Giorgio Tropiano <[email protected]> Mon, 28 Jun 2021 22:10:00 +0200

jnfo (1.0.0-1) unstable; urgency=medium

Expand Down
5 changes: 4 additions & 1 deletion include/defines.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,13 @@
// filesystem
#define MTAB_PATH TEST_PATH "/etc/mtab"

// interfaces
#define INET_GLOB TEST_PATH "/sys/class/net/*"

// power
#define POWER_INPUT_NAME_GLOB \
TEST_PATH "/sys/bus/i2c/drivers/ina3221x/6-0040/iio:device0/rail_name_[0-9]"
#define POWER_INPUT_PATH TEST_PATH "/sys/bus/i2c/drivers/ina3221x/6-0040/iio:device0"

static char* progname = "jnfo";
static const char* progname = "jnfo";
static bool enable_color = false;
29 changes: 19 additions & 10 deletions include/formatter.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,41 +41,42 @@ fmt_measure_t format_frequency(unsigned hertz, int decimals) {
return out;
}

fmt_measure_t format_storage(unsigned long bytes, int decimals, bool use_iec = false) {
fmt_measure_t format_digital(unsigned long bytes, int decimals, string suffix = "",
bool use_iec = false) {
fmt_measure_t out;
char buffer[16];
float result = float(bytes);

if (use_iec && bytes / 1099511627776 >= 1) {
// TiB
result /= 1099511627776; // 1024**4
out.unit = "TiB";
out.unit = "TiB" + suffix;
} else if (bytes * 1e-12 >= 1) {
result *= 1e-12;
out.unit = "TB";
out.unit = "TB" + suffix;
} else if (use_iec && bytes / 1073741824 >= 1) {
result /= 1073741824; // 1024**3
out.unit = "GiB";
out.unit = "GiB" + suffix;
} else if (bytes * 1e-9 >= 1) {
result *= 1e-9;
out.unit = "GB";
out.unit = "GB" + suffix;
} else if (use_iec && bytes / 1048576 >= 1) {
result /= 1048576; // 1024**2
out.unit = "MiB";
out.unit = "MiB" + suffix;
} else if (bytes * 1e-6 >= 1) {
result *= 1e-6;
out.unit = "MB";
out.unit = "MB" + suffix;
} else if (use_iec && bytes / 1024 >= 1) {
result /= 1024;
out.unit = "KiB";
out.unit = "KiB" + suffix;
} else if (bytes * 1e-3 >= 1) {
result *= 1e-3;
out.unit = "kB";
out.unit = "kB" + suffix;
} else {
// return bytes
sprintf(buffer, "%lu", bytes);
out.value = buffer;
out.unit = "B";
out.unit = "B" + suffix;
return out;
}

Expand All @@ -85,6 +86,14 @@ fmt_measure_t format_storage(unsigned long bytes, int decimals, bool use_iec = f
return out;
}

fmt_measure_t format_storage(unsigned long bytes, int decimals, bool use_iec = false) {
return format_digital(bytes, decimals, "", use_iec);
}

fmt_measure_t format_speed(unsigned long bytes, int decimals, bool use_iec = false) {
return format_digital(bytes, decimals, "/s", use_iec);
}

string format_percent(float x, float y, int decimals) {
string out;
char buffer[16];
Expand Down
200 changes: 200 additions & 0 deletions include/inet.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
#pragma once

#include <glob.h>
#include <libgen.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

#include "defines.h"
#include "utils.h"

typedef struct {
unsigned long long packets = 0;
unsigned long long bytes = 0;
unsigned long long dropped = 0;
unsigned long long errors = 0;
} packets_t;

typedef struct {
string name;
string address;
string operstate;
unsigned long speed; // bytes/sec
packets_t tx;
packets_t rx;
} interface_t;

typedef struct {
vector<interface_t> interfaces;
packets_t tx;
packets_t rx;
} network_t;

void get_packets(interface_t* iface, network_t* net, const char* path) {
string file_path;

file_path = path;
file_path += "/address";
iface->address = read_file(file_path.c_str());
iface->operstate = trim(iface->address);

file_path = path;
file_path += "/operstate";
iface->operstate = read_file(file_path.c_str());
iface->operstate = trim(iface->operstate);

if (iface->operstate != "up") {
// don't read speed, otherwise we get a buffer underflow
iface->speed = 0;
} else {
file_path = path;
file_path += "/speed";
iface->speed = std::atol(read_file(file_path.c_str()).c_str());
// the units are stored in MB/s in the file, so multiply to convert into B/s
iface->speed *= 1e+6;
}

char* end_ptr;

file_path = path;
file_path += "/statistics/rx_bytes";
iface->rx.bytes = std::strtoull(read_file(file_path.c_str()).c_str(), &end_ptr, 10);

file_path = path;
file_path += "/statistics/rx_packets";
iface->rx.packets = std::strtoull(read_file(file_path.c_str()).c_str(), &end_ptr, 10);

file_path = path;
file_path += "/statistics/rx_dropped";
iface->rx.dropped = std::strtoull(read_file(file_path.c_str()).c_str(), &end_ptr, 10);

file_path = path;
file_path += "/statistics/rx_errors";
iface->rx.errors = std::strtoull(read_file(file_path.c_str()).c_str(), &end_ptr, 10);

file_path = path;
file_path += "/statistics/tx_bytes";
iface->tx.bytes = std::strtoull(read_file(file_path.c_str()).c_str(), &end_ptr, 10);

file_path = path;
file_path += "/statistics/tx_packets";
iface->tx.packets = std::strtoull(read_file(file_path.c_str()).c_str(), &end_ptr, 10);

file_path = path;
file_path += "/statistics/tx_dropped";
iface->tx.dropped = std::strtoull(read_file(file_path.c_str()).c_str(), &end_ptr, 10);

file_path = path;
file_path += "/statistics/tx_errors";
iface->tx.errors = std::strtoull(read_file(file_path.c_str()).c_str(), &end_ptr, 10);

net->rx.bytes += iface->rx.bytes;
net->rx.packets += iface->rx.packets;
net->rx.dropped += iface->rx.dropped;
net->rx.errors += iface->rx.errors;

net->tx.bytes += iface->tx.bytes;
net->tx.packets += iface->tx.packets;
net->tx.dropped += iface->tx.dropped;
net->tx.errors += iface->tx.errors;
}

network_t get_network() {
network_t result;
glob_t glob_result;

glob(INET_GLOB, GLOB_TILDE, NULL, &glob_result);
for (unsigned i = 0; i < glob_result.gl_pathc; i++) {
// check if symlink
struct stat statbuf;

if (lstat(glob_result.gl_pathv[i], &statbuf) < 0) { /* if error occured */
std::cerr << "Cannot stat file: " << glob_result.gl_pathv[i] << std::endl;
globfree(&glob_result);
exit(EXIT_FAILURE);
}

char* real_path;

if ((real_path = realpath(glob_result.gl_pathv[i], NULL)) != NULL) {
if (strstr(real_path, "/sys/devices/virtual/") == NULL) {
// consider this interface
interface_t iface;

iface.name = basename(glob_result.gl_pathv[i]);

get_packets(&iface, &result, real_path);

result.interfaces.push_back(iface);
} else {
// this is a virtual device, ignore
continue;
}

} else {
std::cerr << "Cannot get path of: " << glob_result.gl_pathv[i] << std::endl;
globfree(&glob_result);
free(real_path);
exit(EXIT_FAILURE);
}

free(real_path);
}

globfree(&glob_result);
return result;
}

void pretty_print(network_t info, bool summary = false) {
fmt_measure_t fmt;

pretty("Network", "", 0);

if (summary) {
fmt = format_storage(info.rx.bytes, 2);
pretty("Receive", fmt.value.c_str(), 1, NUMBER, 1, fmt.unit.c_str());
fmt = format_storage(info.tx.bytes, 2);
pretty("Transmit", fmt.value.c_str(), 1, NUMBER, 0, fmt.unit.c_str());
} else {
pretty("Receive", "", 1, STRING);
fmt = format_storage(info.rx.bytes, 2);
pretty("Bytes", fmt.value.c_str(), 2, NUMBER, 2, fmt.unit.c_str());
pretty("Packets", std::to_string(info.rx.packets).c_str(), 2, NUMBER, 0);
pretty("Dropped", std::to_string(info.rx.dropped).c_str(), 2, NUMBER, 0);
pretty("Errors", std::to_string(info.rx.errors).c_str(), 2, NUMBER, 1);

pretty("Transmit", "", 1, STRING);
fmt = format_storage(info.tx.bytes, 2);
pretty("Bytes", fmt.value.c_str(), 2, NUMBER, 2, fmt.unit.c_str());
pretty("Packets", std::to_string(info.tx.packets).c_str(), 2, NUMBER, 0);
pretty("Dropped", std::to_string(info.tx.dropped).c_str(), 2, NUMBER, 0);
pretty("Errors", std::to_string(info.tx.errors).c_str(), 2, NUMBER, 1);

pretty("Interfaces", "", 1);
for (const auto& iface : info.interfaces) {
pretty("Name", iface.name.c_str(), 3, STRING, 3, "", true);
pretty("Address", iface.address.c_str(), 3, STRING);
pretty("Status", iface.operstate.c_str(), 3, STRING, 1);
fmt = format_speed(iface.speed, 2);
pretty("Speed", fmt.value.c_str(), 3, NUMBER, 2, fmt.unit.c_str());
// pretty("Speed", iface.speed, 3, NUMBER);
pretty("Receive", "", 3, STRING);
fmt = format_storage(iface.rx.bytes, 2);
pretty("Bytes", fmt.value.c_str(), 4, NUMBER, 2, fmt.unit.c_str());
pretty("Packets", std::to_string(iface.rx.packets).c_str(), 4, NUMBER, 0);
pretty("Dropped", std::to_string(iface.rx.dropped).c_str(), 4, NUMBER, 0);
pretty("Errors", std::to_string(iface.rx.errors).c_str(), 4, NUMBER, 1);

pretty("Transmit", "", 3, STRING);
fmt = format_storage(iface.tx.bytes, 2);
pretty("Bytes", fmt.value.c_str(), 4, NUMBER, 2, fmt.unit.c_str());
pretty("Packets", std::to_string(iface.tx.packets).c_str(), 4, NUMBER, 0);
pretty("Dropped", std::to_string(iface.tx.dropped).c_str(), 4, NUMBER, 0);
pretty("Errors", std::to_string(iface.tx.errors).c_str(), 4, NUMBER, 1);
}
}
}
42 changes: 19 additions & 23 deletions include/mem.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@ memory_t get_memory() {
// read /proc/meminfo line by line
vector<string> meminfo = read_lines(MEMINFO);

result.nvmap.total =
std::strtoul(read_file(IRAM_SIZE_PATH).c_str(), NULL, 16);
result.nvmap.total = std::strtoul(read_file(IRAM_SIZE_PATH).c_str(), NULL, 16);

for (const auto& line : meminfo) {
size_t cut_index = 0;
Expand Down Expand Up @@ -86,17 +85,20 @@ void pretty_print(memory_t info, bool summary = false) {
pretty("Memory", "", 0);

if (summary) {
pretty("RAM",
format_percent(info.ram.total - info.ram.free, info.ram.total, 0)
.c_str(),
1, PERCENT, 2);
pretty("Swap",
format_percent(info.swap.total - info.swap.free, info.swap.total, 0)
.c_str(),
1, PERCENT, 1);
pretty("NVMap",
format_percent(info.nvmap.cached, info.nvmap.total, 0).c_str(), 1,
pretty("RAM", "", 1);
fmt = format_storage(info.ram.total, 2);
pretty("Total", fmt.value.c_str(), 2, NUMBER, 0, fmt.unit.c_str());
pretty("Usage", format_percent(info.ram.total - info.ram.free, info.ram.total, 0).c_str(), 2,
PERCENT, 0);
pretty("Swap", "", 1);
fmt = format_storage(info.swap.total, 2);
pretty("Total", fmt.value.c_str(), 2, NUMBER, 0, fmt.unit.c_str());
pretty("Usage", format_percent(info.swap.total - info.swap.free, info.swap.total, 0).c_str(), 2,
PERCENT, 0);
pretty("NVMap", "", 1);
fmt = format_storage(info.nvmap.total, 2);
pretty("Total", fmt.value.c_str(), 2, NUMBER, 0, fmt.unit.c_str());
pretty("Usage", format_percent(info.nvmap.cached, info.nvmap.total, 0).c_str(), 2, PERCENT, 0);
} else {
pretty("RAM", "", 1);

Expand All @@ -108,10 +110,8 @@ void pretty_print(memory_t info, bool summary = false) {

fmt = format_storage(info.ram.cached, 2);
pretty("Cached", fmt.value.c_str(), 2, NUMBER, 0, fmt.unit.c_str());
pretty("Usage",
format_percent(info.ram.total - info.ram.free, info.ram.total, 0)
.c_str(),
2, PERCENT, 1);
pretty("Usage", format_percent(info.ram.total - info.ram.free, info.ram.total, 0).c_str(), 2,
PERCENT, 1);
pretty("Swap", "", 1);

fmt = format_storage(info.swap.total, 2);
Expand All @@ -122,10 +122,8 @@ void pretty_print(memory_t info, bool summary = false) {

fmt = format_storage(info.swap.cached, 2);
pretty("Cached", fmt.value.c_str(), 2, NUMBER, 0, fmt.unit.c_str());
pretty("Usage",
format_percent(info.swap.total - info.swap.free, info.swap.total, 0)
.c_str(),
2, PERCENT, 1);
pretty("Usage", format_percent(info.swap.total - info.swap.free, info.swap.total, 0).c_str(), 2,
PERCENT, 1);
pretty("NVMap", "", 1);

fmt = format_storage(info.nvmap.total, 2);
Expand All @@ -136,8 +134,6 @@ void pretty_print(memory_t info, bool summary = false) {

fmt = format_storage(info.nvmap.cached, 2);
pretty("Used", fmt.value.c_str(), 2, NUMBER, 2, fmt.unit.c_str());
pretty("Usage",
format_percent(info.nvmap.cached, info.nvmap.total, 0).c_str(), 2,
PERCENT, 1);
pretty("Usage", format_percent(info.nvmap.cached, info.nvmap.total, 0).c_str(), 2, PERCENT, 1);
}
}
Loading

0 comments on commit eff08b1

Please sign in to comment.