#include #include #include #include "parser.h" #include "process.h" #include "string.h" #include "debug.h" #include "utils.h" #include "built_in_parsers.h" #define STATFILE "/proc/stat" static int cpu_parser(char *data, const char **p, void **state) { char buf[1024]; char *str = buf; FILE *file = fopen(STATFILE, "r"); long long user, nice, sys, idle, wait, irq, softirq; if (file == NULL) { pr_err("Failed to open file %s\n", STATFILE); return -1; } if (!fgets(buf, sizeof(buf), file)) { pr_err("Failed to read file %s\n", STATFILE); fclose(file); return -1; } user = dec_to_longlong(str, &str); nice = dec_to_longlong(str, &str); sys = dec_to_longlong(str, &str); idle = dec_to_longlong(str, &str); wait = dec_to_longlong(str, &str); irq = dec_to_longlong(str, &str); softirq = dec_to_longlong(str, &str); snprintf(data, RRD_DATA_MAX_LEN, "%lld:%lld:%lld:%lld:%lld:%lld:%lld", user, nice, sys, idle, wait, irq, softirq); fclose(file); return 0; } #define MEMFILE "/proc/meminfo" static int mem_parser(char *data, const char **p, void **state) { char buf[1024], word[1024]; int free = 0, buffered = 0, cache = 0, active = 0, inactive = 0, swapfree = 0, anon = 0, slab = 0, tables = 0, other = 0, swaptotal = 0, total = 0; FILE *file = fopen(MEMFILE, "r"); if (file == NULL) { pr_err("Failed to open file %s\n", MEMFILE); return -1; } while (fgets(buf, sizeof(buf), file)) { get_word(buf, 0, word, sizeof(word)); if (!strcmp(word, "MemFree:")) { free = dec_to_int(buf, NULL); } else if (!strcmp(word, "MemTotal:")) { total = dec_to_int(buf, NULL); } else if (!strcmp(word, "Buffers:")) { buffered = dec_to_int(buf, NULL); } else if (!strcmp(word, "Cached:")) { cache = dec_to_int(buf, NULL); } else if (!strcmp(word, "Active:")) { active = dec_to_int(buf, NULL); } else if (!strcmp(word, "Inactive:")) { inactive = dec_to_int(buf, NULL); } else if (!strcmp(word, "SwapFree:")) { swapfree = dec_to_int(buf, NULL); } else if (!strcmp(word, "AnonPages:")) { anon = dec_to_int(buf, NULL); } else if (!strcmp(word, "Slab:")) { slab = dec_to_int(buf, NULL); } else if (!strcmp(word, "PageTables:")) { tables = dec_to_int(buf, NULL); } else if (!strcmp(word, "SwapTotal:")) { swaptotal = dec_to_int(buf, NULL); } } fclose(file); other = total - free - buffered - cache - anon - slab - tables; snprintf(data, RRD_DATA_MAX_LEN, "%f:%f:%f:%f:%f:%f:%f:%f:%f:%f:%f", free / 1024.0, buffered / 1024.0, cache / 1024.0, active / 1024.0, inactive / 1024.0, swapfree / 1024.0, anon / 1024.0, slab / 1024.0, tables / 1024.0, other / 1024.0, (swaptotal - swapfree) / 1024.0); return 0; } int cpu_mem_parser(char *data, const char **p, void **state) { int ret; char cpu[RRD_DATA_MAX_LEN], mem[RRD_DATA_MAX_LEN]; cpu_parser(cpu, p, state); mem_parser(mem, p, state); ret = snprintf(data, RRD_DATA_MAX_LEN, "%s:%s", cpu, mem); /* No actual data overflow, snprintf just couldn't fit all data in the buffer */ if (ret >= RRD_DATA_MAX_LEN) pr_err("Buffer overlfow\n"); return 0; } /* Run a command and feed the output from stdout directly to rrdtool */ static int script_parser(char *rrd_data, const char **parser_data, void **state) { FILE *readf; int pid, ret; void *tmp = parser_data; char **cmd = tmp; pid = run_piped_stream(cmd[0], &cmd[1], NULL, &readf, NULL); ret = fread(rrd_data, 1, RRD_DATA_MAX_LEN - 1, readf); if (ret < 0) { pr_err("Error on read: %m\n"); goto err_read; } rrd_data[ret] = 0; pr_info("Read %d bytes :%s\n", ret, rrd_data); err_read: fclose(readf); clear_zombie(pid); return 0; } struct iface_stats { long long rx_bytes; long long rx_packets; long long tx_bytes; long long tx_packets; }; #define PROC_NETDEV "/proc/net/dev" static int get_iface_stats(const char *iface, struct iface_stats *stat) { FILE *netdev; char buf[1024]; char if_name[16]; char *str; int error; netdev = fopen(PROC_NETDEV, "r"); if (netdev == NULL) { error = errno; pr_err("Failed to open file %s: %d (%m)\n", PROC_NETDEV, error); return error; } while (fgets(buf, sizeof(buf), netdev)) { get_word(buf, &str, if_name, sizeof(if_name)); /* Remove the ':' at the end of the if_name */ if_name[strlen(if_name) - 1] = 0; if (strncmp(iface, if_name, sizeof(if_name))) continue; stat->rx_bytes = dec_to_longlong(str, &str); stat->rx_packets = dec_to_longlong(str, &str); /* errs */ dec_to_longlong(str, &str); /* drop */ dec_to_longlong(str, &str); /* fifo */ dec_to_longlong(str, &str); /* frame */ dec_to_longlong(str, &str); /* compressed */ dec_to_longlong(str, &str); /* multicast */ dec_to_longlong(str, &str); stat->tx_bytes = dec_to_longlong(str, &str); stat->tx_packets = dec_to_longlong(str, &str); pr_info("rx_b %lld rx_p %lld tx_b %lld tx_p %lld\n", stat->rx_bytes, stat->rx_packets, stat->tx_bytes, stat->tx_packets); fclose(netdev); return 0; } fclose(netdev); pr_err("Interface %s not found\n", iface); return -ENODEV; } int netstats_parser(char *rrd_data, const char **parser_data, void **state) { struct iface_stats stat; const char **iface_name = parser_data; int max_str = RRD_DATA_MAX_LEN; int ret; if (!parser_data) { pr_err("No device names specified\n"); return -1; } while(*iface_name) { pr_info("getting data for iface %s\n", *iface_name); ret = get_iface_stats(*iface_name, &stat); if (!ret) { ret = snprintf(rrd_data, max_str, "%lld:%lld:%lld:%lld", stat.rx_bytes, stat.rx_packets, stat.tx_bytes, stat.tx_packets); } else { ret = snprintf(rrd_data, max_str, "U:U:U:U"); } max_str -= ret; rrd_data += ret; iface_name++; if (!*iface_name) break; ret = snprintf(rrd_data, max_str, ":"); max_str -= ret; rrd_data += ret; } return 0; } static struct parser_info built_in_parsers[] = { { .name = "cpu", .parse = cpu_parser, }, { .name = "mem", .parse = mem_parser, }, { .name = "cpu_mem", .parse = cpu_mem_parser, }, { .name = "script", .parse = script_parser, }, { .name = "netstats", .parse = netstats_parser, }, }; int register_built_in_parsers(void) { int i, ret; for (i = 0; i < ARRAY_SIZE(built_in_parsers); i++) { ret = register_parser(&built_in_parsers[i]); if (ret) break; } return ret; }