New status bar

This commit is contained in:
2024-06-23 22:28:14 +01:00
parent 47fb72f23b
commit 27d10d20ad
57 changed files with 386 additions and 2941 deletions

1
.gitignore vendored
View File

@@ -41,5 +41,6 @@ programs/tabbed/tabbed
programs/slstatus/slstatus programs/slstatus/slstatus
programs/surf/surf programs/surf/surf
programs/herbe/herbe programs/herbe/herbe
programs/dwmblocks/dwmblocks
logs/ logs/

24
dotfiles/.local/bin/sb-battery Executable file
View File

@@ -0,0 +1,24 @@
#!/bin/sh
# Prints all batteries, their percentage remaining and an emoji corresponding
# to charge status (🔌 for plugged up, 🔋 for discharging on battery, etc.).
# Loop through all attached batteries and format the info
for battery in /sys/class/power_supply/BAT?*; do
# If non-first battery, print a space separator.
[ -n "${capacity+x}" ] && printf " "
# Sets up the status and capacity
case "$(cat "$battery/status" 2>&1)" in
"Full") status="󰁹" ;;
"Discharging") status="󰂌" ;;
"Charging") status="󰂄" ;;
"Not charging") status="󰂃" ;;
"Unknown") status="󰂑" ;;
*) exit 1 ;;
esac
capacity="$(cat "$battery/capacity" 2>&1)"
# Will make a warn variable if discharging and low
[ "$status" = "󰂌" ] && [ "$capacity" -le 25 ] && warn=" "
# Prints the info
printf "%s%s%d%%" "$status" "$warn" "$capacity"; unset warn
done && printf "\\n"

26
dotfiles/.local/bin/sb-cpu Executable file
View File

@@ -0,0 +1,26 @@
#!/bin/sh
# Module showing overall CPU usage as a percentage.
# Cache in tmpfs to improve speed and reduce SSD load
cache=/tmp/cpubarscache
# Extract CPU stats (total time and idle time)
cpu_stats=$(awk '/^cpu / {print $2 + $3 + $4 + $5, $5}' /proc/stat)
# Check if cache exists, if not, initialize it
[ ! -f $cache ] && echo "$cpu_stats" > "$cache"
# Read previous CPU stats from cache
prev_stats=$(cat "$cache")
# Calculate CPU usage percentage and exit immediately
echo "$cpu_stats $prev_stats" | awk '{
total_diff = $1 - $3
idle_diff = $2 - $4
usage = 100 * (1 - idle_diff / total_diff)
printf " %.1f%%\n", usage
exit # Terminate script after printing the first line
}'
# Update cache with current stats
echo "$cpu_stats" > "$cache"

3
dotfiles/.local/bin/sb-memory Executable file
View File

@@ -0,0 +1,3 @@
#!/bin/sh
free --mebi | sed -n '2{p;q}' | awk '{printf (" %2.2fGB/%2.2fGB\n", ( $3 / 1024), ($2 / 1024))}'

17
dotfiles/.local/bin/sb-network Executable file
View File

@@ -0,0 +1,17 @@
#!/bin/sh
# Show wifi 📶 and percent strength or 📡 if none.
# Show 🌐 if connected to ethernet or ❎ if none.
# Show 🔒 if a vpn connection is active
# Wifi
if [ "$(cat /sys/class/net/w*/operstate 2>/dev/null)" = 'up' ] ; then
wifiicon="$(awk '/^[[:space:]]*w/ { gsub(/[[:space:]]+/, " "); print " ", int($3 * 100 / 70) "% " }' /proc/net/wireless)"
elif [ "$(cat /sys/class/net/w*/operstate 2>/dev/null)" = 'down' ] ; then
[ "$(cat /sys/class/net/w*/flags 2>/dev/null)" = '0x1003' ] && wifiicon=" " || wifiicon=""
fi
# Ethernet
[ "$(cat /sys/class/net/e*/operstate 2>/dev/null)" = 'up' ] && ethericon="󰛳 " || ethericon="󰅛 "
printf "%s%s\n" "$wifiicon" "$ethericon"

28
dotfiles/.local/bin/sb-volume Executable file
View File

