diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/first_network_device.c | 43 | ||||
-rw-r--r-- | src/general.c | 4 | ||||
-rw-r--r-- | src/print_battery_info.c | 15 | ||||
-rw-r--r-- | src/print_cpu_temperature.c | 8 | ||||
-rw-r--r-- | src/print_disk_info.c | 2 | ||||
-rw-r--r-- | src/print_eth_info.c | 1 | ||||
-rw-r--r-- | src/print_ip_addr.c | 53 | ||||
-rw-r--r-- | src/print_mem.c | 224 | ||||
-rw-r--r-- | src/print_volume.c | 13 | ||||
-rw-r--r-- | src/print_wireless_info.c | 5 | ||||
-rw-r--r-- | src/process_runs.c | 2 |
11 files changed, 318 insertions, 52 deletions
diff --git a/src/first_network_device.c b/src/first_network_device.c index 3f34cf2..b930f53 100644 --- a/src/first_network_device.c +++ b/src/first_network_device.c @@ -14,10 +14,10 @@ #include "i3status.h" -#ifdef __linux__ -#define LOOPBACK_DEV "lo" -#else +#ifdef __OpenBSD__ #define LOOPBACK_DEV "lo0" +#else +#define LOOPBACK_DEV "lo" #endif static bool sysfs_devtype(char *dest, size_t n, const char *ifnam) { @@ -67,24 +67,7 @@ static bool is_virtual(const char *ifname) { } static net_type_t iface_type(const char *ifname) { -#ifdef __linux__ - char devtype[32]; - - if (!sysfs_devtype(devtype, sizeof(devtype), ifname)) - return NET_TYPE_OTHER; - - /* Default to Ethernet when no devtype is available */ - if (!devtype[0]) - return NET_TYPE_ETHERNET; - - if (strcmp(devtype, "wlan") == 0) - return NET_TYPE_WIRELESS; - - if (strcmp(devtype, "wwan") == 0) - return NET_TYPE_OTHER; - - return NET_TYPE_OTHER; -#elif __OpenBSD__ +#ifdef __OpenBSD__ /* *First determine if the device is a wireless device by trying two ioctl(2) * commands against it. If either succeeds we can be sure it's a wireless @@ -127,8 +110,24 @@ static net_type_t iface_type(const char *ifname) { return NET_TYPE_ETHERNET; } #else -#error Missing implementation to determine interface type. + char devtype[32]; + + if (!sysfs_devtype(devtype, sizeof(devtype), ifname)) + return NET_TYPE_OTHER; + + /* Default to Ethernet when no devtype is available */ + if (!devtype[0]) + return NET_TYPE_ETHERNET; + + if (strcmp(devtype, "wlan") == 0) + return NET_TYPE_WIRELESS; + + if (strcmp(devtype, "wwan") == 0) + return NET_TYPE_OTHER; + + return NET_TYPE_OTHER; #endif + return NET_TYPE_OTHER; } const char *first_eth_interface(const net_type_t type) { diff --git a/src/general.c b/src/general.c index f299a2b..2424cc6 100644 --- a/src/general.c +++ b/src/general.c @@ -51,12 +51,10 @@ char *skip_character(char *input, char character, int amount) { * */ void die(const char *fmt, ...) { - char buffer[512]; va_list ap; va_start(ap, fmt); - (void)vsnprintf(buffer, sizeof(buffer), fmt, ap); + (void)vfprintf(stderr, fmt, ap); va_end(ap); - fprintf(stderr, "%s", buffer); exit(EXIT_FAILURE); } diff --git a/src/print_battery_info.c b/src/print_battery_info.c index fa70714..db4d7bd 100644 --- a/src/print_battery_info.c +++ b/src/print_battery_info.c @@ -497,14 +497,17 @@ static bool slurp_all_batteries(struct battery_info *batt_info, yajl_gen json_ge .present_rate = 0, .status = CS_UNKNOWN, }; - if (!slurp_battery_info(&batt_buf, json_gen, buffer, i, globbuf.gl_pathv[i], format_down)) + if (!slurp_battery_info(&batt_buf, json_gen, buffer, i, globbuf.gl_pathv[i], format_down)) { + globfree(&globbuf); + free(globpath); return false; + } is_found = true; add_battery_info(batt_info, &batt_buf); } + globfree(&globbuf); } - globfree(&globbuf); free(globpath); if (!is_found) { @@ -560,13 +563,13 @@ void print_battery_info(yajl_gen json_gen, char *buffer, int number, const char // We prefer the design capacity, but use the last capacity if we don't have it, // or if we are asked to (last_full_capacity == true); but similarly we use // the design capacity if we don't have the last capacity. - // If we don't have either then both full_design and full_last < 0, - // which implies full < 0, which bails out on the following line. + // If we don't have either then both full_design and full_last <= 0, + // which implies full <= 0, which bails out on the following line. int full = batt_info.full_design; - if (full < 0 || (last_full_capacity && batt_info.full_last >= 0)) { + if (full <= 0 || (last_full_capacity && batt_info.full_last > 0)) { full = batt_info.full_last; } - if (full < 0 && batt_info.remaining < 0 && batt_info.percentage_remaining < 0) { + if (full <= 0 && batt_info.remaining < 0 && batt_info.percentage_remaining < 0) { /* We have no physical measurements and no estimates. Nothing * much we can report, then. */ OUTPUT_FULL_TEXT(format_down); diff --git a/src/print_cpu_temperature.c b/src/print_cpu_temperature.c index 56ab62a..feae3ec 100644 --- a/src/print_cpu_temperature.c +++ b/src/print_cpu_temperature.c @@ -112,7 +112,7 @@ static int read_temperature(char *thermal_zone, temperature_t *temperature) { /* 'path' is the node within the full path (defaults to acpitz0). */ if (BEGINS_WITH(sensordev.xname, thermal_zone)) { mib[3] = SENSOR_TEMP; - /* Limit to temo0, but should retrieve from a full path... */ + /* Limit to temp0, but should retrieve from a full path... */ for (numt = 0; numt < 1 /*sensordev.maxnumt[SENSOR_TEMP]*/; numt++) { mib[4] = numt; if (sysctl(mib, 5, &sensor, &slen, NULL, 0) == -1) { @@ -205,7 +205,7 @@ error_netbsd1: /* * Reads the CPU temperature from /sys/class/thermal/thermal_zone%d/temp (or - * the user provided path) and returns the temperature in degree celcius. + * the user provided path) and returns the temperature in degree celsius. * */ void print_cpu_temperature_info(yajl_gen json_gen, char *buffer, int zone, const char *path, const char *format, const char *format_above_threshold, int max_threshold) { @@ -216,12 +216,14 @@ void print_cpu_temperature_info(yajl_gen json_gen, char *buffer, int zone, const bool colorful_output = false; char *thermal_zone; temperature_t temperature; + temperature.raw_value = 0; + sprintf(temperature.formatted_value, "%.2f", 0.0); if (path == NULL) asprintf(&thermal_zone, THERMAL_ZONE, zone); else { static glob_t globbuf; - if (glob(path, GLOB_NOCHECK | GLOB_TILDE, NULL, &globbuf) < 0) + if (glob(path, GLOB_NOCHECK | GLOB_TILDE, NULL, &globbuf) != 0) die("glob() failed\n"); if (globbuf.gl_pathc == 0) { /* No glob matches, the specified path does not contain a wildcard. */ diff --git a/src/print_disk_info.c b/src/print_disk_info.c index fb73480..770e718 100644 --- a/src/print_disk_info.c +++ b/src/print_disk_info.c @@ -7,7 +7,7 @@ #include <sys/stat.h> #include <sys/statvfs.h> #include <sys/types.h> -#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || (__OpenBSD__) || defined(__DragonFly__) || defined(__APPLE__) +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__APPLE__) #include <sys/param.h> #include <sys/mount.h> #elif defined(__NetBSD__) diff --git a/src/print_eth_info.c b/src/print_eth_info.c index b30d2b0..996ce3b 100644 --- a/src/print_eth_info.c +++ b/src/print_eth_info.c @@ -33,7 +33,6 @@ static int print_eth_speed(char *outwalk, const char *interface) { #if defined(LINUX) - /* This code path requires root privileges */ int ethspeed = 0; struct ifreq ifr; struct ethtool_cmd ecmd; diff --git a/src/print_ip_addr.c b/src/print_ip_addr.c index f9cd1f4..30a1ce3 100644 --- a/src/print_ip_addr.c +++ b/src/print_ip_addr.c @@ -13,6 +13,31 @@ #include "i3status.h" /* + * Return a copy of the .ifa_name field passed as argument where the optional + * IP label, if present, is removed. + * + * example: + * - strip_optional_label("eth0") => "eth0" + * - strip_optional_label("eth0:label") => "eth0" + * + * The memory for the returned string is obtained with malloc(3), and can be + * freed with free(3). + * + * + */ +static char *strip_optional_label(const char *ifa_name) { + char *copy = sstrdup(ifa_name); + + char *ptr = strchr(copy, ':'); + + if (ptr) { + *ptr = '\0'; + } + + return copy; +} + +/* * Return the IP address for the given interface or "no IP" if the * interface is up and running but hasn't got an IP address yet * @@ -36,22 +61,30 @@ const char *get_ip_addr(const char *interface, int family) { return NULL; /* Skip until we are at the input family address of interface */ - for (addrp = ifaddr; - - (addrp != NULL && - (strcmp(addrp->ifa_name, interface) != 0 || - addrp->ifa_addr == NULL || - addrp->ifa_addr->sa_family != family)); + for (addrp = ifaddr; addrp != NULL; addrp = addrp->ifa_next) { + /* Strip the label if present in the .ifa_name field. */ + char *stripped_ifa_name = strip_optional_label(addrp->ifa_name); - addrp = addrp->ifa_next) { - /* Check if the interface is down */ - if (strcmp(addrp->ifa_name, interface) != 0) + bool name_matches = strcmp(stripped_ifa_name, interface) != 0; + free(stripped_ifa_name); + if (name_matches) { + /* The interface does not have the right name, skip it. */ continue; - found = true; + } + + if (addrp->ifa_addr != NULL && addrp->ifa_addr->sa_family == family) { + /* We found the right interface with the right address. */ + break; + } + + /* Check if the interface is down. If it is, no need to look any + * further. */ if ((addrp->ifa_flags & IFF_RUNNING) == 0) { freeifaddrs(ifaddr); return NULL; } + + found = true; } if (addrp == NULL) { diff --git a/src/print_mem.c b/src/print_mem.c new file mode 100644 index 0000000..a37fa29 --- /dev/null +++ b/src/print_mem.c @@ -0,0 +1,224 @@ +// vim:ts=4:sw=4:expandtab +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <yajl/yajl_gen.h> +#include <yajl/yajl_version.h> +#include "i3status.h" + +#define BINARY_BASE UINT64_C(1024) + +#define MAX_EXPONENT 4 +static const char *const iec_symbols[MAX_EXPONENT + 1] = {"", "Ki", "Mi", "Gi", "Ti"}; + +static const char memoryfile_linux[] = "/proc/meminfo"; + +/* + * Prints the given amount of bytes in a human readable manner. + * + */ +static int print_bytes_human(char *outwalk, uint64_t bytes) { + double size = bytes; + int exponent = 0; + int bin_base = BINARY_BASE; + while (size >= bin_base && exponent < MAX_EXPONENT) { + size /= bin_base; + exponent += 1; + } + return sprintf(outwalk, "%.1f %sB", size, iec_symbols[exponent]); +} + +/* + * Convert a string to its absolute representation based on the total + * memory of `mem_total`. + * + * The string can contain any percentage values, which then return a + * the value of `size` in relation to `mem_total`. + * Alternatively an absolute value can be given, suffixed with an iec + * symbol. + * + */ +static long memory_absolute(const long mem_total, const char *size) { + char *endptr = NULL; + + long mem_absolute = strtol(size, &endptr, 10); + + if (endptr) { + while (endptr[0] != '\0' && isspace(endptr[0])) + endptr++; + + switch (endptr[0]) { + case 'T': + case 't': + mem_absolute *= BINARY_BASE; + case 'G': + case 'g': + mem_absolute *= BINARY_BASE; + case 'M': + case 'm': + mem_absolute *= BINARY_BASE; + case 'K': + case 'k': + mem_absolute *= BINARY_BASE; + break; + case '%': + mem_absolute = mem_total * mem_absolute / 100; + break; + default: + break; + } + } + + return mem_absolute; +} + +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) { + char *outwalk = buffer; + +#if defined(linux) + const char *selected_format = format; + const char *walk; + const char *output_color = NULL; + + long ram_total = -1; + long ram_free = -1; + long ram_available = -1; + long ram_used = -1; + long ram_shared = -1; + long ram_cached = -1; + long ram_buffers = -1; + + FILE *file = fopen(memoryfile_linux, "r"); + if (!file) { + goto error; + } + char line[128]; + while (fgets(line, sizeof line, file)) { + if (BEGINS_WITH(line, "MemTotal:")) { + ram_total = strtol(line + strlen("MemTotal:"), NULL, 10); + } + if (BEGINS_WITH(line, "MemFree:")) { + 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; + } + } + fclose(file); + + if (ram_total == -1 || ram_free == -1 || ram_available == -1 || ram_buffers == -1 || ram_cached == -1 || ram_shared == -1) { + goto error; + } + + ram_total = ram_total * BINARY_BASE; + ram_free = ram_free * BINARY_BASE; + ram_available = ram_available * BINARY_BASE; + ram_buffers = ram_buffers * BINARY_BASE; + ram_cached = ram_cached * BINARY_BASE; + ram_shared = ram_shared * BINARY_BASE; + + if (BEGINS_WITH(memory_used_method, "memavailable")) { + ram_used = ram_total - ram_available; + } else if (BEGINS_WITH(memory_used_method, "classical")) { + ram_used = ram_total - ram_free - ram_buffers - ram_cached; + } + + if (threshold_degraded) { + long abs = memory_absolute(ram_total, threshold_degraded); + if (ram_available < abs) { + output_color = "color_degraded"; + } + } + + if (threshold_critical) { + long abs = memory_absolute(ram_total, threshold_critical); + if (ram_available < abs) { + output_color = "color_bad"; + } + } + + if (output_color) { + START_COLOR(output_color); + + if (format_degraded) + selected_format = format_degraded; + } + + for (walk = selected_format; *walk != '\0'; walk++) { + if (*walk != '%') { + *(outwalk++) = *walk; + continue; + } + if (BEGINS_WITH(walk + 1, "total")) { + outwalk += print_bytes_human(outwalk, ram_total); + walk += strlen("total"); + } + + if (BEGINS_WITH(walk + 1, "used")) { + outwalk += print_bytes_human(outwalk, ram_used); + walk += strlen("used"); + } + + if (BEGINS_WITH(walk + 1, "free")) { + outwalk += print_bytes_human(outwalk, ram_free); + walk += strlen("free"); + } + + if (BEGINS_WITH(walk + 1, "available")) { + outwalk += print_bytes_human(outwalk, ram_available); + walk += strlen("available"); + } + + if (BEGINS_WITH(walk + 1, "shared")) { + outwalk += print_bytes_human(outwalk, ram_shared); + walk += strlen("shared"); + } + + if (BEGINS_WITH(walk + 1, "percentage_free")) { + outwalk += sprintf(outwalk, "%.01f%s", 100.0 * ram_free / ram_total, pct_mark); + walk += strlen("percentage_free"); + } + + if (BEGINS_WITH(walk + 1, "percentage_available")) { + outwalk += sprintf(outwalk, "%.01f%s", 100.0 * ram_available / ram_total, pct_mark); + walk += strlen("percentage_available"); + } + + if (BEGINS_WITH(walk + 1, "percentage_used")) { + outwalk += sprintf(outwalk, "%.01f%s", 100.0 * ram_used / ram_total, pct_mark); + walk += strlen("percentage_used"); + } + + if (BEGINS_WITH(walk + 1, "percentage_shared")) { + outwalk += sprintf(outwalk, "%.01f%s", 100.0 * ram_shared / ram_total, pct_mark); + walk += strlen("percentage_shared"); + } + } + + if (output_color) + END_COLOR; + + *outwalk = '\0'; + OUTPUT_FULL_TEXT(buffer); + + return; +error: + OUTPUT_FULL_TEXT("can't read memory"); + fputs("i3status: Cannot read system memory using /proc/meminfo\n", stderr); +#else + OUTPUT_FULL_TEXT(""); + fputs("i3status: Memory status information is not supported on this system\n", stderr); +#endif +} diff --git a/src/print_volume.c b/src/print_volume.c index 51e84f3..e28a132 100644 --- a/src/print_volume.c +++ b/src/print_volume.c @@ -151,7 +151,7 @@ void print_volume(yajl_gen json_gen, char *buffer, const char *fmt, const char * snd_mixer_selem_id_set_index(sid, mixer_idx); snd_mixer_selem_id_set_name(sid, mixer); if (!(elem = snd_mixer_find_selem(m, sid))) { - fprintf(stderr, "i3status: ALSA: Cannot find mixer %s (index %i)\n", + fprintf(stderr, "i3status: ALSA: Cannot find mixer %s (index %u)\n", snd_mixer_selem_id_get_name(sid), snd_mixer_selem_id_get_index(sid)); snd_mixer_close(m); snd_mixer_selem_id_free(sid); @@ -211,6 +211,7 @@ void print_volume(yajl_gen json_gen, char *buffer, const char *fmt, const char * #if defined(__OpenBSD__) int oclass_idx = -1, master_idx = -1, master_mute_idx = -1; + int master_next = AUDIO_MIXER_LAST; mixer_devinfo_t devinfo, devinfo2; mixer_ctrl_t vinfo; @@ -228,12 +229,17 @@ void print_volume(yajl_gen json_gen, char *buffer, const char *fmt, const char * devinfo2.index = 0; while (ioctl(mixfd, AUDIO_MIXER_DEVINFO, &devinfo2) >= 0) { - if ((devinfo2.type == AUDIO_MIXER_VALUE) && (devinfo2.mixer_class == oclass_idx) && (strncmp(devinfo2.label.name, AudioNmaster, MAX_AUDIO_DEV_LEN) == 0)) + if ((devinfo2.type == AUDIO_MIXER_VALUE) && (devinfo2.mixer_class == oclass_idx) && (strncmp(devinfo2.label.name, AudioNmaster, MAX_AUDIO_DEV_LEN) == 0)) { master_idx = devinfo2.index; + master_next = devinfo2.next; + } if ((devinfo2.type == AUDIO_MIXER_ENUM) && (devinfo2.mixer_class == oclass_idx) && (strncmp(devinfo2.label.name, AudioNmute, MAX_AUDIO_DEV_LEN) == 0)) - master_mute_idx = devinfo2.index; + if (master_next == devinfo2.index) + master_mute_idx = devinfo2.index; + if (master_next != AUDIO_MIXER_LAST) + master_next = devinfo2.next; devinfo2.index++; } @@ -246,6 +252,7 @@ void print_volume(yajl_gen json_gen, char *buffer, const char *fmt, const char * vinfo.dev = master_idx; vinfo.type = AUDIO_MIXER_VALUE; + vinfo.un.value.num_channels = devinfo.un.v.num_channels; if (ioctl(mixfd, AUDIO_MIXER_READ, &vinfo) == -1) goto out; diff --git a/src/print_wireless_info.c b/src/print_wireless_info.c index c3b5270..dcfde52 100644 --- a/src/print_wireless_info.c +++ b/src/print_wireless_info.c @@ -16,6 +16,7 @@ #endif #ifdef __APPLE__ +#include <sys/socket.h> #define IW_ESSID_MAX_SIZE 32 #endif @@ -479,7 +480,7 @@ error1: * | 127.0.0.1 | no IP | IPv4 | ok | * | 127.0.0.1 | ::1/128 | IPv4 | ok | */ -void print_wireless_info(yajl_gen json_gen, char *buffer, const char *interface, const char *format_up, const char *format_down) { +void print_wireless_info(yajl_gen json_gen, char *buffer, const char *interface, const char *format_up, const char *format_down, const char *format_quality) { const char *walk; char *outwalk = buffer; wireless_info_t info; @@ -539,7 +540,7 @@ void print_wireless_info(yajl_gen json_gen, char *buffer, const char *interface, if (BEGINS_WITH(walk + 1, "quality")) { if (info.flags & WIRELESS_INFO_FLAG_HAS_QUALITY) { if (info.quality_max) - outwalk += sprintf(outwalk, "%3d%s", PERCENT_VALUE(info.quality, info.quality_max), pct_mark); + outwalk += sprintf(outwalk, format_quality, PERCENT_VALUE(info.quality, info.quality_max), pct_mark); else outwalk += sprintf(outwalk, "%d", info.quality); } else { diff --git a/src/process_runs.c b/src/process_runs.c index b5e8f11..da2dba1 100644 --- a/src/process_runs.c +++ b/src/process_runs.c @@ -24,7 +24,7 @@ bool process_runs(const char *path) { static glob_t globbuf; memset(pidbuf, 0, sizeof(pidbuf)); - if (glob(path, GLOB_NOCHECK | GLOB_TILDE, NULL, &globbuf) < 0) + if (glob(path, GLOB_NOCHECK | GLOB_TILDE, NULL, &globbuf) != 0) die("glob() failed\n"); if (globbuf.gl_pathc == 0) { /* No glob matches, the specified path does not contain a wildcard. */ |