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