@@ -0,0 +1,28 @@
#!/bin/sh
# Prints the current volume or  if muted.
vol="$(wpctl get-volume @DEFAULT_AUDIO_SINK@)"
# If muted, print  and exit.
[ "$vol" != "${vol%\[MUTED\]}" ] && echo " " && exit
vol="${vol#Volume: }"
split() {
# For ommiting the . without calling and external program.
IFS=$2
set -- $1
printf '%s' "$@"
}
vol="$(printf "%.0f" "$(split "$vol" ".")")"
case 1 in
$((vol >= 70)) ) icon=" " ;;
$((vol >= 30)) ) icon=" " ;;
$((vol >= 1)) ) icon=" " ;;
* ) echo " " && exit ;;
esac
echo "$icon$vol%"

View File

@@ -1,4 +1,4 @@
slstatus & dwmblocks &
feh --bg-scale "/home/trude/dotfiles/bg2.png" & feh --bg-scale "/home/trude/dotfiles/bg2.png" &
xrdb ~/.Xresources xrdb ~/.Xresources
dunst & dunst &

View File

@@ -195,7 +195,7 @@ for selection in $main_menu; do
dialogDotfiles 85 5 5 5 5 5 5 5 7 4 dialogDotfiles 85 5 5 5 5 5 5 5 7 4
# Compile # Compile
for program in "dwm" "dmenu" "slock" "slstatus" "st" "tabbed" "surf"; do for program in "dwm" "dmenu" "slock" "st" "tabbed" "dwmblocks"; do
compile $program compile $program
done done
dialogDotfiles 95 5 5 5 5 5 5 5 5 7 dialogDotfiles 95 5 5 5 5 5 5 5 5 7

View File

@@ -1,6 +1,5 @@
dmenu - 5.3 dmenu - 5.3
dwm - 6.5 dwm - 6.5
st - 0.9.2 st - 0.9.2
slstatus - 1.0
slock - 1.5 slock - 1.5
tabbed - 0.8 tabbed - 0.8

Binary file not shown.

Binary file not shown.

View File

