Browse Source

add slstatus

master
Evan Burkey 3 months ago
parent
commit
5afd904617
  1. 15
      dwm/config.h
  2. 40
      slstatus/LICENSE
  3. 68
      slstatus/Makefile
  4. 65
      slstatus/README
  5. 33
      slstatus/arg.h
  6. 252
      slstatus/components/battery.c
  7. 164
      slstatus/components/cpu.c
  8. 19
      slstatus/components/datetime.c
  9. 58
      slstatus/components/disk.c
  10. 27
      slstatus/components/entropy.c
  11. 16
      slstatus/components/hostname.c
  12. 60
      slstatus/components/ip.c
  13. 18
      slstatus/components/kernel_release.c
  14. 48
      slstatus/components/keyboard_indicators.c
  15. 87
      slstatus/components/keymap.c
  16. 18
      slstatus/components/load_avg.c
  17. 139
      slstatus/components/netspeeds.c
  18. 31
      slstatus/components/num_files.c
  19. 222
      slstatus/components/ram.c
  20. 30
      slstatus/components/run_command.c
  21. 10
      slstatus/components/separator.c
  22. 284
      slstatus/components/swap.c
  23. 71
      slstatus/components/temperature.c
  24. 33
      slstatus/components/uptime.c
  25. 32
      slstatus/components/user.c
  26. 217
      slstatus/components/volume.c
  27. 272
      slstatus/components/wifi.c
  28. 69
      slstatus/config.def.h
  29. 75
      slstatus/config.h
  30. 22
      slstatus/config.mk
  31. 28
      slstatus/slstatus.1
  32. 141
      slstatus/slstatus.c
  33. 84
      slstatus/slstatus.h
  34. 146
      slstatus/util.c
  35. 16
      slstatus/util.h

15
dwm/config.h

