Merge pull request #373 from zsugabubus/fix-memory

print_mem: Fix overflow on 32-bit systems
This commit is contained in:
Ingo Bürk 2019-11-25 06:16:16 +01:00 committed by GitHub
commit eccd4a7618
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -7,14 +7,11 @@
#include <yajl/yajl_version.h> #include <yajl/yajl_version.h>
#include "i3status.h" #include "i3status.h"
#define BINARY_BASE UINT64_C(1024) #define BINARY_BASE 1024UL
#define MAX_EXPONENT 4
#if defined(linux) #if defined(linux)
static const char *const iec_symbols[MAX_EXPONENT + 1] = {"", "Ki", "Mi", "Gi", "Ti"}; static const char *const iec_symbols[] = {"B", "KiB", "MiB", "GiB", "TiB"};
#define MAX_EXPONENT ((sizeof iec_symbols / sizeof *iec_symbols) - 1)
static const char memoryfile_linux[] = "/proc/meminfo";
#endif #endif
#if defined(linux) #if defined(linux)
@ -22,19 +19,18 @@ static const char memoryfile_linux[] = "/proc/meminfo";
* Prints the given amount of bytes in a human readable manner. * Prints the given amount of bytes in a human readable manner.
* *
*/ */
static int print_bytes_human(char *outwalk, uint64_t bytes, const char *unit, const int decimals) { static int print_bytes_human(char *outwalk, unsigned long bytes, const char *unit, const int decimals) {
double size = bytes; double base = bytes;
int exponent = 0; int exponent = 0;
int bin_base = BINARY_BASE; while (base >= BINARY_BASE && exponent < MAX_EXPONENT) {
while (size >= bin_base && exponent < MAX_EXPONENT) {
if (strcasecmp(unit, iec_symbols[exponent]) == 0) { if (strcasecmp(unit, iec_symbols[exponent]) == 0) {
break; break;
} }
size /= bin_base; base /= BINARY_BASE;
exponent += 1; exponent += 1;
} }
return sprintf(outwalk, "%.*f %sB", decimals, size, iec_symbols[exponent]); return sprintf(outwalk, "%.*f %s", decimals, base, iec_symbols[exponent]);
} }
#endif #endif
@ -44,43 +40,38 @@ static int print_bytes_human(char *outwalk, uint64_t bytes, const char *unit, co
* memory of `mem_total`. * memory of `mem_total`.
* *
* The string can contain any percentage values, which then return a * The string can contain any percentage values, which then return a
* the value of `size` in relation to `mem_total`. * the value of `mem_amount` in relation to `mem_total`.
* Alternatively an absolute value can be given, suffixed with an iec * Alternatively an absolute value can be given, suffixed with an iec
* symbol. * symbol.
* *
*/ */
static long memory_absolute(const long mem_total, const char *size) { static unsigned long memory_absolute(const char *mem_amount, const unsigned long mem_total) {
char *endptr = NULL; char *endptr;
unsigned long amount = strtoul(mem_amount, &endptr, 10);
long mem_absolute = strtol(size, &endptr, 10); while (endptr[0] != '\0' && isspace(endptr[0]))
endptr++;
if (endptr) { switch (endptr[0]) {
while (endptr[0] != '\0' && isspace(endptr[0])) case 'T':
endptr++; case 't':
amount *= BINARY_BASE;
switch (endptr[0]) { case 'G':
case 'T': case 'g':
case 't': amount *= BINARY_BASE;
mem_absolute *= BINARY_BASE; case 'M':
case 'G': case 'm':
case 'g': amount *= BINARY_BASE;
mem_absolute *= BINARY_BASE; case 'K':
case 'M': case 'k':
case 'm': amount *= BINARY_BASE;
mem_absolute *= BINARY_BASE; break;
case 'K': case '%':
case 'k': amount = mem_total * amount / 100;
mem_absolute *= BINARY_BASE; break;
break;
case '%':
mem_absolute = mem_total * mem_absolute / 100;
break;
default:
break;
}
} }
return mem_absolute; return amount;
} }
#endif #endif
@ -92,55 +83,53 @@ void print_memory(yajl_gen json_gen, char *buffer, const char *format, const cha
const char *walk; const char *walk;
const char *output_color = NULL; const char *output_color = NULL;
long ram_total = -1; int unread_fields = 6;
long ram_free = -1; unsigned long ram_total;
long ram_available = -1; unsigned long ram_free;
long ram_used = -1; unsigned long ram_available;
long ram_shared = -1; unsigned long ram_buffers;
long ram_cached = -1; unsigned long ram_cached;
long ram_buffers = -1; unsigned long ram_shared;
FILE *file = fopen(memoryfile_linux, "r"); FILE *file = fopen("/proc/meminfo", "r");
if (!file) { if (!file) {
goto error; goto error;
} }
char line[128]; for (char line[128]; fgets(line, sizeof line, file);) {
while (fgets(line, sizeof line, file)) {
if (BEGINS_WITH(line, "MemTotal:")) { if (BEGINS_WITH(line, "MemTotal:")) {
ram_total = strtol(line + strlen("MemTotal:"), NULL, 10); ram_total = strtoul(line + strlen("MemTotal:"), NULL, 10);
} else if (BEGINS_WITH(line, "MemFree:")) {
ram_free = strtoul(line + strlen("MemFree:"), NULL, 10);
} else if (BEGINS_WITH(line, "MemAvailable:")) {
ram_available = strtoul(line + strlen("MemAvailable:"), NULL, 10);
} else if (BEGINS_WITH(line, "Buffers:")) {
ram_buffers = strtoul(line + strlen("Buffers:"), NULL, 10);
} else if (BEGINS_WITH(line, "Cached:")) {
ram_cached = strtoul(line + strlen("Cached:"), NULL, 10);
} else if (BEGINS_WITH(line, "Shmem:")) {
ram_shared = strtoul(line + strlen("Shmem:"), NULL, 10);
} else {
continue;
} }
if (BEGINS_WITH(line, "MemFree:")) { if (--unread_fields == 0) {
ram_free = strtol(line + strlen("MemFree:"), NULL, 10);
}
if (BEGINS_WITH(line, "MemAvailable:")) {
ram_available = strtol(line + strlen("MemAvailable:"), NULL, 10);
}
if (BEGINS_WITH(line, "Buffers:")) {
ram_buffers = strtol(line + strlen("Buffers:"), NULL, 10);
}
if (BEGINS_WITH(line, "Cached:")) {
ram_cached = strtol(line + strlen("Cached:"), NULL, 10);
}
if (BEGINS_WITH(line, "Shmem:")) {
ram_shared = strtol(line + strlen("Shmem:"), NULL, 10);
}
if (ram_total != -1 && ram_free != -1 && ram_available != -1 && ram_buffers != -1 && ram_cached != -1 && ram_shared != -1) {
break; break;
} }
} }
fclose(file); fclose(file);
if (ram_total == -1 || ram_free == -1 || ram_available == -1 || ram_buffers == -1 || ram_cached == -1 || ram_shared == -1) { if (unread_fields > 0) {
goto error; goto error;
} }
ram_total = ram_total * BINARY_BASE; // Values are in kB, convert them to B.
ram_free = ram_free * BINARY_BASE; ram_total *= 1024UL;
ram_available = ram_available * BINARY_BASE; ram_free *= 1024UL;
ram_buffers = ram_buffers * BINARY_BASE; ram_available *= 1024UL;
ram_cached = ram_cached * BINARY_BASE; ram_buffers *= 1024UL;
ram_shared = ram_shared * BINARY_BASE; ram_cached *= 1024UL;
ram_shared *= 1024UL;
unsigned long ram_used;
if (BEGINS_WITH(memory_used_method, "memavailable")) { if (BEGINS_WITH(memory_used_method, "memavailable")) {
ram_used = ram_total - ram_available; ram_used = ram_total - ram_available;
} else if (BEGINS_WITH(memory_used_method, "classical")) { } else if (BEGINS_WITH(memory_used_method, "classical")) {
@ -148,15 +137,15 @@ void print_memory(yajl_gen json_gen, char *buffer, const char *format, const cha
} }
if (threshold_degraded) { if (threshold_degraded) {
long abs = memory_absolute(ram_total, threshold_degraded); const unsigned long threshold = memory_absolute(threshold_degraded, ram_total);
if (ram_available < abs) { if (ram_available < threshold) {
output_color = "color_degraded"; output_color = "color_degraded";
} }
} }
if (threshold_critical) { if (threshold_critical) {
long abs = memory_absolute(ram_total, threshold_critical); const unsigned long threshold = memory_absolute(threshold_critical, ram_total);
if (ram_available < abs) { if (ram_available < threshold) {
output_color = "color_bad"; output_color = "color_bad";
} }
} }