From de4cf2cf7e7b20594312ce6e7c5fceb6790a5401 Mon Sep 17 00:00:00 2001 From: krolyxon Date: Wed, 1 Jun 2022 23:52:05 +0530 Subject: [PATCH] first commit --- LICENSE | 40 +++++ Makefile | 68 ++++++++ README | 65 +++++++ README.md | 1 + arg.h | 33 ++++ components/battery.c | 252 +++++++++++++++++++++++++++ components/battery.o | Bin 0 -> 5480 bytes components/cpu.c | 164 ++++++++++++++++++ components/cpu.o | Bin 0 -> 3128 bytes components/datetime.c | 19 +++ components/datetime.o | Bin 0 -> 1920 bytes components/disk.c | 58 +++++++ components/disk.o | Bin 0 -> 3104 bytes components/entropy.c | 27 +++ components/entropy.o | Bin 0 -> 1776 bytes components/hostname.c | 16 ++ components/hostname.o | Bin 0 -> 1632 bytes components/ip.c | 60 +++++++ components/ip.o | Bin 0 -> 2552 bytes components/kernel_release.c | 18 ++ components/kernel_release.o | Bin 0 -> 1824 bytes components/keyboard_indicators.c | 48 ++++++ components/keyboard_indicators.o | Bin 0 -> 2400 bytes components/keymap.c | 87 ++++++++++ components/keymap.o | Bin 0 -> 4048 bytes components/load_avg.c | 18 ++ components/load_avg.o | Bin 0 -> 1856 bytes components/netspeeds.c | 139 +++++++++++++++ components/netspeeds.o | Bin 0 -> 2752 bytes components/num_files.c | 31 ++++ components/num_files.o | Bin 0 -> 2144 bytes components/ram.c | 222 ++++++++++++++++++++++++ components/ram.o | Bin 0 -> 3080 bytes components/run_command.c | 30 ++++ components/run_command.o | Bin 0 -> 2128 bytes components/separator.c | 10 ++ components/separator.o | Bin 0 -> 1200 bytes components/swap.c | 284 +++++++++++++++++++++++++++++++ components/swap.o | Bin 0 -> 3920 bytes components/temperature.c | 71 ++++++++ components/temperature.o | Bin 0 -> 1696 bytes components/uptime.c | 33 ++++ components/uptime.o | Bin 0 -> 1960 bytes components/user.c | 32 ++++ components/user.o | Bin 0 -> 2184 bytes components/volume.c | 217 +++++++++++++++++++++++ components/volume.o | Bin 0 -> 3608 bytes components/wifi.c | 272 +++++++++++++++++++++++++++++ components/wifi.o | Bin 0 -> 4288 bytes config.def.h | 71 ++++++++ config.h | 75 ++++++++ config.mk | 22 +++ slstatus | Bin 0 -> 31824 bytes slstatus.1 | 28 +++ slstatus.c | 141 +++++++++++++++ slstatus.h | 84 +++++++++ slstatus.o | Bin 0 -> 6224 bytes util.c | 146 ++++++++++++++++ util.h | 16 ++ util.o | Bin 0 -> 5928 bytes 60 files changed, 2898 insertions(+) create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 README create mode 100644 README.md create mode 100644 arg.h create mode 100644 components/battery.c create mode 100644 components/battery.o create mode 100644 components/cpu.c create mode 100644 components/cpu.o create mode 100644 components/datetime.c create mode 100644 components/datetime.o create mode 100644 components/disk.c create mode 100644 components/disk.o create mode 100644 components/entropy.c create mode 100644 components/entropy.o create mode 100644 components/hostname.c create mode 100644 components/hostname.o create mode 100644 components/ip.c create mode 100644 components/ip.o create mode 100644 components/kernel_release.c create mode 100644 components/kernel_release.o create mode 100644 components/keyboard_indicators.c create mode 100644 components/keyboard_indicators.o create mode 100644 components/keymap.c create mode 100644 components/keymap.o create mode 100644 components/load_avg.c create mode 100644 components/load_avg.o create mode 100644 components/netspeeds.c create mode 100644 components/netspeeds.o create mode 100644 components/num_files.c create mode 100644 components/num_files.o create mode 100644 components/ram.c create mode 100644 components/ram.o create mode 100644 components/run_command.c create mode 100644 components/run_command.o create mode 100644 components/separator.c create mode 100644 components/separator.o create mode 100644 components/swap.c create mode 100644 components/swap.o create mode 100644 components/temperature.c create mode 100644 components/temperature.o create mode 100644 components/uptime.c create mode 100644 components/uptime.o create mode 100644 components/user.c create mode 100644 components/user.o create mode 100644 components/volume.c create mode 100644 components/volume.o create mode 100644 components/wifi.c create mode 100644 components/wifi.o create mode 100644 config.def.h create mode 100644 config.h create mode 100644 config.mk create mode 100755 slstatus create mode 100644 slstatus.1 create mode 100644 slstatus.c create mode 100644 slstatus.h create mode 100644 slstatus.o create mode 100644 util.c create mode 100644 util.h create mode 100644 util.o diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..b88a9cb --- /dev/null +++ b/LICENSE @@ -0,0 +1,40 @@ +ISC License + +Copyright 2016-2020 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 parazyd +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-2019 Michael Buch +Copyright 2018 Ian Remmler +Copyright 2016-2019 Joerg Jung +Copyright 2019 Ryan Kes +Copyright 2019 Cem Keylan +Copyright 2019 dsp +Copyright 2019-2020 Ingo Feinerer +Copyright 2020 Alexandre Ratchov +Copyright 2020 Mart Lubbers +Copyright 2020 Daniel Moch + +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/Makefile b/Makefile new file mode 100644 index 0000000..2f93b87 --- /dev/null +++ b/Makefile @@ -0,0 +1,68 @@ +# See LICENSE file for copyright and license details +# slstatus - suckless status monitor +.POSIX: + +include config.mk + +REQ = util +COM =\ + components/battery\ + 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/separator\ + components/swap\ + components/temperature\ + components/uptime\ + components/user\ + components/volume\ + components/wifi + +all: slstatus + +$(COM:=.o): config.mk $(REQ:=.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) + +dist: + rm -rf "slstatus-$(VERSION)" + mkdir -p "slstatus-$(VERSION)/components" + cp -R LICENSE Makefile README config.mk config.def.h \ + arg.h slstatus.c $(COM:=.c) $(REQ:=.c) $(REQ:=.h) \ + slstatus.1 "slstatus-$(VERSION)" + 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/README b/README new file mode 100644 index 0000000..86fe988 --- /dev/null +++ b/README @@ -0,0 +1,65 @@ +slstatus - suckless status +========================== +slstatus is a suckless status monitor for window managers that use WM_NAME +(e.g. dwm) or stdin to fill the status bar. + + +Features +-------- +- Battery percentage/state/time left +- 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) +- 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. + + +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. + + +Upcoming +-------- + +A release (v1.0) will come soon... ;) +After a long phase of inactivity, development has been continued! diff --git a/README.md b/README.md new file mode 100644 index 0000000..7dd4ab5 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# slstatus \ No newline at end of file diff --git a/arg.h b/arg.h new file mode 100644 index 0000000..e0adb9f --- /dev/null +++ b/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/components/battery.c b/components/battery.c new file mode 100644 index 0000000..f2b0f14 --- /dev/null +++ b/components/battery.c @@ -0,0 +1,252 @@ +/* See LICENSE file for copyright and license details. */ +#include +#include + +#include "../util.h" + +#if defined(__linux__) + #include + #include + #include + + 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 perc; + char path[PATH_MAX]; + + if (esnprintf(path, sizeof(path), + "/sys/class/power_supply/%s/capacity", bat) < 0) { + return NULL; + } + if (pscanf(path, "%d", &perc) != 1) { + return NULL; + } + + return bprintf("%d", perc); + } + + const char * + battery_state(const char *bat) + { + static struct { + char *state; + char *symbol; + } map[] = { + { "Charging", "+" }, + { "Discharging", "-" }, + { "Full", "o" }, + }; + size_t i; + char path[PATH_MAX], state[12]; + + if (esnprintf(path, sizeof(path), + "/sys/class/power_supply/%s/status", bat) < 0) { + return NULL; + } + if (pscanf(path, "%12s", 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), + "/sys/class/power_supply/%s/status", bat) < 0) { + return NULL; + } + if (pscanf(path, "%12s", state) != 1) { + return NULL; + } + + if (!pick(bat, "/sys/class/power_supply/%s/charge_now", + "/sys/class/power_supply/%s/energy_now", path, + sizeof(path)) || + pscanf(path, "%ju", &charge_now) < 0) { + return NULL; + } + + if (!strcmp(state, "Discharging")) { + if (!pick(bat, "/sys/class/power_supply/%s/current_now", + "/sys/class/power_supply/%s/power_now", 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; + + if (load_apm_power_info(&apm_info)) { + if (apm_info.ac_state != APM_AC_ON) { + return bprintf("%uh %02um", + apm_info.minutes_left / 60, + apm_info.minutes_left % 60); + } else { + return ""; + } + } + + return NULL; + } +#elif defined(__FreeBSD__) + #include + + const char * + battery_perc(const char *unused) + { + int cap; + size_t len; + + len = sizeof(cap); + if (sysctlbyname("hw.acpi.battery.life", &cap, &len, NULL, 0) == -1 + || !len) + return NULL; + + return bprintf("%d", cap); + } + + const char * + battery_state(const char *unused) + { + int state; + size_t len; + + len = sizeof(state); + if (sysctlbyname("hw.acpi.battery.state", &state, &len, NULL, 0) == -1 + || !len) + return NULL; + + switch(state) { + case 0: + 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("hw.acpi.battery.time", &rem, &len, NULL, 0) == -1 + || !len + || rem == -1) + return NULL; + + return bprintf("%uh %02um", rem / 60, rem % 60); + } +#endif diff --git a/components/battery.o b/components/battery.o new file mode 100644 index 0000000000000000000000000000000000000000..5ffa41b1f00b8aa1f80b75ade563c92a607681b0 GIT binary patch literal 5480 zcmbW4e{7q@8OP6#y*SXlPTLd=VVjv8X4cl}TPO<~qjA!bx5HxXNEnnB_pS4~N$c3= zecy;=n&_$~)!wycom6Q;{4s6f4>V0%|3I6xNuAdst?M+@@Jkf}5g{bfnjdY1Kul%f zdG5WlpI+@w>Pf!$?sMPgxx44?y?ecXbLN3yAi!h_u=`n~CMjbJosDuoFZQz)Y&lDh zZ1KL(tLfn_-X|l5_aDRi{9(iU*zjI8yv6j^6AbJYP(NGU->p|O-g(1&lT%R1hFfbZ zPlQ0zK$EZ4ZrQBASL;&wg)QD&+cVz$<2%zk(mPM3hoM8?U1b$^Gh!V0AO?Mo8izwY zN$ztd5di>wS4I<&jQ76ibvmS1YpadQS~SzEMrAk=f>y)(hzpiZPrh^5O@v@fdX*F7 z@G=5LzHmiB1?qbY=su4JRVT>?>34i$?U@Cu^$=Z|>l`0b}mG z(J_bUAB)jPt04CUr%`b7;5-N}7#$~3a0UebT8usc!cM-M^U>au4!T=&v9>&#JiQp* zaRzIbjObtgx6zpW)OYoAEoOKZ;e|8i7O=;Tv*-=f=xqmhdyLPy;q7cqg9hw#%~^2u z-;H8#k)7`E+N;(c*Ok9|=_gM0I@3;Xu3$P&Z@Ki8WoMnqa=9?w+XK`ro4Ij!n)Qsb zjqDmi$2HwahxO>|9X2>-+Iz-}d)TINCnw7fOco04S{|&TW$&5J7E4cEOU3)uND*w;jq-|S8SNa=^gVPDNnyqCeeA})+1r^g~XE9^*gTCycel|2X_}zGN=%JB2 z~1&m>UeWeb? zGVyvF;ZpETUf{2-MEvH(Kc57W&I_Uh;t2ZMv>yPp5LMJf7Q^%9VYW+(`GGa9f=l>)cxB=6WBqoMPD?FS>bV=5m(f zFfp=h*|K49PR=am*=`}pX5qrg?aSuI_GR(2!EgO zuM;j0JRJWw2=5l_jpM<$K>8mPT%GR-(ceJyyNI5Sr%3d8mP-E)(cez^0is_<_@Ng1 zV?_T|qJOr9{&}L;i2l!nM+yHs;rO1(@&B7}Jnbd_P;fQQ9pZgb2>8s}|9Pvg9U z=xLny68&;Ao+k-kLHI1;D+&K~3;(|(db%#ZC;HoopBIU~i|~IEj-S3VZZ8vl6XBPL ze>&goZ6Jb#%{RkO`gwuy7~y9KzlHEQ!7={yeK}7!eP2Mv6D~8_Z1t;5-V>597yCe- z&63Oe7RQE3@|8j#=d{7)J)BhdDn*ZR5TWAAM}=N;dC$x!T;31I6<)swQqJ^*Ywl(# zI5Yj{m@L^=!A!Z}1rfag)Za9@wb_pve*HduHa}g&{g2q&#lrsx;Su+&6MR+#$Hq4ZBa+LGu+! zY=b&m110o%z4rJWi9XlEk0#mw%}R%|DxdhBh-J0^U18tbI_eb4ai!i5^=9!iFkq05 z`VSsITq8ApxbLxlJnLvWD*BI82xa+x%4Z%}GyCJhUh1S9*}r@`!hW3;h-X#U<5^1+ z_Jv74e@e={L1eEAd&;mZ?Ig$V3;eF2X92dI6ZY!33R5}Pt`smUWf%0k)+!H z2HKjf-#M{ +#include +#include + +#include "../util.h" + +#if defined(__linux__) + const char * + cpu_freq(void) + { + uintmax_t freq; + + /* in kHz */ + if (pscanf("/sys/devices/system/cpu/cpu0/cpufreq/" + "scaling_cur_freq", "%ju", &freq) != 1) { + return NULL; + } + + return fmt_human(freq * 1000, 1000); + } + + const char * + cpu_perc(void) + { + 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(void) + { + 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(void) + { + 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(void) + { + int freq; + size_t size; + + size = sizeof(freq); + /* in MHz */ + if (sysctlbyname("hw.clockrate", &freq, &size, NULL, 0) == -1 + || !size) { + warn("sysctlbyname 'hw.clockrate':"); + return NULL; + } + + return fmt_human(freq * 1E6, 1000); + } + + const char * + cpu_perc(void) + { + 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) == -1 + || !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/components/cpu.o b/components/cpu.o new file mode 100644 index 0000000000000000000000000000000000000000..d78c5dd09ed005e0f80ca8595831fc8acf3b61f2 GIT binary patch literal 3128 zcma)-L2MgE6hLR4gqSusCIl(aO7&q4DYWZ2B&bvYxg;TbFepL=3bb<8n{^#(JI1?4 zNfm`gp;AL+DF+UfkPs4=95?`H)H;a|1#tkx!I6mtm5>s(s?r+=r11ajd}lMQrG9JY z|9SKO%-`8R<4;H9Z}=32ktpmnw%;Sl*o=SQj&U=_I$40}i+6kU(jXGO^eU=JeYrK< zi~Xe$)gLYEOSiX?pIIuO*}GNj)~ANl?H0yvV8ci5_`qxVtm>cCU+m_gP8%Q47b`s* z`oi56oUPP`vxv27C*2NTu{NisT>#d(hNU;GQw^)PVf8dD|G2)m9TZJT|5Y!Im*XXU zH(rYU6)jUDq3_w|y;??{sO@xqx!yVY+h@ObUR{GM7XNMUym|u+7#y#!K^udX=jXQ6 zBQ3@0=b)sCv5=9dRleW7v<@D7e` zRkx~lx_H}xE&br5xLzCR)kMM{6tMMzwyekFi!5 z3BiNK0Rzm(lrl1^VMX+z*0^*Ftz3SaDKkOkNJqPW1)Px|6=O-%BY}|bLco6l%mKj{ zaniBCb;Wl+@U=1;ScT_1<-@>=;``%Jz(0D}2>6BT0}4Z1+5No-1^~1)vOPH3!r$&7 zYlp7l;dwE9m}`DS4g>@R$35}N)4bEhPJ1EP&kFv5#E%JXNnGXq$0W+waUflu_u_jB ztREgXr-LD{G~vTd_*vjMKh4X(4X_JM{2A1tW-w+bdp<_l9fCk0D0{5~i?c<^idx93U# zAqaBZE#l811i|mq0T1yQ*eJ;H1QUNBAqaAulXwOp2+ohSejYm@wyQYD+{k~{!_lAk z6%WT^CjPmHqd(?~@`bA!>(UweO5%8qP*z>l@E;QWA0!?Z{U0Sx?{!;ndEcH92cPzV z@;@eV%Kv$ZQ~nW&Q$B+dr+m&yoZfdr;zJ_u1rL8580Gnmhad9rn}Xx};`t%}5ZEaA zzW9)w5(e=k4QTdk)-jSyvz>yg(_|H_jG;N!jKj1^!!ekav~8vprm=(WQ4Nla=$f`O zz%+9@o3(P_pPP0p4esBQ{D_GD#avN?OB{}fGYf$@yOoB+Wn|@Bgpzx79RgR}68Ywd z0Ymvm?3dfy|39Gq5ioEsV+4dA7guOrY$nzTPDK}ckMP5DiyY5_SHdFB%g~n6VOSqH zryL&>@pP|aEJ}#C`%M%~oD=U;uTXs23&E!KNyh~1lKfW1`nWe +#include + +#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/components/datetime.o b/components/datetime.o new file mode 100644 index 0000000000000000000000000000000000000000..bb91f79413439b9a6d7decad2baa4f937f15bf96 GIT binary patch literal 1920 zcmb_c&ubG=5PqAcHfmj>RtQ#Q4^b-WBinBjgGikQ1y*nrg1LW;4r4vQ###q?XAMUi<`J8$-z4FQP-I8Ca zIa9`><29?kK}4m#W;m^a;}kt(wOJ}TuHjX-93kd%xhZ2}?$ML$hH1)4nW01QSq8~4 z2}MLqXzj?S(kwbY&t#190BvhgXsx6+K015Y7rzgV1&A2xvyss-5x@E<&XRjBk{|vS;x3XTkEVv+g#rAP0sO=O z-W9yD?K{|~MjxMw1I#pZxPRkdPrezDc>Ul!C4LC?Qr72{gQL8z1N~t$| zN75C(6^=;xYxSnwa2p$r>u*vi8am~C$+c;;{{;qh!QI7-qsS_U?;pqb9kD-724awn0m5_^9a&mSqka}uQX)@M|GmSR!# z*3%R2yZ^FU2=5vD$2;SC=KGzE^ETA^38hDg +#include + +#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.0f - ((float)fs.f_bavail / (float)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/components/disk.o b/components/disk.o new file mode 100644 index 0000000000000000000000000000000000000000..aea683de500e6db36e21a08d1162ce789996e0e7 GIT binary patch literal 3104 zcmcJQ!EYNy6o=osN#jECn$QZ1BIJWZ4Q*F(iiA`Na7iG02o@^OK?Z~?+ z4vMIysHj$`)FWItaN-7k0WyI@KpfyusYi|o5K`qE0+sihovB~94xmVV((KH9@4b05 zZ{FCKUs`xMVOeCvqUUKiGn8mKIUE<&ut+wgXwmKc?QVbDt++d5Q+Zany}4Yc(08we zx#TY}ywcx1&hy?M?zQJISFq6k?YO(Ml}o$!7hAdfS2U&-?#^quPQ^WSOf43UD{FWA z_wHNY96Zz|cV{k_cdzt269d4$I@eWXHvV86LHu-{N{V4uDfZTo(lMWiirpVRgjZYblP+R9~BBz0Hm|2kR_ zdf}yNkUcpSoIFQU738V=0@2=!G(S6gE}Ngfu=rHAP;h3PX~MlzmfJWtR#1YhKA5RN zOV5umgB*)GvfjT)Rwr$pI69HM&c<2hk852W{rOb-!^C{*x|Q%!>GP>1qb#=~H^>k8 z3~hF$joLD+|81SC@Ml@aXShz)tOGnsaIP`Bb$gWV(4A8cwb*x*ogu?WRT>?>8}e*Y zk#T;Rcgv${dRXOKYLK%@5m%j=*^}JT(om0`efZgZIG+5dbuKVRToX^-2eYMp?3cCu zvq&I|@k5VwKGR&?2Mj8!LER~nvoJf2PXV8^_{=C(soM5^(zQzOdF>`u8)2!o(eRp7 zDzTzmFO_TcQq@~si#*o-c9~Yz+pEp68j-LSdRn;=_^NE4Kx`J&Fz)WJ+mRq|kOa3w z+zdzFAh1V`8@>R@0{#Fu!#zM2@CUgW-UDQb$NeP2_r(2F^LX4pg*|j;ee)NA{o}0~ zZtJ{*qZ$p*XpS{dtA?KuT<(8SaG5t>tS|HSuCSMR+ZJ5r?PI}Z+`iy4?vI+s@9T!J zmvIMz%eYA_z=Ax;xLH6JsI`fj&#CW_*Y&&>c(TwjCI;d6o;a$n>oMa`oBg`sgp z@86u)Xpk$2>0jY7)|v(svZnnX5e!2U*YvLoCQUE@&-_){X@XnaysJTcU-9#NpyS8= zztrG!xhWpU{WqD7s-F%v#j>ovM5rIUd*g5F2YHCchRc#Jh^|f)ej~AD+#kO&@!DZT bH}wT=U?Rli-5}J*NPoTmtHx0GasPh+^K$!3 literal 0 HcmV?d00001 diff --git a/components/entropy.c b/components/entropy.c new file mode 100644 index 0000000..2a485de --- /dev/null +++ b/components/entropy.c @@ -0,0 +1,27 @@ +/* See LICENSE file for copyright and license details. */ +#if defined(__linux__) + #include + #include + + #include "../util.h" + + const char * + entropy(void) + { + uintmax_t num; + + if (pscanf("/proc/sys/kernel/random/entropy_avail", "%ju", &num) + != 1) { + return NULL; + } + + return bprintf("%ju", num); + } +#elif defined(__OpenBSD__) | defined(__FreeBSD__) + const char * + entropy(void) + { + /* Unicode Character 'INFINITY' (U+221E) */ + return "\xe2\x88\x9e"; + } +#endif diff --git a/components/entropy.o b/components/entropy.o new file mode 100644 index 0000000000000000000000000000000000000000..e6689e2f58a6ddac9ce86b3c37a066b77428a745 GIT binary patch literal 1776 zcmbtV&1(};5T8vG8?lB}D+pECLn`&7FWurn1SKJARwy3C96ZRn-E3@avm1A}(&)iM zK?tGXf8f6o(1ZR5J$MjL9>kBkP-ou0Nw>@Pq63pR^P8`?GsDa4J1ch!ng&c7+=2s* zQGou`fn1kj9V&1V+ScwOsn+gIc?^G8JKyz=H7d?85InqHEt_L&`1Ko^8^f_VZtQ>D znz2ULs@CwQM6J=oYPn-wnUx`NDFJsr=#SseKih&@KMdSjG>B>&Ug&$9wb1c9L9gcd zaTxRmw)4VS-vnqin>UPw*8TP+!!*URSfYYZL^hC1$Y_HCXk)^dG^O)5&nkoV@&Rbu zx;8g6U4Dzk^N14@+4R$>=x++`icx4)^hTvjP##gauV_tTdPC$7Brpk?Z(fSnY@Fe%uAyj$+5% zu-&x{yDMjs^q+1}K&BP?v!77%oe56!VEi)5M1&nfX1tCv5#iIwjJF9yBAkZ6xPdYe z)g_*ghz7mbSp^ZrVREjq6ndMEh`sF?M8}C85UWuHA`D0&cT<=k+@ROPo`CR!*b}%? zi}ItD{?y+RxUPLKj0YG>3B5JD8#+C2a)bX842-6oqTZybt`wd>+jy^8pF@FqRcAn* zPgIk(l}_`aSYGUN3cslE)N>#$@02}zWb4zOQO+}AwjqCGSM+3>p z>%d+BpOkp!0Fn~N@p%tXmea1E(@ILt`aVJ%?eC$TMEwggQTATk|HKOL90kgmjn`G7 z>+Gn`Y&<@cx%1ys33<*m|KrFU&v;&KDrKqqd!!)EAk! +#include + +#include "../util.h" + +const char * +hostname(void) +{ + if (gethostname(buf, sizeof(buf)) < 0) { + warn("gethostbyname:"); + return NULL; + } + + return buf; +} diff --git a/components/hostname.o b/components/hostname.o new file mode 100644 index 0000000000000000000000000000000000000000..d8f10d0a80a6159de95e78815bda5b992166aa54 GIT binary patch literal 1632 zcmb_cO=}cE5Utrn6EUvq7YI=p4-pO8WO9;#GGU3CK=7b=kQ~hHI?00BnRTXvSv`n| zhdl&5c<|TAfERy)H$CR+JrL{7c4d2qi3jmPrK?`Os_yBo?7Nlqhc(9`fkO{y6bVc8 zt2Xle!u6?6=jchWe;wghnj{JaKMxQr5AtB}W94JsZ+LmIe;-_t@bZms+mY@hnQryt zup2EAtu~uW?yc2FPj9=Prxw)$)aXVo+bK5AQH`7&oWL=$ob|FvIBy=4v)6EDXQrk< zaq=4TFklgXmg|iVwO)N1{$GH;ll1$jN-|M#LoDfRh!g$bAejBTV$>nG`$Yfm}}+k@QgU+;n5H{2Y~!(HsR+$GN7Me6Mh~f z1Ntd8;a&Ct=&ey9Qdz&N!xpbP9j+bm(r71CI@;5uUW7U%)ygtbX@UT9PkE%;Nw*ut zEQu2xDISHpnGV}8O}riNs$QD(qEz>}6b+-!^Q{zL{$Jp77t8|g#)fYKc~8kfYh#uJ z+?8*W>>n86rs2=>3QFb@a|7ID1CKYbk=lXfm-oNJIrRM3dXH<-v;3X1|9Q^Yko{%# zISGIGUp-R3H}0hoRd`Y->l(A-+tSZ=VEJY3GtOa7$7Yh_FQ%q^F1de`rdRBsXSx2n z5!@4@SeFh +#include +#include +#include +#if defined(__OpenBSD__) + #include + #include +#elif defined(__FreeBSD__) + #include + #include +#endif + +#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); +} diff --git a/components/ip.o b/components/ip.o new file mode 100644 index 0000000000000000000000000000000000000000..790ed4eb4684eb45ec2ec47fe90b9cf73b124875 GIT binary patch literal 2552 zcmbuAO>7%Q6vyA@qcx@72B?Ikf>?oD8Btc=P$38cd6SrIDhE}xK`Jy@j=fGy;}6yw z>Ocjmh$~jch+|KPBPWE!sT?9p1SD>i;D9((J@h~n5CRE=1j4-k?o7N{*%x@q?7aEC z_h#PAJWt-qWS<{V6q2IQbJQP6O4K~i*VDe5CY6qm`I5P4dcT|J7tdMVU)I&1v@xQh z)gC*MWG~CxOvD)&U8{2?5zBVm#Qi@aI@>NLVy*7RF{|?|#zxo2yUm4mBC*iAb9D0> z)A{z5MBHli+?}&G6rLvQ{gyGlc}>X}-K_`M?#I9>W_h=~ul(W57h2u*8}seiM7%Wn zbaMSu3wGbs`q_QZ`^8tqvX=L?SUF?d+10Y%AN%u}_qKNr^(U~}!FGz)W5NF1@nE*A z+t_y2yZy?NdC^=lU;T1xg!9|E^-r(2bqLybtgYB?xs)#!oyHWgUd>nRaO(oQsp z|7dPzW=c!Wy|DPGW*GXUp5j2BmNahT+}J`Rq;$cgC}J${?3gepZ@x%Mb3!?O_+acq zHlAgUBZI`@JgrWAFfy&iJEIv@dwSE?7HkrN^*4R3&%|(Ghg8Ps*WMuG=zvN@8S)wIx%+$J(Oo{l zDeV{4ACA-E{h00(T%L(E$63L?qVfoXK|DExpB}=W8N%m=@bg3X#UZ@H{9ZmEc`ou^ z9KjzJM<+Rz>w1Adq-SSR_!#(1qCQ2f(&fBU4c99*T&GZ}Q^~Py>9dkA=NQ|LQ*&s! z?v$%;iE@ncg-f}@>ZM#MUtZ&7-Z+iVlSEH&J`mLML2iHd0+|71!OsUa$8s9`yeCj5~PniN+klFR#lFT&;hlit{}F6qU*n-;o5?q9YTuTKv$j=RC3 zn9yF$l^lNZWXAum*Ek%d9QwE9Pnh<sgij(vI?fbloA#~!PZN;kDG`7>fr>kZ z;C+Cc +#include + +#include "../util.h" + +const char * +kernel_release(void) +{ + struct utsname udata; + + if (uname(&udata) < 0) { + warn("uname:"); + return NULL; + } + + return bprintf("%s", udata.release); +} diff --git a/components/kernel_release.o b/components/kernel_release.o new file mode 100644 index 0000000000000000000000000000000000000000..402cb889f0593ed4aec337044fad1df6b1af37c4 GIT binary patch literal 1824 zcmbtU&ubG=5S~pF8?}ZSiwgCSLo1QmN45tk1xujRt`HOi51zs{*_e`K6L+`Rsvw05 zN-6Z)^eXsg2zt=FQ0IGj({7iPV}-?%ao%F@9e*rNqs};tNwN#_H7s%vHRaI zJNqAIb{R0Z-Payx@2$?SJ9AUIV3Zl)JD+jRr%m7OcuO=J60NPQEES4t_a5FT*tS|w zC6rGy7nn25?4lG|ePBYCvALF}DI=|C56Ie@w5BJ3)3Ef-x`50kHD$r1-{p= z24359Lr>L6RaQ!P*a;Wu5z$jO@M*mlZ1_=ws?{)ZYprUn*{U|&jrL$he3YKo8J53~ z1~dS!Tfttb&@e{!I=*&410u{-dVs538Ew{Br^rDd&qUGY-9E{31RY<&pqK zN}kBOjEf!*{Sr4~dNTGA`>^k)c9QL{CMS6>>A!K)6IM_&nJ<@Glt3es`TVI4oqyI0 zMCOe7<9m{P!H1sBaf{|ff3gmmV8&lCnU9*u*)v2%^FsGw#3 +#include +#include +#include + +#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/components/keyboard_indicators.o b/components/keyboard_indicators.o new file mode 100644 index 0000000000000000000000000000000000000000..59acaab18a63971b47fb2d0e108d3a5e5c2ec37e GIT binary patch literal 2400 zcmbu9&uS5C{djZ0t=PWxeaJ z$0cr&3JR$(#(*j+^_WYg_SU~3SPDPxJt6hN0nt`aA#NN%?tAMQGhNx2_DQ?*=JUSq z&FuWxZx3dt`Xq^PlgI(`vd1YQ_Xl43$-qq#nQS8Zas8M+s~?>;YA>|b5o6_XA#c

