diff options
Diffstat (limited to 'fsbm.c')
-rw-r--r-- | fsbm.c | 202 |
1 files changed, 202 insertions, 0 deletions
@@ -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(×tamp, &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; +} |