]> git.sur5r.net Git - i3/i3status/blob - src/print_mem.c
Rename ram variables consistently
[i3/i3status] / src / print_mem.c
1 // vim:ts=4:sw=4:expandtab
2 #include <ctype.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <yajl/yajl_gen.h>
6 #include <yajl/yajl_version.h>
7 #include "i3status.h"
8
9 #define BINARY_BASE UINT64_C(1024)
10
11 #define MAX_EXPONENT 4
12 static const char *const iec_symbols[MAX_EXPONENT + 1] = {"", "Ki", "Mi", "Gi", "Ti"};
13
14 static const char memoryfile_linux[] = "/proc/meminfo";
15
16 /*
17  * Prints the given amount of bytes in a human readable manner.
18  *
19  */
20 static int print_bytes_human(char *outwalk, uint64_t bytes) {
21     double size = bytes;
22     int exponent = 0;
23     int bin_base = BINARY_BASE;
24     while (size >= bin_base && exponent < MAX_EXPONENT) {
25         size /= bin_base;
26         exponent += 1;
27     }
28     return sprintf(outwalk, "%.1f %sB", size, iec_symbols[exponent]);
29 }
30
31 /*
32  * Determines whether remaining bytes are below given threshold.
33  *
34  */
35 static bool below_threshold(const long ram_total, const long ram_used, const char *threshold_type, const long low_threshold) {
36     // empty is available or free, based on "use_available_memory"
37     long empty = ram_total - ram_used;
38     if (BEGINS_WITH(threshold_type, "percentage_")) {
39         return 100.0 * empty / ram_total < low_threshold;
40     } else if (strcasecmp(threshold_type, "bytes_free") == 0) {
41         return empty < low_threshold;
42     } else if (threshold_type[0] != '\0' && strncasecmp(threshold_type + 1, "bytes_", strlen("bytes_")) == 0) {
43
44         long factor = 1;
45
46         switch (threshold_type[0]) {
47             case 'T':
48             case 't':
49                 factor *= BINARY_BASE;
50             case 'G':
51             case 'g':
52                 factor *= BINARY_BASE;
53             case 'M':
54             case 'm':
55                 factor *= BINARY_BASE;
56             case 'K':
57             case 'k':
58                 factor *= BINARY_BASE;
59                 break;
60             default:
61                 return false;
62         }
63         return empty < low_threshold * factor;
64     }
65     return false;
66 }
67
68 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) {
69     char *outwalk = buffer;
70
71 #if defined(linux)
72     const char *selected_format = format;
73     const char *walk;
74     bool colorful_output = false;
75
76     long ram_total = -1;
77     long ram_free = -1;
78     long ram_available = -1;
79     long ram_used = -1;
80     long ram_shared = -1;
81     long ram_cached = -1;
82     long ram_buffers = -1;
83
84     FILE *file = fopen(memoryfile_linux, "r");
85     if (!file) {
86         goto error;
87     }
88     char line[128];
89     while (fgets(line, sizeof line, file)) {
90         if (BEGINS_WITH(line, "MemTotal:")) {
91             ram_total = strtol(line + strlen("MemTotal:"), NULL, 10);
92         }
93         if (BEGINS_WITH(line, "MemFree:")) {
94             ram_free = strtol(line + strlen("MemFree:"), NULL, 10);
95         }
96         if (BEGINS_WITH(line, "MemAvailable:")) {
97             ram_available = strtol(line + strlen("MemAvailable:"), NULL, 10);
98         }
99         if (BEGINS_WITH(line, "Buffers:")) {
100             ram_buffers = strtol(line + strlen("Buffers:"), NULL, 10);
101         }
102         if (BEGINS_WITH(line, "Cached:")) {
103             ram_cached = strtol(line + strlen("Cached:"), NULL, 10);
104         }
105         if (BEGINS_WITH(line, "Shmem:")) {
106             ram_shared = strtol(line + strlen("Shmem:"), NULL, 10);
107         }
108         if (ram_total != -1 && ram_free != -1 && ram_available != -1 && ram_buffers != -1 && ram_cached != -1 && ram_shared != -1) {
109             break;
110         }
111     }
112     fclose(file);
113
114     if (ram_total == -1 || ram_free == -1 || ram_available == -1 || ram_buffers == -1 || ram_cached == -1 || ram_shared == -1) {
115         goto error;
116     }
117
118     ram_total = ram_total * BINARY_BASE;
119     ram_free = ram_free * BINARY_BASE;
120     ram_available = ram_available * BINARY_BASE;
121     ram_buffers = ram_buffers * BINARY_BASE;
122     ram_cached = ram_cached * BINARY_BASE;
123     ram_shared = ram_shared * BINARY_BASE;
124     if (use_available_memory) {
125         ram_used = ram_total - ram_available;
126     } else {
127         ram_used = ram_total - ram_free - ram_buffers - ram_cached;
128     }
129
130     if (degraded_low_threshold > 0 && below_threshold(ram_total, ram_used, degraded_threshold_type, degraded_low_threshold)) {
131         if (critical_low_threshold > 0 && below_threshold(ram_total, ram_used, critical_threshold_type, critical_low_threshold)) {
132             START_COLOR("color_bad");
133             colorful_output = true;
134             if (critical_format_below_threshold != NULL)
135                 selected_format = critical_format_below_threshold;
136         } else {
137             START_COLOR("color_degraded");
138             colorful_output = true;
139             if (degraded_format_below_threshold != NULL)
140                 selected_format = degraded_format_below_threshold;
141         }
142     }
143
144     for (walk = selected_format; *walk != '\0'; walk++) {
145         if (*walk != '%') {
146             *(outwalk++) = *walk;
147             continue;
148         }
149         if (BEGINS_WITH(walk + 1, "total")) {
150             outwalk += print_bytes_human(outwalk, ram_total);
151             walk += strlen("total");
152         }
153
154         if (BEGINS_WITH(walk + 1, "used")) {
155             outwalk += print_bytes_human(outwalk, ram_used);
156             walk += strlen("used");
157         }
158
159         if (BEGINS_WITH(walk + 1, "free")) {
160             outwalk += print_bytes_human(outwalk, ram_free);
161             walk += strlen("free");
162         }
163
164         if (BEGINS_WITH(walk + 1, "available")) {
165             outwalk += print_bytes_human(outwalk, ram_available);
166             walk += strlen("available");
167         }
168
169         if (BEGINS_WITH(walk + 1, "shared")) {
170             outwalk += print_bytes_human(outwalk, ram_shared);
171             walk += strlen("shared");
172         }
173
174         if (BEGINS_WITH(walk + 1, "percentage_free")) {
175             outwalk += sprintf(outwalk, "%.01f%s", 100.0 * ram_free / ram_total, pct_mark);
176             walk += strlen("percentage_free");
177         }
178
179         if (BEGINS_WITH(walk + 1, "percentage_available")) {
180             outwalk += sprintf(outwalk, "%.01f%s", 100.0 * ram_available / ram_total, pct_mark);
181             walk += strlen("percentage_available");
182         }
183
184         if (BEGINS_WITH(walk + 1, "percentage_used")) {
185             outwalk += sprintf(outwalk, "%.01f%s", 100.0 * ram_used / ram_total, pct_mark);
186             walk += strlen("percentage_used");
187         }
188
189         if (BEGINS_WITH(walk + 1, "percentage_shared")) {
190             outwalk += sprintf(outwalk, "%.01f%s", 100.0 * ram_shared / ram_total, pct_mark);
191             walk += strlen("percentage_shared");
192         }
193     }
194
195     if (colorful_output)
196         END_COLOR;
197
198     *outwalk = '\0';
199     OUTPUT_FULL_TEXT(buffer);
200
201     return;
202 error:
203     OUTPUT_FULL_TEXT("can't read memory");
204     fputs("i3status: Cannot read system memory using /proc/meminfo\n", stderr);
205 #else
206     OUTPUT_FULL_TEXT("");
207     fputs("i3status: Memory status information is not supported on this system\n", stderr);
208 #endif
209 }