G~UB5qknCHZ!~Cp)TrInem|)F9f-5FKeCN?P#1L9 zBdDr92|Ahjxp)FAN3-ub@hDvm=%L|tI! z;=92qdH>2#MqZQpW0Jf-BTwjZ0wf@Xl$0E0MS3(?Izpbdx`q3@oUpBdP&i~P5$C#D z&N$2zYFyeRNj1->Hi*93k~;4y)}U_3nTR(8Q~+)aXB5%ieTF|}MR zQfr>5u;T5uz&+n~ES1{Jl&E=&T11^Mmx=0o*g?6bYDCR>#iH$k#Pz7H!qp!SHiGrP za4TxbhyRC9tB{HX?Si@BTSdDwga73ykd2>=dnH +#include +#include +#include +#include + +#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(void) +{ + Display *dpy; + XkbDescRec *desc; + XkbStateRec state; + char *symbols, *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 = (char *)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/components/keymap.o b/components/keymap.o new file mode 100644 index 0000000000000000000000000000000000000000..5002c0395625c7fd0a5cc3a6df2906afacd19838 GIT binary patch literal 4048 zcmb`KUuYaf9LMLHq)9d1q<^fbt+L`ZL~572+COPg$tIU(LXTQ)qXCWAy}M0wz0 ziH(X4#0tw9D;7k3(l=k!2SGu!q)i+9B2*ECR!~sT(n9NtzKHSno1NcfZoPde{$O`z zKJ)$kW_D)ww|6H8lLuBsB8)7;9%CylqKsX>bEV!Vs(q}Jbujbk__FzwIbt3iIl|{| z@GP%3Z|ea8_Y%?G_`>g~<);>=Hu3pKu^wL-jQ=X=H4g^j-bG*H_YQj(LF{hf-ubi5 z=;_@Q-M|_ISSJG9ZMt`5c^3a^$sMene80jIN}HXT8)Ex}+N zpCzK*Nq-_q@3*A)4?IJ=AM@+xD9)aHi~Q78_oc)>H`@NP%jee$T8(or8SUcUU)*z} z{y@A6HSYZck0L_ABkbl?RL!>tr@3=&eBZgL^Pus^SiUq>_G=wyH}ER^GjTZ5=8nNU z;>$kw7O&6p>aJ-0nGi6i@3So^ZFX@ZH=1COV{7yRoJgA z-|p|8+v0o9UEoRY=V!*uXU#G5IWx65`gqwcCUTW>-kRC3AFy(HJFB}Ty#!d#`kakU zrp!}#WJ`N%+ndmt1in@F-9mA{)_HnWLhE{?sbACQoBOq%*IP_2_S$Mw>z!*&XtR-~ z?;=`nLW`MN4@mm8E^z7B+GLQB0z)^mKb9MHH#N*Cj5Ud;tM|AAni00T2K8DE^(&mP z|J>q*A|%Sq;@-lx)ltUoll(}4KOp(Z0Pm6f;{e|w`S$_7Q}Q1Ie6QqJ0{jtZuUFPb z>=Cd5xHt@ptIJQU z;yP|=5{tZD#G;rflvyg3ac9bQDxHG7$>-of?vvTy!*W{_u?c*}_U=hoNbc_f~IIvU1V2N&^!2*EH; zD_q1g2*FUl9xmcVgkY%06hr(3LNL^;nT$a|P+YlpOV# zbBHfW9vqk6bJXKcA=3Y%=O5zZ`0a{*R?%ZFrFm8reviW6SNIl%f2eSrJH`1_a(u3}3Ku_JpdDQQ zD@vSu6+KjiVRsW;wC?n|BHk+fDW?)|mmJp$jd+LTx}g5~#JSeYfS)9;m1YLMwxXP% znq%iJ!?jPi%*a}<#f)^N!VIT`4V1?X$Sgu62-Kj{z@J5VW@Ji*f?WjHV#&1)`1J1( zZ?SA2FHRX{2Yzfh?u?9KPo%~j{2BAVm=00!(Su*wK456{eezqrmg-pI-s9f&!KKZ6FSRPa`X3+nV^q(N1EQ9{90&lc_y8Qo2=M2vu yBJwBRXlxuRhC#vT{Ay6gE9j5ko`y>$&;JeRS1q`H_$_VZ-z(>TMs +#include + +#include "../util.h" + +const char * +load_avg(void) +{ + 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/components/load_avg.o b/components/load_avg.o new file mode 100644 index 0000000000000000000000000000000000000000..6553ff42bf54c25d9f1ac7cfb2b6c3800f956fca GIT binary patch literal 1856 zcmbu9OKTHR6vxlxVJp@eYmq{g&LWlgx@Ni&3re819ifPnx^NXI$s{d#Oq`6h)rE`V zq7iJLZnWWPcL=W7#=lss&-nr+_ynVQ`lrRhuG3WvHEulo+ zWM40YYJtY-JlQ)xav$NV*n6qj94q$jVs^^v+Ph!ABJN#xdxEX^_hE#@>VBX3eIc`! z&G2(2JF0yLNj6j2FvQ+l%T877o0DP1Al-vIpL3sTZqV?YinCdpH|^5du1P0LbqDvu3OiigP~&4YcEAfpQ=XJBai zEHlVtZzALMDj8cDV|r|4bf1I4uV`Nz^Wu0uQ6C@G=){EjDf)GE!oeUJt={*Jg(`M= zTrP%Ynr)fGmiI zPxvYz3mBRtyavbuj-CrQS%;twMkK1U-3*)(sZQYc=5^70x8bP3-3mxmoWLPf>U2o? z9t?zA$|6&|NQ9eW&S0JNPff +#include + +#include "../util.h" + +#if defined(__linux__) + #include + + 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), + "/sys/class/net/%s/statistics/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), + "/sys/class/net/%s/statistics/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) == -1) { + 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) == -1) { + 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/components/netspeeds.o b/components/netspeeds.o new file mode 100644 index 0000000000000000000000000000000000000000..c88e8757e717ef1ca7b04f6255c02bb0c8212a70 GIT binary patch literal 2752 zcmdUv&udgy6vxk-M2)|OSQP_W86gpW)HitnH!5W$)I3WpQc)Bs)0fE`GiGKozI!7x zmeNYK5Qcz@F8l`+mx1nF$bf}*)kRkY7j-FADz2mE8)VO;Q{7BCtR!!4}=S^Uci30)9Md8e|`#_P7*F22N!#I_nH1<`Iq@;VS593 zdpo|tZ%?S7oeuvVRyr^GSbOt2T=+SiF>L>kCYlb9?n*Q34PAcwC#>u07f;{AB@^XU zOXW+|NU3~1*7*^YS31%ar7INE>aG{K@h36F?hVaW5uKidDUlRO-4+4ONQjWnw)} zZbnrq*K~1az82M~Sme4c%@#{Dv&C{$sjg0-o4h2FXDGw^MsEKscV#b(Ea3bgtlZQ| zKo;EG7H;A{3CQC5U+ChLBbWGJH5~J7wfL;z?mRd@2>3Q`GS4C)3+6$s34Z{{0-oh2 z{4pR4=0VK~{}qr$@(TZ}i`VQ|ehk-tqxq4+?fqsAclW#B^2a$#-eHT|`z=`W*!#U~ zaeKcxvwo}xO~k%0@RfS>Rja0>De{$0y8Vo3NnDM59XB=k(~*wIpHhnaWDWzk2VA&* zX|7g_>+DjW)3MJ_-m$a*&G=e<-ftvxjX2RQ4#kA=OtG9qwOCg6Zhel!aTKU!TMA}S zHs>TZXGo}f+)+UsOuq!k^4tWVW}(WvH3TCI-Y0O}r7aKLM8@dikC +#include +#include + +#include "../util.h" + +const char * +num_files(const char *path) +{ + struct dirent *dp; + DIR *fd; + int num; + + if (!(fd = opendir(path))) { + warn("opendir '%s':", path); + return NULL; + } + + num = 0; + while ((dp = readdir(fd))) { + if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) { + continue; /* skip self and parent */ + } + num++; + } + + closedir(fd); + + return bprintf("%d", num); +} diff --git a/components/num_files.o b/components/num_files.o new file mode 100644 index 0000000000000000000000000000000000000000..21e3eb9dd3eab30590729efde647d865243780ed GIT binary patch literal 2144 zcmbu9OHUI~6vs~s2=W*!_#i=(ae>sJ69(c!jHacn46z{w#DLgfX$NWS180T^x-f=F z(!?e%T=;RC=)w=+R>MxzsBz~)g6BWIw+xeZqbE6Y&-tClo%@)1mPp#q3B#f{~o?(E_@Reoo@s5@@LnFGi+2=`;77@ zqx{oljCPF5Wu!~A^*a#V`ndn?y{ub^mwzl8m1{^!>DB1HXzEL?;D=rn+--JOuP&w# zep^~Ii`kr|4h`BvMzs;N!Ln4=HdYQ%kOEcDQh6_G zzTA@&oCgU!nW4Z&C@|37-tmfqNoHr<2+?bd6H2HOOep;?TcV1(-5OWITWy9i5}fW- z!f{14l>WF9nov3tT{B8Jrl?V+pGz2sCQSysM=Sl>Zxn86aB@9vVjG{;Vd)h-bQsfV z!TWr?wl?h2VL8WcuV-F&?aYQ*{k>5+)`VYe!Y7*Wn@#v^6HdkT!qQ4EZ`xXhv}8=j zV-$}uJVp-UB(4uxW;)B)h-}Bo6xJw{FWDyiS(cd;$=bAqD}PEqpb9)85b zw*^Ok+##92?%~}Yt_qI+(7I^$X2D4>lg8Uv8&{=enfbKlm>Ujh*|d`;ZP~U-vr2G~ zu4{ZsnNp!(7CEI@a!ids(Mz_I&O8+UgW|fjX7Pzx&L)?lp}D%WVxCJVa=!}O|DTa{a-0(No>JG`^8?|_IvHMIqn-88 zokUP1`rk|LKT;r%Sdr?l9})GdNb-okKF_g6=WhVA$aBW|<9{IQC2ur0>fVU?Z;27# mBG&1zM^FFRGooFwpm{hR5$)>aI9rYC?~C_;TF + +#include "../util.h" + +#if defined(__linux__) + #include + + const char * + ram_free(void) + { + 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(void) + { + uintmax_t total, free, buffers, cached; + + 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; + } + + return bprintf("%d", 100 * ((total - free) - (buffers + cached)) + / total); + } + + const char * + ram_total(void) + { + 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(void) + { + uintmax_t total, free, buffers, cached; + + 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; + } + + return fmt_human((total - free - buffers - cached) * 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(void) + { + struct uvmexp uvmexp; + int free_pages; + + if (load_uvmexp(&uvmexp)) { + free_pages = uvmexp.npages - uvmexp.active; + return fmt_human(pagetok(free_pages, uvmexp.pageshift) * + 1024, 1024); + } + + return NULL; + } + + const char * + ram_perc(void) + { + struct uvmexp uvmexp; + int percent; + + if (load_uvmexp(&uvmexp)) { + percent = uvmexp.active * 100 / uvmexp.npages; + return bprintf("%d", percent); + } + + return NULL; + } + + const char * + ram_total(void) + { + struct uvmexp uvmexp; + + if (load_uvmexp(&uvmexp)) { + return fmt_human(pagetok(uvmexp.npages, + uvmexp.pageshift) * 1024, + 1024); + } + + return NULL; + } + + const char * + ram_used(void) + { + struct uvmexp uvmexp; + + if (load_uvmexp(&uvmexp)) { + return fmt_human(pagetok(uvmexp.active, + uvmexp.pageshift) * 1024, + 1024); + } + + return NULL; + } +#elif defined(__FreeBSD__) + #include + #include + #include + #include + + const char * + ram_free(void) { + 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) == -1 + || !len) + return NULL; + + return fmt_human(vm_stats.t_free * getpagesize(), 1024); + } + + const char * + ram_total(void) { + long npages; + size_t len; + + len = sizeof(npages); + if (sysctlbyname("vm.stats.vm.v_page_count", &npages, &len, NULL, 0) == -1 + || !len) + return NULL; + + return fmt_human(npages * getpagesize(), 1024); + } + + const char * + ram_perc(void) { + long npages; + long active; + size_t len; + + len = sizeof(npages); + if (sysctlbyname("vm.stats.vm.v_page_count", &npages, &len, NULL, 0) == -1 + || !len) + return NULL; + + if (sysctlbyname("vm.stats.vm.v_active_count", &active, &len, NULL, 0) == -1 + || !len) + return NULL; + + return bprintf("%d", active * 100 / npages); + } + + const char * + ram_used(void) { + long active; + size_t len; + + len = sizeof(active); + if (sysctlbyname("vm.stats.vm.v_active_count", &active, &len, NULL, 0) == -1 + || !len) + return NULL; + + return fmt_human(active * getpagesize(), 1024); + } +#endif diff --git a/components/ram.o b/components/ram.o new file mode 100644 index 0000000000000000000000000000000000000000..d7e1c891791c1943acdcf4342c7b1f5d47741406 GIT binary patch literal 3080 zcmchY!EYNy6o;Rkq+LR@N=t+ymBSt!w9P;S5l&Kv*r`PSol23C6g@|KJw=J$HTK%MsF@>^#z<`aIw`iF0ukHKqN<4A@KhH4?sCR( z`l9>8YWHi={pM$k=DU5TpWnJO)Hx!0&tyKOVV-#7r_pFo^wu**Ma)b@`r*g`Zhb!a z8M|5d8#h^}U)WyG@Jb4qak0%-&UA0A2}ap9ryrR)cUHL`>6{R~LdFp9d=<`$?oBZR zP5z8K-=ebQM#N^nB5vOj-7lmGEH9g|yag=ppQE7mpWnIJnb^PiU(y__|0w`dqIZ=8 z(Bq8{GBCuu7t>#gnX9~gJsrvWJ>v!IjnJ(vT2rrgtj&|73|3m6r}y)h+>M%Bs_j8K z)@(J(#{w_dsQV3iFe4{BzVEf#yPlTZa@DKsc4?}z-!ReXrKLqHd-{c!rY*;@=j}P1 zMF<~1vbc6pH*MuqZW-fisG@$!3##l=DK==GWw~0Q>d-%k4S4{&rNwD5wy0w!u zHk5F~4@MIag?r^t)E%Lx@5OXj@>4PXsO0a*_)*C}h;fViN3``sv12yPWt>Y~khmni zcpv^ebJ$mQqZ}|>zt8+vCWqIeyU1@>`D6z>4C z#QlCW!2A4uCpqRH;G*nAk0bZtcTD4davKs~&zQ^u>>wt}&V? zsBt|G4b8qDhf5mQ{eG<3(fxj}aoz848rS_=ylx2gi=t#fHWXLq9OoFKxH`|_0Pk{j zp2==s2|~BTb=VrzRn=;FHP;Tk%OTknH+0D^wcBL38t7oUWAm{uH-f;c^OSlc^lW}g zpNNjP>|dyNY<~Rtc!yV56$ZU3Uko?!=a)PFMcqcK)@;Dc8+(}(d=*iLs;{I_@Ve>)t9oB`-c`mvr|JQZMZRKCp zImz(8>hhyp|06o&w$f8I-V@cq#p8*d#v +#include + +#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/components/run_command.o b/components/run_command.o new file mode 100644 index 0000000000000000000000000000000000000000..a148ac66b044e94f14cf52c13bbbf300739e3c67 GIT binary patch literal 2128 zcmbuAOKTHR6vt1J##XIkY+XbuG7D>KwL?-AYC%oY-yHzI<9pt#mj&wp}HoJ^CA{^91H^SkHV_nkbMNKX2FJ`(xp3jOtj z61{KxYsVZjMj9QV_*|lL5q|vET%x>t^ZHjf)8#jbjcTboQU0E&Tn33&orZ6jWMvS3 zqWpS$FF=$m|8N?T|A*PA2`BsMHWiPC6|_Tc}61P{lv3g2WR00i#-nO4(Ooyf*r|x37Ugpvj3Hbpo-9M%CsU!m^oqq}$j)J(_?pu1y_&k%hHxj^xd=ZE$U;2Y zgr5Usf#Gn4<9EJK2`_ zO~qwCztnnPdbq^vE{>eKjN*FMPA!tbds(Yj#InrQlwq4|HW^DPJ4MD~u}FrMhlB8_ z!N-L&G;1&iOaWv_E8Iy6@nGFB>U)@SfvhR)e|YX>~N z#FW3~;qo02+`|U;JSITZVO%1Xt`cyDFy+CA(a1W(1zd##Ir=1qr}mD2p4-vqzvf3d z7kv(KaZAR>`rMN7rH*kUYJ2WH#ZrCLDHZ#0Szb8)ez4Ma& zm+%K{U?^{XOpQM)fvWcAuQG3T{=9$7QI`F{X^$_7{f literal 0 HcmV?d00001 diff --git a/components/separator.c b/components/separator.c new file mode 100644 index 0000000..40fec52 --- /dev/null +++ b/components/separator.c @@ -0,0 +1,10 @@ +/* See LICENSE file for copyright and license details. */ +#include + +#include "../util.h" + +const char * +separator(const char *separator) +{ + return separator; +} diff --git a/components/separator.o b/components/separator.o new file mode 100644 index 0000000000000000000000000000000000000000..eb353e26d90d9aaba53a209a518499e9854c03c8 GIT binary patch literal 1200 zcmbVKJxc>Y5S>k;i5kH#Fc6Dash~?D*jUIxj7cFDf@mXpiDv?Oxp22aVq>eFKgH5g z@E6(H=}d0t+$;eh1A8;??Yx=YoqMVsAEkr6bAdXFF%w<>fhIl*$(O(e7d^Y!ro5Zi_JyXwh zY)|zv@bzQ!gwtbgHjn(0!6!W;ujhuY3PRa}B#!SywNiRfJTw^%eC0MlMk*ZQW_y?moy~81%eQ4M2w8y(_)W)otkd9ygoZ z7g0)YG;Nh|G*0fXG0%t7*D)Y2&4l)c7G`McH*h0|Yf}9-YN;mvVk5@=mq*w*mnc5R zo)Md==O!>>)-hGXAd8FUZ`y?h_POY;rd=YSnzsH~C;g|VJ~Sgo=d&y8gBCO~gPzXG y{h1%vn +#include +#include +#include + +#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(void) + { + long free; + + if (get_swap_info(NULL, &free, NULL)) { + return NULL; + } + + return fmt_human(free * 1024, 1024); + } + + const char * + swap_perc(void) + { + 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(void) + { + long total; + + if (get_swap_info(&total, NULL, NULL)) { + return NULL; + } + + return fmt_human(total * 1024, 1024); + } + + const char * + swap_used(void) + { + 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(void) + { + int total, used; + + if (getstats(&total, &used)) { + return NULL; + } + + return fmt_human((total - used) * 1024, 1024); + } + + const char * + swap_perc(void) + { + int total, used; + + if (getstats(&total, &used)) { + return NULL; + } + + if (total == 0) { + return NULL; + } + + return bprintf("%d", 100 * used / total); + } + + const char * + swap_total(void) + { + int total, used; + + if (getstats(&total, &used)) { + return NULL; + } + + return fmt_human(total * 1024, 1024); + } + + const char * + swap_used(void) + { + 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 */) == -1) { + warn("kvm_getswapinfo:"); + kvm_close(kd); + return 0; + } + + kvm_close(kd); + return 1; + } + + const char * + swap_free(void) + { + 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(void) + { + 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(void) + { + 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(void) + { + 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/components/swap.o b/components/swap.o new file mode 100644 index 0000000000000000000000000000000000000000..d4a86787f1c644ee0927b9d18056b0ab8976d0ab GIT binary patch literal 3920 zcmb`JU5ryj6vwCg0R^Gd6{QAZ`f!m2v~2m%U4ppXU0^mT1Z6>pV(GTGbhG`ky$uU) zRIo(UaVn zbAEHqnXfx@@6$V?J6k*+ro_XxvpGvq#=g8|PVW_JFY~dbEb>U?KxBVpX#c+OC4Tbi zDQZgcO55sAQn)=}jPYta-1$_U+v7$ruRZ{C*-IbuiJKm7TgE|N-6A|DF4g(OpC10% zfYH4OA*Af}LO}}|>BTVYA)|oIT`Du_T+@%hHAtQ!0mi{*gyr} z9}UdAyE0(-cTd%#WCW~jgOwq}J6PFlL~UA+A;a%P6ZJ>QGcZ*v2L`L-D?CyAM%2E* z>t6_mD~Ia!`ryQLAlj2OyybVU>>)c`i+qHw5*|N$xg0U4JYz||-q{1I-Ra@v^eJ*3 zu)lxwaOAPb;mG5W812B-K=`Y0ecpz7!!>UIIAh$b*CTcfn`a#yQqTYjFPZ zVkaRcLcJ^(JFR-55h82nyo>?LSfvT_s%6k9FV9^3Tg%`TZ47nMd%>``EJzOyE48r}=Ba@x z@km?U4a;SN=fuOzGv@cKT(Z#n0yT2tt7MyaJNtb8=Ue)GfitarzF@Vj&)0dnJ>u(n zc0t6~J+W}mSM#*K=J9n8__`v#PI4hv3hDEC8ABgwnd<=R0bj7?A)gog8Q3HzP*8A7 z+2OCiCei%^WWO&cV=2_|kE4g?f_b*F>-9z+tqpESB%?K(br*9d>kdK06*$`lWu@dn zQO^~Q-OlcsLqc0E%65h;P?vSWXlJ+Skn|0bhg^KK3+>t z>WfYIU=zN#2|w6`A8Eo1O?bHpA8*2|#5-so)&7b1h}g?b{NI%R9WA7gi1(4|cj;-g zJ|7TA{?pQ5Op10(@oMvvmx07;MszfOv`$}0l?cs~@6X#7@<4{N+bn^U&?T0R|&Mga-j%Tg-Fx6Jksnbd;nwfaW zGRG_yO2(}?3k{b_EL69C)yZ_txu*|uUYF$+Phz?0t{j0iHvM!h3bvYpScUr}% z8sAB!>nYl>s13yJdx(5+FY50+!n`uxJubEW@PRx*4|2NWyJh@EIBDXJ$N6fs|KG?T zmoXWO{l~ql;?@2)>RW{1<3Ms&4h(k>?sIoMa=Q1P5Ic)SA#so2y?(fR8^!O%fJvTo Js@c*V{|`|qzJ34z literal 0 HcmV?d00001 diff --git a/components/temperature.c b/components/temperature.c new file mode 100644 index 0000000..8e1f222 --- /dev/null +++ b/components/temperature.c @@ -0,0 +1,71 @@ +/* See LICENSE file for copyright and license details. */ +#include + +#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 + + const char * + temp(const char *zone) + { + char buf[256]; + int temp; + size_t len; + + len = sizeof(temp); + snprintf(buf, sizeof(buf), "hw.acpi.thermal.%s.temperature", zone); + if (sysctlbyname(buf, &temp, &len, NULL, 0) == -1 + || !len) + return NULL; + + /* kelvin to decimal celcius */ + return bprintf("%d.%d", (temp - 2731) / 10, abs((temp - 2731) % 10)); + } +#endif diff --git a/components/temperature.o b/components/temperature.o new file mode 100644 index 0000000000000000000000000000000000000000..ccf4cf6d7be982827e68200233811bab8f82521d GIT binary patch literal 1696 zcmbtTO=}Zj5T4zpHe!vd_MlW@!B!&Lmuye!K@y_v3Z)0Jpa)qu$;QMsAMU<^Ru3Ku zVkm+?!K(*FG8HzypwL0?L`M>XXbfk=KY#|ers(-*EC?!;07E- zi~^Wb2YxYfi;#okuwlPiqR{UDuy?;3HG40!n2+L{3t20)`(Fn{m-=C8__=o;>4o}7qi`#NG0ipo10?#-gd1&ork9?dcuRwhe85b|(88$#aO4k~Ha4${8>8^_;2S z%NeCymY_7Dz8Tmbrg2j#H+dpTq}@&m?dw!5KiUIgXHkvG)F?6!!SjdUAiY-C^Ih5V zJy8X*RxU&kbc3qfu0y5kH`}rfjuS|?y6IFKn@-(rZbggXhwoHJpGM)&a3mL00`YVz z##dtakr?j8@R=BHDxCV0jzt7JE$LQ31kxYb27A7@?G`LFdB)>6-9 z)VT2aJXg%|`fQ6xkYC^gW#1`#I)QT?+uO*qA5RVALCjC)-baq+bYdnk4pB*x`{Mf_ zu>eodp`OY5Un=1$Cn}q)rynrw{a>nv{Lb|LM^U++@wByRsk}O9NCC<$Dy@^Or=H2T eM+gS0{u%`_QScZ!iC$X$8@2yu +#include +#include + +#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(void) +{ + char warn_buf[256]; + uintmax_t h, m; + struct timespec uptime; + + if (clock_gettime(UPTIME_FLAG, &uptime) < 0) { + snprintf(warn_buf, 256, "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/components/uptime.o b/components/uptime.o new file mode 100644 index 0000000000000000000000000000000000000000..85a62282583679d0c8af9053717a44b4a3aa7c90 GIT binary patch literal 1960 zcmbtU&ubGw6n>kwHfoJgD-`Ns52>`ML$?>fpD9(lN|7S=;6cJR**3BHhEbt>F7Un^f-)fVG^>V>z`yFYW{1!#kr`7 z?;{MoKHe`3y}q8)?1Zg;OF?K{1sn;KmZ9_Xe3fNwheL-ui5+5Zv4-!U?M^Z`RsLW5 zVqX|{nIJTpKdbW7;b69P|Fm3Wqf`GkR6}&1(SLkrI$!IZ)<$jon*n`}18n238O=w{ fXzy8~=jw%KK|)Yv0|o!vPWhWkd=NyojA;HJm}}ZS literal 0 HcmV?d00001 diff --git a/components/user.c b/components/user.c new file mode 100644 index 0000000..71a0c9d --- /dev/null +++ b/components/user.c @@ -0,0 +1,32 @@ +/* See LICENSE file for copyright and license details. */ +#include +#include +#include +#include + +#include "../util.h" + +const char * +gid(void) +{ + return bprintf("%d", getgid()); +} + +const char * +username(void) +{ + struct passwd *pw; + + if (!(pw = getpwuid(geteuid()))) { + warn("getpwuid '%d':", geteuid()); + return NULL; + } + + return bprintf("%s", pw->pw_name); +} + +const char * +uid(void) +{ + return bprintf("%d", geteuid()); +} diff --git a/components/user.o b/components/user.o new file mode 100644 index 0000000000000000000000000000000000000000..dc32f950ef5dce83ea27b3d894ab7bc4ed06009c GIT binary patch literal 2184 zcmb`H-%Aux6vxk)=H`#ZwxS5v_s%)%c-?)84%|8Ce9n)1XYRf8c53!Pm*bF%L-**wQ%aQU zIk0_W`jn?Zn)?Z7=Hp$crM<6S@(b3y!F%7*=({8?%zPM=EH7C!IoV1S8sAHnzI5n0 zQl?56H@3Id%f-==^5`UuG>N85rOD!z>BrBm7Cp}$cgHY2Q8$kw4=kI5)J0ALrs9aN z?|NDS&g&=S>1HHLV90b28v9r+k^FxpFIm2!VH}B5;MPEKQ)xW^ewC<_Ivvq=w zD6FHKe(xU%FgVs`M=(eFcE)Hu294E2g%(MT)bHV5hvfphg-n05R%Xychf|GrsRO^v z9DTIjd=q9jI^^H(!2J&VCUf*Z^i7%3Rx^y;6>?`wV|a|?;o+cE*2}cqh}LWIs!6H^ z)et=7^V2#=v>ik>wCTcw1!ts}$DjRFP5`nXj&G;@JRl45`*P&^IW*S{!^KJoF(m#eSx5VmRAft%8SC$A46qA z4CQ(*7A&s&Np5qu8VAd)<0#c@YDM8@;Kt!jOl~=d19F#}O>(0;9He`$NA60!S`BNQ zQme7x0OBrHBLa!f35ep7Cpy#WJTvclZ9;S z{HlFn^80ROCt~S&)qvKie#il}H3#~8*2&m*?jpx<@3UtZ=|AvbvDc;FKaCQ-Vgo(x z`kYL(rir5M`c3BT_TL9&nMsxTr{JHY^}7G<=0-_F=ARRde+JH|U5}pj-ZP>^UT6wV XMx +#include +#include +#include +#include + +#include "../util.h" + +#if defined(__OpenBSD__) + #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(); + 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/components/volume.o b/components/volume.o new file mode 100644 index 0000000000000000000000000000000000000000..c92afe82a646207e38f3eb99e58be2c841b46058 GIT binary patch literal 3608 zcmds(O>7%g5P-+|XbtT(Y0+iTXF zGy$ZhYWXq2QYs$>znraAd6A zH}k!jd2ipZPbHE^T09;Q;(;e&%Muh|>b5OC>ZnoZ0tI4|TJ>SFKa1ciHZfdTpB&dt z|Nbjl8EvJlCy0txIUBf+Ww@qQUk&*F{O}5R0g{zp$O~SpE!~@}+|a5|kQJ^u@V7Tm zuUxHsrBx>ao!Zr}{~2jprubt4Un2ao-Wun#H{O*9q?{%Ra<$- z`O1vex5xQxyWL5xonE8zh2ybfvEyG-kN<~amW-mmx2N1Y069~)^ZwrPXC_DEsgdES z#8_%95sRndiRVUQ<4>cT`q%d8PjAcA)?6^jpcRyruvtfEg=+zIUEc%wR=DZCH zxr||gmCoc$D44~ZZCU_BgM$P9;Lzyget$TuM$}M!(%P`_K^8|yBMi^ znTI9*0P~{~??wAASO1+cLq^k5Z+m+Hok@-OKocHq!iSphktTey38ytbUocc1)Z}2~ zQF@0Q^^o&^jNbhr@=BEqO9$Fda58Nb>l+2iwxt(Jpy$o90n;TbSF~p!l`7k5eJ-VE z=TbB2Tprt|bxG2K56$ZOMqQpFh(c?X=0b4#4ifUGSivU|g1Ycub8&aO-!iBCv^9kP_bz{T|9^1tE|>pb zO}JQclz+F&zk@a!3iY4XnP~TZ7r)cRQFWxgKVfs9i0v%6m=Cdb1s~)1ZYj_6Z2Kji zVml~to$Zjs=h!|Z@ebvwcG1XW7n5T&yS2FEKu=>?hWz z;O{bDmh!yE_L~y_fNhaaNMWDs%4TvF<~_fs%{nvMiKpr zrfsNr-yLuc9JXhR^J>Y$lghG}IF*r2%~ literal 0 HcmV?d00001 diff --git a/components/wifi.c b/components/wifi.c new file mode 100644 index 0000000..92c252e --- /dev/null +++ b/components/wifi.c @@ -0,0 +1,272 @@ +/* See LICENSE file for copyright and license details. */ +#include +#include +#include +#include +#include +#include + +#include "../util.h" + +#define RSSI_TO_PERC(rssi) \ + rssi >= -50 ? 100 : \ + (rssi <= -100 ? 0 : \ + (2 * (rssi + 100))) + +#if defined(__linux__) + #include + #include + + const char * + wifi_perc(const char *interface) + { + int cur; + size_t i; + char *p, *datastart; + char path[PATH_MAX]; + char status[5]; + FILE *fp; + + if (esnprintf(path, sizeof(path), "/sys/class/net/%s/operstate", + interface) < 0) { + return NULL; + } + if (!(fp = fopen(path, "r"))) { + warn("fopen '%s':", path); + return NULL; + } + p = fgets(status, 5, fp); + fclose(fp); + if (!p || strcmp(status, "up\n") != 0) { + return NULL; + } + + if (!(fp = fopen("/proc/net/wireless", "r"))) { + warn("fopen '/proc/net/wireless':"); + return NULL; + } + + for (i = 0; i < 3; i++) { + if (!(p = fgets(buf, sizeof(buf) - 1, fp))) + break; + } + fclose(fp); + if (i < 2 || !p) { + return NULL; + } + + if (!(datastart = strstr(buf, interface))) { + return NULL; + } + + datastart = (datastart+(strlen(interface)+1)); + sscanf(datastart + 1, " %*d %d %*d %*d\t\t %*d\t " + "%*d\t\t%*d\t\t %*d\t %*d\t\t %*d", &cur); + + /* 70 is the max of /proc/net/wireless */ + return bprintf("%d", (int)((float)cur / 70 * 100)); + } + + const char * + wifi_essid(const char *interface) + { + static char id[IW_ESSID_MAX_SIZE+1]; + int sockfd; + struct iwreq wreq; + + memset(&wreq, 0, sizeof(struct iwreq)); + wreq.u.essid.length = IW_ESSID_MAX_SIZE+1; + if (esnprintf(wreq.ifr_name, sizeof(wreq.ifr_name), "%s", + interface) < 0) { + return NULL; + } + + if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + warn("socket 'AF_INET':"); + return NULL; + } + wreq.u.essid.pointer = id; + if (ioctl(sockfd,SIOCGIWESSID, &wreq) < 0) { + warn("ioctl 'SIOCGIWESSID':"); + close(sockfd); + return NULL; + } + + close(sockfd); + + if (!strcmp(id, "")) { + return NULL; + } + + return id; + } +#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/components/wifi.o b/components/wifi.o new file mode 100644 index 0000000000000000000000000000000000000000..b028478bd00e2351e0db6543f973f95b9f1e8917 GIT binary patch literal 4288 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 R2Ej9;eER#o#>>Pi{|y*LIfwuN literal 0 HcmV?d00001 diff --git a/slstatus.1 b/slstatus.1 new file mode 100644 index 0000000..d802037 --- /dev/null +++ b/slstatus.1 @@ -0,0 +1,28 @@ +.Dd 2020-06-23 +.Dt SLSTATUS 1 +.Os +.Sh NAME +.Nm slstatus +.Nd suckless status monitor +.Sh SYNOPSIS +.Nm +.Op Fl s +.Op Fl 1 +.Sh DESCRIPTION +.Nm +is a suckless status monitor for window managers that use WM_NAME (e.g. dwm) or +stdin to fill the status bar. +By default, +.Nm +outputs to WM_NAME. +.Sh OPTIONS +.Bl -tag -width Ds +.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. diff --git a/slstatus.c b/slstatus.c new file mode 100644 index 0000000..64da5cb --- /dev/null +++ b/slstatus.c @@ -0,0 +1,141 @@ +/* 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 *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 [-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 '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) { + if (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.h b/slstatus.h new file mode 100644 index 0000000..b0f2564 --- /dev/null +++ b/slstatus.h @@ -0,0 +1,84 @@ +/* See LICENSE file for copyright and license details. */ + +/* battery */ +const char *battery_perc(const char *); +const char *battery_state(const char *); +const char *battery_remaining(const char *); + +/* cpu */ +const char *cpu_freq(void); +const char *cpu_perc(void); + +/* 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(void); + +/* hostname */ +const char *hostname(void); + +/* ip */ +const char *ipv4(const char *interface); +const char *ipv6(const char *interface); + +/* kernel_release */ +const char *kernel_release(void); + +/* keyboard_indicators */ +const char *keyboard_indicators(void); + +/* keymap */ +const char *keymap(void); + +/* load_avg */ +const char *load_avg(void); + +/* 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(void); +const char *ram_perc(void); +const char *ram_total(void); +const char *ram_used(void); + +/* run_command */ +const char *run_command(const char *cmd); + +/* separator */ +const char *separator(const char *separator); + +/* swap */ +const char *swap_free(void); +const char *swap_perc(void); +const char *swap_total(void); +const char *swap_used(void); + +/* temperature */ +const char *temp(const char *); + +/* uptime */ +const char *uptime(void); + +/* user */ +const char *gid(void); +const char *username(void); +const char *uid(void); + +/* volume */ +const char *vol_perc(const char *card); + +/* wifi */ +const char *wifi_perc(const char *interface); +const char *wifi_essid(const char *interface); diff --git a/slstatus.o b/slstatus.o new file mode 100644 index 0000000000000000000000000000000000000000..9b8be57d67ba72f6456fe20972057f091737c23d GIT binary patch literal 6224 zcmcgwZ)_Y#6`%9jv74rMZc2)wKo)vV?8d&{hO}|45PbfVjD-~<5>rRPoY%g!ee&Jj z>2@!%+f;RAo9cQ!2;~EjT2*`kq)Mm~R4O8nOQ310sHnA2iKvhws34LHgrFu;sAArm zojE^mZux@5lXmCLZ+`E+nK!dDbN9@^(EhqWfGG*EeQd3!P{s~Du%`D2wTFFzJ-`-L zH#!^NY(NCfel42Ft6&>bX1CUAYsWh6QF!U2Y~-ss)9O#zxwJ9Yt?f5bX)~!gSuG2& zmUMA8kC69mg%|(M%cA$^>O@n2BqoCD%g}T#3>c|ygzBm1BdS?Hs) zYp5tYSrUnHJ4SSvq{Hhww9?1j_Mzf!KJn~T=oCMHwUGy(MPpvdxf!^7B+^WTD2ePY zRl-YuK%=q~Y5s3X;H9BR3ojjsH0d{asXx-pchpDto_BAAn}wsE@JknY`*mLYEpLDC z1`j{-9yFc|hM%Ya<35PM^yM4jqvvmgM=n5f$0cRRm);7$e1W%L;KfV)))ihn64B89 z9cXyQwO_M>r1nSJ_|o!h8+4<5GNOsGz(`w!vd~rUcxJCU&c!WvR#$OV^vX2AQu0q8 zO;xQ#x*u5*vLL=Xr$NN$r+$MUqh2{S8vjOoH2%$a;;xMjbMb!^>rsPU3#x$Ezl@ss z_SUu*h-wyVMv~qoKsO|ZNcqsO*4gI06 zg~q|q>CM4%Fx1r-ip4{1KmjV4^oAhEeuDk1Xa8KS)gG*lVts26EWEM_02q4}R%3V& zkO1(TqzSbQimX*ls!EV;sOn022o&_ALaQNd6*%r_t|pwynz6Dctc304nUSBeS#+pxC%(RjuU+_h3}27q zD~7M#`0B#f9+oju7MdN8v1H0*c52F)zzgZR8}9m>EHiCOTq7sNm6q8~GFx!ivWHJ6R-7Y)^`ElVVTV`UTS^1J@33(YWGxHwNt&m{0#%<=^*F_Fz=3@gbd za)m_B%uleqky%p;wwYu}NDJPy8QgHq{Ba}A#tV~>#zuHh@VX|B8<|&eXOj3Qq5OE& zm0r+MkdOBRg+GNL2;!8#Bv5y{T0mF)mn80u`wN0oKNkp2^AkkLiiX%#l21V zpCb4@u)a{x55*t$!5<~~r@=<~e_Y~fTp!CbyqDl1!aqR#(EcAJd_2>X|6_!YXOY4u z2_LW73eONe^?#D^ad%hz*9af)0Sf;e!SVL3@b`(I&k_78;p5q;_ex>JA_Zi)rg4)@#eo(;yAybhe!E|5&r!I-%a?`|31RUsa5maNBCbLeg-}Kdii~g z5k8&A8N#RYm?wPNpBD&!Gl}~%g5ytnHQvhvr~I&7r`WxR3BQHl5rRh~j_&a8q5SV4 zeA-W)@KIHH81UdKpX0<2ov)M+-y-~0(w{lP-$L+t!l(T_L-1{c52_GccH5~^5d=|Zr@~)#VX;S{ig=sEu+XHg_*Y~-M(}p2W6?!$jC)PiIl&*1Iu?frj{J{g zeT?9ES5-1C71f_RvYzwccuzpl#M}MuEi? zW6nA(3dfegqT@Ck-1#h4kgi8{s45a5M&2ppBqT`C2z+Iu%IJjcz{!rMrD=h4E9;n1 z__5R}j#OEnvI@~$9{#GzJ9E;dIh~k<6V;SM`JW06tW{2_qaImlrXc7ty;T(V3j9WU zs)(y-cu0WYT1LUW3~igR0-|tS(}>Guj!i<;`cQRMdgFIM1N!vZk4b|~a(|OmrYS|1 zI+W;hrw1RC^>$A{RaNBx@KDD!Ori2_cQ+BG}14^y@b;e~Y;J!x-NDjR1x| zz2om`01#x>Evj#=s<{gOKB^U;j1$Y!D2=eu3X-_fKz1;5shWm(j z{MV$tw_mE?=nLf)c+jWUzC|u5@BDe~e+ag<=5JaiRK>^n!}D9&tM9K?Y@o5zGX5bs qVdxJ3v+&yE|2N*X2N1g||1#L;NtmZ9_JvyZXJr5JcPJIF{eJ*NQx8u7 literal 0 HcmV?d00001 diff --git a/util.c b/util.c new file mode 100644 index 0000000..85366bf --- /dev/null +++ b/util.c @@ -0,0 +1,146 @@ +/* See LICENSE file for copyright and license details. */ +#include +#include +#include +#include +#include +#include + +#include "util.h" + +char *argv0; + +static void +verr(const char *fmt, va_list ap) +{ + if (argv0 && strncmp(fmt, "usage", sizeof("usage") - 1)) { + fprintf(stderr, "%s: ", argv0); + } + + 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/util.h b/util.h new file mode 100644 index 0000000..7f1f26c --- /dev/null +++ b/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)) + +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/util.o b/util.o new file mode 100644 index 0000000000000000000000000000000000000000..b774950929b47849c394cd398b35a031efa83579 GIT binary patch literal 5928 zcmdUye{7q@8OP5~Leo-gw}TPJ&|WrYB<Z+rh>(bxfN2$AH2gEL~x+Fr?B|%bxGO zch2Q%?~h4L+ataA<8#m5J$LuqbN08o;C0Y_~l5_Xf zxci16==38Hz6Mirp96eGW5lsvloP z1r1HSbp|aoQWJN3!!6v6hd0ID&TxC2O8j8S*%)l@4EF?^WK1Q?-pvRNypPL$t)F4~EZ*>YFdrhU;ZRJ)iCjTTltT z&>606Aw2)ne=aWaDe9Es>%AeII&VP}Ct>Xg{=Z?hGFVtYUq@CSho1;j>GaJZXW@1J>hDHN@GEuJk2-%;ej<0NuQg1k#@dU?EKZ@@RoKS zOWAc|$5!`Zd0qbvr?~-k$K98?`}&dxz4i-MOY1Y;sOo~RFB^F3!``&iaXq zu-#dQ8zD}^bM2{vVzecf-+$ib({!!R*CFfSw1O22Jh-lO{u=JiO`i4f-=E_v=YZxG zf?q8y1lRp0TFL}JJ7-_D5WIhmFP8Y^g_Xs(`P3t7Xzxsm*YT;({YuV$)W;`IVs+{jsjqzKA99coyBK%>?Cpwsiq>7cHtxPzKC#&3Z#^^5-^Sf{ zxcf%j{VRDwh?W2cd6#nC53~RyhkPgIp7e@UVhlXJ(>=Qzf%62F|4*e@NbF6s#zLFL zMhm&Toy|F!HmzvgRdn)2$8zjqE}3xBDV7;_`Ui`{iCmktH8+|V%BHM=M1jVLL^D=n zfw6sT8|!AhtcP{6d)ZEQXO?ZtvhFPF&9a^>>&miwvutOU*(@`XPv@+g8VfhIG1lGD z(PlMuZ|`fiqR~ieq($r~-2!IOhc}Vhn4kGdVCt>)$@)rSkgL6n`M!QP^Nodk*RNht zKSRo2ApUXL_6+hZfzY&nOQ7N5n$CbVS=$|G@jtjKV08oL|=>WvuGoEAIXx= zywZW)qCe#yK&Lx!)aQS76^z_YqhO~lfRof~D*e8f(hCzPz=DQOv3!HSCJZDE5oau*}6-Q0*!~F4y;dK3#FyNY_dIE6XE!g-=NS zQG+*1-fHmmlHXzQsN~-;_(sXUX>bJTHNs212CNg(L0?FemM3>s;XA7EyQ}bBRro*^ zK3Ij15MN8@qRvD3I5DS+{voM9Adgb`Ju$b6{&%E)ou3LM%AXHYxzhgpkT~plMe2*Y zLG0-&`bVVx%hDCaJt1~X@|O@aNW}f1{5XA;<~>z~|FH^ZMJGEHNwU$jZL>(cBf1%B zYl}#uB5f7vEh4>Dq#H%Li6!j4qb;o9*tz6zp7In18O?Z67<~+3(=0ufby!-3@TCaO2IO!9#mrLdX8A%gkt2WzOao>M zBgxI1`$sbpCx=ETq?6#63IxXxpzqS6C!Yc&0mrRXya|v5+a07&@tXljppSi5T>Q9^ ze1*n4sSLq5Yv@z@xHk}UoO?Vh^kK8o-y^xH4}XVXe8d=~55IFf49rE%S!BicB+J*PCT+w*}o4vNbD)i8tvc7m(7^)njBzfh$gl^mHq@6(z--U6ln zb4_2j=e9ahBEh_?=~MdMlB1iY@tvAJ-YBJ?()4wEzNhgUHT@?w{z;9CKl@b2yt`6z}t}_??5I;$M;6lDXnLWxdJZ zc#j}0UREAwx2$h6c)zT-8$2QFdkn7DHE8gptmh4$k@YcyXJvid;6t+hkik{Fm@&95 z>v+c?YJZAel|3$V#g!eF-FE`?( zBlJ6dgLuJYeQ&N9$=mc2+0K4BRC=&KV<(2w(yISFv#2Zf-uz|RP7Lxpc`v=1r>n}y z5i4<@+Ue6}9>IfTR>n6}F^{@$4QM36?@Ms01|-Ci2F)szPSNfzP#H`;+6jQW%&E-_}$L~E|q&cDwco%(ODjtAAzKqA71aGe{ zX8-NfsF<#olKpjtvZ;GNF{tWy40?mIziF4b{!!A!m}dXOvVW5?q1pdy)VI?4wXdZH zl36bk=ZE)B^;iB=X>N2WNkuLX7H<=NpPBvfcAIBUh}BE~eFYUwjOB>mUX}XKOZ&&Q Jz9^dg{{;eV_x=C? literal 0 HcmV?d00001