From 737e3face374ffb295c3e293957955b897c9c087 Mon Sep 17 00:00:00 2001 From: bacalhau Date: Fri, 4 Jul 2025 01:18:38 +0100 Subject: [PATCH] removed scripts added slstatus (this is pretty good) --- scripts/status.sh | 8 - slstatus/LICENSE | 46 +++ slstatus/Makefile | 69 ++++ slstatus/README | 65 ++++ slstatus/arg.h | 33 ++ slstatus/components/battery.c | 247 +++++++++++++ slstatus/components/battery.o | Bin 0 -> 5208 bytes slstatus/components/cat.c | 32 ++ slstatus/components/cat.o | Bin 0 -> 2128 bytes slstatus/components/cpu.c | 157 ++++++++ slstatus/components/cpu.o | Bin 0 -> 3168 bytes slstatus/components/datetime.c | 20 ++ slstatus/components/datetime.o | Bin 0 -> 1960 bytes slstatus/components/disk.c | 59 ++++ slstatus/components/disk.o | Bin 0 -> 3168 bytes slstatus/components/entropy.c | 29 ++ slstatus/components/entropy.o | Bin 0 -> 1824 bytes slstatus/components/hostname.c | 17 + slstatus/components/hostname.o | Bin 0 -> 1680 bytes slstatus/components/ip.c | 87 +++++ slstatus/components/ip.o | Bin 0 -> 3144 bytes slstatus/components/kernel_release.c | 19 + slstatus/components/kernel_release.o | Bin 0 -> 1872 bytes slstatus/components/keyboard_indicators.c | 50 +++ slstatus/components/keyboard_indicators.o | Bin 0 -> 2448 bytes slstatus/components/keymap.c | 86 +++++ slstatus/components/keymap.o | Bin 0 -> 4048 bytes slstatus/components/load_avg.c | 19 + slstatus/components/load_avg.o | Bin 0 -> 1904 bytes slstatus/components/netspeeds.c | 129 +++++++ slstatus/components/netspeeds.o | Bin 0 -> 2824 bytes slstatus/components/num_files.c | 32 ++ slstatus/components/num_files.o | Bin 0 -> 2192 bytes slstatus/components/ram.c | 212 +++++++++++ slstatus/components/ram.o | Bin 0 -> 3128 bytes slstatus/components/run_command.c | 31 ++ slstatus/components/run_command.o | Bin 0 -> 2144 bytes slstatus/components/swap.c | 274 ++++++++++++++ slstatus/components/swap.o | Bin 0 -> 3928 bytes slstatus/components/temperature.c | 73 ++++ slstatus/components/temperature.o | Bin 0 -> 1744 bytes slstatus/components/uptime.c | 34 ++ slstatus/components/uptime.o | Bin 0 -> 2024 bytes slstatus/components/user.c | 33 ++ slstatus/components/user.o | Bin 0 -> 2240 bytes slstatus/components/volume.c | 219 ++++++++++++ slstatus/components/volume.o | Bin 0 -> 3632 bytes slstatus/components/wifi.c | 413 ++++++++++++++++++++++ slstatus/components/wifi.o | Bin 0 -> 6176 bytes slstatus/config.def.h | 70 ++++ slstatus/config.h | 72 ++++ slstatus/config.mk | 22 ++ slstatus/slstatus | Bin 0 -> 35392 bytes slstatus/slstatus.1 | 47 +++ slstatus/slstatus.c | 135 +++++++ slstatus/slstatus.h | 85 +++++ slstatus/slstatus.o | Bin 0 -> 6056 bytes slstatus/util.c | 141 ++++++++ slstatus/util.h | 16 + slstatus/util.o | Bin 0 -> 5592 bytes 60 files changed, 3073 insertions(+), 8 deletions(-) delete mode 100755 scripts/status.sh create mode 100644 slstatus/LICENSE create mode 100644 slstatus/Makefile create mode 100644 slstatus/README create mode 100644 slstatus/arg.h create mode 100644 slstatus/components/battery.c create mode 100644 slstatus/components/battery.o create mode 100644 slstatus/components/cat.c create mode 100644 slstatus/components/cat.o create mode 100644 slstatus/components/cpu.c create mode 100644 slstatus/components/cpu.o create mode 100644 slstatus/components/datetime.c create mode 100644 slstatus/components/datetime.o create mode 100644 slstatus/components/disk.c create mode 100644 slstatus/components/disk.o create mode 100644 slstatus/components/entropy.c create mode 100644 slstatus/components/entropy.o create mode 100644 slstatus/components/hostname.c create mode 100644 slstatus/components/hostname.o create mode 100644 slstatus/components/ip.c create mode 100644 slstatus/components/ip.o create mode 100644 slstatus/components/kernel_release.c create mode 100644 slstatus/components/kernel_release.o create mode 100644 slstatus/components/keyboard_indicators.c create mode 100644 slstatus/components/keyboard_indicators.o create mode 100644 slstatus/components/keymap.c create mode 100644 slstatus/components/keymap.o create mode 100644 slstatus/components/load_avg.c create mode 100644 slstatus/components/load_avg.o create mode 100644 slstatus/components/netspeeds.c create mode 100644 slstatus/components/netspeeds.o create mode 100644 slstatus/components/num_files.c create mode 100644 slstatus/components/num_files.o create mode 100644 slstatus/components/ram.c create mode 100644 slstatus/components/ram.o create mode 100644 slstatus/components/run_command.c create mode 100644 slstatus/components/run_command.o create mode 100644 slstatus/components/swap.c create mode 100644 slstatus/components/swap.o create mode 100644 slstatus/components/temperature.c create mode 100644 slstatus/components/temperature.o create mode 100644 slstatus/components/uptime.c create mode 100644 slstatus/components/uptime.o create mode 100644 slstatus/components/user.c create mode 100644 slstatus/components/user.o create mode 100644 slstatus/components/volume.c create mode 100644 slstatus/components/volume.o create mode 100644 slstatus/components/wifi.c create mode 100644 slstatus/components/wifi.o create mode 100644 slstatus/config.def.h create mode 100644 slstatus/config.h create mode 100644 slstatus/config.mk create mode 100755 slstatus/slstatus create mode 100644 slstatus/slstatus.1 create mode 100644 slstatus/slstatus.c create mode 100644 slstatus/slstatus.h create mode 100644 slstatus/slstatus.o create mode 100644 slstatus/util.c create mode 100644 slstatus/util.h create mode 100644 slstatus/util.o diff --git a/scripts/status.sh b/scripts/status.sh deleted file mode 100755 index 6f3daec..0000000 --- a/scripts/status.sh +++ /dev/null @@ -1,8 +0,0 @@ -while true; do - - volume="$(pulsemixer --id 8 --get-volume)" - song="$(cmus-remote -Q | grep 'tag title' | cut -d ' ' -f 3-)" - - xsetroot -name " ♫ $song |  $volume |  $(date +%d) |  $(date +%R)" - sleep 1 -done diff --git a/slstatus/LICENSE b/slstatus/LICENSE new file mode 100644 index 0000000..9fae663 --- /dev/null +++ b/slstatus/LICENSE @@ -0,0 +1,46 @@ +ISC License + +Copyright 2016-2025 Aaron Marcher + +Copyright 2016 Roy Freytag +Copyright 2016 Vincent Loupmon +Copyright 2016 Daniel Walter +Copyright 2016-2018 Ali H. Fardan +Copyright 2016 Jody Leonard +Copyright 2016-2018 Quentin Rameau +Copyright 2016 Mike Coddington +Copyright 2016-2018 Ivan J. +Copyright 2017 Tobias Stoeckmann +Copyright 2017-2018 Laslo Hunhold +Copyright 2018 Darron Anderson +Copyright 2018 Josuah Demangeon +Copyright 2018 Tobias Tschinkowitz +Copyright 2018 David Demelier +Copyright 2018-2012 Michael Buch +Copyright 2018 Ian Remmler +Copyright 2016-2019 Joerg Jung +Copyright 2019 Ryan Kes +Copyright 2019 Cem Keylan +Copyright 2019 Dimitris Papastamos +Copyright 2019-2022 Ingo Feinerer +Copyright 2020 Alexandre Ratchov +Copyright 2020 Mart Lubbers +Copyright 2020 Daniel Moch +Copyright 2022 Nickolas Raymond Kaczynski +Copyright 2022 Patrick Iacob +Copyright 2021-2022 Steven Ward +Copyright 2025 Joakim Sindholt +Copyright 2025 Al +Copyright 2025 sewn + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/slstatus/Makefile b/slstatus/Makefile new file mode 100644 index 0000000..7a18274 --- /dev/null +++ b/slstatus/Makefile @@ -0,0 +1,69 @@ +# See LICENSE file for copyright and license details +# slstatus - suckless status monitor +.POSIX: + +include config.mk + +REQ = util +COM =\ + components/battery\ + components/cat\ + components/cpu\ + components/datetime\ + components/disk\ + components/entropy\ + components/hostname\ + components/ip\ + components/kernel_release\ + components/keyboard_indicators\ + components/keymap\ + components/load_avg\ + components/netspeeds\ + components/num_files\ + components/ram\ + components/run_command\ + components/swap\ + components/temperature\ + components/uptime\ + components/user\ + components/volume\ + components/wifi + +all: slstatus + +$(COM:=.o): config.mk $(REQ:=.h) slstatus.h +slstatus.o: slstatus.c slstatus.h arg.h config.h config.mk $(REQ:=.h) + +.c.o: + $(CC) -o $@ -c $(CPPFLAGS) $(CFLAGS) $< + +config.h: + cp config.def.h $@ + +slstatus: slstatus.o $(COM:=.o) $(REQ:=.o) + $(CC) -o $@ $(LDFLAGS) $(COM:=.o) $(REQ:=.o) slstatus.o $(LDLIBS) + +clean: + rm -f slstatus slstatus.o $(COM:=.o) $(REQ:=.o) slstatus-${VERSION}.tar.gz + +dist: + rm -rf "slstatus-$(VERSION)" + mkdir -p "slstatus-$(VERSION)/components" + cp -R LICENSE Makefile README config.mk config.def.h \ + arg.h slstatus.h slstatus.c $(REQ:=.c) $(REQ:=.h) \ + slstatus.1 "slstatus-$(VERSION)" + cp -R $(COM:=.c) "slstatus-$(VERSION)/components" + tar -cf - "slstatus-$(VERSION)" | gzip -c > "slstatus-$(VERSION).tar.gz" + rm -rf "slstatus-$(VERSION)" + +install: all + mkdir -p "$(DESTDIR)$(PREFIX)/bin" + cp -f slstatus "$(DESTDIR)$(PREFIX)/bin" + chmod 755 "$(DESTDIR)$(PREFIX)/bin/slstatus" + mkdir -p "$(DESTDIR)$(MANPREFIX)/man1" + cp -f slstatus.1 "$(DESTDIR)$(MANPREFIX)/man1" + chmod 644 "$(DESTDIR)$(MANPREFIX)/man1/slstatus.1" + +uninstall: + rm -f "$(DESTDIR)$(PREFIX)/bin/slstatus" + rm -f "$(DESTDIR)$(MANPREFIX)/man1/slstatus.1" diff --git a/slstatus/README b/slstatus/README new file mode 100644 index 0000000..4d592bb --- /dev/null +++ b/slstatus/README @@ -0,0 +1,65 @@ +slstatus - suckless status +========================== +slstatus is a small tool for providing system status information to other +programs over the EWMH property of the root window (used by dwm(1)) or +standard input/output. It is designed to be as efficient as possible by +only issuing the minimum of system calls required. + + +Features +-------- +- Battery percentage/state/time left +- Cat (read file) +- CPU usage +- CPU frequency +- Custom shell commands +- Date and time +- Disk status (free storage, percentage, total storage and used storage) +- Available entropy +- Username/GID/UID +- Hostname +- IP address (IPv4 and IPv6), interface status +- Kernel version +- Keyboard indicators +- Keymap +- Load average +- Network speeds (RX and TX) +- Number of files in a directory (hint: Maildir) +- Memory status (free memory, percentage, total memory and used memory) +- Swap status (free swap, percentage, total swap and used swap) +- Temperature +- Uptime +- Volume percentage +- WiFi signal percentage and ESSID + + +Requirements +------------ +Currently slstatus works on FreeBSD, Linux and OpenBSD. +In order to build slstatus you need the Xlib header files. + +- For volume percentage on Linux the kernel module `snd-mixer-oss` must be + loaded. +- For volume percentage on FreeBSD, `sndio` must be installed. + + +Installation +------------ +Edit config.mk to match your local setup (slstatus is installed into the +/usr/local namespace by default). + +Afterwards enter the following command to build and install slstatus (if +necessary as root): + + make clean install + + +Running slstatus +---------------- +See the man page for details. + + +Configuration +------------- +slstatus can be customized by creating a custom config.h and (re)compiling the +source code. This keeps it fast, secure and simple. diff --git a/slstatus/arg.h b/slstatus/arg.h new file mode 100644 index 0000000..5f1f408 --- /dev/null +++ b/slstatus/arg.h @@ -0,0 +1,33 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef ARG_H +#define ARG_H + +extern char *argv0; + +/* int main(int argc, char *argv[]) */ +#define ARGBEGIN for (argv0 = *argv, *argv ? (argc--, argv++) : ((void *)0); \ + *argv && (*argv)[0] == '-' && (*argv)[1]; argc--, argv++) { \ + int i_, argused_; \ + if ((*argv)[1] == '-' && !(*argv)[2]) { \ + argc--, argv++; \ + break; \ + } \ + for (i_ = 1, argused_ = 0; (*argv)[i_]; i_++) { \ + switch ((*argv)[i_]) +#define ARGEND if (argused_) { \ + if ((*argv)[i_ + 1]) { \ + break; \ + } else { \ + argc--, argv++; \ + break; \ + } \ + } \ + } \ + } +#define ARGC() ((*argv)[i_]) +#define ARGF_(x) (((*argv)[i_ + 1]) ? (argused_ = 1, &((*argv)[i_ + 1])) : \ + (*(argv + 1)) ? (argused_ = 1, *(argv + 1)) : (x)) +#define EARGF(x) ARGF_(((x), exit(1), (char *)0)) +#define ARGF() ARGF_((char *)0) + +#endif diff --git a/slstatus/components/battery.c b/slstatus/components/battery.c new file mode 100644 index 0000000..1c753f9 --- /dev/null +++ b/slstatus/components/battery.c @@ -0,0 +1,247 @@ +/* See LICENSE file for copyright and license details. */ +#include +#include + +#include "../slstatus.h" +#include "../util.h" + +#if defined(__linux__) +/* + * https://www.kernel.org/doc/html/latest/power/power_supply_class.html + */ + #include + #include + #include + + #define POWER_SUPPLY_CAPACITY "/sys/class/power_supply/%s/capacity" + #define POWER_SUPPLY_STATUS "/sys/class/power_supply/%s/status" + #define POWER_SUPPLY_CHARGE "/sys/class/power_supply/%s/charge_now" + #define POWER_SUPPLY_ENERGY "/sys/class/power_supply/%s/energy_now" + #define POWER_SUPPLY_CURRENT "/sys/class/power_supply/%s/current_now" + #define POWER_SUPPLY_POWER "/sys/class/power_supply/%s/power_now" + + static const char * + pick(const char *bat, const char *f1, const char *f2, char *path, + size_t length) + { + if (esnprintf(path, length, f1, bat) > 0 && + access(path, R_OK) == 0) + return f1; + + if (esnprintf(path, length, f2, bat) > 0 && + access(path, R_OK) == 0) + return f2; + + return NULL; + } + + const char * + battery_perc(const char *bat) + { + int cap_perc; + char path[PATH_MAX]; + + if (esnprintf(path, sizeof(path), POWER_SUPPLY_CAPACITY, bat) < 0) + return NULL; + if (pscanf(path, "%d", &cap_perc) != 1) + return NULL; + + return bprintf("%d", cap_perc); + } + + const char * + battery_state(const char *bat) + { + static struct { + char *state; + char *symbol; + } map[] = { + { "Charging", "+" }, + { "Discharging", "-" }, + { "Full", "o" }, + { "Not charging", "o" }, + }; + size_t i; + char path[PATH_MAX], state[12]; + + if (esnprintf(path, sizeof(path), POWER_SUPPLY_STATUS, bat) < 0) + return NULL; + if (pscanf(path, "%12[a-zA-Z ]", state) != 1) + return NULL; + + for (i = 0; i < LEN(map); i++) + if (!strcmp(map[i].state, state)) + break; + + return (i == LEN(map)) ? "?" : map[i].symbol; + } + + const char * + battery_remaining(const char *bat) + { + uintmax_t charge_now, current_now, m, h; + double timeleft; + char path[PATH_MAX], state[12]; + + if (esnprintf(path, sizeof(path), POWER_SUPPLY_STATUS, bat) < 0) + return NULL; + if (pscanf(path, "%12[a-zA-Z ]", state) != 1) + return NULL; + + if (!pick(bat, POWER_SUPPLY_CHARGE, POWER_SUPPLY_ENERGY, path, + sizeof(path)) || + pscanf(path, "%ju", &charge_now) < 0) + return NULL; + + if (!strcmp(state, "Discharging")) { + if (!pick(bat, POWER_SUPPLY_CURRENT, POWER_SUPPLY_POWER, path, + sizeof(path)) || + pscanf(path, "%ju", ¤t_now) < 0) + return NULL; + + if (current_now == 0) + return NULL; + + timeleft = (double)charge_now / (double)current_now; + h = timeleft; + m = (timeleft - (double)h) * 60; + + return bprintf("%juh %jum", h, m); + } + + return ""; + } +#elif defined(__OpenBSD__) + #include + #include + #include + #include + + static int + load_apm_power_info(struct apm_power_info *apm_info) + { + int fd; + + fd = open("/dev/apm", O_RDONLY); + if (fd < 0) { + warn("open '/dev/apm':"); + return 0; + } + + memset(apm_info, 0, sizeof(struct apm_power_info)); + if (ioctl(fd, APM_IOC_GETPOWER, apm_info) < 0) { + warn("ioctl 'APM_IOC_GETPOWER':"); + close(fd); + return 0; + } + return close(fd), 1; + } + + const char * + battery_perc(const char *unused) + { + struct apm_power_info apm_info; + + if (load_apm_power_info(&apm_info)) + return bprintf("%d", apm_info.battery_life); + + return NULL; + } + + const char * + battery_state(const char *unused) + { + struct { + unsigned int state; + char *symbol; + } map[] = { + { APM_AC_ON, "+" }, + { APM_AC_OFF, "-" }, + }; + struct apm_power_info apm_info; + size_t i; + + if (load_apm_power_info(&apm_info)) { + for (i = 0; i < LEN(map); i++) + if (map[i].state == apm_info.ac_state) + break; + + return (i == LEN(map)) ? "?" : map[i].symbol; + } + + return NULL; + } + + const char * + battery_remaining(const char *unused) + { + struct apm_power_info apm_info; + unsigned int h, m; + + if (load_apm_power_info(&apm_info)) { + if (apm_info.ac_state != APM_AC_ON) { + h = apm_info.minutes_left / 60; + m = apm_info.minutes_left % 60; + return bprintf("%uh %02um", h, m); + } else { + return ""; + } + } + + return NULL; + } +#elif defined(__FreeBSD__) + #include + + #define BATTERY_LIFE "hw.acpi.battery.life" + #define BATTERY_STATE "hw.acpi.battery.state" + #define BATTERY_TIME "hw.acpi.battery.time" + + const char * + battery_perc(const char *unused) + { + int cap_perc; + size_t len; + + len = sizeof(cap_perc); + if (sysctlbyname(BATTERY_LIFE, &cap_perc, &len, NULL, 0) < 0 || !len) + return NULL; + + return bprintf("%d", cap_perc); + } + + const char * + battery_state(const char *unused) + { + int state; + size_t len; + + len = sizeof(state); + if (sysctlbyname(BATTERY_STATE, &state, &len, NULL, 0) < 0 || !len) + return NULL; + + switch (state) { + case 0: /* FALLTHROUGH */ + case 2: + return "+"; + case 1: + return "-"; + default: + return "?"; + } + } + + const char * + battery_remaining(const char *unused) + { + int rem; + size_t len; + + len = sizeof(rem); + if (sysctlbyname(BATTERY_TIME, &rem, &len, NULL, 0) < 0 || !len + || rem < 0) + return NULL; + + return bprintf("%uh %02um", rem / 60, rem % 60); + } +#endif diff --git a/slstatus/components/battery.o b/slstatus/components/battery.o new file mode 100644 index 0000000000000000000000000000000000000000..ef58dd05d1833a939f4f2c657f887fc1d1fbce2b GIT binary patch literal 5208 zcmb_gZERat89sIs>acR{jC* zwU$(as!B6gADkls%icc^{&fB1#&kXBUCViIbDSu0Vg14#=h}$V zgsQJDY>-gSyDEroIQ_-}!~4_0!`VaG!_R*Z{p^QB4;rW5g&SjPO@f+t<3?>g{Ba+{ z#!Ophl3PBVh!87XH)_R1ghFiknrutg7q%F+%}@hjFww^2e~Y_ax>&tD;{v*zu5-kg z`7t*(Y;0M_t-I|$e(D0!bkL71JCq%~CA#FY(Loc=4<+I}y35?;be%`HKUW)0tikeK z2$DjfEH7eviEg=_o@KWKZGSsS!@F_wj#j7Z*UnIp<>)9j-Mp!H-elfbgPIRAe5ro;PD@1t5=$HlJMI!umG5T#H#(3S1M7w7lnA>`NVQn;daWQ)6 zMaqNHefPR>*#J5V8eQYvcDnGmut1xQX$1Kk3{7#ka8FM%?Rywwl zmcNPrWx8tHR>_sNM|E;A&U)bx=C`mewzpa=vNGFOcJ+o^B=`R%S9*O*`!cM*xA)6> zvY!Gfm-Y0{)Q;3Pz0z~17&2U=bY2Xn-@k8&g&C^@TSY$z#yb6)>mj}_@B9$+=N-g> ztn)h-I`J(Qnuvuqu2~&!@9z+J;wF?aoCB)h z&H$bk_%{Oh-2(URH5b1k@Q0cZA7uo7GJy99{Fedz>jM8(0RN`I_XlvlhT7S00{8*J ze?5R7;d4~f%`(EL5f)r2a=e`>pGF+9sm1dZ6r5)(e2Vbf=_KWO^O`5@@n!f=EQ3F_ z41Shy*xw*Zjz1%Wom+IQnfFwcu0Uzf0r)VtsWQq&;D*h9J<7!z=KgoYi;6eMpQ~0Pk$$v}Xe_Fw> zEBI#=JR;5y_BSf{4uK;c+~LyxL4~j8;kyd|;|l)~g|Ei*1BH)UNZNl=;p0PE;%5~; z?m&tELE)?MhY>hQF#axq2lKgC;j8gKpzziB^9p|r`H}IADEKE7{DgvQ3Vvo8`%ftR zsKS3r;j8(1M&aZBknudL;A<89yn^4Z;D1)^tNXoAy!f&FNrnG&1;;yH`h8Bp@jWW> z3j#;})jE7r!PRpl8W$WhbZ!&pE$>;0<9i%}y+b4}-vev&R zz&|JOo&YZSy1 zU!!7vtW-_minna~Z1)XXqxlir9JfT&AHCB_6)6sWsbmO){9V+IKl8bAj2^Xwy2;Q_ zl`DA2NhX9oo=NzTbtUWN3jz&? +#include + +#include "../slstatus.h" +#include "../util.h" + +const char * +cat(const char *path) +{ + char *f; + FILE *fp; + + if (!(fp = fopen(path, "r"))) { + warn("fopen '%s':", path); + return NULL; + } + + f = fgets(buf, sizeof(buf) - 1, fp); + if (fclose(fp) < 0) { + warn("fclose '%s':", path); + return NULL; + } + if (!f) + return NULL; + + if ((f = strrchr(buf, '\n'))) + f[0] = '\0'; + + return buf[0] ? buf : NULL; +} + diff --git a/slstatus/components/cat.o b/slstatus/components/cat.o new file mode 100644 index 0000000000000000000000000000000000000000..b861349cd8c0b33a922d298f79481f4e1fc8ae1c GIT binary patch literal 2128 zcmbu9&ubG=5XUD;Ypd2ZN|j(m_Mo;FyCiLuQm`hiwy8v^KMMXTC5@W~Y?8X!VylQk zsSq&W)&Im(3H~~J?ZuM^!Gnr|V1+v0&6{MiO+a+u<;{HF%)EVX-sJK5#JJz*BM~2s zP|Xrb^uDF0M;$dv8ttL)dyo8zO~*^8z+%^?uf~g;mp{RX7eB;HXB=&jB}P>YL{9T+Kp?!CD7(f+xHMOZ)4Puqx`!#9TF4hnWzfXf*s$I+Vdm_7UXKhK14dY196F&? zWFZ_k$OAbiE=`l4s0_y6?Fe+8M{V8btjpc`sNU{$qKJGCu8?mz=egiq4=BKiY)%HsO&b{B#pesibYB z$ViNZ@e{#MKVap#(A-j*((|TWP)~;LC#@V6Y|BbzEY7);2L$(mxA1$bA~-(;?*ex! zTxT5uf2;{V3CIGDVhTSC$O2#NCHw*)3pm<9_;o-QV@|OMooksIl-> zKon@I%su+cpteu=AgYT>|XGF8ig`{Dd%QhKzl6I1exk7;qD-Q$i z5rfN-%4f6Om}KPgwrOzd^%d-7>aMcqb4$je#f@#*D;$c1W@a{RC9`Jr3;s*dIT}5* z!;>YdY25XCcl_s6?J&VP+Z zKOtv754XtvIGW}`G{e?H$8*wky{zGa;@8XSm +#include +#include + +#include "../slstatus.h" +#include "../util.h" + +#if defined(__linux__) + #define CPU_FREQ "/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq" + + const char * + cpu_freq(const char *unused) + { + uintmax_t freq; + + /* in kHz */ + if (pscanf(CPU_FREQ, "%ju", &freq) != 1) + return NULL; + + return fmt_human(freq * 1000, 1000); + } + + const char * + cpu_perc(const char *unused) + { + static long double a[7]; + long double b[7], sum; + + memcpy(b, a, sizeof(b)); + /* cpu user nice system idle iowait irq softirq */ + if (pscanf("/proc/stat", "%*s %Lf %Lf %Lf %Lf %Lf %Lf %Lf", + &a[0], &a[1], &a[2], &a[3], &a[4], &a[5], &a[6]) + != 7) + return NULL; + + if (b[0] == 0) + return NULL; + + sum = (b[0] + b[1] + b[2] + b[3] + b[4] + b[5] + b[6]) - + (a[0] + a[1] + a[2] + a[3] + a[4] + a[5] + a[6]); + + if (sum == 0) + return NULL; + + return bprintf("%d", (int)(100 * + ((b[0] + b[1] + b[2] + b[5] + b[6]) - + (a[0] + a[1] + a[2] + a[5] + a[6])) / sum)); + } +#elif defined(__OpenBSD__) + #include + #include + #include + + const char * + cpu_freq(const char *unused) + { + int freq, mib[2]; + size_t size; + + mib[0] = CTL_HW; + mib[1] = HW_CPUSPEED; + + size = sizeof(freq); + + /* in MHz */ + if (sysctl(mib, 2, &freq, &size, NULL, 0) < 0) { + warn("sysctl 'HW_CPUSPEED':"); + return NULL; + } + + return fmt_human(freq * 1E6, 1000); + } + + const char * + cpu_perc(const char *unused) + { + int mib[2]; + static uintmax_t a[CPUSTATES]; + uintmax_t b[CPUSTATES], sum; + size_t size; + + mib[0] = CTL_KERN; + mib[1] = KERN_CPTIME; + + size = sizeof(a); + + memcpy(b, a, sizeof(b)); + if (sysctl(mib, 2, &a, &size, NULL, 0) < 0) { + warn("sysctl 'KERN_CPTIME':"); + return NULL; + } + if (b[0] == 0) + return NULL; + + sum = (a[CP_USER] + a[CP_NICE] + a[CP_SYS] + a[CP_INTR] + a[CP_IDLE]) - + (b[CP_USER] + b[CP_NICE] + b[CP_SYS] + b[CP_INTR] + b[CP_IDLE]); + + if (sum == 0) + return NULL; + + return bprintf("%d", 100 * + ((a[CP_USER] + a[CP_NICE] + a[CP_SYS] + + a[CP_INTR]) - + (b[CP_USER] + b[CP_NICE] + b[CP_SYS] + + b[CP_INTR])) / sum); + } +#elif defined(__FreeBSD__) + #include + #include + #include + + const char * + cpu_freq(const char *unused) + { + int freq; + size_t size; + + size = sizeof(freq); + /* in MHz */ + if (sysctlbyname("hw.clockrate", &freq, &size, NULL, 0) < 0 || !size) { + warn("sysctlbyname 'hw.clockrate':"); + return NULL; + } + + return fmt_human(freq * 1E6, 1000); + } + + const char * + cpu_perc(const char *unused) + { + size_t size; + static long a[CPUSTATES]; + long b[CPUSTATES], sum; + + size = sizeof(a); + memcpy(b, a, sizeof(b)); + if (sysctlbyname("kern.cp_time", &a, &size, NULL, 0) < 0 || !size) { + warn("sysctlbyname 'kern.cp_time':"); + return NULL; + } + if (b[0] == 0) + return NULL; + + sum = (a[CP_USER] + a[CP_NICE] + a[CP_SYS] + a[CP_INTR] + a[CP_IDLE]) - + (b[CP_USER] + b[CP_NICE] + b[CP_SYS] + b[CP_INTR] + b[CP_IDLE]); + + if (sum == 0) + return NULL; + + return bprintf("%d", 100 * + ((a[CP_USER] + a[CP_NICE] + a[CP_SYS] + + a[CP_INTR]) - + (b[CP_USER] + b[CP_NICE] + b[CP_SYS] + + b[CP_INTR])) / sum); + } +#endif diff --git a/slstatus/components/cpu.o b/slstatus/components/cpu.o new file mode 100644 index 0000000000000000000000000000000000000000..8b3d1b15663a246b52c20830c78340280cebfc84 GIT binary patch literal 3168 zcma)7Z%iCj5Py56aJIN$gUQ7z z5JGKGQ$jA`W8)`2^n)?R_|Z>>0#$5H<2Ube;i7(m&@>YLV2laQynS;luaI;u^JeDv zX5PFvJMZ0%{@CjQMPWn=yTo=aLK#~O?&?vlMp+9}*P$bRy zhV~A$=lb+uWXYWSV*~NI<(>P*Hgl{;-#EnB_c(BTD*!(8SM*@ge5H*Cx`+9MIlCHK z;W=(TTEO*6hjAT|t$M~Yc+Tpyp7sFH-mPn9UF)uE9d#{K*MfuQ>_)3M#7gF$u~PIm zvt<5amIjw1OSBnn_MfJf&$c0L<#BafAFgh$SE{FVP+NgD;7;Hu@ZeNq%coy~W9^69 zJ&}cPw|3XFNP1S~LHWnpDvYb;d(|G@1Iu;S@=AFb^3;B>Jg)qNNv9g!;mX6UK;>a& zTA#s4QTo(;AGhy+@^fMejbac;fr z|81#$YrPC#$n#x6-}VoSEbL4=;iUcXSi*KtckN6#kuM^5;*cuXABCNSH9nRdjVFqQ zI0CHwl%uuBQU@^$=L@++*l{hFwI?Cd+GRG-+j~*#7_hT$E~iDhjB`e(mhV0(RNM}0 z0B!}w_855U9Ts402{Gs}PN-|ZyYmX4r(Rc>XOn*$k77)jdYdT|t;+G{rr-iNBYr~6 z;qI8JYJnj&cpB6$fukRLL%pp8uBnSkzxpNcx5|*ZpagzBq6Yhqj;cZ7`h>vH2DZKP z!~_6`_Pv>itG+#OyJ`1`vM*Ip91E#W%1 z8zq#nlYkuaor~8Lu(QD4p7w^kdH~*g0Dc85aKE@;ROVNaDD9c zYiIyXdV=HFJLG@Ehoe8?pZjoZX2KVIIQrvWk-qRmJuls%I}(of2+ z^J^b|#D}j59M6mQhx|3rk?_38MBPFmJV_IVGnsL%5oS1U!INpy3ih~Vxb}q0jHKmS z%ouSTW)yO0pnJrCDQmM)1wr_p$?j_c81yd+I(KfdBvi literal 0 HcmV?d00001 diff --git a/slstatus/components/datetime.c b/slstatus/components/datetime.c new file mode 100644 index 0000000..5b10daf --- /dev/null +++ b/slstatus/components/datetime.c @@ -0,0 +1,20 @@ +/* See LICENSE file for copyright and license details. */ +#include +#include + +#include "../slstatus.h" +#include "../util.h" + +const char * +datetime(const char *fmt) +{ + time_t t; + + t = time(NULL); + if (!strftime(buf, sizeof(buf), fmt, localtime(&t))) { + warn("strftime: Result string exceeds buffer size"); + return NULL; + } + + return buf; +} diff --git a/slstatus/components/datetime.o b/slstatus/components/datetime.o new file mode 100644 index 0000000000000000000000000000000000000000..9181ae672c36be74ce6163f4d73ed4f323273efc GIT binary patch literal 1960 zcmb_cO=}Zj5S~q2n`(_wDu}JJhbSrP(x^zOD3MsRLJ_Hoh=sUKHf?A=>h1>Hig+j< zLMim<(PRIFQa^ryC-LIZ3SPvU3U!{%JLz`WT*L>a@60n_*>~pc^U0|jF-;?ZMptRq z5|$|4yQ^n?HA@LPNIwsq{B_4%{hlnDYa^%9>@iz2skqtto!Qw&oZ0$nwt7>({)V`U z*?McXKAY<&+TJfJ>Yds8WWM;=OlG#s^(*lC4z||rrs5^@%#dH*>ublaen>ui?|M$z ztJLfXecE=LRZnN4QlHc9rJ`+@Tz$4#F58aoR#t4Hd@eVkr}K8*Yc%xCMdN}orZ0|< zDisX@d}flRk0pQW9>s{Z!1b^I&~=twzvlbp&NSL<4{0MEQCmCO7B@;@9rQVK$Eh;{D&i+));Me;CJ^ zh~iUS_;eRO(}lm(g{P9`*_g3WBx5Q!*0HJDC|Xr`h{sH_3iQNs>QpGWo>g2Z6z3NT zWvfyp^0$q9V1BrbKRa!VvJQaX$0Gb?kPMzb^|J_{1Ia)|s`LS6Ly{xvef~Q`rajM6NubV~RhmczMT)rq`l`&T#*;>_^Ri&BxxO=6RMN zq(ABhA^qjdvJ?7PFo^YU%GN`? +#include + +#include "../slstatus.h" +#include "../util.h" + +const char * +disk_free(const char *path) +{ + struct statvfs fs; + + if (statvfs(path, &fs) < 0) { + warn("statvfs '%s':", path); + return NULL; + } + + return fmt_human(fs.f_frsize * fs.f_bavail, 1024); +} + +const char * +disk_perc(const char *path) +{ + struct statvfs fs; + + if (statvfs(path, &fs) < 0) { + warn("statvfs '%s':", path); + return NULL; + } + + return bprintf("%d", (int)(100 * + (1 - ((double)fs.f_bavail / (double)fs.f_blocks)))); +} + +const char * +disk_total(const char *path) +{ + struct statvfs fs; + + if (statvfs(path, &fs) < 0) { + warn("statvfs '%s':", path); + return NULL; + } + + return fmt_human(fs.f_frsize * fs.f_blocks, 1024); +} + +const char * +disk_used(const char *path) +{ + struct statvfs fs; + + if (statvfs(path, &fs) < 0) { + warn("statvfs '%s':", path); + return NULL; + } + + return fmt_human(fs.f_frsize * (fs.f_blocks - fs.f_bfree), 1024); +} diff --git a/slstatus/components/disk.o b/slstatus/components/disk.o new file mode 100644 index 0000000000000000000000000000000000000000..edb3cfbdd6cfb41a0401c5a915dfe2cefb93ac49 GIT binary patch literal 3168 zcmcJQO>7%Q6vyADO_M_FHKi3+8=*Zo)X=hu8<46Zz$hu%L#Ysjs$at0*y}oS{ULi( z927yMs8X#EDMv1#ic@b~IU$pBNI4*J>jlISK@Y9DwTSZmv-9v|>jEn3lV)e;H}7Ni z?VH(;j~;t-$g)VpqSvTD6H0V-v_H9*Io z=dFh6(O;l?xx26@+x0p>d8@Btu3)zN+a7OaF`e}6FBj99uW74Z@K)YUw~O9^-O5`y zthBx5TT5rJ|DRx&yp`#6#=G2YkMunI1w`+xFaKvbplk~`^6IE};4>mjOw zlH7*5%^ZJ^hKRagTev|mcDVJ|EwwH+Y*94d&N`6YQAgH??~v6_TKjg4jIOb=!+cDy zRnZ?!B$tP#6KmGcY$EwaVw91?EyoS=Jsy3X>!yyp>Oc9p0(+Jw9(_L-#1HTw!Fz3` zJNE~zZ5eQKvF|85n=Mq8(zeZzXS);`=99fyo>9|n6#46~A!oacxaysmJ;x2-EiNvD zL45Kd92dqQ{o~9LSK_Jf!R*vS^v`SkSCBv!v8(VHey(Y*z6TVFbFGS7AotkR1RhyD zCh<6=mhz=$5Rk5M`oM42s8kK}<@u^#qkNth3YC1JT*;UGxr>oSBWMxCt)+vVcFyP53Gx zOFZsp5q==<7n(!gjQgjdk2Uc>tn-WgT8%cn(8 z3$5@lxrKVQ$~Qc@wR#x1e2>4V4v3y#sLi{LW}VMRxWI<+9+dfj`PD%0?$JAkO_AF8 zO_yT^*=r_`=lV0KH9YolL+*3jOj$z_vt+dW4j#i6H2_IPow^6X<$t9yor%R29*=*J z7vS?z?XzqPpNF`aBJrOxA&(`#^f}F<|3Y86q4yuZo8|qbe@olT{Usijw7nxh_Yzn7 zlgwpos$Tt%`75!}2)DSp*uQN$<+1Er@JBpA{J8yX4X%lz?&J0g%m>xaSJ)KGdG#bh z{ove-z0}X3*f9B27sQfI4(>>}jN9XmiPsJzO6mHY$Hb6$u2CNY?RB6lhAoD1`@aCI CzXsF* literal 0 HcmV?d00001 diff --git a/slstatus/components/entropy.c b/slstatus/components/entropy.c new file mode 100644 index 0000000..65010b0 --- /dev/null +++ b/slstatus/components/entropy.c @@ -0,0 +1,29 @@ +/* See LICENSE file for copyright and license details. */ +#include "../slstatus.h" +#if defined(__linux__) + #include + #include + + #include "../util.h" + + #define ENTROPY_AVAIL "/proc/sys/kernel/random/entropy_avail" + + const char * + entropy(const char *unused) + { + uintmax_t num; + + if (pscanf(ENTROPY_AVAIL, "%ju", &num) != 1) + return NULL; + + return bprintf("%ju", num); + } +#elif defined(__OpenBSD__) | defined(__FreeBSD__) + const char * + entropy(const char *unused) + { + // https://www.unicode.org/charts/PDF/U2200.pdf + /* Unicode Character 'INFINITY' (U+221E) */ + return "\u221E"; + } +#endif diff --git a/slstatus/components/entropy.o b/slstatus/components/entropy.o new file mode 100644 index 0000000000000000000000000000000000000000..85471743ed2bac674fd86d6737e4c5d250966806 GIT binary patch literal 1824 zcmbuAPiqrF6u{r6sf`%ZC>4aN>>-uMTbYE>H@jcH(sK8W z(I32TCe7Y*#_WC$nb~`gNmR@Wb74R*J%pWi=|^uDo-`rb@Z56NZ~NID+jHz%*0Y?7 zThH1~;JJ-<(RyZW*8mFn{8fFifYfz$V_94gOL}AFoK&ecKpaOJ$25+@-3^EV^ojBI zNY`XwUC~)=F#h$(h6+I-f#DgT$i8YAW4{ZKU)VDmPLILX(8* z#Np>)(%RI7&KwCH>23E5?U8mt`%&ct8poA9;kzND1`cCXZ-C4J{Ne!|WKTpH#9Drd z9tJaL_+`tfLaE_xJ3$qSML)30JH_(WPO%zx5P%N``x5r#&tNFC^0kQ5o|p^Ci5*h- zO@+@Wd{g06i}UD`Q+^sF5q`TKSS1jC;0@<3);zmriNJ0JASza1fhhSt2+t*h+znxX zD7*DKo(TxY4Qzo|?ozmEX+L(F0xx&N_JTHsQbK#HSoN&BJ$i%xQgn=_J4I)sN=_Qw ze_kVBRp!y4v(2dx^*wn=Ey?K~QY`oHq~vEM=iisa@S2s#9Ia3HjB@^Kyn(Tl^D+)q zxc+$+qR#bs&Plcu@%tccJ;FJT=R3I0y6XB(H55JS`w-XY{_eYzX#bEg>vHCa&!6q5 zs8G&md`=cxVMjSf +#include + +#include "../slstatus.h" +#include "../util.h" + +const char * +hostname(const char *unused) +{ + if (gethostname(buf, sizeof(buf)) < 0) { + warn("gethostbyname:"); + return NULL; + } + + return buf; +} diff --git a/slstatus/components/hostname.o b/slstatus/components/hostname.o new file mode 100644 index 0000000000000000000000000000000000000000..20e1d3388ed7e9eef8888b001cb532dc951dc55f GIT binary patch literal 1680 zcmb_c&ubG=5S~q|tyt4l6be;YFa7|1WNQzlpe%%%2t`EkARcs+ZX2-KO?O{0(SwKL zA%{Z$2QU5=67)atqcWYKZ}aDW+^_GS1ND}siR%4NpW*c1)%zb`edyWlpuT?tOiH_hNAI@+ z-HH<3=!JeeSS6}etE%mLn{+I}fNtGyo^Zg6*)3 z*R6D2?qboTf0|-jyhy0*1AH#2*{!DpF+0L%DUE8BaeusjR$>JBbB$Pi5lMGcb3O1^3V63=>8Cg+K6w&ZF9w`rAeHENs9R#i!M3k- z(AA_ieC?BJBnhcFf`f2Zxulv=yUj0&R2b<%@l&~$XutW?_*>zw>cmkeh;@%sQ7~vd z-i&ec{{n}r;4PpxS$M{gdCD4Mvsh#Yz4Edo+Y6>iPYi#YHF9N6csIaB7Vz@F00-!y z`t3KrKjwv+|C;Y|E^02ZWFh;{XGykYf6<=dD!I5l<2yNC@NA(U-+WEu~o%f qbO48e?+^CL=c8tR_Ds +#include +#include +#include +#include +#if defined(__OpenBSD__) + #include + #include +#elif defined(__FreeBSD__) + #include + #include +#endif + +#include "../slstatus.h" +#include "../util.h" + +static const char * +ip(const char *interface, unsigned short sa_family) +{ + struct ifaddrs *ifaddr, *ifa; + int s; + char host[NI_MAXHOST]; + + if (getifaddrs(&ifaddr) < 0) { + warn("getifaddrs:"); + return NULL; + } + + for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { + if (!ifa->ifa_addr) + continue; + + s = getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in6), + host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST); + if (!strcmp(ifa->ifa_name, interface) && + (ifa->ifa_addr->sa_family == sa_family)) { + freeifaddrs(ifaddr); + if (s != 0) { + warn("getnameinfo: %s", gai_strerror(s)); + return NULL; + } + return bprintf("%s", host); + } + } + + freeifaddrs(ifaddr); + + return NULL; +} + +const char * +ipv4(const char *interface) +{ + return ip(interface, AF_INET); +} + +const char * +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/ip.o b/slstatus/components/ip.o new file mode 100644 index 0000000000000000000000000000000000000000..b4ce491d9caae7bab8b430f6d7e40d219bfc2234 GIT binary patch literal 3144 zcmbuAZ)hAv6u@UMNxRi_bJ{`=Qrkr?8nIpOnjjjqWOGe2#j~U~kyg{jOKvYYo7|my zo1`&?5|S$}mxv!k6pCN1-~1#fQcqeXf}kG@LFgxKxk^!KKS*i%-tN5KbiD)7$L-9# z-@G^T=FOiw*Pk2+DGDP|*g;m)h%&aW*4n*ZvzKXXJ2PK1M@;v&Iegf?J93OK-PD^I zOY`!J9i3ps-LIn&0DSFiR86iq(OuWkmzPJQYN@iYgRi}Wdc5M{YJr#Ad1=Er$IFWm zUfOhS4SlJAd(!>0KmNm8N`Jg^X*bx5K^E1d`>Xq%r@elnRGF>taw3vB^g`$C7rYEJ zdOfAzo!#y&-^HJfyWfi$4 zyNxa*rWc-nMl>-B#vnB;3?IfZcw~e@W-7><;6uT-4qvTb@%riPDePf=C)lDW@4U*C zGhwB@b*uV57!Lu%BZ0CFo%^)#d!arpvewkE>8s6$w9fM_rWRY?GN}EmhF;dLs;_9* z)KRES1an%<)H+Q~2N!Vd(^NlhSf(eMsBtYTqD?FY`bUC&iuHgNUJaRAG zA_T#g3j2t2gdoW9-6B4R5Cr+7@DX1@2!b5X6!A|Gf*{`xAMwu+f*{8n68{__2*!h_ zmiSi)LC{`~XWgT|J>CJb|4DGPZ +#include + +#include "../slstatus.h" +#include "../util.h" + +const char * +kernel_release(const char *unused) +{ + struct utsname udata; + + if (uname(&udata) < 0) { + warn("uname:"); + return NULL; + } + + return bprintf("%s", udata.release); +} diff --git a/slstatus/components/kernel_release.o b/slstatus/components/kernel_release.o new file mode 100644 index 0000000000000000000000000000000000000000..978d5f9747954092bdc31ed1362a7656f5801bc3 GIT binary patch literal 1872 zcmbu9L2DCH5P)aX##XJdmZCyM7HOqYeP*>tDOv(Svtp@55cCu_$;OlnSPd-OrZ$6$(e4*fH?bevp zwl}Ykqlwl2deq*0H~AC+bE~aq?2VT?yJXLd>*c~^hp&I2D(_c4r|!+hH1^Jiz;n4=gzQ6wO|l+6g7#OTe=MifHpDtIb@rtyYq&g$4XiZ==H~iKfDFT z+Nd!xGBmt}!6%TDlKAwwk$OFlD5r+W{)$|)ZaTDInNyXs(UJYmN~`KnF!A@r+AtZzQmju z^-OpZ=ya8&57g`i4K=zuB&0Vuyg4uxCF0#$6( z>v*9-d5zFjcxBJ&qhSA@x2l?cqv`r#3sY%9w~{aW_$0bJ_%Fl6Y`T+l#!<i{PKZqmc%KJFZ{4{fUpN!$H7_l*4|18ean*W+l_n+3hfEpF4 ze;^9cmijVgn5AQJ+w7Y$E_pIu$9b`%p`W5o#E!?_#W}j~J$DlQ&!{BJouT`c^A~U* z4O%mvpXNey63AmbAD?R9{?Bnkq|elUdQXxsykBi9RpI*I$w3)GrGLSAKCKz=JtDZn aKjPB{qc>W)8F1+;s literal 0 HcmV?d00001 diff --git a/slstatus/components/keyboard_indicators.c b/slstatus/components/keyboard_indicators.c new file mode 100644 index 0000000..5f62bb7 --- /dev/null +++ b/slstatus/components/keyboard_indicators.c @@ -0,0 +1,50 @@ +/* See LICENSE file for copyright and license details. */ +#include +#include +#include +#include + +#include "../slstatus.h" +#include "../util.h" + +/* + * fmt consists of uppercase or lowercase 'c' for caps lock and/or 'n' for num + * lock, each optionally followed by '?', in the order of indicators desired. + * If followed by '?', the letter with case preserved is included in the output + * if the corresponding indicator is on. Otherwise, the letter is always + * included, lowercase when off and uppercase when on. + */ +const char * +keyboard_indicators(const char *fmt) +{ + Display *dpy; + XKeyboardState state; + size_t fmtlen, i, n; + int togglecase, isset; + char key; + + if (!(dpy = XOpenDisplay(NULL))) { + warn("XOpenDisplay: Failed to open display"); + return NULL; + } + XGetKeyboardControl(dpy, &state); + XCloseDisplay(dpy); + + fmtlen = strnlen(fmt, 4); + for (i = n = 0; i < fmtlen; i++) { + key = tolower(fmt[i]); + if (key != 'c' && key != 'n') + continue; + + togglecase = (i + 1 >= fmtlen || fmt[i + 1] != '?'); + isset = (state.led_mask & (1 << (key == 'n'))); + + if (togglecase) + buf[n++] = isset ? toupper(key) : key; + else if (isset) + buf[n++] = fmt[i]; + } + + buf[n] = 0; + return buf; +} diff --git a/slstatus/components/keyboard_indicators.o b/slstatus/components/keyboard_indicators.o new file mode 100644 index 0000000000000000000000000000000000000000..7df304bdbb875b6587dd0856d65cdc5e6dab0227 GIT binary patch literal 2448 zcmbuAO>7%Q6vt;1yD`+=m=8fj3tA)>8MUlz2vS-F@Y-&&QC+BLQ_M$Lt?dntve{jB z$4U$bA|*jxjG-KmdgRItZaoD{rR2)72nmjW3PKe(+RD7Qo^dvdeSyF9Ja2yU-puTL z`GYg%xiLW?TmpHK?AJIYBz0)t&j)Uvh~x;zF^K9#z9A{Kl%jrX&+zHO-f%{P~nx0EI2ZAH6Y zdBriT(u(Jpdh4__r>~esU81&R1D5K2PRM+*cv{NL8y2-~DK{-YCub#R=4s~QkSJV` z6j&T={^dmipU_1%4u(Qs0^4sFf_A>Q0y$WJ7-CVvd#@5$@J{>EFQ=g0%M5z-ih?$S$ikSWIkRr}(O_anhgz=;x&XmNgB4!{2LJMN5ASPHR zBMR&~MsD|pHIENDk&gy}_;m+`bA2!rAIuq877W)bDm;tBcwq#;G=je|f;UERX9V9K z!LN?sWYuU@ZQZSFD^`7_rc>MX~+FT}; zqG@{uJFdi|u4Nh)(X<+EIfh1U(_S}R&9rMF)^wZ!^Qc~1)oP7ZZ5d8FOh3?5tiZb!$9WYY2;=Vq1RKHX?^sRQapA#nX$w-Z zL!+TByZV|jn8E*YB*?~34*gvO{pEvS_J%MY3${E1auhsVtNeiU9S0#O!4hy!(B;p{ z6gGnJd?DxWATpF09jK50HU3H9*yn%E&p|E@^( +#include +#include +#include +#include + +#include "../slstatus.h" +#include "../util.h" + +static int +valid_layout_or_variant(char *sym) +{ + size_t i; + /* invalid symbols from xkb rules config */ + static const char *invalid[] = { "evdev", "inet", "pc", "base" }; + + for (i = 0; i < LEN(invalid); i++) + if (!strncmp(sym, invalid[i], strlen(invalid[i]))) + return 0; + + return 1; +} + +static char * +get_layout(char *syms, int grp_num) +{ + char *tok, *layout; + int grp; + + layout = 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])) { + /* ignore :2, :3, :4 (additional layout groups) */ + continue; + } + layout = tok; + grp++; + } + + return layout; +} + +const char * +keymap(const char *unused) +{ + Display *dpy; + XkbDescRec *desc; + XkbStateRec state; + char *symbols; + const char *layout; + + layout = NULL; + + if (!(dpy = XOpenDisplay(NULL))) { + warn("XOpenDisplay: Failed to open display"); + return NULL; + } + if (!(desc = XkbAllocKeyboard())) { + warn("XkbAllocKeyboard: Failed to allocate keyboard"); + goto end; + } + if (XkbGetNames(dpy, XkbSymbolsNameMask, desc)) { + warn("XkbGetNames: Failed to retrieve key symbols"); + goto end; + } + if (XkbGetState(dpy, XkbUseCoreKbd, &state)) { + warn("XkbGetState: Failed to retrieve keyboard state"); + goto end; + } + if (!(symbols = XGetAtomName(dpy, desc->names->symbols))) { + warn("XGetAtomName: Failed to get atom name"); + goto end; + } + layout = bprintf("%s", get_layout(symbols, state.group)); + XFree(symbols); +end: + XkbFreeKeyboard(desc, XkbSymbolsNameMask, 1); + if (XCloseDisplay(dpy)) + warn("XCloseDisplay: Failed to close display"); + + return layout; +} diff --git a/slstatus/components/keymap.o b/slstatus/components/keymap.o new file mode 100644 index 0000000000000000000000000000000000000000..a6823fc07da1ea17864c973f0c96b7ac4758bb45 GIT binary patch literal 4048 zcmb`Ke`p*<6vyZCqm4D)oUPH=YFYFeBDKq1o7zjMC7WE6sU9_$MuS?( z+r&hQ6=H?uOcj5DfBKJq`Qwj*f?$bF0~HjDhzLas{$ooDRm6%S#P@dRC3D+b1o6S_ z%zozk-ptO-zS}!_Fg?%^i7>JVJHXcNh%$EZ*0px8*X(6c*2aEo+xD0Kg#Nfbq8}L< z=5yD0o>%v8?*a*TPsEaml`E*`?h-$>FtwS_KZLi51&>~xg`xa@pC5A1gUs2=-E(J~ zJh$s!H?a0v*Tki(IBV`+=krHmoo8{ zPMC4*VB!X!--DA&`*U$qu~y&3UF4@OIWwuALag<~aX!BhRlJ(uZaUV%-9NbN#6RlyvlB*h9WIaPRwC-*%p`Q#Dk~Z z8)DgTy4+p#ywmQ_pW=Rb%jL&&Y0ajZx%?4yv}~4A6P0qonBAui7!w6EuR4}$0ao)qXQPu@y-=`n zkC?Mr%dqpZ(7+DEG1W=YiRwYqIcyZoiY&BE$DS~!J)v5eEoQAkMQDc|2oR?AMpP>( zVWSXOcdQ}?m-WX?M>T+}CFo!~_GQ?1h}~bXDrTK$%OPKVICDC0PP2)U>9BH+WsQo7 z2jE|9u)lww+BImF9LrJ@-P&#~u9lPcizdU<9fi^iW$^F_YhY{vStArQY^zY#`XgRH z?loG3)!yIkV-|V-F&3GLMz*%DZ+Q*GY2bH@zMs%}K#9KE(5G~qZtPRk`KCUl>y>6* ziNCx~SCVt)0&dYjX{%#2WD1?6!!aob) zUxjd7_j>EbASo4%vX+DQd)g>Wi?n zx+xpV2~SRFHQ9<)9NV!bu_~A)tV+3JnPoCLXSQr+vKh#tEL*lGO3oM?9k5MEc9U7G zDe2bcGw_6zn48Sx#wRmlkhWn381v7$pI_SG{_hpv{Bz4N4|#7H@g8&nqkKgi&nFu4 z+n^AC7$F$OSr3JH79kkwH$fp@L&T-++k{4E1+FA-+Z8cS^il z;VBdVOrjB45no(6{gu1-k?08L1ytp9)T8gYWR^Al6`{#a>BE8FntWjnJXhB=-Yv+<+me=!xJ;G+kBX?ua8(eIOg=WD5r zHSRs0?OrId{esB=?4npi+;bd<_KDWNQ*hi%+3u}b{IwpjO{?GmXkpC%>Yo5#j7j+r znx4`4?STR5mg<9`#&&T0qyVZHZS4}g?}e^<>$iYO3hY_$>c2C%N5S73#DLqz_>>y3>=#W5%tonHmoSc3le+f#R`#QDDl{jvqu4}VMR`6tEv-;kZ5 H9rXVPXkD<2 literal 0 HcmV?d00001 diff --git a/slstatus/components/load_avg.c b/slstatus/components/load_avg.c new file mode 100644 index 0000000..f278a40 --- /dev/null +++ b/slstatus/components/load_avg.c @@ -0,0 +1,19 @@ +/* See LICENSE file for copyright and license details. */ +#include +#include + +#include "../slstatus.h" +#include "../util.h" + +const char * +load_avg(const char *unused) +{ + double avgs[3]; + + if (getloadavg(avgs, 3) < 0) { + warn("getloadavg: Failed to obtain load average"); + return NULL; + } + + return bprintf("%.2f %.2f %.2f", avgs[0], avgs[1], avgs[2]); +} diff --git a/slstatus/components/load_avg.o b/slstatus/components/load_avg.o new file mode 100644 index 0000000000000000000000000000000000000000..735d51d79cd8a483e2d24a00ea5145a8144eac63 GIT binary patch literal 1904 zcmbu9UuzRV5Wwg9$5vX~Sc()Xb{|rS|JGa;)S?n7wkH%3si04BlU&l!Bo{AhZBy_xy#%-r72?!CUVyx3=1z+%B|=z2^6 z_WQebE--U21}EUx_?h3%*7wXunlCv!H)k_wINPt%Q_l9+Zxs2qy*XjGop-m$35ea^ zoB27OT1ltyxttz0bMO1n9Y_Zu&dy4Ds^nal4C?8@5N>_We5$y*=Bbieugr@@Rjs)t zp*`Uhw5m1)%?P#b`l{l>teh*0&I4d+VPRfmmfVK+JYipzS7cT+ub(p}tqx!SM+(Ov zj-`7Kp%0)Q%OUx2B|aH#EqS(h6ju)dJ~zB&aiAOZqN84#yOAmU7Tk- z8ak2$6Jj4Dqx0T#Cecrs{QGD}h4-J?Q#2?vp8v$;$G +#include + +#include "../slstatus.h" +#include "../util.h" + +#if defined(__linux__) + #include + + #define NET_RX_BYTES "/sys/class/net/%s/statistics/rx_bytes" + #define NET_TX_BYTES "/sys/class/net/%s/statistics/tx_bytes" + + const char * + netspeed_rx(const char *interface) + { + uintmax_t oldrxbytes; + static uintmax_t rxbytes; + extern const unsigned int interval; + char path[PATH_MAX]; + + oldrxbytes = rxbytes; + + if (esnprintf(path, sizeof(path), NET_RX_BYTES, interface) < 0) + return NULL; + if (pscanf(path, "%ju", &rxbytes) != 1) + return NULL; + if (oldrxbytes == 0) + return NULL; + + return fmt_human((rxbytes - oldrxbytes) * 1000 / interval, + 1024); + } + + const char * + netspeed_tx(const char *interface) + { + uintmax_t oldtxbytes; + static uintmax_t txbytes; + extern const unsigned int interval; + char path[PATH_MAX]; + + oldtxbytes = txbytes; + + if (esnprintf(path, sizeof(path), NET_TX_BYTES, interface) < 0) + return NULL; + if (pscanf(path, "%ju", &txbytes) != 1) + return NULL; + if (oldtxbytes == 0) + return NULL; + + return fmt_human((txbytes - oldtxbytes) * 1000 / interval, + 1024); + } +#elif defined(__OpenBSD__) | defined(__FreeBSD__) + #include + #include + #include + #include + #include + + const char * + netspeed_rx(const char *interface) + { + struct ifaddrs *ifal, *ifa; + struct if_data *ifd; + uintmax_t oldrxbytes; + static uintmax_t rxbytes; + extern const unsigned int interval; + int if_ok = 0; + + oldrxbytes = rxbytes; + + if (getifaddrs(&ifal) < 0) { + warn("getifaddrs failed"); + return NULL; + } + rxbytes = 0; + for (ifa = ifal; ifa; ifa = ifa->ifa_next) + if (!strcmp(ifa->ifa_name, interface) && + (ifd = (struct if_data *)ifa->ifa_data)) + rxbytes += ifd->ifi_ibytes, if_ok = 1; + + freeifaddrs(ifal); + if (!if_ok) { + warn("reading 'if_data' failed"); + return NULL; + } + if (oldrxbytes == 0) + return NULL; + + return fmt_human((rxbytes - oldrxbytes) * 1000 / interval, + 1024); + } + + const char * + netspeed_tx(const char *interface) + { + struct ifaddrs *ifal, *ifa; + struct if_data *ifd; + uintmax_t oldtxbytes; + static uintmax_t txbytes; + extern const unsigned int interval; + int if_ok = 0; + + oldtxbytes = txbytes; + + if (getifaddrs(&ifal) < 0) { + warn("getifaddrs failed"); + return NULL; + } + txbytes = 0; + for (ifa = ifal; ifa; ifa = ifa->ifa_next) + if (!strcmp(ifa->ifa_name, interface) && + (ifd = (struct if_data *)ifa->ifa_data)) + txbytes += ifd->ifi_obytes, if_ok = 1; + + freeifaddrs(ifal); + if (!if_ok) { + warn("reading 'if_data' failed"); + return NULL; + } + if (oldtxbytes == 0) + return NULL; + + return fmt_human((txbytes - oldtxbytes) * 1000 / interval, + 1024); + } +#endif diff --git a/slstatus/components/netspeeds.o b/slstatus/components/netspeeds.o new file mode 100644 index 0000000000000000000000000000000000000000..4afd7aee5a652e07ed8d0ff06409a0ddbdad47d9 GIT binary patch literal 2824 zcmdT`--{eY5U#nqn2lb>jU>1sDkI#5i_zKLs1QWL9!GK$IYpER8p397Z`NJ2zntll zT}8bRBOc3v4?c+hfUn{o5C#*X4GGJ@b&K6iiq3S6@|E zPuDc_`SGO_6OKb74jrS>Oi-e)c8=_dHY?=PZu%ZuX!SEZs)=F@AuU=g3*uu~M zT;LK;pZV!wufLcKl47kDCP}dqsp4!>OjM|viE7r8V%)DT4^))U><6p#zf2`eT3lFo z#hY7}57^SwHX z$ocp!a{77a!1T`C*Gzt%@u!S0g+A`)znqwN3l}CA-EX~>azlSJ0XcNW)c9XzjdRP&2?oaDuWy6DvkiWB8~j7YQBTSmlIoEM?$)FiMJtJ4 zqqwiz)Gw1VR*C$j1wE8u9r=%5jr$ZOonGARs5c*rIw{RU51AutU`< ze+RX5)mr0RwH`KGqXept684)qxPR#pe*W3ql35E!Ps>RK2FLtSeuV$7!I8)2pS5sY zox*Pz9C;qIa9tG7vw1!Tt?|071WAFE<#kbczX5sdJ-?Q@A`;9H!-mhov3$=>8X$)X^QZpw%8MIZn z%v!};x*=8^wL)J-eMSCCs6z6WlZ5=ZiwWpuZd||CZMXT-B)`*DkV+~3H#U3~VAlJ#Y+G8@QwL;#~@eK~h=%le`#?0{Vo zg3)=?JYEKuIMFBBFSboBnRpw6o#o;l!FQ9TOMJHe?EZ1jB4;*!%>Z)0Fhxr?zQyRc z^S^8wO5O|3e-}RzFXumQZ7g)#tiNV9jBk2eJh1H9Bff9??^8@H$-cim>>C%KGykoh KSg|m(@&5w1xupvL literal 0 HcmV?d00001 diff --git a/slstatus/components/num_files.c b/slstatus/components/num_files.c new file mode 100644 index 0000000..df0acd1 --- /dev/null +++ b/slstatus/components/num_files.c @@ -0,0 +1,32 @@ +/* See LICENSE file for copyright and license details. */ +#include +#include +#include + +#include "../slstatus.h" +#include "../util.h" + +const char * +num_files(const char *path) +{ + struct dirent *dp; + DIR *dir; + int num; + + if (!(dir = opendir(path))) { + warn("opendir '%s':", path); + return NULL; + } + + num = 0; + while ((dp = readdir(dir))) { + if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) + continue; /* skip self and parent */ + + num++; + } + + closedir(dir); + + return bprintf("%d", num); +} diff --git a/slstatus/components/num_files.o b/slstatus/components/num_files.o new file mode 100644 index 0000000000000000000000000000000000000000..a3471434210ba7e7f6702cc34ff0a9f47ab0f1cd GIT binary patch literal 2192 zcmbu9-Afcv6u{4{Zf<@|n?`LIF+G$k=4D3!AlR z*l5AW{+xvf{1bYJ>LH>CjOZmQuybbaU9ZFLOC7j#&iS2>J99tg=~#L^peP_jf$MPK z2?`Jn9@uf$jDreY@Z;FoUy0dtb&y!%)|mcrcE+guzWteeqw?C=t~ql?<(ucDGhkHb zdeW6Wqw?Nmh&~wA%U-&Nwtgy!t+)GMcSYTNs`6>Us9vL_MZK1|n^^qf6};1HoV(5L z=(UAK3co6rtU`9p*80wu`$m8PV{kqTFp*4-XweC);1r9Reu)jUm{z*d&rR&viX)7J zK6hej76Je@Vl6mG$kuQi#1%I#)=YuJ{t3(_Q65i&vJqB#JKI7#n4Cs-#*F~HBt5Q% ztAR;1@}ecBYR_5|YIG}@Qe%Osb~TE`P$MZdJgSDqI;PcVQq>Y_WYh(`NfSly)e7JD z8--gM>~xo#7{t9jEZv;b+Q@Rsb%M|%L$tkblMW4!pF`a(&Fg+UvH=|a-c&N&gkNpK zN1N~)P54X`4u$pn(#l%SDzgl*bW*3s5Iu(J5j%(jKWboGW)_belpQ;hFF__(EL-F+ zm+ZBIvjUGyy8uUVJ`y}v?wR_t@5yPGdgm*Iw&48|r&__?yMR8O$99PuXp>NXii!N2 z1X29?riWeLfwsucb54C|7X{yz_z{Ue=bZY}84~%M67Q6_#yRz;Q5RO;%sb{XFkD7Y zuL{eyawc=E4F_1(bWC8&EIVfA0r&40)>+BM z9kZQHETx9l>e7mB=B@f0{Fk9&HQhN{8(HGq5$9dRC|8zVbZ8CZGDN$?e?TE#Kzl_d zofVRZr{Dr=;^KeBF}x9mPy6S;h;i!quk||CQqLhAvWWRl$`EZaztC~cV!pgR?rT0S z>V%%exUl6^wGnKPJCCdl$DuQcewf#bdxXdpvHrq;hz6zl>+kXURguWGzdnb&(f)4` zL=pQ;`%nJ^Q7?F-xv6efyg%1;7wJ3w_0-e9_lO|E;T$=V@OE`_9IZz6JN*5h)H6N9 GU;h_5xCyKP literal 0 HcmV?d00001 diff --git a/slstatus/components/ram.c b/slstatus/components/ram.c new file mode 100644 index 0000000..15c4b74 --- /dev/null +++ b/slstatus/components/ram.c @@ -0,0 +1,212 @@ +/* See LICENSE file for copyright and license details. */ +#include + +#include "../slstatus.h" +#include "../util.h" + +#if defined(__linux__) + #include + + const char * + ram_free(const char *unused) + { + uintmax_t free; + + if (pscanf("/proc/meminfo", + "MemTotal: %ju kB\n" + "MemFree: %ju kB\n" + "MemAvailable: %ju kB\n", + &free, &free, &free) != 3) + return NULL; + + return fmt_human(free * 1024, 1024); + } + + const char * + ram_perc(const char *unused) + { + uintmax_t total, free, buffers, cached; + int percent; + + 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) + return NULL; + + if (total == 0) + return NULL; + + percent = 100 * ((total - free) - (buffers + cached)) / total; + return bprintf("%d", percent); + } + + const char * + ram_total(const char *unused) + { + uintmax_t total; + + if (pscanf("/proc/meminfo", "MemTotal: %ju kB\n", &total) + != 1) + return NULL; + + return fmt_human(total * 1024, 1024); + } + + const char * + ram_used(const char *unused) + { + uintmax_t total, free, buffers, cached, used; + + 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) + return NULL; + + used = (total - free - buffers - cached); + return fmt_human(used * 1024, 1024); + } +#elif defined(__OpenBSD__) + #include + #include + #include + #include + + #define LOG1024 10 + #define pagetok(size, pageshift) (size_t)(size << (pageshift - LOG1024)) + + inline int + load_uvmexp(struct uvmexp *uvmexp) + { + int uvmexp_mib[] = {CTL_VM, VM_UVMEXP}; + size_t size; + + size = sizeof(*uvmexp); + + if (sysctl(uvmexp_mib, 2, uvmexp, &size, NULL, 0) >= 0) + return 1; + + return 0; + } + + const char * + ram_free(const char *unused) + { + struct uvmexp uvmexp; + int free_pages; + + if (!load_uvmexp(&uvmexp)) + return NULL; + + free_pages = uvmexp.npages - uvmexp.active; + return fmt_human(pagetok(free_pages, uvmexp.pageshift) * + 1024, 1024); + } + + const char * + ram_perc(const char *unused) + { + struct uvmexp uvmexp; + int percent; + + if (!load_uvmexp(&uvmexp)) + return NULL; + + percent = uvmexp.active * 100 / uvmexp.npages; + return bprintf("%d", percent); + } + + const char * + ram_total(const char *unused) + { + struct uvmexp uvmexp; + + if (!load_uvmexp(&uvmexp)) + return NULL; + + return fmt_human(pagetok(uvmexp.npages, + uvmexp.pageshift) * 1024, 1024); + } + + const char * + ram_used(const char *unused) + { + struct uvmexp uvmexp; + + if (!load_uvmexp(&uvmexp)) + return NULL; + + return fmt_human(pagetok(uvmexp.active, + uvmexp.pageshift) * 1024, 1024); + } +#elif defined(__FreeBSD__) + #include + #include + #include + #include + + const char * + ram_free(const char *unused) { + struct vmtotal vm_stats; + int mib[] = {CTL_VM, VM_TOTAL}; + size_t len; + + len = sizeof(struct vmtotal); + if (sysctl(mib, 2, &vm_stats, &len, NULL, 0) < 0 + || !len) + return NULL; + + return fmt_human(vm_stats.t_free * getpagesize(), 1024); + } + + const char * + ram_total(const char *unused) { + unsigned int npages; + size_t len; + + len = sizeof(npages); + if (sysctlbyname("vm.stats.vm.v_page_count", + &npages, &len, NULL, 0) < 0 || !len) + return NULL; + + return fmt_human(npages * getpagesize(), 1024); + } + + const char * + ram_perc(const char *unused) { + unsigned int npages; + unsigned int active; + size_t len; + + len = sizeof(npages); + if (sysctlbyname("vm.stats.vm.v_page_count", + &npages, &len, NULL, 0) < 0 || !len) + return NULL; + + if (sysctlbyname("vm.stats.vm.v_active_count", + &active, &len, NULL, 0) < 0 || !len) + return NULL; + + return bprintf("%d", active * 100 / npages); + } + + const char * + ram_used(const char *unused) { + unsigned int active; + size_t len; + + len = sizeof(active); + if (sysctlbyname("vm.stats.vm.v_active_count", + &active, &len, NULL, 0) < 0 || !len) + return NULL; + + return fmt_human(active * getpagesize(), 1024); + } +#endif diff --git a/slstatus/components/ram.o b/slstatus/components/ram.o new file mode 100644 index 0000000000000000000000000000000000000000..7e34de69a595ab71fb46fd75c1cbac400e367a0b GIT binary patch literal 3128 zcmchYO>7%Q6vxL-Lfp_A6GbSf2<^c^jsn|kn+g*Fa+@}ps4j}CAgDk%YkQ4@y|%H} zRSQKRMI0r zGrRlt>Fjbe5)mvB@vIokmdiU#K zPIkVMbMT`s;e3n1(vKl4y`ud6cIOMHx4XO4klm$ucmG}n6{mA;=bQG_{-^&XN~QXr zDlj9vm#G3>dh-4ejL_rD*)QeXWqN+|Jcd8Hvx(jb^=Y#P|HoTB$DXEy&4sspK_VyP1~ULfI?sPQ^@de_$b2mX;Q+)QVRN z>UGOmu#egERwF&DRoqJmT}F|hHb!mbx#vYxh#uGoH3)Qz+F(7R*7==@h`sYEvV}z6 zI42?(6OqFQ$75H>82k~nBE%*}8MmSv@t8&G0_G$ipp)@TH7=LqYiHu}L_8CHAs&P8 zi&!HmqJ!^CecuM=B=4aM`>w=ez{3Rl9~HNEhOLbZ`67%fLsVg}98}XW@#J1C9@PAF zh(DzH`yqZ1jw<{P9#z>$l207!zoxFyWr1SA1B^M0u4{=C;Uhy8ujIL=MO{*b}{Hn_Q; zNqr88gS*Rd9yYkSA4hXAvkt2UH|vl$xS98Y5#OxCTLw4teq_Wk^L}q|Gw&^fn|UqT zHw4d%#*)?w^G!X+J%%vn`)r;g*7!aPyLHJA+&qmzvp<$uYkF1J4!nzju#0Zs3OnCw z3AXekzru!k4EtA!4?F+w`aedoq5W|Fc#qki&wp5M txZKkD-_gav{}jGqf5gQ`o(>f7 +#include + +#include "../slstatus.h" +#include "../util.h" + +const char * +run_command(const char *cmd) +{ + char *p; + FILE *fp; + + if (!(fp = popen(cmd, "r"))) { + warn("popen '%s':", cmd); + return NULL; + } + + p = fgets(buf, sizeof(buf) - 1, fp); + if (pclose(fp) < 0) { + warn("pclose '%s':", cmd); + return NULL; + } + if (!p) + return NULL; + + if ((p = strrchr(buf, '\n'))) + p[0] = '\0'; + + return buf[0] ? buf : NULL; +} diff --git a/slstatus/components/run_command.o b/slstatus/components/run_command.o new file mode 100644 index 0000000000000000000000000000000000000000..2a88b6578813a617ae6845eb38005800313bf591 GIT binary patch literal 2144 zcmbu9TWb?h5XWbe##XJ{C{-ervM<_N?2@z}Y!y)` z6#@o)^_%!qg17I`7xBRd!G|gef)(ogH|HdqGzHN=oSd28nVGZamM0gI;{in>DTU5b z&6AYqV@u7BduE(eIzZn$x_=qdiPC8>LwEb7E?m0z_pn{%%jOHEy+W#T%D17cq53iE499Fv8Tiaf6@DTH3V(caQ zaWz~DOsbLRK||G^wHRveYUsQg4LnwR85nA0R1J@+Z6akyhxuFR+xCtD2EisL+u;Rz zJ6D%d`Q8xLU8kd-7vi(8S2w$deD%GxFze%neQZ>eK{Jm1XvRl&;l?g}d>2l3Av>GO zWin=VUQdyp9E;*7hMxidVCDMITw#G07A@BiSBM^%c9tC1wo_@F=h({)!am_{{NAqU z2p|jhq?McG8ru-!F(&ybKo&R-SMqa!EW~0i$u9!3!0{|3zX8ZX9h|D3Y z0gwgW&Q0=FK$iTTEwQdr1y{L@*L)l~Rq4)3#x>_i=RK?RX=&NklBv7avP=5B>6)a^ zIS%P|4i3U&Iv)$piXSTJ*_>}a#zHxrs zE7bhg{21q=<^VUpjnFS-Ac-Dd-#jrr-n%wOW%X6K&(WXW^J`Qv@d`6X{QH}YPI`G-Z1w~IU4 kn2(x`XU~YfiUm!<@kx}cl7nnD%fBnW|4}uvVl?Le0has%eE +#include +#include +#include + +#include "../slstatus.h" +#include "../util.h" + +#if defined(__linux__) + static int + get_swap_info(long *s_total, long *s_free, long *s_cached) + { + FILE *fp; + struct { + const char *name; + const size_t len; + long *var; + } ent[] = { + { "SwapTotal", sizeof("SwapTotal") - 1, s_total }, + { "SwapFree", sizeof("SwapFree") - 1, s_free }, + { "SwapCached", sizeof("SwapCached") - 1, s_cached }, + }; + size_t line_len = 0, i, left; + char *line = NULL; + + /* get number of fields we want to extract */ + for (i = 0, left = 0; i < LEN(ent); i++) + if (ent[i].var) + left++; + + if (!(fp = fopen("/proc/meminfo", "r"))) { + warn("fopen '/proc/meminfo':"); + return 1; + } + + /* read file line by line and extract field information */ + while (left > 0 && getline(&line, &line_len, fp) >= 0) { + for (i = 0; i < LEN(ent); i++) { + if (ent[i].var && + !strncmp(line, ent[i].name, ent[i].len)) { + sscanf(line + ent[i].len + 1, + "%ld kB\n", ent[i].var); + left--; + break; + } + } + } + free(line); + if (ferror(fp)) { + warn("getline '/proc/meminfo':"); + return 1; + } + + fclose(fp); + return 0; + } + + const char * + swap_free(const char *unused) + { + long free; + + if (get_swap_info(NULL, &free, NULL)) + return NULL; + + return fmt_human(free * 1024, 1024); + } + + const char * + swap_perc(const char *unused) + { + long total, free, cached; + + if (get_swap_info(&total, &free, &cached) || total == 0) + return NULL; + + return bprintf("%d", 100 * (total - free - cached) / total); + } + + const char * + swap_total(const char *unused) + { + long total; + + if (get_swap_info(&total, NULL, NULL)) + return NULL; + + return fmt_human(total * 1024, 1024); + } + + const char * + swap_used(const char *unused) + { + long total, free, cached; + + if (get_swap_info(&total, &free, &cached)) + return NULL; + + return fmt_human((total - free - cached) * 1024, 1024); + } +#elif defined(__OpenBSD__) + #include + #include + #include + #include + + static int + getstats(int *total, int *used) + { + struct swapent *sep, *fsep; + int rnswap, nswap, i; + + if ((nswap = swapctl(SWAP_NSWAP, 0, 0)) < 1) { + warn("swaptctl 'SWAP_NSWAP':"); + return 1; + } + if (!(fsep = sep = calloc(nswap, sizeof(*sep)))) { + warn("calloc 'nswap':"); + return 1; + } + if ((rnswap = swapctl(SWAP_STATS, (void *)sep, nswap)) < 0) { + warn("swapctl 'SWAP_STATA':"); + return 1; + } + if (nswap != rnswap) { + warn("getstats: SWAP_STATS != SWAP_NSWAP"); + return 1; + } + + *total = 0; + *used = 0; + + for (i = 0; i < rnswap; i++) { + *total += sep->se_nblks >> 1; + *used += sep->se_inuse >> 1; + } + + free(fsep); + + return 0; + } + + const char * + swap_free(const char *unused) + { + int total, used; + + if (getstats(&total, &used)) + return NULL; + + return fmt_human((total - used) * 1024, 1024); + } + + const char * + swap_perc(const char *unused) + { + int total, used; + + if (getstats(&total, &used)) + return NULL; + + if (total == 0) + return NULL; + + return bprintf("%d", 100 * used / total); + } + + const char * + swap_total(const char *unused) + { + int total, used; + + if (getstats(&total, &used)) + return NULL; + + return fmt_human(total * 1024, 1024); + } + + const char * + swap_used(const char *unused) + { + int total, used; + + if (getstats(&total, &used)) + return NULL; + + return fmt_human(used * 1024, 1024); + } +#elif defined(__FreeBSD__) + #include + #include + #include + #include + #include + + static int getswapinfo(struct kvm_swap *swap_info, size_t size) + { + kvm_t *kd; + + kd = kvm_openfiles(NULL, "/dev/null", NULL, 0, NULL); + if (kd == NULL) { + warn("kvm_openfiles '/dev/null':"); + return 0; + } + + if (kvm_getswapinfo(kd, swap_info, size, 0 /* Unused flags */) < 0) { + warn("kvm_getswapinfo:"); + kvm_close(kd); + return 0; + } + + kvm_close(kd); + return 1; + } + + const char * + swap_free(const char *unused) + { + struct kvm_swap swap_info[1]; + long used, total; + + if (!getswapinfo(swap_info, 1)) + return NULL; + + total = swap_info[0].ksw_total; + used = swap_info[0].ksw_used; + + return fmt_human((total - used) * getpagesize(), 1024); + } + + const char * + swap_perc(const char *unused) + { + struct kvm_swap swap_info[1]; + long used, total; + + if (!getswapinfo(swap_info, 1)) + return NULL; + + total = swap_info[0].ksw_total; + used = swap_info[0].ksw_used; + + return bprintf("%d", used * 100 / total); + } + + const char * + swap_total(const char *unused) + { + struct kvm_swap swap_info[1]; + long total; + + if (!getswapinfo(swap_info, 1)) + return NULL; + + total = swap_info[0].ksw_total; + + return fmt_human(total * getpagesize(), 1024); + } + + const char * + swap_used(const char *unused) + { + struct kvm_swap swap_info[1]; + long used; + + if (!getswapinfo(swap_info, 1)) + return NULL; + + used = swap_info[0].ksw_used; + + return fmt_human(used * getpagesize(), 1024); + } +#endif diff --git a/slstatus/components/swap.o b/slstatus/components/swap.o new file mode 100644 index 0000000000000000000000000000000000000000..dfdca6c4c01bdff827e5ebef17c58fb7c32e4ffc GIT binary patch literal 3928 zcmb`JeTW-H6u>9<(WYN}v9=m%Eh}u>Xmy*kSG_B3N$#%goaCg~ySAb=-6osnynHp; z&}%(WNTV!iR0Qz@1r`4gq)<`t51~X`Yt=u5`>W7@1i?E!r4>c7XybdcGncs~0YM+^ z%$wi7_vUNo%|5+5x~IeAAwoQ47iqQxCFIJorXFT$m?&fgi5!d^h>S%>$M%P=((+G} z30m!19{>Yt4{0e{>qc8@PiaAFTNt|>`E`+6-$FS-_H)+Y&7i8LiNgYX(g@h(9V-CnCz!BOPhm(9#%1@W)FT5H2@KvmpCIo zt&QR~u-G%RvwzRW4$|s!jaI(2Hd6aC-82N9L*b(n^#os8`WpS?PikKZ)#rQmx9B+_ zddB(u4!!T-^O?f=%*43 zCQ}BDc*;zW0@<7|t%W@bE_%#ma+Z)Vkv3*g4>WPLiJP7Ew1$4o0do;6z-Bna6% zIJjL6>@~AiE~kci^{skP&G+5SRf4-reDL78-22cN=^&(ztP>s-)Kz$z?>+3j$O#^@ zu)PXwQ9P#}CZ0*3XU+1(-WS1`0$a=85b`=Y4=BDDItCQ~^PK~VTI(860%y7-O7Pi5 z5v8xZc#m?<)A^J~=^Ipn5hVa7U_E3Sck;f+=1Q30pCt~r`L@a5HrwJQC z60=w`W5rUXjFEL%-Ymq)(R^V%Yb70Gv8=}&N=3+Zcd^;x8F6yWUvSHz9F#bo62apV zUnFr$;)^BzoW$`gia2j_j`?kc#NXu{$AkYR!u~7H(O!}Gw8VQP{vGES2hXyIvxI*S z7ze)t!M92L7KuN|ImW?XE@3|=*{_s%QsS5^gneG(m?s6VNPM-#rzL*7#AhTf+wa5y zf?%~A9uYsvInMVEi5n7^V_oU0F6Q1{oe}= zW4g`%t$&Ee+yb>M!hc+bpo{)R9p)_PvipV)NOf`HCu+PWg)W<3b5DrBblW}x9P^_1 z97T-l+<%_{ycX*(@NrNurrSS^n+kH-spdPUR(+$3 u7cU2pxA?#?_h3GE`(w;jOZ6Tu3W$6B?)Af*+{*tD4jAM~r + +#include "../slstatus.h" +#include "../util.h" + + +#if defined(__linux__) + #include + + const char * + temp(const char *file) + { + uintmax_t temp; + + if (pscanf(file, "%ju", &temp) != 1) + return NULL; + + return bprintf("%ju", temp / 1000); + } +#elif defined(__OpenBSD__) + #include + #include /* before for struct timeval */ + #include + #include + + const char * + temp(const char *unused) + { + int mib[5]; + size_t size; + struct sensor temp; + + mib[0] = CTL_HW; + mib[1] = HW_SENSORS; + mib[2] = 0; /* cpu0 */ + mib[3] = SENSOR_TEMP; + mib[4] = 0; /* temp0 */ + + size = sizeof(temp); + + if (sysctl(mib, 5, &temp, &size, NULL, 0) < 0) { + warn("sysctl 'SENSOR_TEMP':"); + return NULL; + } + + /* kelvin to celsius */ + return bprintf("%d", (int)((float)(temp.value-273150000) / 1E6)); + } +#elif defined(__FreeBSD__) + #include + #include + #include + + #define ACPI_TEMP "hw.acpi.thermal.%s.temperature" + + const char * + temp(const char *zone) + { + char buf[256]; + int temp; + size_t len; + + len = sizeof(temp); + snprintf(buf, sizeof(buf), ACPI_TEMP, zone); + if (sysctlbyname(buf, &temp, &len, NULL, 0) < 0 + || !len) + return NULL; + + /* kelvin to decimal celcius */ + return bprintf("%d.%d", (temp - 2731) / 10, abs((temp - 2731) % 10)); + } +#endif diff --git a/slstatus/components/temperature.o b/slstatus/components/temperature.o new file mode 100644 index 0000000000000000000000000000000000000000..5663e46b58219426a8512093a4cae8ce80d54a5e GIT binary patch literal 1744 zcmbtT&1(};5T8v`8?mNQdZ^UO9#XBSkF0vA9wZWLRw$+TMT>{HNj9dY`Ec_BtsXq& z6pG;g;lZokf{F((7XJVRPX)ac4}u7BX7eU_S=NgV%+AbjzTTU8`*dmfdc-h*$$%>` zv={|g9UJOtUrj?C4#SVB6TfcR&*liSJD=_L_e9a&iOw(h_O)cp>e`*Jd*trC>3wL; zp)>h<535<9?9Lba=f2%}Z*~2EZxIaMxt)v^?K9JU1v&0J?Do6Fy|?oZTL9Ti=CZkv zb!)O-H?51}f=HQ-#nVa!h+?Az@;GvKs81C3dttt@kjYQ^fppqYqH`V9 z;{7uqb_|*BA0!ijFnr-JI7qkJa6L!1JXaJzEN4Au1bp`={i(~QDT zDxCip1;Yzg0y5bDEc&VDzvf$*OEu3U>%{%(ZaQ&)mT7d7p3;L*f2nLUfO8(p8|Y_U z5B;bcnjVZ@M<2b@kvECfa>;X%d4(>|6~x^SAzL}0HJTF AIsgCw literal 0 HcmV?d00001 diff --git a/slstatus/components/uptime.c b/slstatus/components/uptime.c new file mode 100644 index 0000000..6227f73 --- /dev/null +++ b/slstatus/components/uptime.c @@ -0,0 +1,34 @@ +/* See LICENSE file for copyright and license details. */ +#include +#include +#include + +#include "../slstatus.h" +#include "../util.h" + +#if defined(CLOCK_BOOTTIME) + #define UPTIME_FLAG CLOCK_BOOTTIME +#elif defined(CLOCK_UPTIME) + #define UPTIME_FLAG CLOCK_UPTIME +#else + #define UPTIME_FLAG CLOCK_MONOTONIC +#endif + +const char * +uptime(const char *unused) +{ + char warn_buf[256]; + uintmax_t h, m; + struct timespec uptime; + + if (clock_gettime(UPTIME_FLAG, &uptime) < 0) { + snprintf(warn_buf, sizeof(warn_buf), "clock_gettime %d", UPTIME_FLAG); + warn(warn_buf); + return NULL; + } + + h = uptime.tv_sec / 3600; + m = uptime.tv_sec % 3600 / 60; + + return bprintf("%juh %jum", h, m); +} diff --git a/slstatus/components/uptime.o b/slstatus/components/uptime.o new file mode 100644 index 0000000000000000000000000000000000000000..aa75195b1f02b4d61b4061848b9b0c0eb08f819f GIT binary patch literal 2024 zcmbu9&ubG=5XWcJ)<&&qlnRB4>>-sD^^w&IRa8=H?FvCeQ4xi(O}0&K^TW+nTRlh- z!B7ew^x$8h7r}#<^q@gSJoZ2ETF{Gl5Q|XfyLqqKEZd6?yu6vu%)EK~=Dj=|&zz5F z8Y$7}EVV2}i3*)9J?*J!iqRhW*?Vx~%KL66=F)eaGxO&1@L&>l?QNo;fw|%)qU%U` z+*mwmuG~uWkJgb;MnYFK8xY1~7-%{rCxkR)ck72Bvn+$am0CG?-LiVQiP}h*1-b;UFXsAYn~rp z3DKzC?rUPw?q4QtA+8PdbVr|ZaDw>(>08A-9*aMUWMXe3k(aUfXe=sy+fAs~Nk2Bj z{2e&$fb8;YuOn@qUdi{iQ6lVnpKl#+kIV*m;CzBI#2}21Y{Sv&u=w$9IL%kkPmv>$ z8B5{EkciqEPT6d=RB>iX?o>8cn5BD`Q=-WxfX}t~aZ_&y4EC# zs_Qi8g3=s&&JwP@;F8E&u0>+9S|#C>VIbTP28mp`SmgIWqEvQm!B_sMcSh2lF3pRI zQ?A&KyU3|n&@N=B9II$=?cl!@owIRUarS;mOGDi|YS_Q~CDIe@BY47G4 zx$0f@OMXal^}Z#h4W$I;VErTP$D03|Z*VTwJjTN>sy@EYFRH$p)9i$v@&~cLUk2y_ zuJY7;f&EJNhn@(7A+a}@;T^QyNw!C1{w3D^qRwBjJFFlynEyoPr&XYwgZX&FVf|l| z4N-kY|MAXLzT#oEQR<7VAC+?tGyHo7^RZ^I_l#&we$X`-K9S395&Z9l<*!TlU@Nkz H1oQs_mr~}- literal 0 HcmV?d00001 diff --git a/slstatus/components/user.c b/slstatus/components/user.c new file mode 100644 index 0000000..3517495 --- /dev/null +++ b/slstatus/components/user.c @@ -0,0 +1,33 @@ +/* See LICENSE file for copyright and license details. */ +#include +#include +#include +#include + +#include "../slstatus.h" +#include "../util.h" + +const char * +gid(const char *unused) +{ + return bprintf("%d", getgid()); +} + +const char * +username(const char *unused) +{ + struct passwd *pw; + + if (!(pw = getpwuid(geteuid()))) { + warn("getpwuid '%d':", geteuid()); + return NULL; + } + + return bprintf("%s", pw->pw_name); +} + +const char * +uid(const char *unused) +{ + return bprintf("%d", geteuid()); +} diff --git a/slstatus/components/user.o b/slstatus/components/user.o new file mode 100644 index 0000000000000000000000000000000000000000..f58bb3ace5c136b63c231c8813b74de54ff86550 GIT binary patch literal 2240 zcmb`H-%Aux6vxl_Bh4S1Nl|3T^k5p)ZAXPfs3vUF$U>w-C5l;h)Ft;vvm z_1dd1z57e;p#rUjadmT}Sa64j3d55$R3n<6nwoS+ro(bvskq*_8dF)fI&sdJcqVG& z(Z>U?GkxbCwGh?8T6sWVyFB*%j`qu$IP~ZG7{@}Kr}N}&^*IAQ9i6W^82q&M5Dh@* zGJUr*otljse$DWQU75~Y_X2y9yt~Gq&NFDA!gICJx7~dX2CYqQ5_=?Xr;WzctF3nG zZ;-@D*6oe+5%(!J`cw7wvobru1LteYAcJQ7EOXS6e0?U&E*=nn=>YB@z{i-Q{sYz! z*@rf2VWgHx%}!-8jbif9RI9}T<*QM#9Ixo0a!?AvL+-Uk)6r%Sl~L~yCKmKf2ajL7 zi6rMq=r4VC!q4y;g7_{T!bbpEz`J<}$NNH12R`A~0a@%iw-T)5(ZdoiJ%#w56wjM@ zyH3$?`}uLd5X7UGr2bVv7Mt@|sm125;i!)xGGPqia$gG;m-{4D+b+dHo^>20dQGe- zTn|(nZpEYuK^&0E*J`Aq3Kj_Wlt*g0QY!HegH*W^hl+m*7iw{^{Mf8l%Nwd1RjOeW zZ*wXNhHH;jBJ{+65tpmr8f6eze7d1zDq($~Wo`!78{-S-uvR2$jvvw^md7^K!U+i?~ zm-HfK+p&x6!*`$VVT6Ch#4?wt#w_PA;0YV3Y3KW9qcsUM+Rk5R-t7Lj09j@drT;01 z*_M2{|7Lq5<&D{Y&gdRy=utZ#HSN1+L_f?6<*-PJDc2xJ*=m+wH_!j95t$fv{%<`8 B{qX<* literal 0 HcmV?d00001 diff --git a/slstatus/components/volume.c b/slstatus/components/volume.c new file mode 100644 index 0000000..6cec556 --- /dev/null +++ b/slstatus/components/volume.c @@ -0,0 +1,219 @@ +/* See LICENSE file for copyright and license details. */ +#include +#include +#include +#include +#include + +#include "../slstatus.h" +#include "../util.h" + +#if defined(__OpenBSD__) | defined(__FreeBSD__) + #include + #include + #include + #include + + struct control { + LIST_ENTRY(control) next; + unsigned int addr; + #define CTRL_NONE 0 + #define CTRL_LEVEL 1 + #define CTRL_MUTE 2 + unsigned int type; + unsigned int maxval; + unsigned int val; + }; + + static LIST_HEAD(, control) controls = LIST_HEAD_INITIALIZER(controls); + static struct pollfd *pfds; + static struct sioctl_hdl *hdl; + static int initialized; + + /* + * Call-back to obtain the description of all audio controls. + */ + static void + ondesc(void *unused, struct sioctl_desc *desc, int val) + { + struct control *c, *ctmp; + unsigned int type = CTRL_NONE; + + if (desc == NULL) + return; + + /* Delete existing audio control with the same address. */ + LIST_FOREACH_SAFE(c, &controls, next, ctmp) { + if (desc->addr == c->addr) { + LIST_REMOVE(c, next); + free(c); + break; + } + } + + /* Only match output.level and output.mute audio controls. */ + if (desc->group[0] != 0 || + strcmp(desc->node0.name, "output") != 0) + return; + if (desc->type == SIOCTL_NUM && + strcmp(desc->func, "level") == 0) + type = CTRL_LEVEL; + else if (desc->type == SIOCTL_SW && + strcmp(desc->func, "mute") == 0) + type = CTRL_MUTE; + else + return; + + c = malloc(sizeof(struct control)); + if (c == NULL) { + warn("sndio: failed to allocate audio control\n"); + return; + } + + c->addr = desc->addr; + c->type = type; + c->maxval = desc->maxval; + c->val = val; + LIST_INSERT_HEAD(&controls, c, next); + } + + /* + * Call-back invoked whenever an audio control changes. + */ + static void + onval(void *unused, unsigned int addr, unsigned int val) + { + struct control *c; + + LIST_FOREACH(c, &controls, next) { + if (c->addr == addr) + break; + } + c->val = val; + } + + static void + cleanup(void) + { + struct control *c; + + if (hdl) { + sioctl_close(hdl); + hdl = NULL; + } + + free(pfds); + pfds = NULL; + + while (!LIST_EMPTY(&controls)) { + c = LIST_FIRST(&controls); + LIST_REMOVE(c, next); + free(c); + } + } + + static int + init(void) + { + hdl = sioctl_open(SIO_DEVANY, SIOCTL_READ, 0); + if (hdl == NULL) { + warn("sndio: cannot open device"); + goto failed; + } + + if (!sioctl_ondesc(hdl, ondesc, NULL)) { + warn("sndio: cannot set control description call-back"); + goto failed; + } + + if (!sioctl_onval(hdl, onval, NULL)) { + warn("sndio: cannot set control values call-back"); + goto failed; + } + + pfds = calloc(sioctl_nfds(hdl), sizeof(struct pollfd)); + if (pfds == NULL) { + warn("sndio: cannot allocate pollfd structures"); + goto failed; + } + + return 1; + failed: + cleanup(); + return 0; + } + + const char * + vol_perc(const char *unused) + { + struct control *c; + int n, v, value; + + if (!initialized) + initialized = init(); + + if (hdl == NULL) + return NULL; + + n = sioctl_pollfd(hdl, pfds, POLLIN); + if (n > 0) { + n = poll(pfds, n, 0); + if (n > 0) { + if (sioctl_revents(hdl, pfds) & POLLHUP) { + warn("sndio: disconnected"); + cleanup(); + initialized = 0; + return NULL; + } + } + } + + value = 100; + LIST_FOREACH(c, &controls, next) { + if (c->type == CTRL_MUTE && c->val == 1) + value = 0; + else if (c->type == CTRL_LEVEL) { + v = (c->val * 100 + c->maxval / 2) / c->maxval; + /* For multiple channels return the minimum. */ + if (v < value) + value = v; + } + } + + return bprintf("%d", value); + } +#else + #include + + const char * + vol_perc(const char *card) + { + size_t i; + int v, afd, devmask; + char *vnames[] = SOUND_DEVICE_NAMES; + + if ((afd = open(card, O_RDONLY | O_NONBLOCK)) < 0) { + warn("open '%s':", card); + return NULL; + } + + if (ioctl(afd, (int)SOUND_MIXER_READ_DEVMASK, &devmask) < 0) { + warn("ioctl 'SOUND_MIXER_READ_DEVMASK':"); + close(afd); + return NULL; + } + for (i = 0; i < LEN(vnames); i++) { + if (devmask & (1 << i) && !strcmp("vol", vnames[i])) { + if (ioctl(afd, MIXER_READ(i), &v) < 0) { + warn("ioctl 'MIXER_READ(%ld)':", i); + close(afd); + return NULL; + } + } + } + + close(afd); + + return bprintf("%d", v & 0xff); + } +#endif diff --git a/slstatus/components/volume.o b/slstatus/components/volume.o new file mode 100644 index 0000000000000000000000000000000000000000..e42a5869a465eeb5cadc482c054884dc7048cd77 GIT binary patch literal 3632 zcmds(O>7%g5P-*VlDZHa14T*|gpA}6S5a1WQXmAV?B;I^NhnE!f}j{@y@{>Z-etW> z9YCt97K90wf`qCZI3N&$1BX^f6-cPEC{VcdMo;t_sihS4hFZeRdS0@A*cXnBv~Om< zH}l@xx9?|9j!llYcswA)1BYPO6BNL_XV;E7W(+#P54SrX`71uBRvstz?En_>V{>Zx z?yP$1#uj=hb-lGGjD}i16S|5zT2(7=hXS`hzX(2}e^3;>Q(b#dE#Fit&yp9dI`I0T z^5ya+wQ?-fpOv^rTyg#we6ekbgAk-NV>v3$*`h*qyJt&fH}IzQVgJbh&S z;Elj09N*-U?Ev3fNkjuSse;%c{>fJmV<(+Czo{#vYEUN zxr_!{3RRKn2Efua$Sfr@c`%%kf}&37fKv`aDzg-&Vt|T4Fw+=ori~RFRx>Hx04tfw z7?3ma8QZV`CPqevgW(B1ZyQE1dQcfuB0+QL0GrT?-z|Vo8$J`$bI<}%CFaG4gzO+b zyY(KYUhE|g)cgA|mc;Ys40wtGPj|;2-v$OhgY03a2B4pk$Nhmy%e24i18>|Pe7AMf zA3ohS;ooTSwtM_xL~(!DVSnJT-^WQ!6gAZfe{MIb_BPz{^lswq>a)DiUJuZ#9S{HJ zG-rVE&W3gDTJeyh+TmUoBeR=%RN{{^e@^1P=s(~ZzcXjZBKXw$u1}zIsu3S}Qu9E?y@!qhDdXy3t!q?NC2DA2M-0XL0p zX*m-XOe>SO7a@@-*hy_Up{17-i^)tD``(KW39eh`tKQkJ$%sR1>zBTT;4d<#cv{nf z&oig>-r?d!<`hq>K*XP9PVx7-`1{N$evgZP$XsrJ)5ZO+`13B_>Ege*xVzt9nNz>C zWyCmtbH%&g>z0eV`@O@Q+M&4>?RaUUq0sngoeAFU;`h5anvT@=C+>On#da2)))k3Z zyMoWuFm$mN{AKoo5>K!nmbk`#MB>Zr4@ul)KPGXTeO2No*gq=qx7eSTc!~YjC4Pqe zw8X`F65|r{u)%RfDgG?`C5eB`{(BPtlzq{jX#Wf5n^OE&?0+J0v0lHF_yzXQN&GwZ zzmfR&>{liJGy6f-v_9$C5v8z}vy%&;;F(d=X<=DP zIZ-7Fie}_;cvFIsH*8(O`>@|RaM)kUuPCO4CzWNdaZ`Fav1lc8`pz)^s}aORntS=C zi6J8q=YP$s#R{7=-7mB^WB9mbiw-%IO==v4&Hyrf?^v_-zqW6UB_ zoR0?-l(@(fdYbd4FbK;p!~r5t#J`3HO_lt*BLAoeWG&`T;8irJO*y~F{m+X))^h$E z$QymXt9-$Vbwb~d{)t4s;EnpGuC8$Z=lF%`&T5oT-87o260hGyYRo0_{L$UhDE}6Z LzvRj#Q_lYfhj+x7 literal 0 HcmV?d00001 diff --git a/slstatus/components/wifi.c b/slstatus/components/wifi.c new file mode 100644 index 0000000..23af201 --- /dev/null +++ b/slstatus/components/wifi.c @@ -0,0 +1,413 @@ +/* See LICENSE file for copyright and license details. */ +#include +#include +#include +#include +#include +#include + +#include "../slstatus.h" +#include "../util.h" + +#define RSSI_TO_PERC(rssi) \ + rssi >= -50 ? 100 : \ + (rssi <= -100 ? 0 : \ + (2 * (rssi + 100))) + +#if defined(__linux__) + #include + #include + #include + #include + #include + + 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; + } + + 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_essid(const char *interface) + { + 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; + } + if (idx < 0) { + fprintf(stderr, "interface %s not found\n", interface); + return NULL; + } + + 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; + } + r = recv(nlsock, resp, sizeof(resp), 0); + if (r < 0) { + warn("recv 'AF_NETLINK':"); + return NULL; + } + + 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; + + return p; + } + + const char * + wifi_perc(const char *interface) + { + 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 (idx < 0) { + fprintf(stderr, "interface %s not found\n", interface); + return NULL; + } + + 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; + } + + *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 + #include + #include + #include /* before for NBBY */ + #include + #include + #include + + static int + load_ieee80211_nodereq(const char *interface, struct ieee80211_nodereq *nr) + { + struct ieee80211_bssid bssid; + int sockfd; + uint8_t zero_bssid[IEEE80211_ADDR_LEN]; + + memset(&bssid, 0, sizeof(bssid)); + memset(nr, 0, sizeof(struct ieee80211_nodereq)); + if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + warn("socket 'AF_INET':"); + return 0; + } + strlcpy(bssid.i_name, interface, sizeof(bssid.i_name)); + if ((ioctl(sockfd, SIOCG80211BSSID, &bssid)) < 0) { + warn("ioctl 'SIOCG80211BSSID':"); + close(sockfd); + return 0; + } + memset(&zero_bssid, 0, sizeof(zero_bssid)); + if (memcmp(bssid.i_bssid, zero_bssid, + IEEE80211_ADDR_LEN) == 0) { + close(sockfd); + return 0; + } + strlcpy(nr->nr_ifname, interface, sizeof(nr->nr_ifname)); + memcpy(&nr->nr_macaddr, bssid.i_bssid, sizeof(nr->nr_macaddr)); + if ((ioctl(sockfd, SIOCG80211NODE, nr)) < 0 && nr->nr_rssi) { + warn("ioctl 'SIOCG80211NODE':"); + close(sockfd); + return 0; + } + + return close(sockfd), 1; + } + + const char * + wifi_perc(const char *interface) + { + struct ieee80211_nodereq nr; + int q; + + if (load_ieee80211_nodereq(interface, &nr)) { + if (nr.nr_max_rssi) + q = IEEE80211_NODEREQ_RSSI(&nr); + else + q = RSSI_TO_PERC(nr.nr_rssi); + + return bprintf("%d", q); + } + + return NULL; + } + + const char * + wifi_essid(const char *interface) + { + struct ieee80211_nodereq nr; + + if (load_ieee80211_nodereq(interface, &nr)) + return bprintf("%s", nr.nr_nwid); + + return NULL; + } +#elif defined(__FreeBSD__) + #include + #include + + int + load_ieee80211req(int sock, const char *interface, void *data, int type, size_t *len) + { + char warn_buf[256]; + struct ieee80211req ireq; + memset(&ireq, 0, sizeof(ireq)); + ireq.i_type = type; + ireq.i_data = (caddr_t) data; + ireq.i_len = *len; + + strlcpy(ireq.i_name, interface, sizeof(ireq.i_name)); + if (ioctl(sock, SIOCG80211, &ireq) < 0) { + snprintf(warn_buf, sizeof(warn_buf), + "ioctl: 'SIOCG80211': %d", type); + warn(warn_buf); + return 0; + } + + *len = ireq.i_len; + return 1; + } + + const char * + wifi_perc(const char *interface) + { + union { + struct ieee80211req_sta_req sta; + uint8_t buf[24 * 1024]; + } info; + uint8_t bssid[IEEE80211_ADDR_LEN]; + int rssi_dbm; + int sockfd; + size_t len; + const char *fmt; + + if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + warn("socket 'AF_INET':"); + return NULL; + } + + /* Retreive MAC address of interface */ + len = IEEE80211_ADDR_LEN; + fmt = NULL; + if (load_ieee80211req(sockfd, interface, &bssid, IEEE80211_IOC_BSSID, &len)) + { + /* Retrieve info on station with above BSSID */ + memset(&info, 0, sizeof(info)); + memcpy(info.sta.is_u.macaddr, bssid, sizeof(bssid)); + + len = sizeof(info); + if (load_ieee80211req(sockfd, interface, &info, IEEE80211_IOC_STA_INFO, &len)) { + rssi_dbm = info.sta.info[0].isi_noise + + info.sta.info[0].isi_rssi / 2; + + fmt = bprintf("%d", RSSI_TO_PERC(rssi_dbm)); + } + } + + close(sockfd); + return fmt; + } + + const char * + wifi_essid(const char *interface) + { + char ssid[IEEE80211_NWID_LEN + 1]; + size_t len; + int sockfd; + const char *fmt; + + if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + warn("socket 'AF_INET':"); + return NULL; + } + + fmt = NULL; + len = sizeof(ssid); + memset(&ssid, 0, len); + if (load_ieee80211req(sockfd, interface, &ssid, IEEE80211_IOC_SSID, &len)) { + if (len < sizeof(ssid)) + len += 1; + else + len = sizeof(ssid); + + ssid[len - 1] = '\0'; + fmt = bprintf("%s", ssid); + } + + close(sockfd); + return fmt; + } +#endif diff --git a/slstatus/components/wifi.o b/slstatus/components/wifi.o new file mode 100644 index 0000000000000000000000000000000000000000..a2a20e4fc49e72765e3f61a97769359549747d12 GIT binary patch literal 6176 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 Kmo4pv)BeA_O`r+@ literal 0 HcmV?d00001 diff --git a/slstatus/config.def.h b/slstatus/config.def.h new file mode 100644 index 0000000..100093e --- /dev/null +++ b/slstatus/config.def.h @@ -0,0 +1,70 @@ +/* See LICENSE file for copyright and license details. */ + +/* interval between updates (in ms) */ +const unsigned int interval = 1000; + +/* text to show if no value can be retrieved */ +static const char unknown_str[] = "n/a"; + +/* maximum output string length */ +#define MAXLEN 2048 + +/* + * function description argument (example) + * + * battery_perc battery percentage battery name (BAT0) + * NULL on OpenBSD/FreeBSD + * battery_remaining battery remaining HH:MM battery name (BAT0) + * NULL on OpenBSD/FreeBSD + * battery_state battery charging state battery name (BAT0) + * NULL on OpenBSD/FreeBSD + * cat read arbitrary file path + * cpu_freq cpu frequency in MHz NULL + * cpu_perc cpu usage in percent NULL + * datetime date and time format string (%F %T) + * disk_free free disk space in GB mountpoint path (/) + * disk_perc disk usage in percent mountpoint path (/) + * disk_total total disk space in GB mountpoint path (/) + * disk_used used disk space in GB mountpoint path (/) + * entropy available entropy NULL + * gid GID of current user NULL + * hostname hostname NULL + * ipv4 IPv4 address interface name (eth0) + * ipv6 IPv6 address interface name (eth0) + * kernel_release `uname -r` NULL + * keyboard_indicators caps/num lock indicators format string (c?n?) + * see keyboard_indicators.c + * keymap layout (variant) of current NULL + * keymap + * load_avg load average NULL + * netspeed_rx receive network speed interface name (wlan0) + * netspeed_tx transfer network speed interface name (wlan0) + * num_files number of files in a directory path + * (/home/foo/Inbox/cur) + * ram_free free memory in GB NULL + * ram_perc memory usage in percent NULL + * ram_total total memory size in GB NULL + * ram_used used memory in GB NULL + * run_command custom shell command command (echo foo) + * swap_free free swap in GB NULL + * swap_perc swap usage in percent NULL + * swap_total total swap size in GB NULL + * swap_used used swap in GB NULL + * temp temperature in degree celsius sensor file + * (/sys/class/thermal/...) + * NULL on OpenBSD + * 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) + * NULL on OpenBSD/FreeBSD + * wifi_essid WiFi ESSID interface name (wlan0) + * wifi_perc WiFi signal in percent interface name (wlan0) + */ +static const struct arg args[] = { + /* function format argument */ + { datetime, "%s", "%F %T" }, +}; diff --git a/slstatus/config.h b/slstatus/config.h new file mode 100644 index 0000000..6be6d79 --- /dev/null +++ b/slstatus/config.h @@ -0,0 +1,72 @@ +/* See LICENSE file for copyright and license details. */ + +/* interval between updates (in ms) */ +const unsigned int interval = 500; + +/* text to show if no value can be retrieved */ +static const char unknown_str[] = "n/a"; + +/* maximum output string length */ +#define MAXLEN 2048 + +/* + * function description argument (example) + * + * battery_perc battery percentage battery name (BAT0) + * NULL on OpenBSD/FreeBSD + * battery_remaining battery remaining HH:MM battery name (BAT0) + * NULL on OpenBSD/FreeBSD + * battery_state battery charging state battery name (BAT0) + * NULL on OpenBSD/FreeBSD + * cat read arbitrary file path + * cpu_freq cpu frequency in MHz NULL + * cpu_perc cpu usage in percent NULL + * datetime date and time format string (%F %T) + * disk_free free disk space in GB mountpoint path (/) + * disk_perc disk usage in percent mountpoint path (/) + * disk_total total disk space in GB mountpoint path (/) + * disk_used used disk space in GB mountpoint path (/) + * entropy available entropy NULL + * gid GID of current user NULL + * hostname hostname NULL + * ipv4 IPv4 address interface name (eth0) + * ipv6 IPv6 address interface name (eth0) + * kernel_release `uname -r` NULL + * keyboard_indicators caps/num lock indicators format string (c?n?) + * see keyboard_indicators.c + * keymap layout (variant) of current NULL + * keymap + * load_avg load average NULL + * netspeed_rx receive network speed interface name (wlan0) + * netspeed_tx transfer network speed interface name (wlan0) + * num_files number of files in a directory path + * (/home/foo/Inbox/cur) + * ram_free free memory in GB NULL + * ram_perc memory usage in percent NULL + * ram_total total memory size in GB NULL + * ram_used used memory in GB NULL + * run_command custom shell command command (echo foo) + * swap_free free swap in GB NULL + * swap_perc swap usage in percent NULL + * swap_total total swap size in GB NULL + * swap_used used swap in GB NULL + * temp temperature in degree celsius sensor file + * (/sys/class/thermal/...) + * NULL on OpenBSD + * 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) + * NULL on OpenBSD/FreeBSD + * wifi_essid WiFi ESSID interface name (wlan0) + * wifi_perc WiFi signal in percent interface name (wlan0) + */ +static const struct arg args[] = { + /* function format argument */ + { cpu_perc, " 🖳 %s%% ", NULL }, + { ram_perc, "| 💾 %s%% ", NULL }, + { datetime, "%s", "| 📆%e | 🕒 %H:%M" }, +}; diff --git a/slstatus/config.mk b/slstatus/config.mk new file mode 100644 index 0000000..a8f5c23 --- /dev/null +++ b/slstatus/config.mk @@ -0,0 +1,22 @@ +# slstatus version +VERSION = 1.1 + +# customize below to fit your system + +# paths +PREFIX = /usr/local +MANPREFIX = $(PREFIX)/share/man + +X11INC = /usr/X11R6/include +X11LIB = /usr/X11R6/lib + +# flags +CPPFLAGS = -I$(X11INC) -D_DEFAULT_SOURCE -DVERSION=\"${VERSION}\" +CFLAGS = -std=c99 -pedantic -Wall -Wextra -Wno-unused-parameter -Os +LDFLAGS = -L$(X11LIB) -s +# OpenBSD: add -lsndio +# FreeBSD: add -lkvm -lsndio +LDLIBS = -lX11 + +# compiler and linker +CC = cc diff --git a/slstatus/slstatus b/slstatus/slstatus new file mode 100755 index 0000000000000000000000000000000000000000..984607c3d421b02026100982b6d2f3d0788c7ad4 GIT binary patch literal 35392 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 literal 0 HcmV?d00001 diff --git a/slstatus/slstatus.1 b/slstatus/slstatus.1 new file mode 100644 index 0000000..73e7a60 --- /dev/null +++ b/slstatus/slstatus.1 @@ -0,0 +1,47 @@ +.Dd 2023-04-23 +.Dt SLSTATUS 1 +.Os +.Sh NAME +.Nm slstatus +.Nd suckless status +.Sh SYNOPSIS +.Nm +.Op Fl s +.Op Fl 1 +.Sh DESCRIPTION +.Nm +is a small tool for providing system status information to other programs +over the EWMH +.Em WM_NAME +property of the root window (used by +.Xr dwm 1 ) or standard input/output. It is designed to be as efficient as possible by +only issuing the minimum of system calls required. +.P +By default, +.Nm +outputs to WM_NAME. +.Sh OPTIONS +.Bl -tag -width Ds +.It Fl v +Print version information to stderr, then exit. +.It Fl s +Write to stdout instead of WM_NAME. +.It Fl 1 +Write once to stdout and quit. +.El +.Sh CUSTOMIZATION +.Nm +can be customized by creating a custom config.h and (re)compiling the source +code. This keeps it fast, secure and simple. +.Sh SIGNALS +.Nm +responds to the following signals: +.Pp +.Bl -tag -width TERM -compact +.It USR1 +Triggers an instant redraw. +.El +.Sh AUTHORS +See the LICENSE file for the authors. +.Sh SEE ALSO +.Xr dwm 1 diff --git a/slstatus/slstatus.c b/slstatus/slstatus.c new file mode 100644 index 0000000..16d88fe --- /dev/null +++ b/slstatus/slstatus.c @@ -0,0 +1,135 @@ +/* See LICENSE file for copyright and license details. */ +#include +#include +#include +#include +#include +#include +#include + +#include "arg.h" +#include "slstatus.h" +#include "util.h" + +struct arg { + const char *(*func)(const char *); + const char *fmt; + const char *args; +}; + +char buf[1024]; +static volatile sig_atomic_t done; +static Display *dpy; + +#include "config.h" + +static void +terminate(const int signo) +{ + if (signo != SIGUSR1) + done = 1; +} + +static void +difftimespec(struct timespec *res, struct timespec *a, struct timespec *b) +{ + res->tv_sec = a->tv_sec - b->tv_sec - (a->tv_nsec < b->tv_nsec); + res->tv_nsec = a->tv_nsec - b->tv_nsec + + (a->tv_nsec < b->tv_nsec) * 1E9; +} + +static void +usage(void) +{ + die("usage: %s [-v] [-s] [-1]", argv0); +} + +int +main(int argc, char *argv[]) +{ + struct sigaction act; + struct timespec start, current, diff, intspec, wait; + size_t i, len; + int sflag, ret; + char status[MAXLEN]; + const char *res; + + sflag = 0; + ARGBEGIN { + case 'v': + die("slstatus-"VERSION); + break; + case '1': + done = 1; + /* FALLTHROUGH */ + case 's': + sflag = 1; + break; + default: + usage(); + } ARGEND + + if (argc) + usage(); + + memset(&act, 0, sizeof(act)); + act.sa_handler = terminate; + sigaction(SIGINT, &act, NULL); + sigaction(SIGTERM, &act, NULL); + act.sa_flags |= SA_RESTART; + sigaction(SIGUSR1, &act, NULL); + + if (!sflag && !(dpy = XOpenDisplay(NULL))) + die("XOpenDisplay: Failed to open display"); + + do { + if (clock_gettime(CLOCK_MONOTONIC, &start) < 0) + die("clock_gettime:"); + + status[0] = '\0'; + for (i = len = 0; i < LEN(args); i++) { + if (!(res = args[i].func(args[i].args))) + res = unknown_str; + + if ((ret = esnprintf(status + len, sizeof(status) - len, + args[i].fmt, res)) < 0) + break; + + len += ret; + } + + if (sflag) { + puts(status); + fflush(stdout); + if (ferror(stdout)) + die("puts:"); + } else { + if (XStoreName(dpy, DefaultRootWindow(dpy), status) < 0) + die("XStoreName: Allocation failed"); + XFlush(dpy); + } + + if (!done) { + if (clock_gettime(CLOCK_MONOTONIC, ¤t) < 0) + die("clock_gettime:"); + difftimespec(&diff, ¤t, &start); + + intspec.tv_sec = interval / 1000; + intspec.tv_nsec = (interval % 1000) * 1E6; + difftimespec(&wait, &intspec, &diff); + + if (wait.tv_sec >= 0 && + nanosleep(&wait, NULL) < 0 && + errno != EINTR) + die("nanosleep:"); + } + } while (!done); + + if (!sflag) { + XStoreName(dpy, DefaultRootWindow(dpy), NULL); + if (XCloseDisplay(dpy) < 0) + die("XCloseDisplay: Failed to close display"); + } + + return 0; +} diff --git a/slstatus/slstatus.h b/slstatus/slstatus.h new file mode 100644 index 0000000..394281c --- /dev/null +++ b/slstatus/slstatus.h @@ -0,0 +1,85 @@ +/* See LICENSE file for copyright and license details. */ + +/* battery */ +const char *battery_perc(const char *); +const char *battery_remaining(const char *); +const char *battery_state(const char *); + +/* cat */ +const char *cat(const char *path); + +/* cpu */ +const char *cpu_freq(const char *unused); +const char *cpu_perc(const char *unused); + +/* datetime */ +const char *datetime(const char *fmt); + +/* disk */ +const char *disk_free(const char *path); +const char *disk_perc(const char *path); +const char *disk_total(const char *path); +const char *disk_used(const char *path); + +/* entropy */ +const char *entropy(const char *unused); + +/* hostname */ +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); + +/* keyboard_indicators */ +const char *keyboard_indicators(const char *fmt); + +/* keymap */ +const char *keymap(const char *unused); + +/* load_avg */ +const char *load_avg(const char *unused); + +/* netspeeds */ +const char *netspeed_rx(const char *interface); +const char *netspeed_tx(const char *interface); + +/* num_files */ +const char *num_files(const char *path); + +/* ram */ +const char *ram_free(const char *unused); +const char *ram_perc(const char *unused); +const char *ram_total(const char *unused); +const char *ram_used(const char *unused); + +/* run_command */ +const char *run_command(const char *cmd); + +/* swap */ +const char *swap_free(const char *unused); +const char *swap_perc(const char *unused); +const char *swap_total(const char *unused); +const char *swap_used(const char *unused); + +/* temperature */ +const char *temp(const char *); + +/* uptime */ +const char *uptime(const char *unused); + +/* user */ +const char *gid(const char *unused); +const char *uid(const char *unused); +const char *username(const char *unused); + +/* volume */ +const char *vol_perc(const char *card); + +/* wifi */ +const char *wifi_essid(const char *interface); +const char *wifi_perc(const char *interface); diff --git a/slstatus/slstatus.o b/slstatus/slstatus.o new file mode 100644 index 0000000000000000000000000000000000000000..7b8eb2c2c9c11e59ee1ece9d342e561ba3d789f0 GIT binary patch literal 6056 zcmbtYeQaA-6~B)2;gw*!?MAbWt&h$w$=Z1Kma#PIAWoX}Mwn8OWDDDZ=h`ocslV`h zuOw4eTBTX#c`j8ez9huNA5237iH{+zTDQ9FgHBrotu$I`(x_k>LjkFD&`PDkoO69| zbMofLA8@31?>WEwJLlee?tS-N`x`^C;U<@hDRHsSvSmx5j6J(%S??EWKf95wWgq%( zzq(LcWv=>73!>=y3Mxj%FcYR_bVouFW*LcTy-y1o+QZ#@CZRB}h)lAHFBbINwzN^m zB0f;RU(b6O~B0qew zYPQzi$@zM$Uft9IuFJooEv1wm?|) z7C8&eCwzbra}}8Tp9;JH6^LK73@yHAt&h}%zMLVeo!3Vx@%K;QjD@jSo%6~@Ifd5` z1WsW*e2t<>}zAS4Ot{&3X}rX!gWPa*Sn>JwfF}hs7IRIjp5Y*&Zuh<;jB=pksdW zLK}AW^Na9Mi@flzQ;|0=`M!Mel5gVIK->H~jIsYJ(@)># zd-^0aA48RQo#CZz0SyD4k~lICFYv-yKZf7^Be{;_VG#CrZ^nz zu*BZR4u`$|Z#E5hI}W)AyjrDsz}xv$OVk^FqBZL6U1%He9$w@Ax!c=2=nY4`oj?KV zfY(3Zg{(RWjLG7eg9*7_0f zRzNV0>RL@{y}*?PFQxPh2prG2x~%MXnXlThcC%%^!t41LFQ$S-Ee>xOzj#$iOP|nN z*hYe(DmEPOKX1dg3A=?oWWz@!{-_P#A?%OYP{u|jZlBqNz+2c}o5!TYOEx?S_8O9Z zvF`wzfd}`fU2*_4!ix_0yaSHoXcXr=4)_lp@Mj$GpE}^rJK!%m;IBL2rycNf4)_NS z_+iykwqOwnvuq-r!$5n&ES1)o zk)BQ@@$$IhHoEfG$#f%ED5i7fl(>E}!%XEZlTA%!EMtaE>BVBcNUo%8Vpud>zlO4S z95}grTwPRGUQ3}FZp(1VP0s9&;}w=A3s$_K7n7`*$kvq<$h zdNc6?CcY6ej}f_Qhn!vx2(MB(2fIF0jTiDTHC3I7*_PvajWxR>y&61T@W zPxv&>9|%t4yzdal1N#XD=ZlY;*E)$~zqb&4qXXXWfX4`q-v$+bRN^ZC*F^FdixV6# z!it|FacDljMsWNtEB-u*gXfjP7YLumIYRijHx&PQg5$SS;b%yk+X#M<;I|X}3Wp781V9wdCazJ~~(j^|avUkh>7_}?Np-h~vtTJA?| zru-g>R74!4&trw{0u=5JiAa3?-E+Q(4?;T$E6)6_?=S6 zs+Zsx{|#yP+wixft;rhKS8f4;^bovF>Y@r6b6GR7i-q9pS+8f5R@5_zkg3m_ECgSh z1Pkpl3>GTp(Lg%>l@q#70whs1t%8IE2^xW~d{iAu8YX;!llg2Ge)h0XE^q1~_;J%M zK6=ug&RL;C5&rlonsYLwJ`CRRI4u1shPv`o_)$>s9I?+|`R`OjS*vj? z_&HE8rrrO7?0;4fWo`F=2JlAfSC#9h@`5Jbx0HW}jMu1dY?_c8x>qh3uFpDn?EW_Z gX5V`NvBUBw{9U$$*-Wvo8u?$8 +#include +#include +#include +#include +#include + +#include "util.h" + +char *argv0; + +static void +verr(const char *fmt, va_list ap) +{ + vfprintf(stderr, fmt, ap); + + if (fmt[0] && fmt[strlen(fmt) - 1] == ':') { + fputc(' ', stderr); + perror(NULL); + } else { + fputc('\n', stderr); + } +} + +void +warn(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + verr(fmt, ap); + va_end(ap); +} + +void +die(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + verr(fmt, ap); + va_end(ap); + + exit(1); +} + +static int +evsnprintf(char *str, size_t size, const char *fmt, va_list ap) +{ + int ret; + + ret = vsnprintf(str, size, fmt, ap); + + if (ret < 0) { + warn("vsnprintf:"); + return -1; + } else if ((size_t)ret >= size) { + warn("vsnprintf: Output truncated"); + return -1; + } + + return ret; +} + +int +esnprintf(char *str, size_t size, const char *fmt, ...) +{ + va_list ap; + int ret; + + va_start(ap, fmt); + ret = evsnprintf(str, size, fmt, ap); + va_end(ap); + + return ret; +} + +const char * +bprintf(const char *fmt, ...) +{ + va_list ap; + int ret; + + va_start(ap, fmt); + ret = evsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + + return (ret < 0) ? NULL : buf; +} + +const char * +fmt_human(uintmax_t num, int base) +{ + double scaled; + size_t i, prefixlen; + const char **prefix; + const char *prefix_1000[] = { "", "k", "M", "G", "T", "P", "E", "Z", + "Y" }; + const char *prefix_1024[] = { "", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", + "Zi", "Yi" }; + + switch (base) { + case 1000: + prefix = prefix_1000; + prefixlen = LEN(prefix_1000); + break; + case 1024: + prefix = prefix_1024; + prefixlen = LEN(prefix_1024); + break; + default: + warn("fmt_human: Invalid base"); + return NULL; + } + + scaled = num; + for (i = 0; i < prefixlen && scaled >= base; i++) + scaled /= base; + + return bprintf("%.1f %s", scaled, prefix[i]); +} + +int +pscanf(const char *path, const char *fmt, ...) +{ + FILE *fp; + va_list ap; + int n; + + if (!(fp = fopen(path, "r"))) { + warn("fopen '%s':", path); + return -1; + } + va_start(ap, fmt); + n = vfscanf(fp, fmt, ap); + va_end(ap); + fclose(fp); + + return (n == EOF) ? -1 : n; +} diff --git a/slstatus/util.h b/slstatus/util.h new file mode 100644 index 0000000..cf4b027 --- /dev/null +++ b/slstatus/util.h @@ -0,0 +1,16 @@ +/* See LICENSE file for copyright and license details. */ +#include + +extern char buf[1024]; + +#define LEN(x) (sizeof(x) / sizeof((x)[0])) + +extern char *argv0; + +void warn(const char *, ...); +void die(const char *, ...); + +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, ...); diff --git a/slstatus/util.o b/slstatus/util.o new file mode 100644 index 0000000000000000000000000000000000000000..b5454d1ee1f21b726739ad8f08ae46c353362b57 GIT binary patch literal 5592 zcmdUyZ){sv6~K?3v~}C<*&U-~+8;e>FEnX2FW$1Q&7hMs&LYtv>-Ih9z-Iyk} zd43KlidZ6-iYG5qBtYtiN$kTWhCow345_Q8)ggs35Tb}LWt!9uA(X0vZRv!nY{Q&$ z-?{e7#r}c-!I9p*_x$cT_y0ZDe!6d9Uoa2=B>~t2HBC`~mfLFOZdvSxFc@%HxU0hb zNVp%oPHv+3ZbXzmPX^1B%sc|3^bnPt`-OW&xQ-Q)6{3WtndzoVS7GY~6YD)%ycmg9 zj$I=Mf#nOEu;8gT!uPC-*>^8f4YtxI+##z&xC7R%0k_xc9>9_~U3MN0xA$6u;r0RR zc({GY%7xpXvu4mI-2Q?!FY}*R&&&K3YeD9(S!K*eMX9;94GRKWYl)S`+-d8oRR8=& zvlZfskeKVWOfreQ(Q7q#AYNYmd!-^u=rk&JcuhF#yvfX7q|q)N-tS)8@4k87Tc0;8 z!oA_u&&hTAc6ll+5|_m8x9ly#L$R_nDE_i?Y>DPQc;tU%=4#S%1(pG4et~8sN4sW& z{`1@N4sJ`!nr&G-xHEEFhUB)~E_YVj78>tiT-Qsok^jbtx*L1K^M&{29d*23hh{=o z{^^XZoy@DBR4SG7Iq4tnTN0)E^P;JECkE&BlI-l}t8{VkbbD(c-0xXu5x6U2ZrZ}* zEbr!x7fBmrO?upTadvgN39s#r*;N{&vz_il?P814Y1vTi(4V?)i#fd1*Vj=tDDYfw zSP|jvY5S*tke&aV31Dyb|92t5`V|zJJlabtU}NqNtQb@#e2yG7rnfEdGZ?-SQaEn*mpL?YS zL56nST|V~Y-Y1r@^nW6g`Ap7EXPi_Q)QaYp3r?=!n2ue@B;rnT6jBq;@K|9Yp6N38 zXC~w0=}~heo=-w+G?p@3^8hE|QRs&u7=%7}9FD?)G(4Jy{xl4wVK5DSX?Q#hN7GWxv zZBuo(YMj<9=(Cq=&ect@zGld!TiO0z?n16FGFo$}V}B3x%`&egw9jO}t%hW2yG+-^ z7c@?5NA@|5?__Rk{Bx*BG)8Jq1AeFhKiYr~H{dDcx8ZuKb(Cil*~td>bQbH4^BHa@ z&g(4CDzf9Y^}?7!sWv`?!2&+z_H`=9dhhkcx4w6fpBoci71 z<6rS{+B0Q;#Mch};!=D)HGo3>(%cn)*~k6kxsT5wRo~&WKf_!f|Dw;HimLtJYWxYT zBYDrqH=?fWKV(kr`^P^)0ENawf5w#k40C-vP4pn5kUhmfWxts@+27^kcl+#b@$qdw zd;fTz^l|zyNN7A;@Kg3lf+)oO=SMp6`d zV|_~FPq99u@i^<>(fBCq^BOKEb-lIh{lLl&JktT)kVWf5p{%Kf{iS ztM};sk3baTx0jEplARonN1f!915sHVjXQCO zj^y*GXGtNSSTqLFM0R2Vf8#{1-%C%cKCemzdJpIhc2|j4$Wf3$IY%3ULMrtWA_b+z%U}oQ z#5t@n1-QihzEmY%!PNB6qF%56HhOGO7N~I)>Yw`1`;Rfx`=86>k^GJOH>FlfbbpFJiq)*}4Wq}fj_9^@|H+iMsp`?f z{)1KG74-Q}BBnNV|1tJ&(>m1szmC53_V04U>#yu(a{uUEQ~v7w)a#pE=9M9DEd7R| oPhsUxZ>zrdh+v)`MU<;DttHxY