slstatus-1.0004075500017540001754000000000001445106606700125725ustar00drkhshdrkhshslstatus-1.0/components004075500017540001754000000000001445106606700147575ustar00drkhshdrkhshslstatus-1.0/components/battery.c010064400017540001754000000121601445106606700166510ustar00drkhshdrkhsh/* See LICENSE file for copyright and license details. */ #include #include #include "../slstatus.h" #include "../util.h" #if defined(__linux__) /* * https://www.kernel.org/doc/html/latest/power/power_supply_class.html */ #include #include #include #define POWER_SUPPLY_CAPACITY "/sys/class/power_supply/%s/capacity" #define POWER_SUPPLY_STATUS "/sys/class/power_supply/%s/status" #define POWER_SUPPLY_CHARGE "/sys/class/power_supply/%s/charge_now" #define POWER_SUPPLY_ENERGY "/sys/class/power_supply/%s/energy_now" #define POWER_SUPPLY_CURRENT "/sys/class/power_supply/%s/current_now" #define POWER_SUPPLY_POWER "/sys/class/power_supply/%s/power_now" static const char * pick(const char *bat, const char *f1, const char *f2, char *path, size_t length) { if (esnprintf(path, length, f1, bat) > 0 && access(path, R_OK) == 0) return f1; if (esnprintf(path, length, f2, bat) > 0 && access(path, R_OK) == 0) return f2; return NULL; } const char * battery_perc(const char *bat) { int cap_perc; char path[PATH_MAX]; if (esnprintf(path, sizeof(path), POWER_SUPPLY_CAPACITY, bat) < 0) return NULL; if (pscanf(path, "%d", &cap_perc) != 1) return NULL; return bprintf("%d", cap_perc); } const char * battery_state(const char *bat) { static struct { char *state; char *symbol; } map[] = { { "Charging", "+" }, { "Discharging", "-" }, { "Full", "o" }, { "Not charging", "o" }, }; size_t i; char path[PATH_MAX], state[12]; if (esnprintf(path, sizeof(path), POWER_SUPPLY_STATUS, bat) < 0) return NULL; if (pscanf(path, "%12[a-zA-Z ]", state) != 1) return NULL; for (i = 0; i < LEN(map); i++) if (!strcmp(map[i].state, state)) break; return (i == LEN(map)) ? "?" : map[i].symbol; } const char * battery_remaining(const char *bat) { uintmax_t charge_now, current_now, m, h; double timeleft; char path[PATH_MAX], state[12]; if (esnprintf(path, sizeof(path), POWER_SUPPLY_STATUS, bat) < 0) return NULL; if (pscanf(path, "%12[a-zA-Z ]", state) != 1) return NULL; if (!pick(bat, POWER_SUPPLY_CHARGE, POWER_SUPPLY_ENERGY, path, sizeof(path)) || pscanf(path, "%ju", &charge_now) < 0) return NULL; if (!strcmp(state, "Discharging")) { if (!pick(bat, POWER_SUPPLY_CURRENT, POWER_SUPPLY_POWER, path, sizeof(path)) || pscanf(path, "%ju", ¤t_now) < 0) return NULL; if (current_now == 0) return NULL; timeleft = (double)charge_now / (double)current_now; h = timeleft; m = (timeleft - (double)h) * 60; return bprintf("%juh %jum", h, m); } return ""; } #elif defined(__OpenBSD__) #include #include #include #include static int load_apm_power_info(struct apm_power_info *apm_info) { int fd; fd = open("/dev/apm", O_RDONLY); if (fd < 0) { warn("open '/dev/apm':"); return 0; } memset(apm_info, 0, sizeof(struct apm_power_info)); if (ioctl(fd, APM_IOC_GETPOWER, apm_info) < 0) { warn("ioctl 'APM_IOC_GETPOWER':"); close(fd); return 0; } return close(fd), 1; } const char * battery_perc(const char *unused) { struct apm_power_info apm_info; if (load_apm_power_info(&apm_info)) return bprintf("%d", apm_info.battery_life); return NULL; } const char * battery_state(const char *unused) { struct { unsigned int state; char *symbol; } map[] = { { APM_AC_ON, "+" }, { APM_AC_OFF, "-" }, }; struct apm_power_info apm_info; size_t i; if (load_apm_power_info(&apm_info)) { for (i = 0; i < LEN(map); i++) if (map[i].state == apm_info.ac_state) break; return (i == LEN(map)) ? "?" : map[i].symbol; } return NULL; } const char * battery_remaining(const char *unused) { struct apm_power_info apm_info; unsigned int h, m; if (load_apm_power_info(&apm_info)) { if (apm_info.ac_state != APM_AC_ON) { h = apm_info.minutes_left / 60; m = apm_info.minutes_left % 60; return bprintf("%uh %02um", h, m); } else { return ""; } } return NULL; } #elif defined(__FreeBSD__) #include #define BATTERY_LIFE "hw.acpi.battery.life" #define BATTERY_STATE "hw.acpi.battery.state" #define BATTERY_TIME "hw.acpi.battery.time" const char * battery_perc(const char *unused) { int cap_perc; size_t len; len = sizeof(cap_perc); if (sysctlbyname(BATTERY_LIFE, &cap_perc, &len, NULL, 0) < 0 || !len) return NULL; return bprintf("%d", cap_perc); } const char * battery_state(const char *unused) { int state; size_t len; len = sizeof(state); if (sysctlbyname(BATTERY_STATE, &state, &len, NULL, 0) < 0 || !len) return NULL; switch (state) { case 0: /* FALLTHROUGH */ case 2: return "+"; case 1: return "-"; default: return "?"; } } const char * battery_remaining(const char *unused) { int rem; size_t len; len = sizeof(rem); if (sysctlbyname(BATTERY_TIME, &rem, &len, NULL, 0) < 0 || !len || rem < 0) return NULL; return bprintf("%uh %02um", rem / 60, rem % 60); } #endif slstatus-1.0/components/cat.c010064400017540001754000000012141445106606700157440ustar00drkhshdrkhsh/* See LICENSE file for copyright and license details. */ #include #include #include "../slstatus.h" #include "../util.h" const char * cat(const char *path) { char *f; FILE *fp; if (!(fp = fopen(path, "r"))) { warn("fopen '%s':", path); return NULL; } f = fgets(buf, sizeof(buf) - 1, fp); if (fclose(fp) < 0) { warn("fclose '%s':", path); return NULL; } if (!f) return NULL; if ((f = strrchr(buf, '\n'))) f[0] = '\0'; return buf[0] ? buf : NULL; } slstatus-1.0/components/cpu.c010064400017540001754000000065521445106606700157760ustar00drkhshdrkhsh/* See LICENSE file for copyright and license details. */ #include #include #include #include "../slstatus.h" #include "../util.h" #if defined(__linux__) #define CPU_FREQ "/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq" const char * cpu_freq(const char *unused) { uintmax_t freq; /* in kHz */ if (pscanf(CPU_FREQ, "%ju", &freq) != 1) return NULL; return fmt_human(freq * 1000, 1000); } const char * cpu_perc(const char *unused) { static long double a[7]; long double b[7], sum; memcpy(b, a, sizeof(b)); /* cpu user nice system idle iowait irq softirq */ if (pscanf("/proc/stat", "%*s %Lf %Lf %Lf %Lf %Lf %Lf %Lf", &a[0], &a[1], &a[2], &a[3], &a[4], &a[5], &a[6]) != 7) return NULL; if (b[0] == 0) return NULL; sum = (b[0] + b[1] + b[2] + b[3] + b[4] + b[5] + b[6]) - (a[0] + a[1] + a[2] + a[3] + a[4] + a[5] + a[6]); if (sum == 0) return NULL; return bprintf("%d", (int)(100 * ((b[0] + b[1] + b[2] + b[5] + b[6]) - (a[0] + a[1] + a[2] + a[5] + a[6])) / sum)); } #elif defined(__OpenBSD__) #include #include #include const char * cpu_freq(const char *unused) { int freq, mib[2]; size_t size; mib[0] = CTL_HW; mib[1] = HW_CPUSPEED; size = sizeof(freq); /* in MHz */ if (sysctl(mib, 2, &freq, &size, NULL, 0) < 0) { warn("sysctl 'HW_CPUSPEED':"); return NULL; } return fmt_human(freq * 1E6, 1000); } const char * cpu_perc(const char *unused) { int mib[2]; static uintmax_t a[CPUSTATES]; uintmax_t b[CPUSTATES], sum; size_t size; mib[0] = CTL_KERN; mib[1] = KERN_CPTIME; size = sizeof(a); memcpy(b, a, sizeof(b)); if (sysctl(mib, 2, &a, &size, NULL, 0) < 0) { warn("sysctl 'KERN_CPTIME':"); return NULL; } if (b[0] == 0) return NULL; sum = (a[CP_USER] + a[CP_NICE] + a[CP_SYS] + a[CP_INTR] + a[CP_IDLE]) - (b[CP_USER] + b[CP_NICE] + b[CP_SYS] + b[CP_INTR] + b[CP_IDLE]); if (sum == 0) return NULL; return bprintf("%d", 100 * ((a[CP_USER] + a[CP_NICE] + a[CP_SYS] + a[CP_INTR]) - (b[CP_USER] + b[CP_NICE] + b[CP_SYS] + b[CP_INTR])) / sum); } #elif defined(__FreeBSD__) #include #include #include const char * cpu_freq(const char *unused) { int freq; size_t size; size = sizeof(freq); /* in MHz */ if (sysctlbyname("hw.clockrate", &freq, &size, NULL, 0) < 0 || !size) { warn("sysctlbyname 'hw.clockrate':"); return NULL; } return fmt_human(freq * 1E6, 1000); } const char * cpu_perc(const char *unused) { size_t size; static long a[CPUSTATES]; long b[CPUSTATES], sum; size = sizeof(a); memcpy(b, a, sizeof(b)); if (sysctlbyname("kern.cp_time", &a, &size, NULL, 0) < 0 || !size) { warn("sysctlbyname 'kern.cp_time':"); return NULL; } if (b[0] == 0) return NULL; sum = (a[CP_USER] + a[CP_NICE] + a[CP_SYS] + a[CP_INTR] + a[CP_IDLE]) - (b[CP_USER] + b[CP_NICE] + b[CP_SYS] + b[CP_INTR] + b[CP_IDLE]); if (sum == 0) return NULL; return bprintf("%d", 100 * ((a[CP_USER] + a[CP_NICE] + a[CP_SYS] + a[CP_INTR]) - (b[CP_USER] + b[CP_NICE] + b[CP_SYS] + b[CP_INTR])) / sum); } #endif slstatus-1.0/components/datetime.c010064400017540001754000000005461445106606700170000ustar00drkhshdrkhsh/* See LICENSE file for copyright and license details. */ #include #include #include "../slstatus.h" #include "../util.h" const char * datetime(const char *fmt) { time_t t; t = time(NULL); if (!strftime(buf, sizeof(buf), fmt, localtime(&t))) { warn("strftime: Result string exceeds buffer size"); return NULL; } return buf; } slstatus-1.0/components/disk.c010064400017540001754000000017701445106606700161360ustar00drkhshdrkhsh/* See LICENSE file for copyright and license details. */ #include #include #include "../slstatus.h" #include "../util.h" const char * disk_free(const char *path) { struct statvfs fs; if (statvfs(path, &fs) < 0) { warn("statvfs '%s':", path); return NULL; } return fmt_human(fs.f_frsize * fs.f_bavail, 1024); } const char * disk_perc(const char *path) { struct statvfs fs; if (statvfs(path, &fs) < 0) { warn("statvfs '%s':", path); return NULL; } return bprintf("%d", (int)(100 * (1 - ((double)fs.f_bavail / (double)fs.f_blocks)))); } const char * disk_total(const char *path) { struct statvfs fs; if (statvfs(path, &fs) < 0) { warn("statvfs '%s':", path); return NULL; } return fmt_human(fs.f_frsize * fs.f_blocks, 1024); } const char * disk_used(const char *path) { struct statvfs fs; if (statvfs(path, &fs) < 0) { warn("statvfs '%s':", path); return NULL; } return fmt_human(fs.f_frsize * (fs.f_blocks - fs.f_bfree), 1024); } slstatus-1.0/components/entropy.c010064400017540001754000000011511445106606700166750ustar00drkhshdrkhsh/* See LICENSE file for copyright and license details. */ #include "../slstatus.h" #if defined(__linux__) #include #include #include "../util.h" #define ENTROPY_AVAIL "/proc/sys/kernel/random/entropy_avail" const char * entropy(const char *unused) { uintmax_t num; if (pscanf(ENTROPY_AVAIL, "%ju", &num) != 1) return NULL; return bprintf("%ju", num); } #elif defined(__OpenBSD__) | defined(__FreeBSD__) const char * entropy(const char *unused) { // https://www.unicode.org/charts/PDF/U2200.pdf /* Unicode Character 'INFINITY' (U+221E) */ return "\u221E"; } #endif slstatus-1.0/components/hostname.c010064400017540001754000000004431445106606700170160ustar00drkhshdrkhsh/* See LICENSE file for copyright and license details. */ #include #include #include "../slstatus.h" #include "../util.h" const char * hostname(const char *unused) { if (gethostname(buf, sizeof(buf)) < 0) { warn("gethostbyname:"); return NULL; } return buf; } slstatus-1.0/components/ip.c010064400017540001754000000022671445106606700156160ustar00drkhshdrkhsh/* See LICENSE file for copyright and license details. */ #include #include #include #include #if defined(__OpenBSD__) #include #include #elif defined(__FreeBSD__) #include #include #endif #include "../slstatus.h" #include "../util.h" static const char * ip(const char *interface, unsigned short sa_family) { struct ifaddrs *ifaddr, *ifa; int s; char host[NI_MAXHOST]; if (getifaddrs(&ifaddr) < 0) { warn("getifaddrs:"); return NULL; } for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { if (!ifa->ifa_addr) continue; s = getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in6), host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST); if (!strcmp(ifa->ifa_name, interface) && (ifa->ifa_addr->sa_family == sa_family)) { freeifaddrs(ifaddr); if (s != 0) { warn("getnameinfo: %s", gai_strerror(s)); return NULL; } return bprintf("%s", host); } } freeifaddrs(ifaddr); return NULL; } const char * ipv4(const char *interface) { return ip(interface, AF_INET); } const char * ipv6(const char *interface) { return ip(interface, AF_INET6); } slstatus-1.0/components/kernel_release.c010064400017540001754000000005071445106606700201610ustar00drkhshdrkhsh/* See LICENSE file for copyright and license details. */ #include #include #include "../slstatus.h" #include "../util.h" const char * kernel_release(const char *unused) { struct utsname udata; if (uname(&udata) < 0) { warn("uname:"); return NULL; } return bprintf("%s", udata.release); } slstatus-1.0/components/keyboard_indicators.c010064400017540001754000000023261445106606700212210ustar00drkhshdrkhsh/* See LICENSE file for copyright and license details. */ #include #include #include #include #include "../slstatus.h" #include "../util.h" /* * fmt consists of uppercase or lowercase 'c' for caps lock and/or 'n' for num * lock, each optionally followed by '?', in the order of indicators desired. * If followed by '?', the letter with case preserved is included in the output * if the corresponding indicator is on. Otherwise, the letter is always * included, lowercase when off and uppercase when on. */ const char * keyboard_indicators(const char *fmt) { Display *dpy; XKeyboardState state; size_t fmtlen, i, n; int togglecase, isset; char key; if (!(dpy = XOpenDisplay(NULL))) { warn("XOpenDisplay: Failed to open display"); return NULL; } XGetKeyboardControl(dpy, &state); XCloseDisplay(dpy); fmtlen = strnlen(fmt, 4); for (i = n = 0; i < fmtlen; i++) { key = tolower(fmt[i]); if (key != 'c' && key != 'n') continue; togglecase = (i + 1 >= fmtlen || fmt[i + 1] != '?'); isset = (state.led_mask & (1 << (key == 'n'))); if (togglecase) buf[n++] = isset ? toupper(key) : key; else if (isset) buf[n++] = fmt[i]; } buf[n] = 0; return buf; } slstatus-1.0/components/keymap.c010064400017540001754000000035131445106606700164670ustar00drkhshdrkhsh/* See LICENSE file for copyright and license details. */ #include #include #include #include #include #include "../slstatus.h" #include "../util.h" static int valid_layout_or_variant(char *sym) { size_t i; /* invalid symbols from xkb rules config */ static const char *invalid[] = { "evdev", "inet", "pc", "base" }; for (i = 0; i < LEN(invalid); i++) if (!strncmp(sym, invalid[i], strlen(invalid[i]))) return 0; return 1; } static char * get_layout(char *syms, int grp_num) { char *tok, *layout; int grp; layout = NULL; tok = strtok(syms, "+:"); for (grp = 0; tok && grp <= grp_num; tok = strtok(NULL, "+:")) { if (!valid_layout_or_variant(tok)) { continue; } else if (strlen(tok) == 1 && isdigit(tok[0])) { /* ignore :2, :3, :4 (additional layout groups) */ continue; } layout = tok; grp++; } return layout; } const char * keymap(const char *unused) { Display *dpy; XkbDescRec *desc; XkbStateRec state; char *symbols; const char *layout; layout = NULL; if (!(dpy = XOpenDisplay(NULL))) { warn("XOpenDisplay: Failed to open display"); return NULL; } if (!(desc = XkbAllocKeyboard())) { warn("XkbAllocKeyboard: Failed to allocate keyboard"); goto end; } if (XkbGetNames(dpy, XkbSymbolsNameMask, desc)) { warn("XkbGetNames: Failed to retrieve key symbols"); goto end; } if (XkbGetState(dpy, XkbUseCoreKbd, &state)) { warn("XkbGetState: Failed to retrieve keyboard state"); goto end; } if (!(symbols = XGetAtomName(dpy, desc->names->symbols))) { warn("XGetAtomName: Failed to get atom name"); goto end; } layout = bprintf("%s", get_layout(symbols, state.group)); XFree(symbols); end: XkbFreeKeyboard(desc, XkbSymbolsNameMask, 1); if (XCloseDisplay(dpy)) warn("XCloseDisplay: Failed to close display"); return layout; } slstatus-1.0/components/load_avg.c010064400017540001754000000005671445106606700167630ustar00drkhshdrkhsh/* See LICENSE file for copyright and license details. */ #include #include #include "../slstatus.h" #include "../util.h" const char * load_avg(const char *unused) { double avgs[3]; if (getloadavg(avgs, 3) < 0) { warn("getloadavg: Failed to obtain load average"); return NULL; } return bprintf("%.2f %.2f %.2f", avgs[0], avgs[1], avgs[2]); } slstatus-1.0/components/netspeeds.c010064400017540001754000000055121445106606700171740ustar00drkhshdrkhsh/* See LICENSE file for copyright and license details. */ #include #include #include "../slstatus.h" #include "../util.h" #if defined(__linux__) #include #define NET_RX_BYTES "/sys/class/net/%s/statistics/rx_bytes" #define NET_TX_BYTES "/sys/class/net/%s/statistics/tx_bytes" const char * netspeed_rx(const char *interface) { uintmax_t oldrxbytes; static uintmax_t rxbytes; extern const unsigned int interval; char path[PATH_MAX]; oldrxbytes = rxbytes; if (esnprintf(path, sizeof(path), NET_RX_BYTES, interface) < 0) return NULL; if (pscanf(path, "%ju", &rxbytes) != 1) return NULL; if (oldrxbytes == 0) return NULL; return fmt_human((rxbytes - oldrxbytes) * 1000 / interval, 1024); } const char * netspeed_tx(const char *interface) { uintmax_t oldtxbytes; static uintmax_t txbytes; extern const unsigned int interval; char path[PATH_MAX]; oldtxbytes = txbytes; if (esnprintf(path, sizeof(path), NET_TX_BYTES, interface) < 0) return NULL; if (pscanf(path, "%ju", &txbytes) != 1) return NULL; if (oldtxbytes == 0) return NULL; return fmt_human((txbytes - oldtxbytes) * 1000 / interval, 1024); } #elif defined(__OpenBSD__) | defined(__FreeBSD__) #include #include #include #include #include const char * netspeed_rx(const char *interface) { struct ifaddrs *ifal, *ifa; struct if_data *ifd; uintmax_t oldrxbytes; static uintmax_t rxbytes; extern const unsigned int interval; int if_ok = 0; oldrxbytes = rxbytes; if (getifaddrs(&ifal) < 0) { warn("getifaddrs failed"); return NULL; } rxbytes = 0; for (ifa = ifal; ifa; ifa = ifa->ifa_next) if (!strcmp(ifa->ifa_name, interface) && (ifd = (struct if_data *)ifa->ifa_data)) rxbytes += ifd->ifi_ibytes, if_ok = 1; freeifaddrs(ifal); if (!if_ok) { warn("reading 'if_data' failed"); return NULL; } if (oldrxbytes == 0) return NULL; return fmt_human((rxbytes - oldrxbytes) * 1000 / interval, 1024); } const char * netspeed_tx(const char *interface) { struct ifaddrs *ifal, *ifa; struct if_data *ifd; uintmax_t oldtxbytes; static uintmax_t txbytes; extern const unsigned int interval; int if_ok = 0; oldtxbytes = txbytes; if (getifaddrs(&ifal) < 0) { warn("getifaddrs failed"); return NULL; } txbytes = 0; for (ifa = ifal; ifa; ifa = ifa->ifa_next) if (!strcmp(ifa->ifa_name, interface) && (ifd = (struct if_data *)ifa->ifa_data)) txbytes += ifd->ifi_obytes, if_ok = 1; freeifaddrs(ifal); if (!if_ok) { warn("reading 'if_data' failed"); return NULL; } if (oldtxbytes == 0) return NULL; return fmt_human((txbytes - oldtxbytes) * 1000 / interval, 1024); } #endif slstatus-1.0/components/num_files.c010064400017540001754000000010261445106606700171570ustar00drkhshdrkhsh/* See LICENSE file for copyright and license details. */ #include #include #include #include "../slstatus.h" #include "../util.h" const char * num_files(const char *path) { struct dirent *dp; DIR *dir; int num; if (!(dir = opendir(path))) { warn("opendir '%s':", path); return NULL; } num = 0; while ((dp = readdir(dir))) { if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) continue; /* skip self and parent */ num++; } closedir(dir); return bprintf("%d", num); } slstatus-1.0/components/ram.c010064400017540001754000000104701445106606700157600ustar00drkhshdrkhsh/* See LICENSE file for copyright and license details. */ #include #include "../slstatus.h" #include "../util.h" #if defined(__linux__) #include const char * ram_free(const char *unused) { uintmax_t free; if (pscanf("/proc/meminfo", "MemTotal: %ju kB\n" "MemFree: %ju kB\n" "MemAvailable: %ju kB\n", &free, &free, &free) != 3) return NULL; return fmt_human(free * 1024, 1024); } const char * ram_perc(const char *unused) { uintmax_t total, free, buffers, cached; int percent; if (pscanf("/proc/meminfo", "MemTotal: %ju kB\n" "MemFree: %ju kB\n" "MemAvailable: %ju kB\n" "Buffers: %ju kB\n" "Cached: %ju kB\n", &total, &free, &buffers, &buffers, &cached) != 5) return NULL; if (total == 0) return NULL; percent = 100 * ((total - free) - (buffers + cached)) / total; return bprintf("%d", percent); } const char * ram_total(const char *unused) { uintmax_t total; if (pscanf("/proc/meminfo", "MemTotal: %ju kB\n", &total) != 1) return NULL; return fmt_human(total * 1024, 1024); } const char * ram_used(const char *unused) { uintmax_t total, free, buffers, cached, used; if (pscanf("/proc/meminfo", "MemTotal: %ju kB\n" "MemFree: %ju kB\n" "MemAvailable: %ju kB\n" "Buffers: %ju kB\n" "Cached: %ju kB\n", &total, &free, &buffers, &buffers, &cached) != 5) return NULL; used = (total - free - buffers - cached); return fmt_human(used * 1024, 1024); } #elif defined(__OpenBSD__) #include #include #include #include #define LOG1024 10 #define pagetok(size, pageshift) (size_t)(size << (pageshift - LOG1024)) inline int load_uvmexp(struct uvmexp *uvmexp) { int uvmexp_mib[] = {CTL_VM, VM_UVMEXP}; size_t size; size = sizeof(*uvmexp); if (sysctl(uvmexp_mib, 2, uvmexp, &size, NULL, 0) >= 0) return 1; return 0; } const char * ram_free(const char *unused) { struct uvmexp uvmexp; int free_pages; if (!load_uvmexp(&uvmexp)) return NULL; free_pages = uvmexp.npages - uvmexp.active; return fmt_human(pagetok(free_pages, uvmexp.pageshift) * 1024, 1024); } const char * ram_perc(const char *unused) { struct uvmexp uvmexp; int percent; if (!load_uvmexp(&uvmexp)) return NULL; percent = uvmexp.active * 100 / uvmexp.npages; return bprintf("%d", percent); } const char * ram_total(const char *unused) { struct uvmexp uvmexp; if (!load_uvmexp(&uvmexp)) return NULL; return fmt_human(pagetok(uvmexp.npages, uvmexp.pageshift) * 1024, 1024); } const char * ram_used(const char *unused) { struct uvmexp uvmexp; if (!load_uvmexp(&uvmexp)) return NULL; return fmt_human(pagetok(uvmexp.active, uvmexp.pageshift) * 1024, 1024); } #elif defined(__FreeBSD__) #include #include #include #include const char * ram_free(const char *unused) { struct vmtotal vm_stats; int mib[] = {CTL_VM, VM_TOTAL}; size_t len; len = sizeof(struct vmtotal); if (sysctl(mib, 2, &vm_stats, &len, NULL, 0) < 0 || !len) return NULL; return fmt_human(vm_stats.t_free * getpagesize(), 1024); } const char * ram_total(const char *unused) { unsigned int npages; size_t len; len = sizeof(npages); if (sysctlbyname("vm.stats.vm.v_page_count", &npages, &len, NULL, 0) < 0 || !len) return NULL; return fmt_human(npages * getpagesize(), 1024); } const char * ram_perc(const char *unused) { unsigned int npages; unsigned int active; size_t len; len = sizeof(npages); if (sysctlbyname("vm.stats.vm.v_page_count", &npages, &len, NULL, 0) < 0 || !len) return NULL; if (sysctlbyname("vm.stats.vm.v_active_count", &active, &len, NULL, 0) < 0 || !len) return NULL; return bprintf("%d", active * 100 / npages); } const char * ram_used(const char *unused) { unsigned int active; size_t len; len = sizeof(active); if (sysctlbyname("vm.stats.vm.v_active_count", &active, &len, NULL, 0) < 0 || !len) return NULL; return fmt_human(active * getpagesize(), 1024); } #endif slstatus-1.0/components/run_command.c010064400017540001754000000007651445106606700175110ustar00drkhshdrkhsh/* See LICENSE file for copyright and license details. */ #include #include #include "../slstatus.h" #include "../util.h" const char * run_command(const char *cmd) { char *p; FILE *fp; if (!(fp = popen(cmd, "r"))) { warn("popen '%s':", cmd); return NULL; } p = fgets(buf, sizeof(buf) - 1, fp); if (pclose(fp) < 0) { warn("pclose '%s':", cmd); return NULL; } if (!p) return NULL; if ((p = strrchr(buf, '\n'))) p[0] = '\0'; return buf[0] ? buf : NULL; } slstatus-1.0/components/swap.c010064400017540001754000000116641445106606700161610ustar00drkhshdrkhsh/* See LICENSE file for copyright and license details. */ #include #include #include #include #include "../slstatus.h" #include "../util.h" #if defined(__linux__) static int get_swap_info(long *s_total, long *s_free, long *s_cached) { FILE *fp; struct { const char *name; const size_t len; long *var; } ent[] = { { "SwapTotal", sizeof("SwapTotal") - 1, s_total }, { "SwapFree", sizeof("SwapFree") - 1, s_free }, { "SwapCached", sizeof("SwapCached") - 1, s_cached }, }; size_t line_len = 0, i, left; char *line = NULL; /* get number of fields we want to extract */ for (i = 0, left = 0; i < LEN(ent); i++) if (ent[i].var) left++; if (!(fp = fopen("/proc/meminfo", "r"))) { warn("fopen '/proc/meminfo':"); return 1; } /* read file line by line and extract field information */ while (left > 0 && getline(&line, &line_len, fp) >= 0) { for (i = 0; i < LEN(ent); i++) { if (ent[i].var && !strncmp(line, ent[i].name, ent[i].len)) { sscanf(line + ent[i].len + 1, "%ld kB\n", ent[i].var); left--; break; } } } free(line); if (ferror(fp)) { warn("getline '/proc/meminfo':"); return 1; } fclose(fp); return 0; } const char * swap_free(const char *unused) { long free; if (get_swap_info(NULL, &free, NULL)) return NULL; return fmt_human(free * 1024, 1024); } const char * swap_perc(const char *unused) { long total, free, cached; if (get_swap_info(&total, &free, &cached) || total == 0) return NULL; return bprintf("%d", 100 * (total - free - cached) / total); } const char * swap_total(const char *unused) { long total; if (get_swap_info(&total, NULL, NULL)) return NULL; return fmt_human(total * 1024, 1024); } const char * swap_used(const char *unused) { long total, free, cached; if (get_swap_info(&total, &free, &cached)) return NULL; return fmt_human((total - free - cached) * 1024, 1024); } #elif defined(__OpenBSD__) #include #include #include #include static int getstats(int *total, int *used) { struct swapent *sep, *fsep; int rnswap, nswap, i; if ((nswap = swapctl(SWAP_NSWAP, 0, 0)) < 1) { warn("swaptctl 'SWAP_NSWAP':"); return 1; } if (!(fsep = sep = calloc(nswap, sizeof(*sep)))) { warn("calloc 'nswap':"); return 1; } if ((rnswap = swapctl(SWAP_STATS, (void *)sep, nswap)) < 0) { warn("swapctl 'SWAP_STATA':"); return 1; } if (nswap != rnswap) { warn("getstats: SWAP_STATS != SWAP_NSWAP"); return 1; } *total = 0; *used = 0; for (i = 0; i < rnswap; i++) { *total += sep->se_nblks >> 1; *used += sep->se_inuse >> 1; } free(fsep); return 0; } const char * swap_free(const char *unused) { int total, used; if (getstats(&total, &used)) return NULL; return fmt_human((total - used) * 1024, 1024); } const char * swap_perc(const char *unused) { int total, used; if (getstats(&total, &used)) return NULL; if (total == 0) return NULL; return bprintf("%d", 100 * used / total); } const char * swap_total(const char *unused) { int total, used; if (getstats(&total, &used)) return NULL; return fmt_human(total * 1024, 1024); } const char * swap_used(const char *unused) { int total, used; if (getstats(&total, &used)) return NULL; return fmt_human(used * 1024, 1024); } #elif defined(__FreeBSD__) #include #include #include #include #include static int getswapinfo(struct kvm_swap *swap_info, size_t size) { kvm_t *kd; kd = kvm_openfiles(NULL, "/dev/null", NULL, 0, NULL); if (kd == NULL) { warn("kvm_openfiles '/dev/null':"); return 0; } if (kvm_getswapinfo(kd, swap_info, size, 0 /* Unused flags */) < 0) { warn("kvm_getswapinfo:"); kvm_close(kd); return 0; } kvm_close(kd); return 1; } const char * swap_free(const char *unused) { struct kvm_swap swap_info[1]; long used, total; if (!getswapinfo(swap_info, 1)) return NULL; total = swap_info[0].ksw_total; used = swap_info[0].ksw_used; return fmt_human((total - used) * getpagesize(), 1024); } const char * swap_perc(const char *unused) { struct kvm_swap swap_info[1]; long used, total; if (!getswapinfo(swap_info, 1)) return NULL; total = swap_info[0].ksw_total; used = swap_info[0].ksw_used; return bprintf("%d", used * 100 / total); } const char * swap_total(const char *unused) { struct kvm_swap swap_info[1]; long total; if (!getswapinfo(swap_info, 1)) return NULL; total = swap_info[0].ksw_total; return fmt_human(total * getpagesize(), 1024); } const char * swap_used(const char *unused) { struct kvm_swap swap_info[1]; long used; if (!getswapinfo(swap_info, 1)) return NULL; used = swap_info[0].ksw_used; return fmt_human(used * getpagesize(), 1024); } #endif slstatus-1.0/components/temperature.c010064400017540001754000000026341445106606700175410ustar00drkhshdrkhsh/* See LICENSE file for copyright and license details. */ #include #include "../slstatus.h" #include "../util.h" #if defined(__linux__) #include const char * temp(const char *file) { uintmax_t temp; if (pscanf(file, "%ju", &temp) != 1) return NULL; return bprintf("%ju", temp / 1000); } #elif defined(__OpenBSD__) #include #include /* before for struct timeval */ #include #include const char * temp(const char *unused) { int mib[5]; size_t size; struct sensor temp; mib[0] = CTL_HW; mib[1] = HW_SENSORS; mib[2] = 0; /* cpu0 */ mib[3] = SENSOR_TEMP; mib[4] = 0; /* temp0 */ size = sizeof(temp); if (sysctl(mib, 5, &temp, &size, NULL, 0) < 0) { warn("sysctl 'SENSOR_TEMP':"); return NULL; } /* kelvin to celsius */ return bprintf("%d", (int)((float)(temp.value-273150000) / 1E6)); } #elif defined(__FreeBSD__) #include #include #include #define ACPI_TEMP "hw.acpi.thermal.%s.temperature" const char * temp(const char *zone) { char buf[256]; int temp; size_t len; len = sizeof(temp); snprintf(buf, sizeof(buf), ACPI_TEMP, zone); if (sysctlbyname(buf, &temp, &len, NULL, 0) < 0 || !len) return NULL; /* kelvin to decimal celcius */ return bprintf("%d.%d", (temp - 2731) / 10, abs((temp - 2731) % 10)); } #endif slstatus-1.0/components/uptime.c010064400017540001754000000012761445106606700165100ustar00drkhshdrkhsh/* See LICENSE file for copyright and license details. */ #include #include #include #include "../slstatus.h" #include "../util.h" #if defined(CLOCK_BOOTTIME) #define UPTIME_FLAG CLOCK_BOOTTIME #elif defined(CLOCK_UPTIME) #define UPTIME_FLAG CLOCK_UPTIME #else #define UPTIME_FLAG CLOCK_MONOTONIC #endif const char * uptime(const char *unused) { char warn_buf[256]; uintmax_t h, m; struct timespec uptime; if (clock_gettime(UPTIME_FLAG, &uptime) < 0) { snprintf(warn_buf, sizeof(warn_buf), "clock_gettime %d", UPTIME_FLAG); warn(warn_buf); return NULL; } h = uptime.tv_sec / 3600; m = uptime.tv_sec % 3600 / 60; return bprintf("%juh %jum", h, m); } slstatus-1.0/components/user.c010064400017540001754000000010231445106606700161510ustar00drkhshdrkhsh/* See LICENSE file for copyright and license details. */ #include #include #include #include #include "../slstatus.h" #include "../util.h" const char * gid(const char *unused) { return bprintf("%d", getgid()); } const char * username(const char *unused) { struct passwd *pw; if (!(pw = getpwuid(geteuid()))) { warn("getpwuid '%d':", geteuid()); return NULL; } return bprintf("%s", pw->pw_name); } const char * uid(const char *unused) { return bprintf("%d", geteuid()); } slstatus-1.0/components/volume.c010064400017540001754000000103371445106606700165120ustar00drkhshdrkhsh/* See LICENSE file for copyright and license details. */ #include #include #include #include #include #include "../slstatus.h" #include "../util.h" #if defined(__OpenBSD__) | defined(__FreeBSD__) #include #include #include #include struct control { LIST_ENTRY(control) next; unsigned int addr; #define CTRL_NONE 0 #define CTRL_LEVEL 1 #define CTRL_MUTE 2 unsigned int type; unsigned int maxval; unsigned int val; }; static LIST_HEAD(, control) controls = LIST_HEAD_INITIALIZER(controls); static struct pollfd *pfds; static struct sioctl_hdl *hdl; static int initialized; /* * Call-back to obtain the description of all audio controls. */ static void ondesc(void *unused, struct sioctl_desc *desc, int val) { struct control *c, *ctmp; unsigned int type = CTRL_NONE; if (desc == NULL) return; /* Delete existing audio control with the same address. */ LIST_FOREACH_SAFE(c, &controls, next, ctmp) { if (desc->addr == c->addr) { LIST_REMOVE(c, next); free(c); break; } } /* Only match output.level and output.mute audio controls. */ if (desc->group[0] != 0 || strcmp(desc->node0.name, "output") != 0) return; if (desc->type == SIOCTL_NUM && strcmp(desc->func, "level") == 0) type = CTRL_LEVEL; else if (desc->type == SIOCTL_SW && strcmp(desc->func, "mute") == 0) type = CTRL_MUTE; else return; c = malloc(sizeof(struct control)); if (c == NULL) { warn("sndio: failed to allocate audio control\n"); return; } c->addr = desc->addr; c->type = type; c->maxval = desc->maxval; c->val = val; LIST_INSERT_HEAD(&controls, c, next); } /* * Call-back invoked whenever an audio control changes. */ static void onval(void *unused, unsigned int addr, unsigned int val) { struct control *c; LIST_FOREACH(c, &controls, next) { if (c->addr == addr) break; } c->val = val; } static void cleanup(void) { struct control *c; if (hdl) { sioctl_close(hdl); hdl = NULL; } free(pfds); pfds = NULL; while (!LIST_EMPTY(&controls)) { c = LIST_FIRST(&controls); LIST_REMOVE(c, next); free(c); } } static int init(void) { hdl = sioctl_open(SIO_DEVANY, SIOCTL_READ, 0); if (hdl == NULL) { warn("sndio: cannot open device"); goto failed; } if (!sioctl_ondesc(hdl, ondesc, NULL)) { warn("sndio: cannot set control description call-back"); goto failed; } if (!sioctl_onval(hdl, onval, NULL)) { warn("sndio: cannot set control values call-back"); goto failed; } pfds = calloc(sioctl_nfds(hdl), sizeof(struct pollfd)); if (pfds == NULL) { warn("sndio: cannot allocate pollfd structures"); goto failed; } return 1; failed: cleanup(); return 0; } const char * vol_perc(const char *unused) { struct control *c; int n, v, value; if (!initialized) initialized = init(); if (hdl == NULL) return NULL; n = sioctl_pollfd(hdl, pfds, POLLIN); if (n > 0) { n = poll(pfds, n, 0); if (n > 0) { if (sioctl_revents(hdl, pfds) & POLLHUP) { warn("sndio: disconnected"); cleanup(); initialized = 0; return NULL; } } } value = 100; LIST_FOREACH(c, &controls, next) { if (c->type == CTRL_MUTE && c->val == 1) value = 0; else if (c->type == CTRL_LEVEL) { v = (c->val * 100 + c->maxval / 2) / c->maxval; /* For multiple channels return the minimum. */ if (v < value) value = v; } } return bprintf("%d", value); } #else #include const char * vol_perc(const char *card) { size_t i; int v, afd, devmask; char *vnames[] = SOUND_DEVICE_NAMES; if ((afd = open(card, O_RDONLY | O_NONBLOCK)) < 0) { warn("open '%s':", card); return NULL; } if (ioctl(afd, (int)SOUND_MIXER_READ_DEVMASK, &devmask) < 0) { warn("ioctl 'SOUND_MIXER_READ_DEVMASK':"); close(afd); return NULL; } for (i = 0; i < LEN(vnames); i++) { if (devmask & (1 << i) && !strcmp("vol", vnames[i])) { if (ioctl(afd, MIXER_READ(i), &v) < 0) { warn("ioctl 'MIXER_READ(%ld)':", i); close(afd); return NULL; } } } close(afd); return bprintf("%d", v & 0xff); } #endif slstatus-1.0/components/wifi.c010064400017540001754000000134771445106606700161510ustar00drkhshdrkhsh/* See LICENSE file for copyright and license details. */ #include #include #include #include #include #include #include "../slstatus.h" #include "../util.h" #define RSSI_TO_PERC(rssi) \ rssi >= -50 ? 100 : \ (rssi <= -100 ? 0 : \ (2 * (rssi + 100))) #if defined(__linux__) #include #include #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 #include #include #include /* before for NBBY */ #include #include #include static int load_ieee80211_nodereq(const char *interface, struct ieee80211_nodereq *nr) { struct ieee80211_bssid bssid; int sockfd; uint8_t zero_bssid[IEEE80211_ADDR_LEN]; memset(&bssid, 0, sizeof(bssid)); memset(nr, 0, sizeof(struct ieee80211_nodereq)); if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { warn("socket 'AF_INET':"); return 0; } strlcpy(bssid.i_name, interface, sizeof(bssid.i_name)); if ((ioctl(sockfd, SIOCG80211BSSID, &bssid)) < 0) { warn("ioctl 'SIOCG80211BSSID':"); close(sockfd); return 0; } memset(&zero_bssid, 0, sizeof(zero_bssid)); if (memcmp(bssid.i_bssid, zero_bssid, IEEE80211_ADDR_LEN) == 0) { close(sockfd); return 0; } strlcpy(nr->nr_ifname, interface, sizeof(nr->nr_ifname)); memcpy(&nr->nr_macaddr, bssid.i_bssid, sizeof(nr->nr_macaddr)); if ((ioctl(sockfd, SIOCG80211NODE, nr)) < 0 && nr->nr_rssi) { warn("ioctl 'SIOCG80211NODE':"); close(sockfd); return 0; } return close(sockfd), 1; } const char * wifi_perc(const char *interface) { struct ieee80211_nodereq nr; int q; if (load_ieee80211_nodereq(interface, &nr)) { if (nr.nr_max_rssi) q = IEEE80211_NODEREQ_RSSI(&nr); else q = RSSI_TO_PERC(nr.nr_rssi); return bprintf("%d", q); } return NULL; } const char * wifi_essid(const char *interface) { struct ieee80211_nodereq nr; if (load_ieee80211_nodereq(interface, &nr)) return bprintf("%s", nr.nr_nwid); return NULL; } #elif defined(__FreeBSD__) #include #include int load_ieee80211req(int sock, const char *interface, void *data, int type, size_t *len) { char warn_buf[256]; struct ieee80211req ireq; memset(&ireq, 0, sizeof(ireq)); ireq.i_type = type; ireq.i_data = (caddr_t) data; ireq.i_len = *len; strlcpy(ireq.i_name, interface, sizeof(ireq.i_name)); if (ioctl(sock, SIOCG80211, &ireq) < 0) { snprintf(warn_buf, sizeof(warn_buf), "ioctl: 'SIOCG80211': %d", type); warn(warn_buf); return 0; } *len = ireq.i_len; return 1; } const char * wifi_perc(const char *interface) { union { struct ieee80211req_sta_req sta; uint8_t buf[24 * 1024]; } info; uint8_t bssid[IEEE80211_ADDR_LEN]; int rssi_dbm; int sockfd; size_t len; const char *fmt; if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { warn("socket 'AF_INET':"); return NULL; } /* Retreive MAC address of interface */ len = IEEE80211_ADDR_LEN; fmt = NULL; if (load_ieee80211req(sockfd, interface, &bssid, IEEE80211_IOC_BSSID, &len)) { /* Retrieve info on station with above BSSID */ memset(&info, 0, sizeof(info)); memcpy(info.sta.is_u.macaddr, bssid, sizeof(bssid)); len = sizeof(info); if (load_ieee80211req(sockfd, interface, &info, IEEE80211_IOC_STA_INFO, &len)) { rssi_dbm = info.sta.info[0].isi_noise + info.sta.info[0].isi_rssi / 2; fmt = bprintf("%d", RSSI_TO_PERC(rssi_dbm)); } } close(sockfd); return fmt; } const char * wifi_essid(const char *interface) { char ssid[IEEE80211_NWID_LEN + 1]; size_t len; int sockfd; const char *fmt; if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { warn("socket 'AF_INET':"); return NULL; } fmt = NULL; len = sizeof(ssid); memset(&ssid, 0, len); if (load_ieee80211req(sockfd, interface, &ssid, IEEE80211_IOC_SSID, &len)) { if (len < sizeof(ssid)) len += 1; else len = sizeof(ssid); ssid[len - 1] = '\0'; fmt = bprintf("%s", ssid); } close(sockfd); return fmt; } #endif slstatus-1.0/LICENSE010064400017540001754000000041661445106606700136620ustar00drkhshdrkhshISC License Copyright 2016-2022 Aaron Marcher Copyright 2016 Roy Freytag Copyright 2016 Vincent Loupmon Copyright 2016 Daniel Walter Copyright 2016-2018 Ali H. Fardan Copyright 2016 Jody Leonard Copyright 2016-2018 Quentin Rameau Copyright 2016 Mike Coddington Copyright 2016-2018 Ivan J. Copyright 2017 Tobias Stoeckmann Copyright 2017-2018 Laslo Hunhold Copyright 2018 Darron Anderson Copyright 2018 Josuah Demangeon Copyright 2018 Tobias Tschinkowitz Copyright 2018 David Demelier Copyright 2018-2012 Michael Buch Copyright 2018 Ian Remmler Copyright 2016-2019 Joerg Jung Copyright 2019 Ryan Kes Copyright 2019 Cem Keylan Copyright 2019 Dimitris Papastamos Copyright 2019-2022 Ingo Feinerer Copyright 2020 Alexandre Ratchov Copyright 2020 Mart Lubbers Copyright 2020 Daniel Moch Copyright 2022 Nickolas Raymond Kaczynski Copyright 2022 Patrick Iacob Copyright 2021-2022 Steven Ward 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. slstatus-1.0/Makefile010064400017540001754000000033551445106606700143140ustar00drkhshdrkhsh# 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" slstatus-1.0/README010064400017540001754000000033201445106606700135240ustar00drkhshdrkhshslstatus - 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. slstatus-1.0/config.mk010064400017540001754000000007101445106606700144420ustar00drkhshdrkhsh# 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 slstatus-1.0/config.def.h010064400017540001754000000075121445106606700150260ustar00drkhshdrkhsh/* See LICENSE file for copyright and license details. */ /* interval between updates (in ms) */ const unsigned int interval = 1000; /* text to show if no value can be retrieved */ static const char unknown_str[] = "n/a"; /* maximum output string length */ #define MAXLEN 2048 /* * function description argument (example) * * battery_perc battery percentage battery name (BAT0) * NULL on OpenBSD/FreeBSD * battery_remaining battery remaining HH:MM battery name (BAT0) * NULL on OpenBSD/FreeBSD * battery_state battery charging state battery name (BAT0) * NULL on OpenBSD/FreeBSD * cat read arbitrary file path * cpu_freq cpu frequency in MHz NULL * cpu_perc cpu usage in percent NULL * datetime date and time format string (%F %T) * disk_free free disk space in GB mountpoint path (/) * disk_perc disk usage in percent mountpoint path (/) * disk_total total disk space in GB mountpoint path (/) * disk_used used disk space in GB mountpoint path (/) * entropy available entropy NULL * gid GID of current user NULL * hostname hostname NULL * ipv4 IPv4 address interface name (eth0) * ipv6 IPv6 address interface name (eth0) * kernel_release `uname -r` NULL * keyboard_indicators caps/num lock indicators format string (c?n?) * see keyboard_indicators.c * keymap layout (variant) of current NULL * keymap * load_avg load average NULL * netspeed_rx receive network speed interface name (wlan0) * netspeed_tx transfer network speed interface name (wlan0) * num_files number of files in a directory path * (/home/foo/Inbox/cur) * ram_free free memory in GB NULL * ram_perc memory usage in percent NULL * ram_total total memory size in GB NULL * ram_used used memory in GB NULL * run_command custom shell command command (echo foo) * swap_free free swap in GB NULL * swap_perc swap usage in percent NULL * swap_total total swap size in GB NULL * swap_used used swap in GB NULL * temp temperature in degree celsius sensor file * (/sys/class/thermal/...) * NULL on OpenBSD * thermal zone on FreeBSD * (tz0, tz1, etc.) * uid UID of current user NULL * uptime system uptime NULL * username username of current user NULL * vol_perc OSS/ALSA volume in percent mixer file (/dev/mixer) * NULL on OpenBSD/FreeBSD * wifi_essid WiFi ESSID interface name (wlan0) * wifi_perc WiFi signal in percent interface name (wlan0) */ static const struct arg args[] = { /* function format argument */ { datetime, "%s", "%F %T" }, }; slstatus-1.0/arg.h010064400017540001754000000032241445106606700135710ustar00drkhshdrkhsh/* 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 slstatus-1.0/slstatus.h010064400017540001754000000037521445106606700147100ustar00drkhshdrkhsh/* 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); slstatus-1.0/slstatus.c010064400017540001754000000051121445106606700146730ustar00drkhshdrkhsh/* See LICENSE file for copyright and license details. */ #include #include #include #include #include #include #include #include "arg.h" #include "slstatus.h" #include "util.h" struct arg { const char *(*func)(const char *); const char *fmt; const char *args; }; char buf[1024]; static volatile sig_atomic_t done; static Display *dpy; #include "config.h" static void terminate(const int signo) { if (signo != SIGUSR1) done = 1; } static void difftimespec(struct timespec *res, struct timespec *a, struct timespec *b) { res->tv_sec = a->tv_sec - b->tv_sec - (a->tv_nsec < b->tv_nsec); res->tv_nsec = a->tv_nsec - b->tv_nsec + (a->tv_nsec < b->tv_nsec) * 1E9; } static void usage(void) { die("usage: %s [-v] [-s] [-1]", argv0); } int main(int argc, char *argv[]) { struct sigaction act; struct timespec start, current, diff, intspec, wait; size_t i, len; int sflag, ret; char status[MAXLEN]; const char *res; sflag = 0; ARGBEGIN { case 'v': die("slstatus-"VERSION); case '1': done = 1; /* FALLTHROUGH */ case 's': sflag = 1; break; default: usage(); } ARGEND if (argc) usage(); memset(&act, 0, sizeof(act)); act.sa_handler = terminate; sigaction(SIGINT, &act, NULL); sigaction(SIGTERM, &act, NULL); act.sa_flags |= SA_RESTART; sigaction(SIGUSR1, &act, NULL); if (!sflag && !(dpy = XOpenDisplay(NULL))) die("XOpenDisplay: Failed to open display"); do { if (clock_gettime(CLOCK_MONOTONIC, &start) < 0) die("clock_gettime:"); status[0] = '\0'; for (i = len = 0; i < LEN(args); i++) { if (!(res = args[i].func(args[i].args))) res = unknown_str; if ((ret = esnprintf(status + len, sizeof(status) - len, args[i].fmt, res)) < 0) break; len += ret; } if (sflag) { puts(status); fflush(stdout); if (ferror(stdout)) die("puts:"); } else { if (XStoreName(dpy, DefaultRootWindow(dpy), status) < 0) die("XStoreName: Allocation failed"); XFlush(dpy); } if (!done) { if (clock_gettime(CLOCK_MONOTONIC, ¤t) < 0) die("clock_gettime:"); difftimespec(&diff, ¤t, &start); intspec.tv_sec = interval / 1000; intspec.tv_nsec = (interval % 1000) * 1E6; difftimespec(&wait, &intspec, &diff); if (wait.tv_sec >= 0 && nanosleep(&wait, NULL) < 0 && errno != EINTR) die("nanosleep:"); } } while (!done); if (!sflag) { XStoreName(dpy, DefaultRootWindow(dpy), NULL); if (XCloseDisplay(dpy) < 0) die("XCloseDisplay: Failed to close display"); } return 0; } slstatus-1.0/util.c010064400017540001754000000042761445106606700140000ustar00drkhshdrkhsh/* See LICENSE file for copyright and license details. */ #include #include #include #include #include #include #include "util.h" char *argv0; static void verr(const char *fmt, va_list ap) { vfprintf(stderr, fmt, ap); if (fmt[0] && fmt[strlen(fmt) - 1] == ':') { fputc(' ', stderr); perror(NULL); } else { fputc('\n', stderr); } } void warn(const char *fmt, ...) { va_list ap; va_start(ap, fmt); verr(fmt, ap); va_end(ap); } void die(const char *fmt, ...) { va_list ap; va_start(ap, fmt); verr(fmt, ap); va_end(ap); exit(1); } static int evsnprintf(char *str, size_t size, const char *fmt, va_list ap) { int ret; ret = vsnprintf(str, size, fmt, ap); if (ret < 0) { warn("vsnprintf:"); return -1; } else if ((size_t)ret >= size) { warn("vsnprintf: Output truncated"); return -1; } return ret; } int esnprintf(char *str, size_t size, const char *fmt, ...) { va_list ap; int ret; va_start(ap, fmt); ret = evsnprintf(str, size, fmt, ap); va_end(ap); return ret; } const char * bprintf(const char *fmt, ...) { va_list ap; int ret; va_start(ap, fmt); ret = evsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); return (ret < 0) ? NULL : buf; } const char * fmt_human(uintmax_t num, int base) { double scaled; size_t i, prefixlen; const char **prefix; const char *prefix_1000[] = { "", "k", "M", "G", "T", "P", "E", "Z", "Y" }; const char *prefix_1024[] = { "", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi", "Yi" }; switch (base) { case 1000: prefix = prefix_1000; prefixlen = LEN(prefix_1000); break; case 1024: prefix = prefix_1024; prefixlen = LEN(prefix_1024); break; default: warn("fmt_human: Invalid base"); return NULL; } scaled = num; for (i = 0; i < prefixlen && scaled >= base; i++) scaled /= base; return bprintf("%.1f %s", scaled, prefix[i]); } int pscanf(const char *path, const char *fmt, ...) { FILE *fp; va_list ap; int n; if (!(fp = fopen(path, "r"))) { warn("fopen '%s':", path); return -1; } va_start(ap, fmt); n = vfscanf(fp, fmt, ap); va_end(ap); fclose(fp); return (n == EOF) ? -1 : n; } slstatus-1.0/util.h010064400017540001754000000006611445106606700137770ustar00drkhshdrkhsh/* See LICENSE file for copyright and license details. */ #include extern char buf[1024]; #define LEN(x) (sizeof(x) / sizeof((x)[0])) extern char *argv0; void warn(const char *, ...); void die(const char *, ...); int esnprintf(char *str, size_t size, const char *fmt, ...); const char *bprintf(const char *fmt, ...); const char *fmt_human(uintmax_t num, int base); int pscanf(const char *path, const char *fmt, ...); slstatus-1.0/slstatus.1010064400017540001754000000017051445106606700146150ustar00drkhshdrkhsh.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