summaryrefslogtreecommitdiff
path: root/src/print_mem.c
diff options
context:
space:
mode:
authorIngo Bürk <admin@airblader.de>2018-05-19 22:08:42 +0200
committerGitHub <noreply@github.com>2018-05-19 22:08:42 +0200
commitb850f5852d0e455c246827a603ac28577a70428d (patch)
tree81530fd72f1d81d80e4d960d9009a857e55a59a6 /src/print_mem.c
parentffe41cc9440d0404101dae9420f91d2e0cdf3468 (diff)
parentcba8f559384008f187e7388186b9885343be0678 (diff)
Merge pull request #270 from Stunkymonkey/mem-support
initial support of memory-usage for linux
Diffstat (limited to 'src/print_mem.c')
-rw-r--r--src/print_mem.c225
1 files changed, 225 insertions, 0 deletions
diff --git a/src/print_mem.c b/src/print_mem.c
new file mode 100644
index 0000000..46523d6
--- /dev/null
+++ b/src/print_mem.c
@@ -0,0 +1,225 @@
+// vim:ts=4:sw=4:expandtab
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <yajl/yajl_gen.h>
+#include <yajl/yajl_version.h>
+#include "i3status.h"
+
+#define BINARY_BASE UINT64_C(1024)
+
+#define MAX_EXPONENT 4
+static const char *const iec_symbols[MAX_EXPONENT + 1] = {"", "Ki", "Mi", "Gi", "Ti"};
+
+static const char memoryfile_linux[] = "/proc/meminfo";
+
+/*
+ * Prints the given amount of bytes in a human readable manner.
+ *
+ */
+static int print_bytes_human(char *outwalk, uint64_t bytes) {
+ double size = bytes;
+ int exponent = 0;
+ int bin_base = BINARY_BASE;
+ while (size >= bin_base && exponent < MAX_EXPONENT) {
+ size /= bin_base;
+ exponent += 1;
+ }
+ return sprintf(outwalk, "%.1f %sB", size, iec_symbols[exponent]);
+}
+
+/*
+ * Convert a string to its absolute representation based on the total
+ * memory of `mem_total`.
+ *
+ * The string can contain any percentage values, which then return a
+ * the value of `size` in relation to `mem_total`.
+ * Alternatively an absolute value can be given, suffixed with an iec
+ * symbol.
+ *
+ */
+static long memory_absolute(const long mem_total, const char *size) {
+ long mem_absolute = -1;
+ char *endptr = NULL;
+
+ mem_absolute = strtol(size, &endptr, 10);
+
+ if (endptr) {
+ while (endptr[0] != '\0' && isspace(endptr[0]))
+ endptr++;
+
+ switch (endptr[0]) {
+ case 'T':
+ case 't':
+ mem_absolute *= BINARY_BASE;
+ case 'G':
+ case 'g':
+ mem_absolute *= BINARY_BASE;
+ case 'M':
+ case 'm':
+ mem_absolute *= BINARY_BASE;
+ case 'K':
+ case 'k':
+ mem_absolute *= BINARY_BASE;
+ break;
+ case '%':
+ mem_absolute = mem_total * mem_absolute / 100;
+ break;
+ default:
+ break;
+ }
+ }
+
+ return mem_absolute;
+}
+
+void print_memory(yajl_gen json_gen, char *buffer, const char *format, const char *format_degraded, const char *threshold_degraded, const char *threshold_critical, const char *memory_used_method) {
+ char *outwalk = buffer;
+
+#if defined(linux)
+ const char *selected_format = format;
+ const char *walk;
+ const char *output_color = NULL;
+
+ long ram_total = -1;
+ long ram_free = -1;
+ long ram_available = -1;
+ long ram_used = -1;
+ long ram_shared = -1;
+ long ram_cached = -1;
+ long ram_buffers = -1;
+
+ FILE *file = fopen(memoryfile_linux, "r");
+ if (!file) {
+ goto error;
+ }
+ char line[128];
+ while (fgets(line, sizeof line, file)) {
+ if (BEGINS_WITH(line, "MemTotal:")) {
+ ram_total = strtol(line + strlen("MemTotal:"), NULL, 10);
+ }
+ if (BEGINS_WITH(line, "MemFree:")) {
+ ram_free = strtol(line + strlen("MemFree:"), NULL, 10);
+ }
+ if (BEGINS_WITH(line, "MemAvailable:")) {
+ ram_available = strtol(line + strlen("MemAvailable:"), NULL, 10);
+ }
+ if (BEGINS_WITH(line, "Buffers:")) {
+ ram_buffers = strtol(line + strlen("Buffers:"), NULL, 10);
+ }
+ if (BEGINS_WITH(line, "Cached:")) {
+ ram_cached = strtol(line + strlen("Cached:"), NULL, 10);
+ }
+ if (BEGINS_WITH(line, "Shmem:")) {
+ ram_shared = strtol(line + strlen("Shmem:"), NULL, 10);
+ }
+ if (ram_total != -1 && ram_free != -1 && ram_available != -1 && ram_buffers != -1 && ram_cached != -1 && ram_shared != -1) {
+ break;
+ }
+ }
+ fclose(file);
+
+ if (ram_total == -1 || ram_free == -1 || ram_available == -1 || ram_buffers == -1 || ram_cached == -1 || ram_shared == -1) {
+ goto error;
+ }
+
+ ram_total = ram_total * BINARY_BASE;
+ ram_free = ram_free * BINARY_BASE;
+ ram_available = ram_available * BINARY_BASE;
+ ram_buffers = ram_buffers * BINARY_BASE;
+ ram_cached = ram_cached * BINARY_BASE;
+ ram_shared = ram_shared * BINARY_BASE;
+
+ if (BEGINS_WITH(memory_used_method, "memavailable")) {
+ ram_used = ram_total - ram_available;
+ } else if (BEGINS_WITH(memory_used_method, "classical")) {
+ ram_used = ram_total - ram_free - ram_buffers - ram_cached;
+ }
+
+ if (threshold_degraded) {
+ long abs = memory_absolute(ram_total, threshold_degraded);
+ if (ram_available < abs) {
+ output_color = "color_degraded";
+ }
+ }
+
+ if (threshold_critical) {
+ long abs = memory_absolute(ram_total, threshold_critical);
+ if (ram_available < abs) {
+ output_color = "color_bad";
+ }
+ }
+
+ if (output_color) {
+ START_COLOR(output_color);
+
+ if (format_degraded)
+ selected_format = format_degraded;
+ }
+
+ for (walk = selected_format; *walk != '\0'; walk++) {
+ if (*walk != '%') {
+ *(outwalk++) = *walk;
+ continue;
+ }
+ if (BEGINS_WITH(walk + 1, "total")) {
+ outwalk += print_bytes_human(outwalk, ram_total);
+ walk += strlen("total");
+ }
+
+ if (BEGINS_WITH(walk + 1, "used")) {
+ outwalk += print_bytes_human(outwalk, ram_used);
+ walk += strlen("used");
+ }
+
+ if (BEGINS_WITH(walk + 1, "free")) {
+ outwalk += print_bytes_human(outwalk, ram_free);
+ walk += strlen("free");
+ }
+
+ if (BEGINS_WITH(walk + 1, "available")) {
+ outwalk += print_bytes_human(outwalk, ram_available);
+ walk += strlen("available");
+ }
+
+ if (BEGINS_WITH(walk + 1, "shared")) {
+ outwalk += print_bytes_human(outwalk, ram_shared);
+ walk += strlen("shared");
+ }
+
+ if (BEGINS_WITH(walk + 1, "percentage_free")) {
+ outwalk += sprintf(outwalk, "%.01f%s", 100.0 * ram_free / ram_total, pct_mark);
+ walk += strlen("percentage_free");
+ }
+
+ if (BEGINS_WITH(walk + 1, "percentage_available")) {
+ outwalk += sprintf(outwalk, "%.01f%s", 100.0 * ram_available / ram_total, pct_mark);
+ walk += strlen("percentage_available");
+ }
+
+ if (BEGINS_WITH(walk + 1, "percentage_used")) {
+ outwalk += sprintf(outwalk, "%.01f%s", 100.0 * ram_used / ram_total, pct_mark);
+ walk += strlen("percentage_used");
+ }
+
+ if (BEGINS_WITH(walk + 1, "percentage_shared")) {
+ outwalk += sprintf(outwalk, "%.01f%s", 100.0 * ram_shared / ram_total, pct_mark);
+ walk += strlen("percentage_shared");
+ }
+ }
+
+ if (output_color)
+ END_COLOR;
+
+ *outwalk = '\0';
+ OUTPUT_FULL_TEXT(buffer);
+
+ return;
+error:
+ OUTPUT_FULL_TEXT("can't read memory");
+ fputs("i3status: Cannot read system memory using /proc/meminfo\n", stderr);
+#else
+ OUTPUT_FULL_TEXT("");
+ fputs("i3status: Memory status information is not supported on this system\n", stderr);
+#endif
+}