@@ -57,11 +57,6 @@ static const Layout layouts[] = {
/* helper for spawning shell commands in the pre dwm-5.0 fashion */ /* helper for spawning shell commands in the pre dwm-5.0 fashion */
#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } } #define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }
/* volume commands */
static const char *upvol[] = { "/usr/bin/wpctl", "set-volume", "@DEFAULT_AUDIO_SINK@", "5%+", NULL };
static const char *downvol[] = { "/usr/bin/wpctl", "set-volume", "@DEFAULT_AUDIO_SINK@", "5%-", NULL };
static const char *mutevol[] = { "/usr/bin/wpctl", "set-mute", "@DEFAULT_AUDIO_SINK@", "toggle", NULL };
/* commands */ /* commands */
static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */ static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */
static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, NULL }; static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, NULL };
@@ -72,9 +67,9 @@ static const char *webcmd[] = { "firefox", "--new-window", "/home/trude/.
static const Key keys[] = { static const Key keys[] = {
/* Volume keys support */ /* Volume keys support */
{ 0, XF86XK_AudioLowerVolume, spawn, {.v = downvol } }, { 0, XF86XK_AudioLowerVolume, spawn, SHCMD("/usr/bin/wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-; pkill -RTMIN+10 dwmblocks") },
{ 0, XF86XK_AudioMute, spawn, {.v = mutevol } }, { 0, XF86XK_AudioMute, spawn, SHCMD("/usr/bin/wpctl set-volume @DEFAULT_AUDIO_SINK@ toggle; pkill -RTMIN+10 dwmblocks") },
{ 0, XF86XK_AudioRaiseVolume, spawn, {.v = upvol } }, { 0, XF86XK_AudioRaiseVolume, spawn, SHCMD("/usr/bin/wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+; pkill -RTMIN+10 dwmblocks") },
/* modifier key function argument */ /* modifier key function argument */
{ MODKEY, XK_p, spawn, {.v = dmenucmd } }, { MODKEY, XK_p, spawn, {.v = dmenucmd } },

View File

@@ -57,11 +57,6 @@ static const Layout layouts[] = {
/* helper for spawning shell commands in the pre dwm-5.0 fashion */ /* helper for spawning shell commands in the pre dwm-5.0 fashion */
#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } } #define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }
/* volume commands */
static const char *upvol[] = { "/usr/bin/wpctl", "set-volume", "@DEFAULT_AUDIO_SINK@", "5%+", NULL };
static const char *downvol[] = { "/usr/bin/wpctl", "set-volume", "@DEFAULT_AUDIO_SINK@", "5%-", NULL };
static const char *mutevol[] = { "/usr/bin/wpctl", "set-mute", "@DEFAULT_AUDIO_SINK@", "toggle", NULL };
/* commands */ /* commands */
static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */ static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */
static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, NULL }; static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, NULL };
@@ -72,9 +67,9 @@ static const char *webcmd[] = { "firefox", "--new-window", "/home/trude/.
static const Key keys[] = { static const Key keys[] = {
/* Volume keys support */ /* Volume keys support */
{ 0, XF86XK_AudioLowerVolume, spawn, {.v = downvol } }, { 0, XF86XK_AudioLowerVolume, spawn, SHCMD("/usr/bin/wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-; pkill -RTMIN+10 dwmblocks") },
{ 0, XF86XK_AudioMute, spawn, {.v = mutevol } }, { 0, XF86XK_AudioMute, spawn, SHCMD("/usr/bin/wpctl set-volume @DEFAULT_AUDIO_SINK@ toggle; pkill -RTMIN+10 dwmblocks") },
{ 0, XF86XK_AudioRaiseVolume, spawn, {.v = upvol } }, { 0, XF86XK_AudioRaiseVolume, spawn, SHCMD("/usr/bin/wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+; pkill -RTMIN+10 dwmblocks") },
/* modifier key function argument */ /* modifier key function argument */
{ MODKEY, XK_p, spawn, {.v = dmenucmd } }, { MODKEY, XK_p, spawn, {.v = dmenucmd } },

Binary file not shown.

View File

@@ -0,0 +1,36 @@
PREFIX := /usr/local
CC := cc
CFLAGS := -pedantic -Wall -Wno-deprecated-declarations -Os
LDFLAGS := -lX11
# FreeBSD (uncomment)
#LDFLAGS += -L/usr/local/lib -I/usr/local/include
# # OpenBSD (uncomment)
#LDFLAGS += -L/usr/X11R6/lib -I/usr/X11R6/include
all: options dwmblocks
options:
@echo dwmblocks build options:
@echo "CFLAGS = ${CFLAGS}"
@echo "LDFLAGS = ${LDFLAGS}"
@echo "CC = ${CC}"
dwmblocks: dwmblocks.c blocks.def.h blocks.h
${CC} -o dwmblocks dwmblocks.c ${CFLAGS} ${LDFLAGS}
blocks.h:
cp blocks.def.h $@
clean:
rm -f *.o *.gch dwmblocks blocks.h
install: dwmblocks
mkdir -p ${DESTDIR}${PREFIX}/bin
cp -f dwmblocks ${DESTDIR}${PREFIX}/bin
chmod 755 ${DESTDIR}${PREFIX}/bin/dwmblocks
uninstall:
rm -f ${DESTDIR}${PREFIX}/bin/dwmblocks
.PHONY: all options clean install uninstall

View File

@@ -0,0 +1,15 @@
//Modify this file to change what commands output to your statusbar, and recompile using the make command.
static const Block blocks[] = {
/*Icon*/ /*Command*/ /*Update Interval*/ /*Update Signal*/
{"", "sb-network", 10, 0},
{"", "sb-battery", 20, 0},
{"", "sb-volume", 0, 10},
{"", "sb-cpu", 5, 0},
{"", "sb-memory", 10, 0},
{"", "date '+%d/%m/%y (%a) %I:%M%p'", 60, 0},
};
//sets delimiter between status commands. NULL character ('\0') means no delimiter.
static char delim[] = " | ";
static unsigned int delimLen = 5;

View File

@@ -0,0 +1,15 @@
//Modify this file to change what commands output to your statusbar, and recompile using the make command.
static const Block blocks[] = {
/*Icon*/ /*Command*/ /*Update Interval*/ /*Update Signal*/
{"", "sb-network", 10, 0},
{"", "sb-battery", 20, 0},
{"", "sb-volume", 0, 10},
{"", "sb-cpu", 5, 0},
{"", "sb-memory", 10, 0},
{"", "date '+%d/%m/%y (%a) %I:%M%p'", 60, 0},
};
//sets delimiter between status commands. NULL character ('\0') means no delimiter.
static char delim[] = " | ";
static unsigned int delimLen = 5;

View File

@@ -0,0 +1,213 @@
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<signal.h>
#ifndef NO_X
#include<X11/Xlib.h>
#endif
#ifdef __OpenBSD__
#define SIGPLUS SIGUSR1+1
#define SIGMINUS SIGUSR1-1
#else
#define SIGPLUS SIGRTMIN
#define SIGMINUS SIGRTMIN
#endif
#define LENGTH(X) (sizeof(X) / sizeof (X[0]))
#define CMDLENGTH 50
#define MIN( a, b ) ( ( a < b) ? a : b )
#define STATUSLENGTH (LENGTH(blocks) * CMDLENGTH + 1)
typedef struct {
char* icon;
char* command;
unsigned int interval;
unsigned int signal;
} Block;
#ifndef __OpenBSD__
void dummysighandler(int num);
#endif
void sighandler(int num);
void getcmds(int time);
void getsigcmds(unsigned int signal);
void setupsignals();
void sighandler(int signum);
int getstatus(char *str, char *last);
void statusloop();
void termhandler();
void pstdout();
#ifndef NO_X
void setroot();
static void (*writestatus) () = setroot;
static int setupX();
static Display *dpy;
static int screen;
static Window root;
#else
static void (*writestatus) () = pstdout;
#endif
#include "blocks.h"
static char statusbar[LENGTH(blocks)][CMDLENGTH] = {0};
static char statusstr[2][STATUSLENGTH];
static int statusContinue = 1;
// static int returnStatus = 0;
//opens process *cmd and stores output in *output
void getcmd(const Block *block, char *output)
{
strcpy(output, block->icon);
FILE *cmdf = popen(block->command, "r");
if (!cmdf)
return;
int i = strlen(block->icon);
fgets(output+i, CMDLENGTH-i-delimLen, cmdf);
i = strlen(output);
if (i == 0) {
//return if block and command output are both empty
pclose(cmdf);
return;
}
//only chop off newline if one is present at the end
i = output[i-1] == '\n' ? i-1 : i;
if (delim[0] != '\0') {
strncpy(output+i, delim, delimLen);
}
else
output[i++] = '\0';
pclose(cmdf);
}
void getcmds(int time)
{
const Block* current;
for (unsigned int i = 0; i < LENGTH(blocks); i++) {
current = blocks + i;
if ((current->interval != 0 && time % current->interval == 0) || time == -1)
getcmd(current,statusbar[i]);
}
}
void getsigcmds(unsigned int signal)
{
const Block *current;
for (unsigned int i = 0; i < LENGTH(blocks); i++) {
current = blocks + i;
if (current->signal == signal)
getcmd(current,statusbar[i]);
}
}
void setupsignals()
{
#ifndef __OpenBSD__
/* initialize all real time signals with dummy handler */
for (int i = SIGRTMIN; i <= SIGRTMAX; i++)
signal(i, dummysighandler);
#endif
for (unsigned int i = 0; i < LENGTH(blocks); i++) {
if (blocks[i].signal > 0)
signal(SIGMINUS+blocks[i].signal, sighandler);
}
}
int getstatus(char *str, char *last)
{
strcpy(last, str);
str[0] = '\0';
for (unsigned int i = 0; i < LENGTH(blocks); i++)
strcat(str, statusbar[i]);
str[strlen(str)-strlen(delim)] = '\0';
return strcmp(str, last);//0 if they are the same
}
#ifndef NO_X
void setroot()
{
if (!getstatus(statusstr[0], statusstr[1]))//Only set root if text has changed.
return;
XStoreName(dpy, root, statusstr[0]);
XFlush(dpy);
}
int setupX()
{
dpy = XOpenDisplay(NULL);
if (!dpy) {
fprintf(stderr, "dwmblocks: Failed to open display\n");
return 0;
}
screen = DefaultScreen(dpy);
root = RootWindow(dpy, screen);
return 1;
}
#endif
void pstdout()
{
if (!getstatus(statusstr[0], statusstr[1]))//Only write out if text has changed.
return;
printf("%s\n",statusstr[0]);
fflush(stdout);
}
void statusloop()
{
setupsignals();
int i = 0;
getcmds(-1);
while (1) {
getcmds(i++);
writestatus();
if (!statusContinue)
break;
sleep(1.0);
}
}
#ifndef __OpenBSD__
/* this signal handler should do nothing */
void dummysighandler(int signum)
{
return;
}
#endif
void sighandler(int signum)
{
getsigcmds(signum-SIGPLUS);
writestatus();
}
void termhandler()
{
statusContinue = 0;
}
int main(int argc, char** argv)
{
for (int i = 0; i < argc; i++) {//Handle command line arguments
if (!strcmp("-d",argv[i]))
strncpy(delim, argv[++i], delimLen);
else if (!strcmp("-p",argv[i]))
writestatus = pstdout;
}
#ifndef NO_X
if (!setupX())
return 1;
#endif
delimLen = MIN(delimLen, strlen(delim));
delim[delimLen++] = '\0';
signal(SIGTERM, termhandler);
signal(SIGINT, termhandler);
statusloop();
#ifndef NO_X
XCloseDisplay(dpy);
#endif
return 0;
}

Binary file not shown.

View File

@@ -1,43 +0,0 @@
ISC License
Copyright 2016-2022 Aaron Marcher <me@drkhsh.at>
Copyright 2016 Roy Freytag <rfreytag@hs-mittweida.de>
Copyright 2016 Vincent Loupmon <vincentloupmon@gmail.com>
Copyright 2016 Daniel Walter <d.walter@0x90.at>
Copyright 2016-2018 Ali H. Fardan <raiz@firemail.cc>
Copyright 2016 Jody Leonard <me@jodyleonard.com>
Copyright 2016-2018 Quentin Rameau <quinq@fifth.space>
Copyright 2016 Mike Coddington <mike@coddington.us>
Copyright 2016-2018 Ivan J. <parazyd@dyne.org>
Copyright 2017 Tobias Stoeckmann <tobias@stoeckmann.org>
Copyright 2017-2018 Laslo Hunhold <dev@frign.de>
Copyright 2018 Darron Anderson <darronanderson@protonmail.com>
Copyright 2018 Josuah Demangeon <mail@josuah.net>
Copyright 2018 Tobias Tschinkowitz <tobias@he4d.net>
Copyright 2018 David Demelier <markand@malikania.fr>
Copyright 2018-2012 Michael Buch <michaelbuch12@gmail.com>
Copyright 2018 Ian Remmler <ian@remmler.org>
Copyright 2016-2019 Joerg Jung <jung@openbsd.org>
Copyright 2019 Ryan Kes <alrayyes@gmail.com>
Copyright 2019 Cem Keylan <cem@ckyln.com>
Copyright 2019 Dimitris Papastamos <dsp@2f30.org>
Copyright 2019-2022 Ingo Feinerer <feinerer@logic.at>
Copyright 2020 Alexandre Ratchov <alex@caoua.org>
Copyright 2020 Mart Lubbers <mart@martlubbers.net>
Copyright 2020 Daniel Moch <daniel@danielmoch.com>
Copyright 2022 Nickolas Raymond Kaczynski <nrk@disroot.org>
Copyright 2022 Patrick Iacob <iacobp@oregonstate.edu>
Copyright 2021-2022 Steven Ward <planet36@gmail.com>
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.

View File

@@ -1,69 +0,0 @@
# 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"

View File

@@ -1,65 +0,0 @@
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)
- 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.

View File

@@ -1,33 +0,0 @@
/* 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

View File

@@ -1,247 +0,0 @@
/* See LICENSE file for copyright and license details. */
#include <stdio.h>
#include <string.h>
#include "../slstatus.h"
#include "../util.h"
#if defined(__linux__)
/*
* https://www.kernel.org/doc/html/latest/power/power_supply_class.html
*/
#include <limits.h>
#include <stdint.h>
#include <unistd.h>
#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", &current_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 <fcntl.h>
#include <machine/apmvar.h>
#include <sys/ioctl.h>
#include <unistd.h>
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 <sys/sysctl.h>
#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

View File

@@ -1,32 +0,0 @@
/* See LICENSE file for copyright and license details. */
#include <stdio.h>
#include <string.h>
#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;
}

View File

@@ -1,157 +0,0 @@
/* See LICENSE file for copyright and license details. */
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#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 <sys/param.h>
#include <sys/sched.h>
#include <sys/sysctl.h>
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 <devstat.h>
#include <sys/param.h>
#include <sys/sysctl.h>
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

View File

@@ -1,20 +0,0 @@
/* See LICENSE file for copyright and license details. */
#include <stdio.h>
#include <time.h>
#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;
}

View File

@@ -1,59 +0,0 @@
/* See LICENSE file for copyright and license details. */
#include <stdio.h>
#include <sys/statvfs.h>
#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);
}

View File

@@ -1,29 +0,0 @@
/* See LICENSE file for copyright and license details. */
#include "../slstatus.h"
#if defined(__linux__)
#include <stdint.h>
#include <stdio.h>
#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

View File

@@ -1,17 +0,0 @@
/* See LICENSE file for copyright and license details. */
#include <stdio.h>
#include <unistd.h>
#include "../slstatus.h"
#include "../util.h"
const char *
hostname(const char *unused)
{
if (gethostname(buf, sizeof(buf)) < 0) {
warn("gethostbyname:");
return NULL;
}
return buf;
}

View File

@@ -1,61 +0,0 @@
/* See LICENSE file for copyright and license details. */
#include <ifaddrs.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#if defined(__OpenBSD__)
#include <sys/socket.h>
#include <sys/types.h>
#elif defined(__FreeBSD__)
#include <netinet/in.h>
#include <sys/socket.h>
#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);
}

