1 // vim:ts=4:sw=4:expandtab
5 #include <yajl/yajl_gen.h>
6 #include <yajl/yajl_version.h>
9 #define BINARY_BASE UINT64_C(1024)
11 #define MAX_EXPONENT 4
12 static const char *const iec_symbols[MAX_EXPONENT + 1] = {"", "Ki", "Mi", "Gi", "Ti"};
14 static const char memoryfile_linux[] = "/proc/meminfo";
17 * Prints the given amount of bytes in a human readable manner.
20 static int print_bytes_human(char *outwalk, uint64_t bytes) {
23 int bin_base = BINARY_BASE;
24 while (size >= bin_base && exponent < MAX_EXPONENT) {
28 return sprintf(outwalk, "%.1f %sB", size, iec_symbols[exponent]);
32 * Convert a string to its absolute representation based on the total
33 * memory of `mem_total`.
35 * The string can contain any percentage values, which then return a
36 * the value of `size` in relation to `mem_total`.
37 * Alternatively an absolute value can be given, suffixed with an iec
41 static long memory_absolute(const long mem_total, const char *size) {
44 long mem_absolute = strtol(size, &endptr, 10);
47 while (endptr[0] != '\0' && isspace(endptr[0]))
53 mem_absolute *= BINARY_BASE;
56 mem_absolute *= BINARY_BASE;
59 mem_absolute *= BINARY_BASE;
62 mem_absolute *= BINARY_BASE;
65 mem_absolute = mem_total * mem_absolute / 100;
75 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) {
76 char *outwalk = buffer;
79 const char *selected_format = format;
81 const char *output_color = NULL;
85 long ram_available = -1;
89 long ram_buffers = -1;
91 FILE *file = fopen(memoryfile_linux, "r");
96 while (fgets(line, sizeof line, file)) {
97 if (BEGINS_WITH(line, "MemTotal:")) {
98 ram_total = strtol(line + strlen("MemTotal:"), NULL, 10);
100 if (BEGINS_WITH(line, "MemFree:")) {
101 ram_free = strtol(line + strlen("MemFree:"), NULL, 10);
103 if (BEGINS_WITH(line, "MemAvailable:")) {
104 ram_available = strtol(line + strlen("MemAvailable:"), NULL, 10);
106 if (BEGINS_WITH(line, "Buffers:")) {
107 ram_buffers = strtol(line + strlen("Buffers:"), NULL, 10);
109 if (BEGINS_WITH(line, "Cached:")) {
110 ram_cached = strtol(line + strlen("Cached:"), NULL, 10);
112 if (BEGINS_WITH(line, "Shmem:")) {
113 ram_shared = strtol(line + strlen("Shmem:"), NULL, 10);
115 if (ram_total != -1 && ram_free != -1 && ram_available != -1 && ram_buffers != -1 && ram_cached != -1 && ram_shared != -1) {
121 if (ram_total == -1 || ram_free == -1 || ram_available == -1 || ram_buffers == -1 || ram_cached == -1 || ram_shared == -1) {
125 ram_total = ram_total * BINARY_BASE;
126 ram_free = ram_free * BINARY_BASE;
127 ram_available = ram_available * BINARY_BASE;
128 ram_buffers = ram_buffers * BINARY_BASE;
129 ram_cached = ram_cached * BINARY_BASE;
130 ram_shared = ram_shared * BINARY_BASE;
132 if (BEGINS_WITH(memory_used_method, "memavailable")) {
133 ram_used = ram_total - ram_available;
134 } else if (BEGINS_WITH(memory_used_method, "classical")) {
135 ram_used = ram_total - ram_free - ram_buffers - ram_cached;
138 if (threshold_degraded) {
139 long abs = memory_absolute(ram_total, threshold_degraded);
140 if (ram_available < abs) {
141 output_color = "color_degraded";
145 if (threshold_critical) {
146 long abs = memory_absolute(ram_total, threshold_critical);
147 if (ram_available < abs) {
148 output_color = "color_bad";
153 START_COLOR(output_color);
156 selected_format = format_degraded;
159 for (walk = selected_format; *walk != '\0'; walk++) {
161 *(outwalk++) = *walk;
163 } else if (BEGINS_WITH(walk + 1, "total")) {
164 outwalk += print_bytes_human(outwalk, ram_total);
165 walk += strlen("total");
167 } else if (BEGINS_WITH(walk + 1, "used")) {
168 outwalk += print_bytes_human(outwalk, ram_used);
169 walk += strlen("used");
171 } else if (BEGINS_WITH(walk + 1, "free")) {
172 outwalk += print_bytes_human(outwalk, ram_free);
173 walk += strlen("free");
175 } else if (BEGINS_WITH(walk + 1, "available")) {
176 outwalk += print_bytes_human(outwalk, ram_available);
177 walk += strlen("available");
179 } else if (BEGINS_WITH(walk + 1, "shared")) {
180 outwalk += print_bytes_human(outwalk, ram_shared);
181 walk += strlen("shared");
183 } else if (BEGINS_WITH(walk + 1, "percentage_free")) {
184 outwalk += sprintf(outwalk, "%.01f%s", 100.0 * ram_free / ram_total, pct_mark);
185 walk += strlen("percentage_free");
187 } else if (BEGINS_WITH(walk + 1, "percentage_available")) {
188 outwalk += sprintf(outwalk, "%.01f%s", 100.0 * ram_available / ram_total, pct_mark);
189 walk += strlen("percentage_available");
191 } else if (BEGINS_WITH(walk + 1, "percentage_used")) {
192 outwalk += sprintf(outwalk, "%.01f%s", 100.0 * ram_used / ram_total, pct_mark);
193 walk += strlen("percentage_used");
195 } else if (BEGINS_WITH(walk + 1, "percentage_shared")) {
196 outwalk += sprintf(outwalk, "%.01f%s", 100.0 * ram_shared / ram_total, pct_mark);
197 walk += strlen("percentage_shared");
208 OUTPUT_FULL_TEXT(buffer);
212 OUTPUT_FULL_TEXT("can't read memory");
213 fputs("i3status: Cannot read system memory using /proc/meminfo\n", stderr);
215 OUTPUT_FULL_TEXT("");
216 fputs("i3status: Memory status information is not supported on this system\n", stderr);