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 filename[] = "/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 * Determines whether remaining bytes are below given threshold.
35 static bool below_threshold(const long totalRam, const long usedRam, const char *threshold_type, const long low_threshold) {
36 // empty is available or free, based on "use_available_memory"
37 long empty = totalRam - usedRam;
38 if (BEGINS_WITH(threshold_type, "percentage_")) {
39 return 100.0 * empty / totalRam < 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 uint64_t base = BINARY_BASE;
46 switch (threshold_type[0]) {
63 return empty < low_threshold * factor;
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;
72 const char *selected_format = format;
74 bool colorful_output = false;
78 long availableRam = -1;
84 FILE *file = fopen(filename, "r");
89 while (fgets(line, sizeof line, file)) {
90 if (BEGINS_WITH(line, "MemTotal:")) {
91 totalRam = strtol(line + strlen("MemTotal:"), NULL, 10);
93 if (BEGINS_WITH(line, "MemFree:")) {
94 freeRam = strtol(line + strlen("MemFree:"), NULL, 10);
96 if (BEGINS_WITH(line, "MemAvailable:")) {
97 availableRam = strtol(line + strlen("MemAvailable:"), NULL, 10);
99 if (BEGINS_WITH(line, "Buffers:")) {
100 buffers = strtol(line + strlen("Buffers:"), NULL, 10);
102 if (BEGINS_WITH(line, "Cached:")) {
103 cached = strtol(line + strlen("Cached:"), NULL, 10);
105 if (BEGINS_WITH(line, "Shmem:")) {
106 sharedRam = strtol(line + strlen("Shmem:"), NULL, 10);
108 if (totalRam != -1 && freeRam != -1 && availableRam != -1 && buffers != -1 && cached != -1 && sharedRam != -1) {
114 if (totalRam == -1 || freeRam == -1 || availableRam == -1 || buffers == -1 || cached == -1 || sharedRam == -1) {
118 totalRam = totalRam * BINARY_BASE;
119 freeRam = freeRam * BINARY_BASE;
120 availableRam = availableRam * BINARY_BASE;
121 buffers = buffers * BINARY_BASE;
122 cached = cached * BINARY_BASE;
123 sharedRam = sharedRam * BINARY_BASE;
124 if (use_available_memory) {
125 usedRam = totalRam - availableRam;
127 usedRam = totalRam - freeRam - buffers - cached;
130 if (degraded_low_threshold > 0 && below_threshold(totalRam, usedRam, degraded_threshold_type, degraded_low_threshold)) {
131 if (critical_low_threshold > 0 && below_threshold(totalRam, usedRam, 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;
137 START_COLOR("color_degraded");
138 colorful_output = true;
139 if (degraded_format_below_threshold != NULL)
140 selected_format = degraded_format_below_threshold;
144 for (walk = selected_format; *walk != '\0'; walk++) {
146 *(outwalk++) = *walk;
149 if (BEGINS_WITH(walk + 1, "total")) {
150 outwalk += print_bytes_human(outwalk, totalRam);
151 walk += strlen("total");
154 if (BEGINS_WITH(walk + 1, "used")) {
155 outwalk += print_bytes_human(outwalk, usedRam);
156 walk += strlen("used");
159 if (BEGINS_WITH(walk + 1, "free")) {
160 outwalk += print_bytes_human(outwalk, freeRam);
161 walk += strlen("free");
164 if (BEGINS_WITH(walk + 1, "available")) {
165 outwalk += print_bytes_human(outwalk, availableRam);
166 walk += strlen("available");
169 if (BEGINS_WITH(walk + 1, "shared")) {
170 outwalk += print_bytes_human(outwalk, sharedRam);
171 walk += strlen("shared");
174 if (BEGINS_WITH(walk + 1, "percentage_free")) {
175 outwalk += sprintf(outwalk, "%.01f%s", 100.0 * freeRam / totalRam, pct_mark);
176 walk += strlen("percentage_free");
179 if (BEGINS_WITH(walk + 1, "percentage_available")) {
180 outwalk += sprintf(outwalk, "%.01f%s", 100.0 * availableRam / totalRam, pct_mark);
181 walk += strlen("percentage_available");
184 if (BEGINS_WITH(walk + 1, "percentage_used")) {
185 outwalk += sprintf(outwalk, "%.01f%s", 100.0 * usedRam / totalRam, pct_mark);
186 walk += strlen("percentage_used");
189 if (BEGINS_WITH(walk + 1, "percentage_shared")) {
190 outwalk += sprintf(outwalk, "%.01f%s", 100.0 * sharedRam / totalRam, pct_mark);
191 walk += strlen("percentage_shared");
199 OUTPUT_FULL_TEXT(buffer);
203 OUTPUT_FULL_TEXT("can't read memory");
204 fputs("i3status: Cannot read system memory using /proc/meminfo\n", stderr);
206 fputs("i3status: Memory status information is not supported on this system\n", stderr);