View File

@@ -1,19 +0,0 @@
/* See LICENSE file for copyright and license details. */
#include <stdio.h>
#include <sys/utsname.h>
#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);
}

View File

@@ -1,50 +0,0 @@
/* See LICENSE file for copyright and license details. */
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <X11/Xlib.h>
#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;
}

View File

@@ -1,86 +0,0 @@
/* See LICENSE file for copyright and license details. */
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <X11/XKBlib.h>
#include <X11/Xlib.h>
#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;
}

View File

@@ -1,19 +0,0 @@
/* See LICENSE file for copyright and license details. */
#include <stdio.h>
#include <stdlib.h>
#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]);
}

View File

@@ -1,129 +0,0 @@
/* See LICENSE file for copyright and license details. */
#include <limits.h>
#include <stdio.h>
#include "../slstatus.h"
#include "../util.h"
#if defined(__linux__)
#include <stdint.h>
#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 <ifaddrs.h>
#include <net/if.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
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

View File

@@ -1,32 +0,0 @@
/* See LICENSE file for copyright and license details. */
#include <dirent.h>
#include <stdio.h>
#include <string.h>
#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);
}

View File

@@ -1,212 +0,0 @@
/* See LICENSE file for copyright and license details. */
#include <stdio.h>
#include "../slstatus.h"
#include "../util.h"
#if defined(__linux__)
#include <stdint.h>
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 <stdlib.h>
#include <sys/sysctl.h>
#include <sys/types.h>
#include <unistd.h>
#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 <sys/sysctl.h>
#include <sys/vmmeter.h>
#include <unistd.h>
#include <vm/vm_param.h>
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

