aboutsummaryrefslogtreecommitdiff
path: root/fsbm.c
diff options
context:
space:
mode:
Diffstat (limited to 'fsbm.c')
-rw-r--r--fsbm.c202
1 files changed, 202 insertions, 0 deletions
diff --git a/fsbm.c b/fsbm.c
new file mode 100644
index 0000000..1769370
--- /dev/null
+++ b/fsbm.c
@@ -0,0 +1,202 @@
+#include <getopt.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <arpa/inet.h>
+#include <net/if.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stddef.h>
+
+#define PROC_NET_DEV "/proc/net/dev"
+
+struct iface {
+ char interface[IFNAMSIZ];
+ struct timeval timestamp;
+ unsigned long long rx_bytes;
+ unsigned long long tx_bytes;
+};
+
+
+volatile bool q = false;
+bool use_bits = false;
+struct iface *interfaces = NULL;
+size_t no_iface = 0;
+
+void endHandler(int signum) {
+ q = true;
+}
+
+void print_bps(double bytesPerSecond) {
+ const char* prefixes[] = { "", "k", "M", "G", "T", "P", "E", "Z", "Y" };
+
+ // Calculate the value
+ double value;
+ const char* unit;
+ if(use_bits) {
+ value = bytesPerSecond * 8;
+ unit = "b/s";
+ }
+ else {
+ value = bytesPerSecond;
+ unit = "B/s";
+ }
+
+ // Choose the prefix
+ unsigned prefix = 0;
+ while (prefix < (sizeof(prefixes) / sizeof(const char*)) && value > 1000.) {
+ value /= 1000.;
+ ++prefix;
+ }
+
+ // Format the string
+ printf("%.2f %s%s", value, prefixes[prefix], unit);
+
+}
+
+void print_stats() {
+ // Open /proc/net/dev
+ FILE *dev = fopen(PROC_NET_DEV, "r");
+ if (!dev) {
+ fprintf(stderr, "cannot open %s - %s\n", PROC_NET_DEV, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ // Read /proc/dev/net
+ while (!feof(dev)) {
+ char buf[512];
+ char *name, *statistics_string;
+ long long unsigned rx_bytes, tx_bytes;
+ struct timezone unused_timezone;
+ struct timeval timestamp;
+
+ // Read a line
+ fgets(buf, sizeof(buf), dev);
+
+ // get timestamp
+ gettimeofday(&timestamp, &unused_timezone);
+
+ // Find the colon separating the name from the statistics
+ statistics_string = strchr(buf, ':');
+ if (!statistics_string) continue;
+
+ // Get a pointer to the statistics
+ *statistics_string = 0;
+ ++statistics_string;
+
+ // Remove leading whitespace from the name
+ name = buf;
+ ptrdiff_t len = 0;
+ while (*name == ' ' || *name == '\t') {
+ ++name;
+ }
+ len = name - buf;
+
+ // Parse the statistics, alls well, then get this shit going, otherwise f it.
+ if (sscanf(statistics_string, "%Lu %*Lu %*Lu %*Lu %*Lu %*Lu %*Lu %*Lu %Lu",
+ &rx_bytes, &tx_bytes) == 2) {
+
+ size_t i = 0;
+ bool found = false;
+ if(interfaces == NULL) {
+ goto skip;
+ }
+ for(i = 0; i < no_iface; i++) {
+ // if it exists in our interfaces, great. reuse the iface struct
+ if(strncmp(name, interfaces[i].interface, len) == 0) {
+ found = true;
+ break;
+ }
+ }
+ skip:
+ if(found) {
+ double timeDelta, rx_speed, tx_speed = 0;
+
+ // print our new speeds
+ timeDelta = (timestamp.tv_sec - interfaces[i].timestamp.tv_sec) * 1.0 +
+ (timestamp.tv_usec - interfaces[i].timestamp.tv_usec) * .000001;
+
+ rx_speed = (rx_bytes - interfaces[i].rx_bytes) / timeDelta;
+ tx_speed = (tx_bytes - interfaces[i].tx_bytes) / timeDelta;
+
+ printf("%s (", interfaces[i].interface);
+ print_bps(rx_speed);
+ printf(", ");
+ print_bps(tx_speed);
+ printf(")\t");
+
+ // update our interface
+ strcpy(interfaces[i].interface, name);
+ interfaces[i].rx_bytes = rx_bytes;
+ interfaces[i].timestamp = timestamp;
+ interfaces[i].tx_bytes = tx_bytes;
+ }
+ else {
+ interfaces = realloc(interfaces, sizeof(struct iface) * (no_iface + 1));
+ if(interfaces == NULL) {
+ fprintf(stderr, "Error: %s\n", strerror(errno));
+ exit(1);
+ }
+ strcpy(interfaces[no_iface].interface, name);
+ interfaces[no_iface].rx_bytes = rx_bytes;
+ interfaces[no_iface].tx_bytes = tx_bytes;
+ no_iface++;
+ }
+
+ }
+
+ }
+ // Close the file
+ fclose(dev);
+
+}
+
+int main(int argc, char **argv) {
+
+ // parse the command line
+ int c;
+
+ int interval = 10 * 100000;
+
+ while ((c = getopt (argc, argv, "bi:hv")) != -1)
+ switch (c)
+ {
+ case 'b':
+ use_bits = true;
+ break;
+ case 'i':
+ // Magic numbers? fuck it that's not a magic number, that's a 'real' number.
+ interval = atoi(optarg) * 100000;
+ break;
+ case 'h':
+ printf("USAGE: fsbm, -b specifies bits, -i sets interval in 10ths of seconds, 1 sec default\n");
+ exit(EXIT_SUCCESS);
+ break;
+ case 'v':
+ printf("Version 1\n");
+ exit(EXIT_SUCCESS);
+ break;
+ case '?':
+ fprintf(stderr,"bad flag\n");
+ break;
+ default:
+ exit(EXIT_FAILURE);
+ }
+
+ // Catch SIGINT
+ signal(SIGINT, endHandler);
+
+ // populate first.
+ print_stats();
+ while (!q) {
+ print_stats();
+ printf("\n");
+ usleep(interval);
+ }
+
+ return EXIT_SUCCESS;
+}