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. */  | 