View File

@@ -1,31 +0,0 @@
/* See LICENSE file for copyright and license details. */
#include <stdio.h>
#include <string.h>
#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;
}

View File

@@ -1,274 +0,0 @@
/* See LICENSE file for copyright and license details. */
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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 <stdlib.h>
#include <sys/swap.h>
#include <sys/types.h>
#include <unistd.h>
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 <fcntl.h>
#include <kvm.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
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

View File

@@ -1,73 +0,0 @@
/* See LICENSE file for copyright and license details. */
#include <stddef.h>
#include "../slstatus.h"
#include "../util.h"
#if defined(__linux__)
#include <stdint.h>
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 <stdio.h>
#include <sys/time.h> /* before <sys/sensors.h> for struct timeval */
#include <sys/sensors.h>
#include <sys/sysctl.h>
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 <stdio.h>
#include <stdlib.h>
#include <sys/sysctl.h>
#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

View File

@@ -1,34 +0,0 @@
/* See LICENSE file for copyright and license details. */
#include <stdint.h>
#include <stdio.h>
#include <time.h>
#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);
}

View File

@@ -1,33 +0,0 @@
/* See LICENSE file for copyright and license details. */
#include <pwd.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#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());
}

View File

@@ -1,219 +0,0 @@
/* See LICENSE file for copyright and license details. */
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include "../slstatus.h"
#include "../util.h"
#if defined(__OpenBSD__) | defined(__FreeBSD__)
#include <poll.h>
#include <sndio.h>
#include <stdlib.h>
#include <sys/queue.h>
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 <sys/soundcard.h>
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

