]> git.sur5r.net Git - i3/i3status/blob - src/print_mem.c
able to print percentage
[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  * Convert a string to its absolute representation based on the total
33  * memory of `mem_total`.
34  *
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
38  * symbol.
39  *
40  */
41 static long memory_absolute(const long mem_total, const char *size) {
42     char *endptr = NULL;
43
44     long mem_absolute = strtol(size, &endptr, 10);
45
46     if (endptr) {
47         while (endptr[0] != '\0' && isspace(endptr[0]))
48             endptr++;
49
50         switch (endptr[0]) {
51             case 'T':
52             case 't':
53                 mem_absolute *= BINARY_BASE;
54             case 'G':
55             case 'g':
56                 mem_absolute *= BINARY_BASE;
57             case 'M':
58             case 'm':
59                 mem_absolute *= BINARY_BASE;
60             case 'K':
61             case 'k':
62                 mem_absolute *= BINARY_BASE;
63                 break;
64             case '%':
65                 mem_absolute = mem_total * mem_absolute / 100;
66                 break;
67             default:
68                 break;
69         }
70     }
71
72     return mem_absolute;
73 }
74
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;
77
78 #if defined(linux)
79     const char *selected_format = format;
80     const char *walk;
81     const char *output_color = NULL;
82
83     long ram_total = -1;
84     long ram_free = -1;
85     long ram_available = -1;
86     long ram_used = -1;
87     long ram_shared = -1;
88     long ram_cached = -1;
89     long ram_buffers = -1;
90
91     FILE *file = fopen(memoryfile_linux, "r");
92     if (!file) {
93         goto error;
94     }
95     char line[128];
96     while (fgets(line, sizeof line, file)) {
97         if (BEGINS_WITH(line, "MemTotal:")) {
98             ram_total = strtol(line + strlen("MemTotal:"), NULL, 10);
99         }
100         if (BEGINS_WITH(line, "MemFree:")) {
101             ram_free = strtol(line + strlen("MemFree:"), NULL, 10);
102         }
103         if (BEGINS_WITH(line, "MemAvailable:")) {
104             ram_available = strtol(line + strlen("MemAvailable:"), NULL, 10);
105         }
106         if (BEGINS_WITH(line, "Buffers:")) {
107             ram_buffers = strtol(line + strlen("Buffers:"), NULL, 10);
108         }
109         if (BEGINS_WITH(line, "Cached:")) {
110             ram_cached = strtol(line + strlen("Cached:"), NULL, 10);
111         }
112         if (BEGINS_WITH(line, "Shmem:")) {
113             ram_shared = strtol(line + strlen("Shmem:"), NULL, 10);
114         }
115         if (ram_total != -1 && ram_free != -1 && ram_available != -1 && ram_buffers != -1 && ram_cached != -1 && ram_shared != -1) {
116             break;
117         }
118     }
119     fclose(file);
120
121     if (ram_total == -1 || ram_free == -1 || ram_available == -1 || ram_buffers == -1 || ram_cached == -1 || ram_shared == -1) {
122         goto error;
123     }
124
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;
131
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;
136     }
137
138     if (threshold_degraded) {
139         long abs = memory_absolute(ram_total, threshold_degraded);
140         if (ram_available < abs) {
141             output_color = "color_degraded";
142         }
143     }
144
145     if (threshold_critical) {
146         long abs = memory_absolute(ram_total, threshold_critical);
147         if (ram_available < abs) {
148             output_color = "color_bad";
149         }
150     }
151
152     if (output_color) {
153         START_COLOR(output_color);
154
155         if (format_degraded)
156             selected_format = format_degraded;
157     }
158
159     for (walk = selected_format; *walk != '\0'; walk++) {
160         if (*walk != '%') {
161             *(outwalk++) = *walk;
162
163         } else if (BEGINS_WITH(walk + 1, "total")) {
164             outwalk += print_bytes_human(outwalk, ram_total);
165             walk += strlen("total");
166
167         } else if (BEGINS_WITH(walk + 1, "used")) {
168             outwalk += print_bytes_human(outwalk, ram_used);
169             walk += strlen("used");
170
171         } else if (BEGINS_WITH(walk + 1, "free")) {
172             outwalk += print_bytes_human(outwalk, ram_free);
173             walk += strlen("free");
174
175         } else if (BEGINS_WITH(walk + 1, "available")) {
176             outwalk += print_bytes_human(outwalk, ram_available);
177             walk += strlen("available");
178
179         } else if (BEGINS_WITH(walk + 1, "shared")) {
180             outwalk += print_bytes_human(outwalk, ram_shared);
181             walk += strlen("shared");
182
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");
186
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");
190
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");
194
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");
198
199         } else {
200             *(outwalk++) = '%';
201         }
202     }
203
204     if (output_color)
205         END_COLOR;
206
207     *outwalk = '\0';
208     OUTPUT_FULL_TEXT(buffer);
209
210     return;
211 error:
212     OUTPUT_FULL_TEXT("can't read memory");
213     fputs("i3status: Cannot read system memory using /proc/meminfo\n", stderr);
214 #else
215     OUTPUT_FULL_TEXT("");
216     fputs("i3status: Memory status information is not supported on this system\n", stderr);
217 #endif
218 }