@ -28,13 +28,12 @@ static const Rule rules[] = {
*/
/* class instance title tags mask isfloating monitor */
{ "Gimp", NULL, NULL, 0, 1, -1 },
{ "Firefox", NULL, NULL, 1 << 8, 0, -1 },
};
/* layout(s) */
static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */
static const int nmaster = 1; /* number of clients in master area */
static const int resizehints = 1; /* 1 means respect size hints in tiled resizals */
static const int resizehints = 0; /* 1 means respect size hints in tiled resizals */
static const Layout layouts[] = {
/* symbol arrange function */
@ -57,12 +56,12 @@ static const Layout layouts[] = {
/* commands */
static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */
static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL };
static const char *termcmd[] = { "st", NULL };
static const char *termcmd[] = { "alacritty", NULL };
static Key keys[] = {
/* modifier key function argument */
{ MODKEY, XK_p, spawn, {.v = dmenucmd } },
{ MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } },
{ MODKEY, XK_d, spawn, {.v = dmenucmd } },
{ MODKEY, XK_Return, spawn, {.v = termcmd } },
{ MODKEY, XK_b, togglebar, {0} },
{ MODKEY, XK_j, focusstack, {.i = +1 } },
{ MODKEY, XK_k, focusstack, {.i = -1 } },
@ -70,9 +69,9 @@ static Key keys[] = {
{ MODKEY, XK_d, incnmaster, {.i = -1 } },
{ MODKEY, XK_h, setmfact, {.f = -0.05} },
{ MODKEY, XK_l, setmfact, {.f = +0.05} },
{ MODKEY, XK_Return, zoom, {0} },
{ MODKEY|ShiftMask, XK_Return, zoom, {0} },
{ MODKEY, XK_Tab, view, {0} },
{ MODKEY|ShiftMask, XK_c, killclient, {0} },
{ MODKEY, XK_q, killclient, {0} },
{ MODKEY, XK_t, setlayout, {.v = &layouts[0]} },
{ MODKEY, XK_f, setlayout, {.v = &layouts[1]} },
{ MODKEY, XK_m, setlayout, {.v = &layouts[2]} },
@ -93,7 +92,7 @@ static Key keys[] = {
TAGKEYS( XK_7, 6)
TAGKEYS( XK_8, 7)
TAGKEYS( XK_9, 8)
{ MODKEY|ShiftMask, XK_q, quit, {0} },
{ MODKEY|ShiftMask, XK_e, quit, {0} },
};
/* button definitions */

40
slstatus/LICENSE

@ -0,0 +1,40 @@
ISC License
Copyright 2016-2020 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 parazyd <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-2019 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 dsp <dsp@2f30.org>
Copyright 2019-2020 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>
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.

68
slstatus/Makefile

@ -0,0 +1,68 @@
# See LICENSE file for copyright and license details
# slstatus - suckless status monitor
.POSIX:
include config.mk
REQ = util
COM =\
components/battery\
components/cpu\
components/datetime\
components/disk\
components/entropy\
components/hostname\
components/ip\
components/kernel_release\
components/keyboard_indicators\
components/keymap\
components/load_avg\
components/netspeeds\
components/num_files\
components/ram\
components/run_command\
components/separator\
components/swap\
components/temperature\
components/uptime\
components/user\
components/volume\
components/wifi
all: slstatus
$(COM:=.o): config.mk $(REQ:=.h)
slstatus.o: slstatus.c slstatus.h arg.h config.h config.mk $(REQ:=.h)
.c.o:
$(CC) -o $@ -c $(CPPFLAGS) $(CFLAGS) $<
config.h:
cp config.def.h $@
slstatus: slstatus.o $(COM:=.o) $(REQ:=.o)
$(CC) -o $@ $(LDFLAGS) $(COM:=.o) $(REQ:=.o) slstatus.o $(LDLIBS)
clean:
rm -f slstatus slstatus.o $(COM:=.o) $(REQ:=.o)
dist:
rm -rf "slstatus-$(VERSION)"
mkdir -p "slstatus-$(VERSION)/components"
cp -R LICENSE Makefile README config.mk config.def.h \
arg.h slstatus.c $(COM:=.c) $(REQ:=.c) $(REQ:=.h) \
slstatus.1 "slstatus-$(VERSION)"
tar -cf - "slstatus-$(VERSION)" | gzip -c > "slstatus-$(VERSION).tar.gz"
rm -rf "slstatus-$(VERSION)"
install: all
mkdir -p "$(DESTDIR)$(PREFIX)/bin"
cp -f slstatus "$(DESTDIR)$(PREFIX)/bin"
chmod 755 "$(DESTDIR)$(PREFIX)/bin/slstatus"
mkdir -p "$(DESTDIR)$(MANPREFIX)/man1"
cp -f slstatus.1 "$(DESTDIR)$(MANPREFIX)/man1"
chmod 644 "$(DESTDIR)$(MANPREFIX)/man1/slstatus.1"
uninstall:
rm -f "$(DESTDIR)$(PREFIX)/bin/slstatus"
rm -f "$(DESTDIR)$(MANPREFIX)/man1/slstatus.1"

65
slstatus/README

@ -0,0 +1,65 @@
slstatus - suckless status
==========================
slstatus is a suckless status monitor for window managers that use WM_NAME
(e.g. dwm) or stdin to fill the status bar.
Features
--------
- Battery percentage/state/time left
- CPU usage
- CPU frequency
- Custom shell commands
- Date and time
- Disk status (free storage, percentage, total storage and used storage)
- Available entropy
- Username/GID/UID
- Hostname
- IP address (IPv4 and IPv6)
- Kernel version
- Keyboard indicators
- Keymap
- Load average
- Network speeds (RX and TX)
- Number of files in a directory (hint: Maildir)
- Memory status (free memory, percentage, total memory and used memory)
- Swap status (free swap, percentage, total swap and used swap)
- Temperature
- Uptime
- Volume percentage
- WiFi signal percentage and ESSID
Requirements
------------
Currently slstatus works on FreeBSD, Linux and OpenBSD.
In order to build slstatus you need the Xlib header files.
Installation
------------
Edit config.mk to match your local setup (slstatus is installed into the
/usr/local namespace by default).
Afterwards enter the following command to build and install slstatus (if
necessary as root):
make clean install
Running slstatus
----------------
See the man page for details.
Configuration
-------------
slstatus can be customized by creating a custom config.h and (re)compiling the
source code. This keeps it fast, secure and simple.
Upcoming
--------
A release (v1.0) will come soon... ;)
After a long phase of inactivity, development has been continued!

33
slstatus/arg.h

@ -0,0 +1,33 @@
/* See LICENSE file for copyright and license details. */
#ifndef ARG_H
#define ARG_H
extern char *argv0;
/* int main(int argc, char *argv[]) */
#define ARGBEGIN for (argv0 = *argv, *argv ? (argc--, argv++) : ((void *)0); \
*argv && (*argv)[0] == '-' && (*argv)[1]; argc--, argv++) { \
int i_, argused_; \
if ((*argv)[1] == '-' && !(*argv)[2]) { \
argc--, argv++; \
break; \
} \
for (i_ = 1, argused_ = 0; (*argv)[i_]; i_++) { \
switch((*argv)[i_])
#define ARGEND if (argused_) { \
if ((*argv)[i_ + 1]) { \
break; \
} else { \
argc--, argv++; \
break; \
} \
} \
} \
}
#define ARGC() ((*argv)[i_])
#define ARGF_(x) (((*argv)[i_ + 1]) ? (argused_ = 1, &((*argv)[i_ + 1])) : \
(*(argv + 1)) ? (argused_ = 1, *(argv + 1)) : (x))
#define EARGF(x) ARGF_(((x), exit(1), (char *)0))
#define ARGF() ARGF_((char *)0)
#endif