View File

@@ -1,267 +0,0 @@
/* See LICENSE file for copyright and license details. */
#include <ifaddrs.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <unistd.h>
#include "../slstatus.h"
#include "../util.h"
#define RSSI_TO_PERC(rssi) \
rssi >= -50 ? 100 : \
(rssi <= -100 ? 0 : \
(2 * (rssi + 100)))
#if defined(__linux__)
#include <limits.h>
#include <linux/wireless.h>
#define NET_OPERSTATE "/sys/class/net/%s/operstate"
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), NET_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 <net/if.h>
#include <net/if_media.h>
#include <net80211/ieee80211.h>
#include <sys/select.h> /* before <sys/ieee80211_ioctl.h> for NBBY */
#include <net80211/ieee80211_ioctl.h>
#include <stdlib.h>
#include <sys/types.h>
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 <net/if.h>
#include <net80211/ieee80211_ioctl.h>
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

View File

@@ -1,84 +0,0 @@
/* 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[] = "";
/* 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
* 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 */
{ wifi_essid, "[ %s", "wlan0" },
{ wifi_essid, "%s", "wlo1" },
{ wifi_perc, " %s", "wlan0" },
{ wifi_perc, "%s%%] ", "wlo1" },
{ battery_perc, "[󰂉 %s", "BAT0" },
{ battery_perc, "%s%%] ", "cw2015-battery" },
{ run_command, "[ %s%%] ", "wpctl get-volume @DEFAULT_AUDIO_SINK@ | cut -c 11-" },
{ cpu_perc, "[ %s%%", NULL },
{ temp, " %sC] ", "/sys/class/thermal/thermal_zone0/temp" },
{ ram_used, "[ %s", NULL },
{ ram_perc, " %s%%] ", NULL },
{ datetime, "[ %s]", "%d/%m/%y %l:%M %p" },
};

