From 4e0432ad4989f7bea5db936009f924e2a1f1cc53 Mon Sep 17 00:00:00 2001 From: c2ny Date: Sat, 24 Jan 2026 16:28:23 -0500 Subject: [PATCH] slstatus and dwm tweaks for laptop :) --- .bashrc | 5 +- .xinitrc | 11 + __once_setup.sh | 2 + dconf/user | Bin 20323 -> 20323 bytes dwm-6.6/config.h | 26 +- dwm-6.6/drw.o | Bin 0 -> 14240 bytes dwm-6.6/dwm | Bin 0 -> 77392 bytes dwm-6.6/dwm.o | Bin 0 -> 80448 bytes dwm-6.6/util.o | Bin 0 -> 2392 bytes gtk-2.0/gtkfilechooser.ini | 11 + nemo/desktop-metadata | 8 +- nitrogen/bg-saved.cfg | 9 +- nitrogen/nitrogen.cfg | 8 +- slstatus-1.1/LICENSE | 46 ++ slstatus-1.1/Makefile | 69 +++ slstatus-1.1/README | 65 +++ slstatus-1.1/arg.h | 33 ++ slstatus-1.1/components/battery.c | 247 +++++++++++ slstatus-1.1/components/cat.c | 32 ++ slstatus-1.1/components/cpu.c | 157 +++++++ slstatus-1.1/components/datetime.c | 20 + slstatus-1.1/components/disk.c | 59 +++ slstatus-1.1/components/entropy.c | 29 ++ slstatus-1.1/components/hostname.c | 17 + slstatus-1.1/components/ip.c | 87 ++++ slstatus-1.1/components/kernel_release.c | 19 + slstatus-1.1/components/keyboard_indicators.c | 50 +++ slstatus-1.1/components/keymap.c | 86 ++++ slstatus-1.1/components/load_avg.c | 19 + slstatus-1.1/components/netspeeds.c | 129 ++++++ slstatus-1.1/components/num_files.c | 32 ++ slstatus-1.1/components/ram.c | 212 +++++++++ slstatus-1.1/components/run_command.c | 31 ++ slstatus-1.1/components/swap.c | 274 ++++++++++++ slstatus-1.1/components/temperature.c | 73 ++++ slstatus-1.1/components/uptime.c | 34 ++ slstatus-1.1/components/user.c | 33 ++ slstatus-1.1/components/volume.c | 219 ++++++++++ slstatus-1.1/components/wifi.c | 413 ++++++++++++++++++ slstatus-1.1/config.def.h | 70 +++ slstatus-1.1/config.h | 121 +++++ slstatus-1.1/config.mk | 22 + slstatus-1.1/slstatus.1 | 47 ++ slstatus-1.1/slstatus.c | 135 ++++++ slstatus-1.1/slstatus.h | 85 ++++ slstatus-1.1/util.c | 141 ++++++ slstatus-1.1/util.h | 16 + spotify | 3 + wallpaper/nohup.out | 20 - 49 files changed, 3178 insertions(+), 47 deletions(-) create mode 100644 .xinitrc create mode 100644 dwm-6.6/drw.o create mode 100755 dwm-6.6/dwm create mode 100644 dwm-6.6/dwm.o create mode 100644 dwm-6.6/util.o create mode 100644 gtk-2.0/gtkfilechooser.ini create mode 100644 slstatus-1.1/LICENSE create mode 100644 slstatus-1.1/Makefile create mode 100644 slstatus-1.1/README create mode 100644 slstatus-1.1/arg.h create mode 100644 slstatus-1.1/components/battery.c create mode 100644 slstatus-1.1/components/cat.c create mode 100644 slstatus-1.1/components/cpu.c create mode 100644 slstatus-1.1/components/datetime.c create mode 100644 slstatus-1.1/components/disk.c create mode 100644 slstatus-1.1/components/entropy.c create mode 100644 slstatus-1.1/components/hostname.c create mode 100644 slstatus-1.1/components/ip.c create mode 100644 slstatus-1.1/components/kernel_release.c create mode 100644 slstatus-1.1/components/keyboard_indicators.c create mode 100644 slstatus-1.1/components/keymap.c create mode 100644 slstatus-1.1/components/load_avg.c create mode 100644 slstatus-1.1/components/netspeeds.c create mode 100644 slstatus-1.1/components/num_files.c create mode 100644 slstatus-1.1/components/ram.c create mode 100644 slstatus-1.1/components/run_command.c create mode 100644 slstatus-1.1/components/swap.c create mode 100644 slstatus-1.1/components/temperature.c create mode 100644 slstatus-1.1/components/uptime.c create mode 100644 slstatus-1.1/components/user.c create mode 100644 slstatus-1.1/components/volume.c create mode 100644 slstatus-1.1/components/wifi.c create mode 100644 slstatus-1.1/config.def.h create mode 100644 slstatus-1.1/config.h create mode 100644 slstatus-1.1/config.mk create mode 100644 slstatus-1.1/slstatus.1 create mode 100644 slstatus-1.1/slstatus.c create mode 100644 slstatus-1.1/slstatus.h create mode 100644 slstatus-1.1/util.c create mode 100644 slstatus-1.1/util.h create mode 100755 spotify delete mode 100644 wallpaper/nohup.out diff --git a/.bashrc b/.bashrc index 13d8d90..8609176 100644 --- a/.bashrc +++ b/.bashrc @@ -10,7 +10,8 @@ export PATH="$JAVA_HOME/bin:$PATH" [[ $- != *i* ]] && return alias ls='ls --color=auto' -alias cclear="printf '\e[3J\e[H\e[2J'" +alias nohup='nohup > "${TMPDIR:-/tmp}/nohup.$USER.$$.out" 2>&1' +alias cclear="printf '\e[3J\e[H\e[2J'" # Doesn't work in st? Should clear the terminal completely alias v="nvim" alias sagentsource="source ~/.local/bin/sagent" alias rms="shred -uzn8" @@ -24,7 +25,7 @@ if command -v dnf &> /dev/null; then fi PS1='[\u@\h \W]\$ ' -# . "$HOME/.cargo/env" +. "$HOME/.cargo/env" p="$HOME/projects" ls="ls -Utp --color=auto" diff --git a/.xinitrc b/.xinitrc new file mode 100644 index 0000000..d6f5d77 --- /dev/null +++ b/.xinitrc @@ -0,0 +1,11 @@ +#!/bin/sh + +# Dark theme +export GTK_THEME=Adwaita:dark +export GDK_BACKEND=x11 +export QT_STYLE_OVERRIDE=Fusion +export XDG_CURRENT_DESKTOP=dwm +export XDG_SESSION_DESKTOP=dwm +export XDG_SESSION_TYPE=x11 + +exec dbus-run-session -- /usr/local/bin/dwm diff --git a/__once_setup.sh b/__once_setup.sh index 0ddb8d1..880610b 100755 --- a/__once_setup.sh +++ b/__once_setup.sh @@ -118,6 +118,8 @@ flatpak mask com.spotify.Client # spotify fix bash <(curl -sSL https://spotx-official.github.io/run.sh) -fh +chmod +x spotify +ln -s ~/.config/spotify ~/.local/bin # packer (nvim) git clone --depth 1 https://github.com/wbthomason/packer.nvim\ diff --git a/dconf/user b/dconf/user index 218f43fcaf4705d4de63e2a9518606cb1c8dbca4..96fab400cc4aed7d14a8706bda1eaf069274041f 100644 GIT binary patch delta 87 zcmaDnkMZ$5#tl63yw2_n433}swq`IeFgS0Pl%LGTXuWx@YP2xFp@Fe!g`t6=iMF9B r5N#H>e8|gfVPs)!u4iCqXk}f delta 87 zcmaDnkMZ$5#tl63ysqvH433}swq`IeFt~1(l%LGTD7|^DYP2xFg@HkZsi}dsp#d0g p7PoxJ%WH08ZeXfsXk=h+VPHC$+1-r!_}9OaZQP|cN4Rry0045p8D9VZ diff --git a/dwm-6.6/config.h b/dwm-6.6/config.h index 80694f7..fead8b3 100644 --- a/dwm-6.6/config.h +++ b/dwm-6.6/config.h @@ -1,11 +1,11 @@ /* See LICENSE file for copyright and license details. */ /* appearance */ -static const unsigned int borderpx = 2; /* border pixel of windows */ +static const unsigned int borderpx = 3; /* border pixel of windows */ static const unsigned int snap = 32; /* snap pixel */ static const int showbar = 10; /* 0 means no bar */ -static const int topbar = 0; /* 0 means bottom bar */ -static const char *fonts[] = { "CommitMono:size=17" }; +static const int topbar = 1; /* 0 means bottom bar */ +static const char *fonts[] = { "CommitMono:size=15" }; static const char dmenufont[] = "CommitMono:size=17"; // static const char col_foreground[] = "#BCC4C9"; @@ -16,10 +16,10 @@ static const char dmenufont[] = "CommitMono:size=17"; // static const char col_norm_border[] = "#182221"; static const char col_foreground[] = "#788799"; -static const char col_foreground2[] = "#9AA3B2"; -static const char col_background[] = "#e5e6e8"; -static const char col_background2[] = "#CFCFD1"; -static const char col_sel_border[] = "#e5e6e8"; +static const char col_foreground2[] = "#8792A4"; +static const char col_background[] = "#e5e6e8"; +static const char col_background2[] = "#CFCFD1"; +static const char col_sel_border[] = "#f78ade"; static const char col_norm_border[] = "#5a6a7c"; static const char *colors[][3] = { @@ -58,7 +58,8 @@ static const char *const autostart[] = { // "nitrogen", "--set-zoom-fill", "/home/plky/.config/wallpaper/kirino.png", "--head=0", NULL, // "nitrogen", "--set-zoom-fill", "/home/plky/.config/wallpaper/kirino_win7.png", "--head=1", NULL, "nitrogen", "--restore", NULL, - "/home/plky/.config/dwmstat.sh", NULL, + // "/home/plky/.config/dwmstat.sh", NULL, + "slstatus", NULL, "redshift", "-l", "40.7:-74.0", "-t", "6500:3600", NULL, "xcompmgr", NULL, @@ -115,13 +116,15 @@ static const char *volmute[] = { "pactl", "set-sink-mute", "@DEFAULT_SINK@", " static const char *mplaypause[] = { "playerctl", "play-pause", NULL }; static const char *mnext[] = { "playerctl", "next", NULL }; static const char *mprev[] = { "playerctl", "previous", NULL }; -static const char *slock[] = {"slock", NULL}; +static const char *brightup[] = { "brightnessctl", "set", "+5%", NULL }; +static const char *brightdown[] = { "brightnessctl", "set", "5%-", NULL }; +// static const char *slock[] = { "slock", NULL }; static const Key keys[] = { /* modifier key function argument */ { MODKEY, XK_p, spawn, {.v = dmenucmd } }, { MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } }, - { MODKEY|ShiftMask, XK_l, spawn, {.v = slock } }, + { MODKEY|ShiftMask, XK_l, spawn, SHCMD("cinnamon-screensaver-command --lock || slock") }, { MODKEY, XK_b, togglebar, {0} }, { MODKEY, XK_j, focusstack, {.i = +1 } }, { MODKEY, XK_k, focusstack, {.i = -1 } }, @@ -155,6 +158,9 @@ static const Key keys[] = { { MODKEY|ShiftMask, XK_q, quit, {0} }, { MODKEY, XK_f, togglefullscr, {0} }, + { 0, XF86XK_MonBrightnessDown, spawn, { .v = brightdown } }, + { 0, XF86XK_MonBrightnessUp, spawn, { .v = brightup } }, + { 0, XF86XK_AudioRaiseVolume, spawn, { .v = volup } }, { 0, XF86XK_AudioLowerVolume, spawn, { .v = voldown } }, { 0, XF86XK_AudioMute, spawn, { .v = volmute } }, diff --git a/dwm-6.6/drw.o b/dwm-6.6/drw.o new file mode 100644 index 0000000000000000000000000000000000000000..23dd8c3b554148372e9d2110222fdd5a45374e3c GIT binary patch literal 14240 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 J5Ea4j{|BEC<%|FT literal 0 HcmV?d00001 diff --git a/dwm-6.6/dwm.o b/dwm-6.6/dwm.o new file mode 100644 index 0000000000000000000000000000000000000000..b7dd27fbbadabd5c0a48a0d321a0ef7577363f4c GIT binary patch literal 80448 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 hyM-ZwbnL3?`%M|%$u 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 + +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-1.1/Makefile b/slstatus-1.1/Makefile new file mode 100644 index 0000000..7a18274 --- /dev/null +++ b/slstatus-1.1/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-1.1/README b/slstatus-1.1/README new file mode 100644 index 0000000..4d592bb --- /dev/null +++ b/slstatus-1.1/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-1.1/arg.h b/slstatus-1.1/arg.h new file mode 100644 index 0000000..5f1f408 --- /dev/null +++ b/slstatus-1.1/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-1.1/components/battery.c b/slstatus-1.1/components/battery.c new file mode 100644 index 0000000..1c753f9 --- /dev/null +++ b/slstatus-1.1/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-1.1/components/cat.c b/slstatus-1.1/components/cat.c new file mode 100644 index 0000000..07944cc --- /dev/null +++ b/slstatus-1.1/components/cat.c @@ -0,0 +1,32 @@ +/* See LICENSE file for copyright and license details. */ +#include +#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-1.1/components/cpu.c b/slstatus-1.1/components/cpu.c new file mode 100644 index 0000000..d0d03c7 --- /dev/null +++ b/slstatus-1.1/components/cpu.c @@ -0,0 +1,157 @@ +/* See LICENSE file for copyright and license details. */ +#include +#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-1.1/components/datetime.c b/slstatus-1.1/components/datetime.c new file mode 100644 index 0000000..5b10daf --- /dev/null +++ b/slstatus-1.1/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-1.1/components/disk.c b/slstatus-1.1/components/disk.c new file mode 100644 index 0000000..e19a693 --- /dev/null +++ b/slstatus-1.1/components/disk.c @@ -0,0 +1,59 @@ +/* See LICENSE file for copyright and license details. */ +#include +#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-1.1/components/entropy.c b/slstatus-1.1/components/entropy.c new file mode 100644 index 0000000..65010b0 --- /dev/null +++ b/slstatus-1.1/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-1.1/components/hostname.c b/slstatus-1.1/components/hostname.c new file mode 100644 index 0000000..dab8b63 --- /dev/null +++ b/slstatus-1.1/components/hostname.c @@ -0,0 +1,17 @@ +/* See LICENSE file for copyright and license details. */ +#include +#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-1.1/components/ip.c b/slstatus-1.1/components/ip.c new file mode 100644 index 0000000..2cdad46 --- /dev/null +++ b/slstatus-1.1/components/ip.c @@ -0,0 +1,87 @@ +/* See LICENSE file for copyright and license details. */ +#include +#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-1.1/components/kernel_release.c b/slstatus-1.1/components/kernel_release.c new file mode 100644 index 0000000..36a6a44 --- /dev/null +++ b/slstatus-1.1/components/kernel_release.c @@ -0,0 +1,19 @@ +/* See LICENSE file for copyright and license details. */ +#include +#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-1.1/components/keyboard_indicators.c b/slstatus-1.1/components/keyboard_indicators.c new file mode 100644 index 0000000..5f62bb7 --- /dev/null +++ b/slstatus-1.1/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-1.1/components/keymap.c b/slstatus-1.1/components/keymap.c new file mode 100644 index 0000000..22224f3 --- /dev/null +++ b/slstatus-1.1/components/keymap.c @@ -0,0 +1,86 @@ +/* See LICENSE file for copyright and license details. */ +#include +#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-1.1/components/load_avg.c b/slstatus-1.1/components/load_avg.c new file mode 100644 index 0000000..f278a40 --- /dev/null +++ b/slstatus-1.1/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-1.1/components/netspeeds.c b/slstatus-1.1/components/netspeeds.c new file mode 100644 index 0000000..cde6fa9 --- /dev/null +++ b/slstatus-1.1/components/netspeeds.c @@ -0,0 +1,129 @@ +/* See LICENSE file for copyright and license details. */ +#include +#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-1.1/components/num_files.c b/slstatus-1.1/components/num_files.c new file mode 100644 index 0000000..df0acd1 --- /dev/null +++ b/slstatus-1.1/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-1.1/components/ram.c b/slstatus-1.1/components/ram.c new file mode 100644 index 0000000..15c4b74 --- /dev/null +++ b/slstatus-1.1/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-1.1/components/run_command.c b/slstatus-1.1/components/run_command.c new file mode 100644 index 0000000..93bf6da --- /dev/null +++ b/slstatus-1.1/components/run_command.c @@ -0,0 +1,31 @@ +/* See LICENSE file for copyright and license details. */ +#include +#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-1.1/components/swap.c b/slstatus-1.1/components/swap.c new file mode 100644 index 0000000..f270d93 --- /dev/null +++ b/slstatus-1.1/components/swap.c @@ -0,0 +1,274 @@ +/* See LICENSE file for copyright and license details. */ +#include +#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-1.1/components/temperature.c b/slstatus-1.1/components/temperature.c new file mode 100644 index 0000000..7cf1394 --- /dev/null +++ b/slstatus-1.1/components/temperature.c @@ -0,0 +1,73 @@ +/* See LICENSE file for copyright and license details. */ +#include + +#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-1.1/components/uptime.c b/slstatus-1.1/components/uptime.c new file mode 100644 index 0000000..6227f73 --- /dev/null +++ b/slstatus-1.1/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-1.1/components/user.c b/slstatus-1.1/components/user.c new file mode 100644 index 0000000..3517495 --- /dev/null +++ b/slstatus-1.1/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-1.1/components/volume.c b/slstatus-1.1/components/volume.c new file mode 100644 index 0000000..6cec556 --- /dev/null +++ b/slstatus-1.1/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-1.1/components/wifi.c b/slstatus-1.1/components/wifi.c new file mode 100644 index 0000000..23af201 --- /dev/null +++ b/slstatus-1.1/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-1.1/config.def.h b/slstatus-1.1/config.def.h new file mode 100644 index 0000000..100093e --- /dev/null +++ b/slstatus-1.1/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-1.1/config.h b/slstatus-1.1/config.h new file mode 100644 index 0000000..7921491 --- /dev/null +++ b/slstatus-1.1/config.h @@ -0,0 +1,121 @@ +/* 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 char vol[] = + "out=`wpctl get-volume @DEFAULT_SINK@`; " + "muted=`printf \"%s\" \"$out\" | awk '{print $3}'`; " + "v=`printf \"%s\" \"$out\" | awk '{print $2}'`; " + "pct=`awk -v v=\"$v\" 'BEGIN{printf \"%d\", (v*100)+0.5}'`; " + "if [ \"$muted\" = \"[MUTED]\" ] || [ \"$pct\" -le 0 ]; then " + "printf \"󰝟 MUT\"; " + "elif [ \"$pct\" -lt 34 ]; then " + "printf \"󰕿 %s%%\" \"$pct\"; " + "elif [ \"$pct\" -lt 67 ]; then " + "printf \"󰖀 %s%%\" \"$pct\"; " + "else " + "printf \"󰕾 %s%%\" \"$pct\"; " + "fi"; + +static const char bright[] = + "b=`brightnessctl -m get 2>/dev/null`; " + "max=`brightnessctl -m max 2>/dev/null`; " + "pct=`awk -v b=\"$b\" -v m=\"$max\" 'BEGIN{ if(m>0) printf \"%d\", (b/m*100)+0.5; else print 0 }'`; " + "if [ \"$pct\" -le 0 ]; then " + "printf \"󰃞 %s%%\" \"$pct\"; " + "elif [ \"$pct\" -lt 34 ]; then " + "printf \"󰃟 %s%%\" \"$pct\"; " + "else " + "printf \"󰃠 %s%%\" \"$pct\"; " + "fi"; + +static const char bt[] = + "if ! command -v bluetoothctl >/dev/null 2>&1; then " + "printf \"󰂯 N/A\"; exit; " + "fi; " + "powered=`bluetoothctl show 2>/dev/null | awk -F': ' '/Powered:/ {print $2}'`; " + "if [ \"$powered\" != \"yes\" ]; then " + "printf \"󰂯 OFF\"; exit; " + "fi; " + "dev=`bluetoothctl devices Connected 2>/dev/null | head -n1`; " + "if [ -n \"$dev\" ]; then " + "name=`printf \"%s\" \"$dev\" | cut -d' ' -f3-`; " + "printf \"󰂱 %s\" \"$name\"; " + "else " + "printf \"󰂲 ON\"; " + "fi"; + +static const struct arg args[] = { + /* function format argument */ + { wifi_essid, "%s ", "wlp3s0" }, + { wifi_perc, "%s%%", "wlp3s0" }, + { run_command, "| %s", bright }, + { run_command, "| %s", vol }, + { run_command, "| %s", bt }, + { battery_perc, "|  %s%%", "BAT0" }, + { battery_state, "(%s) ", "BAT0" }, + { cpu_freq, "|  %sHz", NULL }, + { datetime, "| %s", "%A %I:%M %p - %m/%d" }, +}; diff --git a/slstatus-1.1/config.mk b/slstatus-1.1/config.mk new file mode 100644 index 0000000..5655183 --- /dev/null +++ b/slstatus-1.1/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 -march=native +LDFLAGS = -L$(X11LIB) -s +# OpenBSD: add -lsndio +# FreeBSD: add -lkvm -lsndio +LDLIBS = -lX11 + +# compiler and linker +CC = cc diff --git a/slstatus-1.1/slstatus.1 b/slstatus-1.1/slstatus.1 new file mode 100644 index 0000000..73e7a60 --- /dev/null +++ b/slstatus-1.1/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-1.1/slstatus.c b/slstatus-1.1/slstatus.c new file mode 100644 index 0000000..16d88fe --- /dev/null +++ b/slstatus-1.1/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-1.1/slstatus.h b/slstatus-1.1/slstatus.h new file mode 100644 index 0000000..394281c --- /dev/null +++ b/slstatus-1.1/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-1.1/util.c b/slstatus-1.1/util.c new file mode 100644 index 0000000..bca9b2e --- /dev/null +++ b/slstatus-1.1/util.c @@ -0,0 +1,141 @@ +/* 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) +{ + 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-1.1/util.h b/slstatus-1.1/util.h new file mode 100644 index 0000000..cf4b027 --- /dev/null +++ b/slstatus-1.1/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/spotify b/spotify new file mode 100755 index 0000000..89de98e --- /dev/null +++ b/spotify @@ -0,0 +1,3 @@ +#!/bin/sh + +flatpak run com.spotify.Client diff --git a/wallpaper/nohup.out b/wallpaper/nohup.out deleted file mode 100644 index 20d057d..0000000 --- a/wallpaper/nohup.out +++ /dev/null @@ -1,20 +0,0 @@ - -(nemo:39725): Gtk-WARNING **: 13:30:55.465: Failed to register client: GDBus.Error:org.gnome.SessionManager.AlreadyRegistered: Unable to register client -Initializing nemo-image-converter extension -WARNING: Glycin running without sandbox. -WARNING: Glycin running without sandbox. -WARNING: Glycin running without sandbox. -WARNING: Glycin running without sandbox. -WARNING: Glycin running without sandbox. -WARNING: Glycin running without sandbox. -WARNING: Glycin running without sandbox. -WARNING: Glycin running without sandbox. -WARNING: Glycin running without sandbox. -WARNING: Glycin running without sandbox. -WARNING: Glycin running without sandbox. -WARNING: Glycin running without sandbox. -WARNING: Glycin running without sandbox. -WARNING: Glycin running without sandbox. -WARNING: Glycin running without sandbox. -WARNING: Glycin running without sandbox. -WARNING: Glycin running without sandbox.