diff options
| author | pml68 <contact@pml68.dev> | 2025-09-16 21:48:56 +0200 |
|---|---|---|
| committer | pml68 <contact@pml68.dev> | 2025-09-16 22:15:01 +0200 |
| commit | fd3a7cc487ad5dc36d99ccf46f9e3c6461687f99 (patch) | |
| tree | e1627f8ea07510d06a99ea55f275ae3b6e1919a7 | |
| parent | chore: bump dwm and dmenu versions (diff) | |
| download | suckless-setup-fd3a7cc487ad5dc36d99ccf46f9e3c6461687f99.tar.gz | |
chore: sync slstatus with upstream
| -rw-r--r-- | slstatus/LICENSE | 7 | ||||
| -rw-r--r-- | slstatus/README | 2 | ||||
| -rw-r--r-- | slstatus/components/ip.c | 26 | ||||
| -rw-r--r-- | slstatus/components/keymap.c | 4 | ||||
| -rw-r--r-- | slstatus/components/ram.c | 61 | ||||
| -rw-r--r-- | slstatus/components/wifi.c | 258 | ||||
| -rw-r--r-- | slstatus/config.def.h | 14 | ||||
| -rw-r--r-- | slstatus/config.h | 14 | ||||
| -rw-r--r-- | slstatus/config.mk | 2 | ||||
| -rw-r--r-- | slstatus/slstatus.c | 1 | ||||
| -rw-r--r-- | slstatus/slstatus.h | 1 | ||||
| -rw-r--r-- | slstatus/util.c | 17 | ||||
| -rw-r--r-- | slstatus/util.h | 2 |
13 files changed, 308 insertions, 101 deletions
diff --git a/slstatus/LICENSE b/slstatus/LICENSE index 8bee9c8..3fcac59 100644 --- a/slstatus/LICENSE +++ b/slstatus/LICENSE @@ -1,6 +1,6 @@ ISC License -Copyright 2016-2022 Aaron Marcher <me@drkhsh.at> +Copyright 2016-2025 Aaron Marcher <me@drkhsh.at> Copyright 2016 Roy Freytag <rfreytag@hs-mittweida.de> Copyright 2016 Vincent Loupmon <vincentloupmon@gmail.com> @@ -21,7 +21,7 @@ Copyright 2018 Ian Remmler <ian@remmler.org> Copyright 2016-2019 Joerg Jung <jung@openbsd.org> Copyright 2019 Ryan Kes <alrayyes@gmail.com> Copyright 2019 Cem Keylan <cem@ckyln.com> -Copyright 2019 Dimitris Papastamos <dsp@2f30.org> +Copyright 2019 Spiros Thanasoulas <dsp@2f30.org> Copyright 2019-2022 Ingo Feinerer <feinerer@logic.at> Copyright 2020 Alexandre Ratchov <alex@caoua.org> Copyright 2020 Mart Lubbers <mart@martlubbers.net> @@ -29,6 +29,9 @@ Copyright 2020 Daniel Moch <daniel@danielmoch.com> Copyright 2022 Nickolas Raymond Kaczynski <nrk@disroot.org> Copyright 2022 Patrick Iacob <iacobp@oregonstate.edu> Copyright 2021-2022 Steven Ward <planet36@gmail.com> +Copyright 2025 Joakim Sindholt <opensource@zhasha.com> +Copyright 2025 Al <eirann@disroot.org> +Copyright 2025 sewn <sewn@disroot.org> Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above diff --git a/slstatus/README b/slstatus/README index 12d38bf..4d592bb 100644 --- a/slstatus/README +++ b/slstatus/README @@ -18,7 +18,7 @@ Features - Available entropy - Username/GID/UID - Hostname -- IP address (IPv4 and IPv6) +- IP address (IPv4 and IPv6), interface status - Kernel version - Keyboard indicators - Keymap diff --git a/slstatus/components/ip.c b/slstatus/components/ip.c index 9476549..2cdad46 100644 --- a/slstatus/components/ip.c +++ b/slstatus/components/ip.c @@ -1,6 +1,7 @@ /* See LICENSE file for copyright and license details. */ #include <ifaddrs.h> #include <netdb.h> +#include <net/if.h> #include <stdio.h> #include <string.h> #if defined(__OpenBSD__) @@ -59,3 +60,28 @@ ipv6(const char *interface) { return ip(interface, AF_INET6); } + +const char * +up(const char *interface) +{ + struct ifaddrs *ifaddr, *ifa; + + if (getifaddrs(&ifaddr) < 0) { + warn("getifaddrs:"); + return NULL; + } + + for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { + if (!ifa->ifa_addr) + continue; + + if (!strcmp(ifa->ifa_name, interface)) { + freeifaddrs(ifaddr); + return ifa->ifa_flags & IFF_UP ? "up" : "down"; + } + } + + freeifaddrs(ifaddr); + + return NULL; +} diff --git a/slstatus/components/keymap.c b/slstatus/components/keymap.c index f8a2a47..22224f3 100644 --- a/slstatus/components/keymap.c +++ b/slstatus/components/keymap.c @@ -29,8 +29,8 @@ get_layout(char *syms, int grp_num) int grp; layout = NULL; - tok = strtok(syms, "+:"); - for (grp = 0; tok && grp <= grp_num; tok = strtok(NULL, "+:")) { + tok = strtok(syms, "+:_"); + for (grp = 0; tok && grp <= grp_num; tok = strtok(NULL, "+:_")) { if (!valid_layout_or_variant(tok)) { continue; } else if (strlen(tok) == 1 && isdigit(tok[0])) { diff --git a/slstatus/components/ram.c b/slstatus/components/ram.c index 15c4b74..bf71dcf 100644 --- a/slstatus/components/ram.c +++ b/slstatus/components/ram.c @@ -11,36 +11,45 @@ ram_free(const char *unused) { uintmax_t free; + FILE *fp; - if (pscanf("/proc/meminfo", - "MemTotal: %ju kB\n" - "MemFree: %ju kB\n" - "MemAvailable: %ju kB\n", - &free, &free, &free) != 3) + if (!(fp = fopen("/proc/meminfo", "r"))) return NULL; + if (lscanf(fp, "MemFree:", "%ju kB", &free) != 1) { + fclose(fp); + return NULL; + } + + fclose(fp); return fmt_human(free * 1024, 1024); } const char * ram_perc(const char *unused) { - uintmax_t total, free, buffers, cached; + uintmax_t total, free, buffers, cached, shmem, sreclaimable; int percent; + FILE *fp; + + if (!(fp = fopen("/proc/meminfo", "r"))) + return NULL; - if (pscanf("/proc/meminfo", - "MemTotal: %ju kB\n" - "MemFree: %ju kB\n" - "MemAvailable: %ju kB\n" - "Buffers: %ju kB\n" - "Cached: %ju kB\n", - &total, &free, &buffers, &buffers, &cached) != 5) + if (lscanf(fp, "MemTotal:", "%ju kB", &total) != 1 || + lscanf(fp, "MemFree:", "%ju kB", &free) != 1 || + lscanf(fp, "Buffers:", "%ju kB", &buffers) != 1 || + lscanf(fp, "Cached:", "%ju kB", &cached) != 1 || + lscanf(fp, "Shmem:", "%ju kB", &shmem) != 1 || + lscanf(fp, "SReclaimable:", "%ju kB", &sreclaimable) != 1) { + fclose(fp); return NULL; + } + fclose(fp); if (total == 0) return NULL; - percent = 100 * ((total - free) - (buffers + cached)) / total; + percent = 100 * (total - free - buffers - cached - sreclaimable + shmem) / total; return bprintf("%d", percent); } @@ -59,18 +68,24 @@ const char * ram_used(const char *unused) { - uintmax_t total, free, buffers, cached, used; + uintmax_t total, free, buffers, cached, used, shmem, sreclaimable; + FILE *fp; + + if (!(fp = fopen("/proc/meminfo", "r"))) + return NULL; - if (pscanf("/proc/meminfo", - "MemTotal: %ju kB\n" - "MemFree: %ju kB\n" - "MemAvailable: %ju kB\n" - "Buffers: %ju kB\n" - "Cached: %ju kB\n", - &total, &free, &buffers, &buffers, &cached) != 5) + if (lscanf(fp, "MemTotal:", "%ju kB", &total) != 1 || + lscanf(fp, "MemFree:", "%ju kB", &free) != 1 || + lscanf(fp, "Buffers:", "%ju kB", &buffers) != 1 || + lscanf(fp, "Cached:", "%ju kB", &cached) != 1 || + lscanf(fp, "Shmem:", "%ju kB", &shmem) != 1 || + lscanf(fp, "SReclaimable:", "%ju kB", &sreclaimable) != 1) { + fclose(fp); return NULL; + } + fclose(fp); - used = (total - free - buffers - cached); + used = total - free - buffers - cached - sreclaimable + shmem; return fmt_human(used * 1024, 1024); } #elif defined(__OpenBSD__) diff --git a/slstatus/components/wifi.c b/slstatus/components/wifi.c index 4543d32..23af201 100644 --- a/slstatus/components/wifi.c +++ b/slstatus/components/wifi.c @@ -15,86 +15,232 @@ (2 * (rssi + 100))) #if defined(__linux__) - #include <limits.h> - #include <linux/wireless.h> + #include <stdint.h> + #include <net/if.h> + #include <linux/netlink.h> + #include <linux/genetlink.h> + #include <linux/nl80211.h> + + static int nlsock = -1; + static uint32_t seq = 1; + static char resp[4096]; + + static char * + findattr(int attr, const char *p, const char *e, size_t *len) + { + while (p < e) { + struct nlattr nla; + memcpy(&nla, p, sizeof(nla)); + if (nla.nla_type == attr) { + *len = nla.nla_len - NLA_HDRLEN; + return (char *)(p + NLA_HDRLEN); + } + p += NLA_ALIGN(nla.nla_len); + } + return NULL; + } - #define NET_OPERSTATE "/sys/class/net/%s/operstate" + static uint16_t + nl80211fam(void) + { + static const char family[] = "nl80211"; + static uint16_t id; + ssize_t r; + size_t len; + char ctrl[NLMSG_HDRLEN+GENL_HDRLEN+NLA_HDRLEN+NLA_ALIGN(sizeof(family))] = {0}, *p = ctrl; + + if (id) + return id; + + memcpy(p, &(struct nlmsghdr){ + .nlmsg_len = sizeof(ctrl), + .nlmsg_type = GENL_ID_CTRL, + .nlmsg_flags = NLM_F_REQUEST, + .nlmsg_seq = seq++, + .nlmsg_pid = 0, + }, sizeof(struct nlmsghdr)); + p += NLMSG_HDRLEN; + memcpy(p, &(struct genlmsghdr){ + .cmd = CTRL_CMD_GETFAMILY, + .version = 1, + }, sizeof(struct genlmsghdr)); + p += GENL_HDRLEN; + memcpy(p, &(struct nlattr){ + .nla_len = NLA_HDRLEN+sizeof(family), + .nla_type = CTRL_ATTR_FAMILY_NAME, + }, sizeof(struct nlattr)); + p += NLA_HDRLEN; + memcpy(p, family, sizeof(family)); + + if (nlsock < 0) + nlsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC); + if (nlsock < 0) { + warn("socket 'AF_NETLINK':"); + return 0; + } + if (send(nlsock, ctrl, sizeof(ctrl), 0) != sizeof(ctrl)) { + warn("send 'AF_NETLINK':"); + return 0; + } + r = recv(nlsock, resp, sizeof(resp), 0); + if (r < 0) { + warn("recv 'AF_NETLINK':"); + return 0; + } + if ((size_t)r <= sizeof(ctrl)) + return 0; + p = findattr(CTRL_ATTR_FAMILY_ID, resp + sizeof(ctrl), resp + r, &len); + if (p && len == 2) + memcpy(&id, p, 2); + + return id; + } + + static int + ifindex(const char *interface) + { + static struct ifreq ifr; + static int ifsock = -1; + + if (ifsock < 0) + ifsock = socket(AF_UNIX, SOCK_DGRAM, 0); + if (ifsock < 0) { + warn("socket 'AF_UNIX':"); + return -1; + } + if (strcmp(ifr.ifr_name, interface) != 0) { + strcpy(ifr.ifr_name, interface); + if (ioctl(ifsock, SIOCGIFINDEX, &ifr) != 0) { + warn("ioctl 'SIOCGIFINDEX':"); + return -1; + } + } + return ifr.ifr_ifindex; + } const char * - wifi_perc(const char *interface) + wifi_essid(const char *interface) { - int cur; - size_t i; - char *p, *datastart; - char path[PATH_MAX]; - char status[5]; - FILE *fp; - - if (esnprintf(path, sizeof(path), NET_OPERSTATE, interface) < 0) - return NULL; - if (!(fp = fopen(path, "r"))) { - warn("fopen '%s':", path); + uint16_t fam = nl80211fam(); + ssize_t r; + size_t len; + char req[NLMSG_HDRLEN+GENL_HDRLEN+NLA_HDRLEN+NLA_ALIGN(4)] = {0}, *p = req; + int idx = ifindex(interface); + if (!fam) { + fprintf(stderr, "nl80211 family not found\n"); return NULL; } - p = fgets(status, 5, fp); - fclose(fp); - if (!p || strcmp(status, "up\n") != 0) + if (idx < 0) { + fprintf(stderr, "interface %s not found\n", interface); return NULL; + } - if (!(fp = fopen("/proc/net/wireless", "r"))) { - warn("fopen '/proc/net/wireless':"); + memcpy(p, &(struct nlmsghdr){ + .nlmsg_len = sizeof(req), + .nlmsg_type = fam, + .nlmsg_flags = NLM_F_REQUEST, + .nlmsg_seq = seq++, + .nlmsg_pid = 0, + }, sizeof(struct nlmsghdr)); + p += NLMSG_HDRLEN; + memcpy(p, &(struct genlmsghdr){ + .cmd = NL80211_CMD_GET_INTERFACE, + .version = 1, + }, sizeof(struct genlmsghdr)); + p += GENL_HDRLEN; + memcpy(p, &(struct nlattr){ + .nla_len = NLA_HDRLEN+4, + .nla_type = NL80211_ATTR_IFINDEX, + }, sizeof(struct nlattr)); + p += NLA_HDRLEN; + memcpy(p, &(uint32_t){idx}, 4); + + if (send(nlsock, req, sizeof(req), 0) != sizeof(req)) { + warn("send 'AF_NETLINK':"); return NULL; } - - for (i = 0; i < 3; i++) - if (!(p = fgets(buf, sizeof(buf) - 1, fp))) - break; - - fclose(fp); - if (i < 2 || !p) + r = recv(nlsock, resp, sizeof(resp), 0); + if (r < 0) { + warn("recv 'AF_NETLINK':"); return NULL; + } - if (!(datastart = strstr(buf, interface))) + if ((size_t)r <= NLMSG_HDRLEN + GENL_HDRLEN) return NULL; + p = findattr(NL80211_ATTR_SSID, resp + NLMSG_HDRLEN + GENL_HDRLEN, resp + r, &len); + if (p) + p[len] = 0; - datastart = (datastart+(strlen(interface)+1)); - sscanf(datastart + 1, " %*d %d %*d %*d\t\t %*d\t " - "%*d\t\t%*d\t\t %*d\t %*d\t\t %*d", &cur); - - /* 70 is the max of /proc/net/wireless */ - return bprintf("%d", (int)((float)cur / 70 * 100)); + return p; } const char * - wifi_essid(const char *interface) + wifi_perc(const char *interface) { - static char id[IW_ESSID_MAX_SIZE+1]; - int sockfd; - struct iwreq wreq; - - memset(&wreq, 0, sizeof(struct iwreq)); - wreq.u.essid.length = IW_ESSID_MAX_SIZE+1; - if (esnprintf(wreq.ifr_name, sizeof(wreq.ifr_name), "%s", - interface) < 0) - return NULL; + static char strength[4]; + struct nlmsghdr hdr; + uint16_t fam = nl80211fam(); + ssize_t r; + size_t len; + char req[NLMSG_HDRLEN + GENL_HDRLEN + NLA_HDRLEN + NLA_ALIGN(4)] = {0}, *p = req, *e; + int idx = ifindex(interface); - if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { - warn("socket 'AF_INET':"); - return NULL; - } - wreq.u.essid.pointer = id; - if (ioctl(sockfd,SIOCGIWESSID, &wreq) < 0) { - warn("ioctl 'SIOCGIWESSID':"); - close(sockfd); + if (idx < 0) { + fprintf(stderr, "interface %s not found\n", interface); return NULL; } - close(sockfd); - - if (!strcmp(id, "")) + memcpy(p, &(struct nlmsghdr){ + .nlmsg_len = sizeof(req), + .nlmsg_type = fam, + .nlmsg_flags = NLM_F_REQUEST|NLM_F_DUMP, + .nlmsg_seq = seq++, + .nlmsg_pid = 0, + }, sizeof(struct nlmsghdr)); + p += NLMSG_HDRLEN; + memcpy(p, &(struct genlmsghdr){ + .cmd = NL80211_CMD_GET_STATION, + .version = 1, + }, sizeof(struct genlmsghdr)); + p += GENL_HDRLEN; + memcpy(p, &(struct nlattr){ + .nla_len = NLA_HDRLEN + 4, + .nla_type = NL80211_ATTR_IFINDEX, + }, sizeof(struct nlattr)); + p += NLA_HDRLEN; + memcpy(p, &idx, 4); + + if (send(nlsock, req, sizeof(req), 0) != sizeof(req)) { + warn("send 'AF_NETLINK':"); return NULL; + } - return id; + *strength = 0; + while (1) { + r = recv(nlsock, resp, sizeof(resp), 0); + if (r < 0) { + warn("recv 'AF_NETLINK':"); + return NULL; + } + if ((size_t)r < sizeof(hdr)) + return NULL; + + for (p = resp; p != resp + r && (size_t)(resp + r-p) >= sizeof(hdr); p = e) { + memcpy(&hdr, p, sizeof(hdr)); + e = resp + r - p < hdr.nlmsg_len ? resp + r : p + hdr.nlmsg_len; + + if (!*strength && hdr.nlmsg_len > NLMSG_HDRLEN+GENL_HDRLEN) { + p += NLMSG_HDRLEN+GENL_HDRLEN; + p = findattr(NL80211_ATTR_STA_INFO, p, e, &len); + if (p) + p = findattr(NL80211_STA_INFO_SIGNAL_AVG, p, e, &len); + if (p && len == 1) + snprintf(strength, sizeof(strength), "%d", RSSI_TO_PERC(*p)); + } + if (hdr.nlmsg_type == NLMSG_DONE) + return *strength ? strength : NULL; + } + } } #elif defined(__OpenBSD__) #include <net/if.h> diff --git a/slstatus/config.def.h b/slstatus/config.def.h index c273999..b48aa4b 100644 --- a/slstatus/config.def.h +++ b/slstatus/config.def.h @@ -56,6 +56,7 @@ static const char unknown_str[] = "n/a"; * thermal zone on FreeBSD * (tz0, tz1, etc.) * uid UID of current user NULL + * up interface is running interface name (eth0) * uptime system uptime NULL * username username of current user NULL * vol_perc OSS/ALSA volume in percent mixer file (/dev/mixer) @@ -64,12 +65,9 @@ static const char unknown_str[] = "n/a"; * wifi_perc WiFi signal in percent interface name (wlan0) */ static const struct arg args[] = { - - /* function format argument interval (in ms) */ - - {datetime, "%s;", "%G. %B. %e. %a"}, - {run_command, "%s%% ", "pulsemixer --get-volume | awk '{print $2 }'"}, - {keymap, "%s ", NULL}, - {datetime, "%s ", "%H:%M:%S"}, - + /* function format argument */ + {datetime, "%s;", "%G. %B. %e. %a"}, + {run_command, "%s%% ", "pulsemixer --get-volume | awk '{print $2 }'"}, + {keymap, "%s ", NULL}, + {datetime, "%s ", "%H:%M:%S"}, }; diff --git a/slstatus/config.h b/slstatus/config.h index c273999..b48aa4b 100644 --- a/slstatus/config.h +++ b/slstatus/config.h @@ -56,6 +56,7 @@ static const char unknown_str[] = "n/a"; * thermal zone on FreeBSD * (tz0, tz1, etc.) * uid UID of current user NULL + * up interface is running interface name (eth0) * uptime system uptime NULL * username username of current user NULL * vol_perc OSS/ALSA volume in percent mixer file (/dev/mixer) @@ -64,12 +65,9 @@ static const char unknown_str[] = "n/a"; * wifi_perc WiFi signal in percent interface name (wlan0) */ static const struct arg args[] = { - - /* function format argument interval (in ms) */ - - {datetime, "%s;", "%G. %B. %e. %a"}, - {run_command, "%s%% ", "pulsemixer --get-volume | awk '{print $2 }'"}, - {keymap, "%s ", NULL}, - {datetime, "%s ", "%H:%M:%S"}, - + /* function format argument */ + {datetime, "%s;", "%G. %B. %e. %a"}, + {run_command, "%s%% ", "pulsemixer --get-volume | awk '{print $2 }'"}, + {keymap, "%s ", NULL}, + {datetime, "%s ", "%H:%M:%S"}, }; diff --git a/slstatus/config.mk b/slstatus/config.mk index 07af883..a8f5c23 100644 --- a/slstatus/config.mk +++ b/slstatus/config.mk @@ -1,5 +1,5 @@ # slstatus version -VERSION = 1.0 +VERSION = 1.1 # customize below to fit your system diff --git a/slstatus/slstatus.c b/slstatus/slstatus.c index fd31313..16d88fe 100644 --- a/slstatus/slstatus.c +++ b/slstatus/slstatus.c @@ -58,6 +58,7 @@ main(int argc, char *argv[]) ARGBEGIN { case 'v': die("slstatus-"VERSION); + break; case '1': done = 1; /* FALLTHROUGH */ diff --git a/slstatus/slstatus.h b/slstatus/slstatus.h index 8ef5874..394281c 100644 --- a/slstatus/slstatus.h +++ b/slstatus/slstatus.h @@ -30,6 +30,7 @@ const char *hostname(const char *unused); /* ip */ const char *ipv4(const char *interface); const char *ipv6(const char *interface); +const char *up(const char *interface); /* kernel_release */ const char *kernel_release(const char *unused); diff --git a/slstatus/util.c b/slstatus/util.c index bca9b2e..d33cf9d 100644 --- a/slstatus/util.c +++ b/slstatus/util.c @@ -139,3 +139,20 @@ pscanf(const char *path, const char *fmt, ...) return (n == EOF) ? -1 : n; } + +int +lscanf(FILE *fp, const char *key, const char *fmt, void *res) +{ + int n; + char line[256]; + + n = -1; + while (fgets(line, sizeof(line), fp)) + if (strncmp(line, key, strlen(key)) == 0) { + n = sscanf(line + strlen(key), fmt, res); + break; + } + + rewind(fp); + return (n == 1) ? 1 : -1; +} diff --git a/slstatus/util.h b/slstatus/util.h index cf4b027..7a960aa 100644 --- a/slstatus/util.h +++ b/slstatus/util.h @@ -1,5 +1,6 @@ /* See LICENSE file for copyright and license details. */ #include <stdint.h> +#include <stdio.h> extern char buf[1024]; @@ -14,3 +15,4 @@ int esnprintf(char *str, size_t size, const char *fmt, ...); const char *bprintf(const char *fmt, ...); const char *fmt_human(uintmax_t num, int base); int pscanf(const char *path, const char *fmt, ...); +int lscanf(FILE *fp, const char *key, const char *fmt, void *res); |