View File

@@ -1,84 +0,0 @@
/* 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[] = "";
/* 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
* 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 */
{ wifi_essid, "[ %s", "wlan0" },
{ wifi_essid, "%s", "wlo1" },
{ wifi_perc, " %s", "wlan0" },
{ wifi_perc, "%s%%] ", "wlo1" },
{ battery_perc, "[󰂉 %s", "BAT0" },
{ battery_perc, "%s%%] ", "cw2015-battery" },
{ run_command, "[ %s%%] ", "wpctl get-volume @DEFAULT_AUDIO_SINK@ | cut -c 11-" },
{ cpu_perc, "[ %s%%", NULL },
{ temp, " %sC] ", "/sys/class/thermal/thermal_zone0/temp" },
{ ram_used, "[ %s", NULL },
{ ram_perc, " %s%%] ", NULL },
{ datetime, "[ %s]", "%d/%m/%y %l:%M %p" },
};

View File

@@ -1,22 +0,0 @@
# slstatus version
VERSION = 1.0
# customize below to fit your system
# paths
PREFIX = /usr/local
MANPREFIX = $(PREFIX)/share/man
X11INC = /usr/X11R6/include
X11LIB = /usr/X11R6/lib
# flags
CPPFLAGS = -I$(X11INC) -D_DEFAULT_SOURCE -DVERSION=\"${VERSION}\"
CFLAGS = -std=c99 -pedantic -Wall -Wextra -Wno-unused-parameter -Os
LDFLAGS = -L$(X11LIB) -s
# OpenBSD: add -lsndio
# FreeBSD: add -lkvm -lsndio
LDLIBS = -lX11
# compiler and linker
CC = cc

Binary file not shown.

View File

@@ -1,47 +0,0 @@
.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

View File

@@ -1,134 +0,0 @@
/* See LICENSE file for copyright and license details. */
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <X11/Xlib.h>
#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);
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, &current) < 0)
die("clock_gettime:");
difftimespec(&diff, &current, &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;
}

View File

@@ -1,84 +0,0 @@
/* 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);
/* 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);

View File

@@ -1,141 +0,0 @@
/* See LICENSE file for copyright and license details. */
#include <errno.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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;
}

View File

@@ -1,16 +0,0 @@
/* See LICENSE file for copyright and license details. */
#include <stdint.h>
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, ...);

Binary file not shown.

Binary file not shown.

Binary file not shown.