]> git.sur5r.net Git - i3/i3status/blobdiff - src/print_mem.c
fix: use SYSCONFDIR in error message
[i3/i3status] / src / print_mem.c
index c2f48f4ee60ba63f3bbb6b5af3aaf394e9249663..840f997eea99659fc53c9f1509cf4847877980d9 100644 (file)
@@ -1,4 +1,5 @@
 // vim:ts=4:sw=4:expandtab
+#include <config.h>
 #include <ctype.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -11,7 +12,7 @@
 #define MAX_EXPONENT 4
 static const char *const iec_symbols[MAX_EXPONENT + 1] = {"", "Ki", "Mi", "Gi", "Ti"};
 
-static const char filename[] = "/proc/meminfo";
+static const char memoryfile_linux[] = "/proc/meminfo";
 
 /*
  * Prints the given amount of bytes in a human readable manner.
@@ -29,170 +30,179 @@ static int print_bytes_human(char *outwalk, uint64_t bytes) {
 }
 
 /*
- * Determines whether remaining bytes are below given threshold.
+ * 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 bool below_threshold(const long totalRam, const long usedRam, const char *threshold_type, const long low_threshold) {
-    // empty is available or free, based on "use_available_memory"
-    long empty = totalRam - usedRam;
-    if (BEGINS_WITH(threshold_type, "percentage_")) {
-        return 100.0 * empty / totalRam < low_threshold;
-    } else if (strcasecmp(threshold_type, "bytes_free") == 0) {
-        return empty < low_threshold;
-    } else if (threshold_type[0] != '\0' && strncasecmp(threshold_type + 1, "bytes_", strlen("bytes_")) == 0) {
-        uint64_t base = BINARY_BASE;
-        long factor = 1;
-
-        switch (threshold_type[0]) {
+static long memory_absolute(const long mem_total, const char *size) {
+    char *endptr = NULL;
+
+    long mem_absolute = strtol(size, &endptr, 10);
+
+    if (endptr) {
+        while (endptr[0] != '\0' && isspace(endptr[0]))
+            endptr++;
+
+        switch (endptr[0]) {
             case 'T':
             case 't':
-                factor *= base;
+                mem_absolute *= BINARY_BASE;
             case 'G':
             case 'g':
-                factor *= base;
+                mem_absolute *= BINARY_BASE;
             case 'M':
             case 'm':
-                factor *= base;
+                mem_absolute *= BINARY_BASE;
             case 'K':
             case 'k':
-                factor *= base;
+                mem_absolute *= BINARY_BASE;
+                break;
+            case '%':
+                mem_absolute = mem_total * mem_absolute / 100;
                 break;
             default:
-                return false;
+                break;
         }
-        return empty < low_threshold * factor;
     }
-    return false;
+
+    return mem_absolute;
 }
 
-void print_memory(yajl_gen json_gen, char *buffer, const char *format, const char *degraded_format_below_threshold, const char *degraded_threshold_type, const float degraded_low_threshold, const char *critical_format_below_threshold, const char *critical_threshold_type, const float critical_low_threshold, const bool use_available_memory) {
+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;
-    bool colorful_output = false;
+    const char *output_color = NULL;
 
-    long totalRam = -1;
-    long freeRam = -1;
-    long availableRam = -1;
-    long usedRam = -1;
-    long sharedRam = -1;
-    long cached = -1;
-    long buffers = -1;
+    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(filename, "r");
+    FILE *file = fopen(memoryfile_linux, "r");
     if (!file) {
         goto error;
     }
     char line[128];
     while (fgets(line, sizeof line, file)) {
         if (BEGINS_WITH(line, "MemTotal:")) {
-            totalRam = strtol(line + strlen("MemTotal:"), NULL, 10);
+            ram_total = strtol(line + strlen("MemTotal:"), NULL, 10);
         }
         if (BEGINS_WITH(line, "MemFree:")) {
-            freeRam = strtol(line + strlen("MemFree:"), NULL, 10);
+            ram_free = strtol(line + strlen("MemFree:"), NULL, 10);
         }
         if (BEGINS_WITH(line, "MemAvailable:")) {
-            availableRam = strtol(line + strlen("MemAvailable:"), NULL, 10);
+            ram_available = strtol(line + strlen("MemAvailable:"), NULL, 10);
         }
         if (BEGINS_WITH(line, "Buffers:")) {
-            buffers = strtol(line + strlen("Buffers:"), NULL, 10);
+            ram_buffers = strtol(line + strlen("Buffers:"), NULL, 10);
         }
         if (BEGINS_WITH(line, "Cached:")) {
-            cached = strtol(line + strlen("Cached:"), NULL, 10);
+            ram_cached = strtol(line + strlen("Cached:"), NULL, 10);
         }
         if (BEGINS_WITH(line, "Shmem:")) {
-            sharedRam = strtol(line + strlen("Shmem:"), NULL, 10);
+            ram_shared = strtol(line + strlen("Shmem:"), NULL, 10);
         }
-        if (totalRam != -1 && freeRam != -1 && availableRam != -1 && buffers != -1 && cached != -1 && sharedRam != -1) {
+        if (ram_total != -1 && ram_free != -1 && ram_available != -1 && ram_buffers != -1 && ram_cached != -1 && ram_shared != -1) {
             break;
         }
     }
     fclose(file);
 
-    if (totalRam == -1 || freeRam == -1 || availableRam == -1 || buffers == -1 || cached == -1 || sharedRam == -1) {
+    if (ram_total == -1 || ram_free == -1 || ram_available == -1 || ram_buffers == -1 || ram_cached == -1 || ram_shared == -1) {
         goto error;
     }
 
-    totalRam = totalRam * BINARY_BASE;
-    freeRam = freeRam * BINARY_BASE;
-    availableRam = availableRam * BINARY_BASE;
-    buffers = buffers * BINARY_BASE;
-    cached = cached * BINARY_BASE;
-    sharedRam = sharedRam * BINARY_BASE;
-    if (use_available_memory) {
-        usedRam = totalRam - availableRam;
-    } else {
-        usedRam = totalRam - freeRam - buffers - cached;
+    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 (degraded_low_threshold > 0 && below_threshold(totalRam, usedRam, degraded_threshold_type, degraded_low_threshold)) {
-        if (critical_low_threshold > 0 && below_threshold(totalRam, usedRam, critical_threshold_type, critical_low_threshold)) {
-            START_COLOR("color_bad");
-            colorful_output = true;
-            if (critical_format_below_threshold != NULL)
-                selected_format = critical_format_below_threshold;
-        } else {
-            START_COLOR("color_degraded");
-            colorful_output = true;
-            if (degraded_format_below_threshold != NULL)
-                selected_format = degraded_format_below_threshold;
+    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, totalRam);
+
+        } else 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, usedRam);
+        } else 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, freeRam);
+        } else 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, availableRam);
+        } else 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, sharedRam);
+        } else 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 * freeRam / totalRam, pct_mark);
+        } else 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 * availableRam / totalRam, pct_mark);
+        } else 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 * usedRam / totalRam, pct_mark);
+        } else 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 * sharedRam / totalRam, pct_mark);
+        } else if (BEGINS_WITH(walk + 1, "percentage_shared")) {
+            outwalk += sprintf(outwalk, "%.01f%s", 100.0 * ram_shared / ram_total, pct_mark);
             walk += strlen("percentage_shared");
+
+        } else {
+            *(outwalk++) = '%';
         }
     }
 
-    if (colorful_output)
+    if (output_color)
         END_COLOR;
 
     *outwalk = '\0';
@@ -203,6 +213,7 @@ 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
 }