252
slstatus/components/battery.c

@ -0,0 +1,252 @@
/* See LICENSE file for copyright and license details. */
#include <stdio.h>
#include <string.h>
#include "../util.h"
#if defined(__linux__)
#include <limits.h>
#include <stdint.h>
#include <unistd.h>
static const char *
pick(const char *bat, const char *f1, const char *f2, char *path,
size_t length)
{
if (esnprintf(path, length, f1, bat) > 0 &&
access(path, R_OK) == 0) {
return f1;
}
if (esnprintf(path, length, f2, bat) > 0 &&
access(path, R_OK) == 0) {
return f2;
}
return NULL;
}
const char *
battery_perc(const char *bat)
{
int perc;
char path[PATH_MAX];
if (esnprintf(path, sizeof(path),
"/sys/class/power_supply/%s/capacity", bat) < 0) {
return NULL;
}
if (pscanf(path, "%d", &perc) != 1) {
return NULL;
}
return bprintf("%d", perc);
}
const char *
battery_state(const char *bat)
{
static struct {
char *state;
char *symbol;
} map[] = {
{ "Charging", "+" },
{ "Discharging", "-" },
{ "Full", "o" },
};
size_t i;
char path[PATH_MAX], state[12];
if (esnprintf(path, sizeof(path),
"/sys/class/power_supply/%s/status", bat) < 0) {
return NULL;
}
if (pscanf(path, "%12s", state) != 1) {
return NULL;
}
for (i = 0; i < LEN(map); i++) {
if (!strcmp(map[i].state, state)) {
break;
}
}
return (i == LEN(map)) ? "?" : map[i].symbol;
}
const char *
battery_remaining(const char *bat)
{
uintmax_t charge_now, current_now, m, h;
double timeleft;
char path[PATH_MAX], state[12];
if (esnprintf(path, sizeof(path),
"/sys/class/power_supply/%s/status", bat) < 0) {
return NULL;
}
if (pscanf(path, "%12s", state) != 1) {
return NULL;
}
if (!pick(bat, "/sys/class/power_supply/%s/charge_now",
"/sys/class/power_supply/%s/energy_now", path,
sizeof(path)) ||
pscanf(path, "%ju", &charge_now) < 0) {
return NULL;
}
if (!strcmp(state, "Discharging")) {
if (!pick(bat, "/sys/class/power_supply/%s/current_now",
"/sys/class/power_supply/%s/power_now", path,
sizeof(path)) ||
pscanf(path, "%ju", &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;
if (load_apm_power_info(&apm_info)) {
if (apm_info.ac_state != APM_AC_ON) {
return bprintf("%uh %02um",
apm_info.minutes_left / 60,
apm_info.minutes_left % 60);
} else {
return "";
}
}
return NULL;
}
#elif defined(__FreeBSD__)
#include <sys/sysctl.h>
const char *
battery_perc(const char *unused)
{
int cap;
size_t len;
len = sizeof(cap);
if (sysctlbyname("hw.acpi.battery.life", &cap, &len, NULL, 0) == -1
|| !len)
return NULL;
return bprintf("%d", cap);
}
const char *
battery_state(const char *unused)
{
int state;
size_t len;
len = sizeof(state);
if (sysctlbyname("hw.acpi.battery.state", &state, &len, NULL, 0) == -1
|| !len)
return NULL;
switch(state) {
case 0:
case 2:
return "+";
case 1:
return "-";
default:
return "?";
}
}
const char *
battery_remaining(const char *unused)
{
int rem;
size_t len;
len = sizeof(rem);
if (sysctlbyname("hw.acpi.battery.time", &rem, &len, NULL, 0) == -1
|| !len
|| rem == -1)
return NULL;
return bprintf("%uh %02um", rem / 60, rem % 60);
}
#endif

164
slstatus/components/cpu.c

@ -0,0 +1,164 @@
/* See LICENSE file for copyright and license details. */
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "../util.h"
#if defined(__linux__)
const char *
cpu_freq(void)
{
uintmax_t freq;
/* in kHz */
if (pscanf("/sys/devices/system/cpu/cpu0/cpufreq/"
"scaling_cur_freq", "%ju", &freq) != 1) {
return NULL;
}
return fmt_human(freq * 1000, 1000);
}
const char *
cpu_perc(void)
{
static long double a[7];
long double b[7], sum;
memcpy(b, a, sizeof(b));
/* cpu user nice system idle iowait irq softirq */
if (pscanf("/proc/stat", "%*s %Lf %Lf %Lf %Lf %Lf %Lf %Lf",
&a[0], &a[1], &a[2], &a[3], &a[4], &a[5], &a[6])
!= 7) {
return NULL;
}
if (b[0] == 0) {
return NULL;
}
sum = (b[0] + b[1] + b[2] + b[3] + b[4] + b[5] + b[6]) -
(a[0] + a[1] + a[2] + a[3] + a[4] + a[5] + a[6]);
if (sum == 0) {
return NULL;
}
return bprintf("%d", (int)(100 *
((b[0] + b[1] + b[2] + b[5] + b[6]) -
(a[0] + a[1] + a[2] + a[5] + a[6])) / sum));
}
#elif defined(__OpenBSD__)
#include <sys/param.h>
#include <sys/sched.h>
#include <sys/sysctl.h>
const char *
cpu_freq(void)
{
int freq, mib[2];
size_t size;
mib[0] = CTL_HW;
mib[1] = HW_CPUSPEED;
size = sizeof(freq);
/* in MHz */
if (sysctl(mib, 2, &freq, &size, NULL, 0) < 0) {
warn("sysctl 'HW_CPUSPEED':");
return NULL;
}
return fmt_human(freq * 1E6, 1000);
}
const char *
cpu_perc(void)
{
int mib[2];
static uintmax_t a[CPUSTATES];
uintmax_t b[CPUSTATES], sum;
size_t size;
mib[0] = CTL_KERN;
mib[1] = KERN_CPTIME;
size = sizeof(a);
memcpy(b, a, sizeof(b));
if (sysctl(mib, 2, &a, &size, NULL, 0) < 0) {
warn("sysctl 'KERN_CPTIME':");
return NULL;
}
if (b[0] == 0) {
return NULL;
}
sum = (a[CP_USER] + a[CP_NICE] + a[CP_SYS] + a[CP_INTR] + a[CP_IDLE]) -
(b[CP_USER] + b[CP_NICE] + b[CP_SYS] + b[CP_INTR] + b[CP_IDLE]);
if (sum == 0) {
return NULL;
}
return bprintf("%d", 100 *
((a[CP_USER] + a[CP_NICE] + a[CP_SYS] +
a[CP_INTR]) -
(b[CP_USER] + b[CP_NICE] + b[CP_SYS] +
b[CP_INTR])) / sum);
}
#elif defined(__FreeBSD__)
#include <sys/param.h>
#include <sys/sysctl.h>
#include <devstat.h>
const char *
cpu_freq(void)
{
int freq;
size_t size;
size = sizeof(freq);
/* in MHz */
if (sysctlbyname("hw.clockrate", &freq, &size, NULL, 0) == -1
|| !size) {
warn("sysctlbyname 'hw.clockrate':");
return NULL;
}
return fmt_human(freq * 1E6, 1000);
}
const char *
cpu_perc(void)
{
size_t size;
static long a[CPUSTATES];
long b[CPUSTATES], sum;
size = sizeof(a);
memcpy(b, a, sizeof(b));
if (sysctlbyname("kern.cp_time", &a, &size, NULL, 0) == -1
|| !size) {
warn("sysctlbyname 'kern.cp_time':");
return NULL;
}
if (b[0] == 0) {
return NULL;
}
sum = (a[CP_USER] + a[CP_NICE] + a[CP_SYS] + a[CP_INTR] + a[CP_IDLE]) -
(b[CP_USER] + b[CP_NICE] + b[CP_SYS] + b[CP_INTR] + b[CP_IDLE]);
if (sum == 0) {
return NULL;
}
return bprintf("%d", 100 *
((a[CP_USER] + a[CP_NICE] + a[CP_SYS] +
a[CP_INTR]) -
(b[CP_USER] + b[CP_NICE] + b[CP_SYS] +
b[CP_INTR])) / sum);
}
#endif

19
slstatus/components/datetime.c

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

58
slstatus/components/disk.c

@ -0,0 +1,58 @@
/* See LICENSE file for copyright and license details. */
#include <stdio.h>
#include <sys/statvfs.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.0f - ((float)fs.f_bavail / (float)fs.f_blocks))));
}
const char *
disk_total(const char *path)
{
struct statvfs fs;
if (statvfs(path, &fs) < 0) {
warn("statvfs '%s':", path);
return NULL;
}
return fmt_human(fs.f_frsize * fs.f_blocks, 1024);
}
const char *
disk_used(const char *path)
{
struct statvfs fs;
if (statvfs(path, &fs) < 0) {
warn("statvfs '%s':", path);
return NULL;
}
return fmt_human(fs.f_frsize * (fs.f_blocks - fs.f_bfree), 1024);
}

27
slstatus/components/entropy.c

@ -0,0 +1,27 @@
/* See LICENSE file for copyright and license details. */
#if defined(__linux__)
#include <stdint.h>
#include <stdio.h>
#include "../util.h"
const char *
entropy(void)
{
uintmax_t num;
if (pscanf("/proc/sys/kernel/random/entropy_avail", "%ju", &num)
!= 1) {
return NULL;
}
return bprintf("%ju", num);
}
#elif defined(__OpenBSD__) | defined(__FreeBSD__)
const char *
entropy(void)
{
/* Unicode Character 'INFINITY' (U+221E) */
return "\xe2\x88\x9e";
}
#endif

16
slstatus/components/hostname.c

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

60
slstatus/components/ip.c

@ -0,0 +1,60 @@
/* 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/types.h>
#include <sys/socket.h>
#elif defined(__FreeBSD__)
#include <netinet/in.h>
#include <sys/socket.h>
#endif
#include "../util.h"
static const char *
ip(const char *interface, unsigned short sa_family)
{
struct ifaddrs *ifaddr, *ifa;
int s;
char host[NI_MAXHOST];
if (getifaddrs(&ifaddr) < 0) {
warn("getifaddrs:");
return NULL;
}
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
if (!ifa->ifa_addr) {
continue;
}
s = getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in6),
host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
if (!strcmp(ifa->ifa_name, interface) &&
(ifa->ifa_addr->sa_family == sa_family)) {
freeifaddrs(ifaddr);
if (s != 0) {
warn("getnameinfo: %s", gai_strerror(s));
return NULL;
}
return bprintf("%s", host);
}
}
freeifaddrs(ifaddr);
return NULL;
}
const char *
ipv4(const char *interface)
{
return ip(interface, AF_INET);
}
const char *
ipv6(const char *interface)
{
return ip(interface, AF_INET6);
}

18
slstatus/components/kernel_release.c

@ -0,0 +1,18 @@
/* See LICENSE file for copyright and license details. */
#include <sys/utsname.h>
#include <stdio.h>
#include "../util.h"
const char *
kernel_release(void)
{
struct utsname udata;
if (uname(&udata) < 0) {
warn("uname:");
return NULL;
}
return bprintf("%s", udata.release);
}

48
slstatus/components/keyboard_indicators.c

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

87
slstatus/components/keymap.c

@ -0,0 +1,87 @@
/* 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 "../util.h"
static int
valid_layout_or_variant(char *sym)
{
size_t i;
/* invalid symbols from xkb rules config */
static const char *invalid[] = { "evdev", "inet", "pc", "base" };
for (i = 0; i < LEN(invalid); i++) {
if (!strncmp(sym, invalid[i], strlen(invalid[i]))) {
return 0;
}
}
return 1;
}
static char *
get_layout(char *syms, int grp_num)
{
char *tok, *layout;
int grp;
layout = NULL;
tok = strtok(syms, "+:");
for (grp = 0; tok && grp <= grp_num; tok = strtok(NULL, "+:")) {
if (!valid_layout_or_variant(tok)) {
continue;
} else if (strlen(tok) == 1 && isdigit(tok[0])) {
/* ignore :2, :3, :4 (additional layout groups) */
continue;
}
layout = tok;
grp++;
}
return layout;
}
const char *
keymap(void)
{
Display *dpy;
XkbDescRec *desc;
XkbStateRec state;
char *symbols, *layout;
layout = NULL;
if (!(dpy = XOpenDisplay(NULL))) {
warn("XOpenDisplay: Failed to open display");
return NULL;
}
if (!(desc = XkbAllocKeyboard())) {
warn("XkbAllocKeyboard: Failed to allocate keyboard");
goto end;
}
if (XkbGetNames(dpy, XkbSymbolsNameMask, desc)) {
warn("XkbGetNames: Failed to retrieve key symbols");
goto end;
}
if (XkbGetState(dpy, XkbUseCoreKbd, &state)) {
warn("XkbGetState: Failed to retrieve keyboard state");
goto end;
}
if (!(symbols = XGetAtomName(dpy, desc->names->symbols))) {
warn("XGetAtomName: Failed to get atom name");
goto end;
}
layout = (char *)bprintf("%s", get_layout(symbols, state.group));
XFree(symbols);
end:
XkbFreeKeyboard(desc, XkbSymbolsNameMask, 1);
if (XCloseDisplay(dpy)) {
warn("XCloseDisplay: Failed to close display");
}
return layout;
}

18
slstatus/components/load_avg.c

@ -0,0 +1,18 @@
/* See LICENSE file for copyright and license details. */
#include <stdio.h>
#include <stdlib.h>
#include "../util.h"
const char *
load_avg(void)
{
double avgs[3];
if (getloadavg(avgs, 3) < 0) {
warn("getloadavg: Failed to obtain load average");
return NULL;
}
return bprintf("%.2f %.2f %.2f", avgs[0], avgs[1], avgs[2]);
}

139
slstatus/components/netspeeds.c

@ -0,0 +1,139 @@
/* See LICENSE file for copyright and license details. */
#include <stdio.h>
#include <limits.h>
#include "../util.h"
#if defined(__linux__)
#include <stdint.h>
const char *
netspeed_rx(const char *interface)
{
uintmax_t oldrxbytes;
static uintmax_t rxbytes;
extern const unsigned int interval;
char path[PATH_MAX];
oldrxbytes = rxbytes;
if (esnprintf(path, sizeof(path),
"/sys/class/net/%s/statistics/rx_bytes",
interface) < 0) {
return NULL;
}
if (pscanf(path, "%ju", &rxbytes) != 1) {
return NULL;
}
if (oldrxbytes == 0) {
return NULL;
}
return fmt_human((rxbytes - oldrxbytes) * 1000 / interval,
1024);
}
const char *
netspeed_tx(const char *interface)
{
uintmax_t oldtxbytes;
static uintmax_t txbytes;
extern const unsigned int interval;
char path[PATH_MAX];
oldtxbytes = txbytes;
if (esnprintf(path, sizeof(path),
"/sys/class/net/%s/statistics/tx_bytes",
interface) < 0) {
return NULL;
}
if (pscanf(path, "%ju", &txbytes) != 1) {
return NULL;
}
if (oldtxbytes == 0) {
return NULL;
}
return fmt_human((txbytes - oldtxbytes) * 1000 / interval,
1024);
}
#elif defined(__OpenBSD__) | defined(__FreeBSD__)
#include <string.h>
#include <ifaddrs.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <net/if.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) == -1) {
warn("getifaddrs failed");
return NULL;
}
rxbytes = 0;
for (ifa = ifal; ifa; ifa = ifa->ifa_next) {
if (!strcmp(ifa->ifa_name, interface) &&
(ifd = (struct if_data *)ifa->ifa_data)) {
rxbytes += ifd->ifi_ibytes, if_ok = 1;
}
}
freeifaddrs(ifal);
if (!if_ok) {
warn("reading 'if_data' failed");
return NULL;
}
if (oldrxbytes == 0) {
return NULL;
}
return fmt_human((rxbytes - oldrxbytes) * 1000 / interval,
1024);
}
const char *
netspeed_tx(const char *interface)
{
struct ifaddrs *ifal, *ifa;
struct if_data *ifd;
uintmax_t oldtxbytes;
static uintmax_t txbytes;
extern const unsigned int interval;
int if_ok = 0;
oldtxbytes = txbytes;
if (getifaddrs(&ifal) == -1) {
warn("getifaddrs failed");
return NULL;
}
txbytes = 0;
for (ifa = ifal; ifa; ifa = ifa->ifa_next) {
if (!strcmp(ifa->ifa_name, interface) &&
(ifd = (struct if_data *)ifa->ifa_data)) {
txbytes += ifd->ifi_obytes, if_ok = 1;
}
}
freeifaddrs(ifal);
if (!if_ok) {
warn("reading 'if_data' failed");
return NULL;
}
if (oldtxbytes == 0) {
return NULL;
}
return fmt_human((txbytes - oldtxbytes) * 1000 / interval,
1024);
}
#endif

