summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/first_network_device.c43
-rw-r--r--src/general.c4
-rw-r--r--src/print_battery_info.c15
-rw-r--r--src/print_cpu_temperature.c8
-rw-r--r--src/print_disk_info.c2
-rw-r--r--src/print_eth_info.c1
-rw-r--r--src/print_ip_addr.c53
-rw-r--r--src/print_mem.c224
-rw-r--r--src/print_volume.c13
-rw-r--r--src/print_wireless_info.c5
-rw-r--r--src/process_runs.c2
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. */