31
slstatus/components/num_files.c

@ -0,0 +1,31 @@
/* See LICENSE file for copyright and license details. */
#include <dirent.h>
#include <stdio.h>
#include <string.h>
#include "../util.h"
const char *
num_files(const char *path)
{
struct dirent *dp;
DIR *fd;
int num;
if (!(fd = opendir(path))) {
warn("opendir '%s':", path);
return NULL;
}
num = 0;
while ((dp = readdir(fd))) {
if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) {
continue; /* skip self and parent */
}
num++;
}
closedir(fd);
return bprintf("%d", num);
}

222
slstatus/components/ram.c

@ -0,0 +1,222 @@
/* See LICENSE file for copyright and license details. */
#include <stdio.h>
#include "../util.h"
#if defined(__linux__)
#include <stdint.h>
const char *
ram_free(void)
{
uintmax_t free;
if (pscanf("/proc/meminfo",
"MemTotal: %ju kB\n"
"MemFree: %ju kB\n"
"MemAvailable: %ju kB\n",
&free, &free, &free) != 3) {
return NULL;
}
return fmt_human(free * 1024, 1024);
}
const char *
ram_perc(void)
{
uintmax_t total, free, buffers, cached;
if (pscanf("/proc/meminfo",
"MemTotal: %ju kB\n"
"MemFree: %ju kB\n"
"MemAvailable: %ju kB\n"
"Buffers: %ju kB\n"
"Cached: %ju kB\n",
&total, &free, &buffers, &buffers, &cached) != 5) {
return NULL;
}
if (total == 0) {
return NULL;
}
return bprintf("%d", 100 * ((total - free) - (buffers + cached))
/ total);
}
const char *
ram_total(void)
{
uintmax_t total;
if (pscanf("/proc/meminfo", "MemTotal: %ju kB\n", &total)
!= 1) {
return NULL;
}
return fmt_human(total * 1024, 1024);
}
const char *
ram_used(void)
{
uintmax_t total, free, buffers, cached;
if (pscanf("/proc/meminfo",
"MemTotal: %ju kB\n"
"MemFree: %ju kB\n"
"MemAvailable: %ju kB\n"
"Buffers: %ju kB\n"
"Cached: %ju kB\n",
&total, &free, &buffers, &buffers, &cached) != 5) {
return NULL;
}
return fmt_human((total - free - buffers - cached) * 1024,
1024);
}
#elif defined(__OpenBSD__)
#include <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(void)
{
struct uvmexp uvmexp;
int free_pages;
if (load_uvmexp(&uvmexp)) {
free_pages = uvmexp.npages - uvmexp.active;
return fmt_human(pagetok(free_pages, uvmexp.pageshift) *
1024, 1024);
}
return NULL;
}
const char *
ram_perc(void)
{
struct uvmexp uvmexp;
int percent;
if (load_uvmexp(&uvmexp)) {
percent = uvmexp.active * 100 / uvmexp.npages;
return bprintf("%d", percent);
}
return NULL;
}
const char *
ram_total(void)
{
struct uvmexp uvmexp;
if (load_uvmexp(&uvmexp)) {
return fmt_human(pagetok(uvmexp.npages,
uvmexp.pageshift) * 1024,
1024);
}
return NULL;
}
const char *
ram_used(void)
{
struct uvmexp uvmexp;
if (load_uvmexp(&uvmexp)) {
return fmt_human(pagetok(uvmexp.active,
uvmexp.pageshift) * 1024,
1024);
}
return NULL;
}
#elif defined(__FreeBSD__)
#include <sys/sysctl.h>
#include <sys/vmmeter.h>
#include <unistd.h>
#include <vm/vm_param.h>
const char *
ram_free(void) {
struct vmtotal vm_stats;
int mib[] = {CTL_VM, VM_TOTAL};
size_t len;
len = sizeof(struct vmtotal);
if (sysctl(mib, 2, &vm_stats, &len, NULL, 0) == -1
|| !len)
return NULL;
return fmt_human(vm_stats.t_free * getpagesize(), 1024);
}
const char *
ram_total(void) {
long npages;
size_t len;
len = sizeof(npages);
if (sysctlbyname("vm.stats.vm.v_page_count", &npages, &len, NULL, 0) == -1
|| !len)
return NULL;
return fmt_human(npages * getpagesize(), 1024);
}
const char *
ram_perc(void) {
long npages;
long active;
size_t len;
len = sizeof(npages);
if (sysctlbyname("vm.stats.vm.v_page_count", &npages, &len, NULL, 0) == -1
|| !len)
return NULL;
if (sysctlbyname("vm.stats.vm.v_active_count", &active, &len, NULL, 0) == -1
|| !len)
return NULL;
return bprintf("%d", active * 100 / npages);
}
const char *
ram_used(void) {
long active;
size_t len;
len = sizeof(active);
if (sysctlbyname("vm.stats.vm.v_active_count", &active, &len, NULL, 0) == -1
|| !len)
return NULL;
return fmt_human(active * getpagesize(), 1024);
}
#endif

30
slstatus/components/run_command.c

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

10
slstatus/components/separator.c

@ -0,0 +1,10 @@
/* See LICENSE file for copyright and license details. */
#include <stdio.h>
#include "../util.h"
const char *
separator(const char *separator)
{
return separator;
}

284
slstatus/components/swap.c

@ -0,0 +1,284 @@
/* See LICENSE file for copyright and license details. */
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.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(void)
{
long free;
if (get_swap_info(NULL, &free, NULL)) {
return NULL;
}
return fmt_human(free * 1024, 1024);
}
const char *
swap_perc(void)
{
long total, free, cached;
if (get_swap_info(&total, &free, &cached) || total == 0) {
return NULL;
}
return bprintf("%d", 100 * (total - free - cached) / total);
}
const char *
swap_total(void)
{
long total;
if (get_swap_info(&total, NULL, NULL)) {
return NULL;
}
return fmt_human(total * 1024, 1024);
}
const char *
swap_used(void)
{
long total, free, cached;
if (get_swap_info(&total, &free, &cached)) {
return NULL;
}
return fmt_human((total - free - cached) * 1024, 1024);
}
#elif defined(__OpenBSD__)
#include <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;
</