sta
minimal & simple status monitoring app.
git clone https://git.pi66.xyz/sta
About | Files | Commits | Refs | License
add slstatus patch
Author: pi66
Date: 2025-10-10 23:51
commit: 0ec8219d
Stat
| A | patcher.py | 32 | +32 | -0 |
| A | patches/slstatus/components/battery.c | 257 | +257 | -0 |
| A | patches/slstatus/components/cpu.c | 162 | +162 | -0 |
| A | patches/slstatus/components/datetime.c | 20 | +20 | -0 |
| A | patches/slstatus/components/disk.c | 62 | +62 | -0 |
| A | patches/slstatus/components/ram.c | 220 | +220 | -0 |
| A | patches/slstatus/components/run_command.c | 29 | +29 | -0 |
| A | patches/slstatus/components/temperature.c | 75 | +75 | -0 |
| A | patches/slstatus/components/util.c | 146 | +146 | -0 |
| A | patches/slstatus/components/wifi.c | 275 | +275 | -0 |
| A | patches/slstatus/slstatus.patch | 415 | +415 | -0 |
Diff
diff --git a/patcher.py b/patcher.py
new file mode 100644
index 0000000..3b204d7
--- /dev/null
+++ b/patcher.py
@@ -0,0 +1,32 @@
+from os import listdir,system
+
+patches = listdir("./patches")
+
+
+for index,patch in enumerate(patches):
+ print(f"[{index+1}]- {patch}")
+
+try:
+ patch_id = int(input("\nchooce patche id: "))
+except ValueError:
+ print("Not a valid number")
+ exit(1)
+
...
Show all
Show less
diff --git a/patcher.py b/patcher.py
new file mode 100644
index 0000000..3b204d7
--- /dev/null
+++ b/patcher.py
@@ -0,0 +1,32 @@
+from os import listdir,system
+
+patches = listdir("./patches")
+
+
+for index,patch in enumerate(patches):
+ print(f"[{index+1}]- {patch}")
+
+try:
+ patch_id = int(input("\nchooce patche id: "))
+except ValueError:
+ print("Not a valid number")
+ exit(1)
+
...
diff --git a/patcher.py b/patcher.py
new file mode 100644
index 0000000..3b204d7
--- /dev/null
+++ b/patcher.py
@@ -0,0 +1,32 @@
+from os import listdir,system
+
+patches = listdir("./patches")
+
+
+for index,patch in enumerate(patches):
+ print(f"[{index+1}]- {patch}")
+
+try:
+ patch_id = int(input("\nchooce patche id: "))
+except ValueError:
+ print("Not a valid number")
+ exit(1)
+
+
+if patch_id <1 or patch_id > len(patches):
+ print("Out of range!!")
+ exit(1)
+
+
+
+if patches[patch_id-1] == "slstatus":
+ print("")
+ system("cp -r patches/slstatus/components .")
+ system("patch < patches/slstatus/slstatus.patch")
+ print("")
+ print("don't forget to run:\n\t sudo make install")
+else:
+ print("Out of range!!")
+ exit(1)
+
+
diff --git a/patches/slstatus/components/battery.c b/patches/slstatus/components/battery.c
new file mode 100644
index 0000000..734bc1d
--- /dev/null
+++ b/patches/slstatus/components/battery.c
@@ -0,0 +1,257 @@
+/* See LICENSE file for copyright and license details. */
+#include <stdio.h>
+#include <string.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)
+ {
+ static _Thread_local char buf[1024];
+ if (esnprintf(buf, path, length, f1, bat) > 0 &&
+ access(path, R_OK) == 0)
+ return f1;
+
+ if (esnprintf(buf, path, length, f2, bat) > 0 &&
+ access(path, R_OK) == 0)
+ return f2;
+
+ return NULL;
+ }
+
+ const char *
+ battery_perc(const char *bat)
+ {
+ static _Thread_local char buf[1024];
+ int cap_perc;
+ char path[PATH_MAX];
+
+ if (esnprintf(buf, path, sizeof(path), POWER_SUPPLY_CAPACITY, bat) < 0)
+ return NULL;
+ if (pscanf(buf, path, "%d", &cap_perc) != 1)
+ return NULL;
+
+ return bprintf(buf, "%d", cap_perc);
+ }
+
+ const char *
+ battery_state(const char *bat)
+ {
+ static _Thread_local char buf[1024];
+ static struct {
+ char *state;
+ char *symbol;
+ } map[] = {
+ { "Charging", "" },
+ { "Discharging", "" },
+ { "Full", "" },
+ { "Not charging", ""},
+ };
+ size_t i;
+ char path[PATH_MAX], state[12];
+
+ if (esnprintf(buf, path, sizeof(path), POWER_SUPPLY_STATUS, bat) < 0)
+ return NULL;
+ if (pscanf(buf, 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)
+ {
+ static _Thread_local char buf[1024];
+ uintmax_t charge_now, current_now, m, h;
+ double timeleft;
+ char path[PATH_MAX], state[12];
+
+ if (esnprintf(buf, path, sizeof(path), POWER_SUPPLY_STATUS, bat) < 0)
+ return NULL;
+ if (pscanf(buf, path, "%12[a-zA-Z ]", state) != 1)
+ return NULL;
+
+ if (!pick(bat, POWER_SUPPLY_CHARGE, POWER_SUPPLY_ENERGY, path,
+ sizeof(path)) ||
+ pscanf(buf, path, "%ju", &charge_now) < 0)
+ return NULL;
+
+ if (!strcmp(state, "Discharging")) {
+ if (!pick(bat, POWER_SUPPLY_CURRENT, POWER_SUPPLY_POWER, path,
+ sizeof(path)) ||
+ pscanf(buf, 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(buf, "%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)
+ {
+ static _Thread_local char buf[1024];
+ 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)
+ {
+ static _Thread_local char buf[1024];
+ struct apm_power_info apm_info;
+
+ if (load_apm_power_info(&apm_info))
+ return bprintf(buf, "%d", apm_info.battery_life);
+
+ return NULL;
+ }
+
+ const char *
+ battery_state(const char *unused)
+ {
+ static _Thread_local char buf[1024];
+ 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)
+ {
+ static _Thread_local char buf[1024];
+ 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(buf, "%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)
+ {
+ static _Thread_local char buf[1024];
+ 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(buf, "%d", cap_perc);
+ }
+
+ const char *
+ battery_state(const char *unused)
+ {
+ static _Thread_local char buf[1024];
+ 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)
+ {
+ static _Thread_local char buf[1024];
+ int rem;
+ size_t len;
+
+ len = sizeof(rem);
+ if (sysctlbyname(BATTERY_TIME, &rem, &len, NULL, 0) < 0 || !len
+ || rem < 0)
+ return NULL;
+
+ return bprintf(buf, "%uh %02um", rem / 60, rem % 60);
+ }
+#endif
diff --git a/patches/slstatus/components/cpu.c b/patches/slstatus/components/cpu.c
new file mode 100644
index 0000000..f95759a
--- /dev/null
+++ b/patches/slstatus/components/cpu.c
@@ -0,0 +1,162 @@
+/* See LICENSE file for copyright and license details. */
+#include <stdint.h>
+#include <stdio.h>
+#include <string.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)
+ {
+ static _Thread_local char buf[1024];
+ uintmax_t freq;
+
+ /* in kHz */
+ if (pscanf(buf, CPU_FREQ, "%ju", &freq) != 1)
+ return NULL;
+
+ return fmt_human(buf, freq * 1000, 1000);
+ }
+
+ const char *
+ cpu_perc(const char *unused)
+ {
+ static _Thread_local char buf[1024];
+ 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(buf, "/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(buf, "%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)
+ {
+ static _Thread_local char buf[1024];
+ 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(buf, freq * 1E6, 1000);
+ }
+
+ const char *
+ cpu_perc(const char *unused)
+ {
+ static _Thread_local char buf[1024];
+ 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(buf, "%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)
+ {
+ static _Thread_local char buf[1024];
+ 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(buf, freq * 1E6, 1000);
+ }
+
+ const char *
+ cpu_perc(const char *unused)
+ {
+ static _Thread_local char buf[1024];
+ 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(buf, "%d", 100 *
+ ((a[CP_USER] + a[CP_NICE] + a[CP_SYS] +
+ a[CP_INTR]) -
+ (b[CP_USER] + b[CP_NICE] + b[CP_SYS] +
+ b[CP_INTR])) / sum);
+ }
+#endif
diff --git a/patches/slstatus/components/datetime.c b/patches/slstatus/components/datetime.c
new file mode 100644
index 0000000..b06ece2
--- /dev/null
+++ b/patches/slstatus/components/datetime.c
@@ -0,0 +1,20 @@
+/* See LICENSE file for copyright and license details. */
+#include <stdio.h>
+#include <time.h>
+
+#include "../util.h"
+
+const char *
+datetime(const char *fmt)
+{
+ static _Thread_local char buf[1024];
+ time_t t;
+
+ t = time(NULL);
+ if (!strftime(buf, sizeof(buf), fmt, localtime(&t))) {
+ warn("strftime: Result string exceeds buffer size");
+ return NULL;
+ }
+
+ return buf;
+}
diff --git a/patches/slstatus/components/disk.c b/patches/slstatus/components/disk.c
new file mode 100644
index 0000000..3d2028a
--- /dev/null
+++ b/patches/slstatus/components/disk.c
@@ -0,0 +1,62 @@
+/* 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)
+{
+ static _Thread_local char buf[1024];
+ struct statvfs fs;
+
+ if (statvfs(path, &fs) < 0) {
+ warn("statvfs '%s':", path);
+ return NULL;
+ }
+
+ return fmt_human(buf, fs.f_frsize * fs.f_bavail, 1024);
+}
+
+const char *
+disk_perc(const char *path)
+{
+ static _Thread_local char buf[1024];
+ struct statvfs fs;
+
+ if (statvfs(path, &fs) < 0) {
+ warn("statvfs '%s':", path);
+ return NULL;
+ }
+
+ return bprintf(buf, "%d", (int)(100 *
+ (1 - ((double)fs.f_bavail / (double)fs.f_blocks))));
+}
+
+const char *
+disk_total(const char *path)
+{
+ static _Thread_local char buf[1024];
+ struct statvfs fs;
+
+ if (statvfs(path, &fs) < 0) {
+ warn("statvfs '%s':", path);
+ return NULL;
+ }
+
+ return fmt_human(buf, fs.f_frsize * fs.f_blocks, 1024);
+}
+
+const char *
+disk_used(const char *path)
+{
+ static _Thread_local char buf[1024];
+ struct statvfs fs;
+
+ if (statvfs(path, &fs) < 0) {
+ warn("statvfs '%s':", path);
+ return NULL;
+ }
+
+ return fmt_human(buf, fs.f_frsize * (fs.f_blocks - fs.f_bfree), 1024);
+}
diff --git a/patches/slstatus/components/ram.c b/patches/slstatus/components/ram.c
new file mode 100644
index 0000000..4fe2752
--- /dev/null
+++ b/patches/slstatus/components/ram.c
@@ -0,0 +1,220 @@
+/* See LICENSE file for copyright and license details. */
+#include <stdio.h>
+
+#include "../util.h"
+
+#if defined(__linux__)
+ #include <stdint.h>
+
+ const char *
+ ram_free(const char *unused)
+ {
+ static _Thread_local char buf[1024];
+ uintmax_t free;
+
+ if (pscanf(buf, "/proc/meminfo",
+ "MemTotal: %ju kB\n"
+ "MemFree: %ju kB\n"
+ "MemAvailable: %ju kB\n",
+ &free, &free, &free) != 3)
+ return NULL;
+
+ return fmt_human(buf, free * 1024, 1024);
+ }
+
+ const char *
+ ram_perc(const char *unused)
+ {
+ static _Thread_local char buf[1024];
+ uintmax_t total, free, buffers, cached;
+ int percent;
+
+ if (pscanf(buf, "/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(buf, "%d", percent);
+ }
+
+ const char *
+ ram_total(const char *unused)
+ {
+ static _Thread_local char buf[1024];
+ uintmax_t total;
+
+ if (pscanf(buf, "/proc/meminfo", "MemTotal: %ju kB\n", &total)
+ != 1)
+ return NULL;
+
+ return fmt_human(buf, total * 1024, 1024);
+ }
+
+ const char *
+ ram_used(const char *unused)
+ {
+ static _Thread_local char buf[1024];
+ uintmax_t total, free, buffers, cached, used;
+
+ if (pscanf(buf, "/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(buf, 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)
+ {
+ static _Thread_local char buf[1024];
+ 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)
+ {
+ static _Thread_local char buf[1024];
+ struct uvmexp uvmexp;
+ int free_pages;
+
+ if (!load_uvmexp(&uvmexp))
+ return NULL;
+
+ free_pages = uvmexp.npages - uvmexp.active;
+ return fmt_human(buf, pagetok(free_pages, uvmexp.pageshift) *
+ 1024, 1024);
+ }
+
+ const char *
+ ram_perc(const char *unused)
+ {
+ static _Thread_local char buf[1024];
+ struct uvmexp uvmexp;
+ int percent;
+
+ if (!load_uvmexp(&uvmexp))
+ return NULL;
+
+ percent = uvmexp.active * 100 / uvmexp.npages;
+ return bprintf(buf, "%d", percent);
+ }
+
+ const char *
+ ram_total(const char *unused)
+ {
+ static _Thread_local char buf[1024];
+ struct uvmexp uvmexp;
+
+ if (!load_uvmexp(&uvmexp))
+ return NULL;
+
+ return fmt_human(buf, pagetok(uvmexp.npages,
+ uvmexp.pageshift) * 1024, 1024);
+ }
+
+ const char *
+ ram_used(const char *unused)
+ {
+ static _Thread_local char buf[1024];
+ struct uvmexp uvmexp;
+
+ if (!load_uvmexp(&uvmexp))
+ return NULL;
+
+ return fmt_human(buf, 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(buf, 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(buf, 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(buf, "%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(buf, active * getpagesize(), 1024);
+ }
+#endif
diff --git a/patches/slstatus/components/run_command.c b/patches/slstatus/components/run_command.c
new file mode 100644
index 0000000..b9fc3a2
--- /dev/null
+++ b/patches/slstatus/components/run_command.c
@@ -0,0 +1,29 @@
+/* See LICENSE file for copyright and license details. */
+#include <stdio.h>
+#include <string.h>
+
+const char *
+run_command(const char *cmd)
+{
+ static _Thread_local char buf[1024];
+ char *p;
+ FILE *fp;
+
+ if (!(fp = popen(cmd, "r"))) {
+ fprintf(stderr,"error '%s':", cmd);
+ return "";
+ }
+
+ p = fgets(buf, sizeof(buf) - 1, fp);
+ if (pclose(fp) < 0) {
+ fprintf(stderr,"pclose '%s':", cmd);
+ return "";
+ }
+ if (!p)
+ return "";
+
+ if ((p = strrchr(buf, '\n')))
+ p[0] = '\0';
+
+ return buf[0] ? buf : "";
+}
diff --git a/patches/slstatus/components/temperature.c b/patches/slstatus/components/temperature.c
new file mode 100644
index 0000000..9d9e45d
--- /dev/null
+++ b/patches/slstatus/components/temperature.c
@@ -0,0 +1,75 @@
+/* See LICENSE file for copyright and license details. */
+#include <stddef.h>
+
+#include "../util.h"
+
+
+#if defined(__linux__)
+ #include <stdint.h>
+
+ const char *
+ temp(const char *file)
+ {
+ static _Thread_local char buf[1024];
+ uintmax_t temp;
+
+ if (pscanf(buf, file, "%ju", &temp) != 1)
+ return NULL;
+
+ return bprintf(buf, "%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)
+ {
+ static _Thread_local char buf[1024];
+ 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(buf, "%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)
+ {
+ static _Thread_local char buf[1024];
+ 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(buf, "%d.%d", (temp - 2731) / 10, abs((temp - 2731) % 10));
+ }
+#endif
diff --git a/patches/slstatus/components/util.c b/patches/slstatus/components/util.c
new file mode 100644
index 0000000..9524d85
--- /dev/null
+++ b/patches/slstatus/components/util.c
@@ -0,0 +1,146 @@
+#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(const char *buf, 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;
+}
+
+char *
+bprintf(const char *buf, 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(const char *buf, 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(buf, "%.1f %s", scaled, prefix[i]);
+}
+
+int
+pscanf(const char *buf, const char *path, const char *fmt, ...)
+{
+
+ FILE *fp;
+ va_list ap;
+ int n;
+
+ if (!(fp = fopen(path, "r"))) {
+ warn("fopen '%s':", path);
+ return -1;
+ }
+ va_start(ap, fmt);
+ n = vfscanf(fp, fmt, ap);
+ va_end(ap);
+ fclose(fp);
+
+ return (n == EOF) ? -1 : n;
+}
+
diff --git a/patches/slstatus/components/wifi.c b/patches/slstatus/components/wifi.c
new file mode 100644
index 0000000..5808175
--- /dev/null
+++ b/patches/slstatus/components/wifi.c
@@ -0,0 +1,275 @@
+/* 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 "../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)
+ {
+ static _Thread_local char buf[1024];
+ int cur;
+ size_t i;
+ char *p, *datastart;
+ char path[PATH_MAX];
+ char status[5];
+ FILE *fp;
+
+ if (esnprintf(buf, 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(buf, "%d", (int)((float)cur / 70 * 100));
+ }
+
+ const char *
+ wifi_essid(const char *interface)
+ {
+ static _Thread_local char buf[1024];
+ 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(buf, 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)
+ {
+ static _Thread_local char buf[1024];
+ 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)
+ {
+ static _Thread_local char buf[1024];
+ 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(buf, "%d", q);
+ }
+
+ return NULL;
+ }
+
+ const char *
+ wifi_essid(const char *interface)
+ {
+ static _Thread_local char buf[1024];
+ struct ieee80211_nodereq nr;
+
+ if (load_ieee80211_nodereq(interface, &nr))
+ return bprintf(buf, "%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)
+ {
+ static _Thread_local char buf[1024];
+ 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)
+ {
+ static _Thread_local char buf[1024];
+ 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))
+ {
+ static _Thread_local char buf[1024];
+ /* 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(buf, "%d", RSSI_TO_PERC(rssi_dbm));
+ }
+ }
+
+ close(sockfd);
+ return fmt;
+ }
+
+ const char *
+ wifi_essid(const char *interface)
+ {
+ static _Thread_local char buf[1024];
+ 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(buf, "%s", ssid);
+ }
+
+ close(sockfd);
+ return fmt;
+ }
+#endif
diff --git a/patches/slstatus/slstatus.patch b/patches/slstatus/slstatus.patch
new file mode 100644
index 0000000..4c34c1c
--- /dev/null
+++ b/patches/slstatus/slstatus.patch
@@ -0,0 +1,415 @@
+diff --git a/Makefile b/Makefile
+index 33a1ec7..31660a3 100644
+--- a/Makefile
++++ b/Makefile
+@@ -1,8 +1,10 @@
+-compile:
+- cc -o sta main.c
++config.h:
++ cp config.def.h config.h
++compile: config.h
++ cc -o sta main.c ./components/* -pthread
+
+ install: compile
+ cp sta /usr/local/bin
+
+ uninstall:
+- rm /usr/local/bin/sta
++ rm -f /usr/local/bin/sta
+diff --git a/config.def.h b/config.def.h
+new file mode 100644
+index 0000000..d8165c3
+--- /dev/null
++++ b/config.def.h
+@@ -0,0 +1,60 @@
++/*
++ * 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 Args commands[] = {
++ /* function format argument id delay(ms) */
++ {run_command, "%s", "date +%H:%M:%S", 1, 1000},
++
++};
+diff --git a/main.c b/main.c
+index 9a74044..289705e 100644
+--- a/main.c
++++ b/main.c
+@@ -1,15 +1,29 @@
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <sys/socket.h>
+-#include <stdarg.h>
+ #include <sys/un.h>
+ #include <unistd.h>
++#include <pthread.h>
+ #include <string.h>
+ #include <signal.h>
+ #include <errno.h>
+
+ #define SOCKET_PATH "/tmp/sta"
+
++typedef struct{
++ const char *(*func)(const char *);
++ char *fmt;
++ char *parm;
++ int id;
++ int delay;
++}Args;
++
++
++#include "util.h"
++#include "config.h"
++
++pthread_mutex_t list_mutex = PTHREAD_MUTEX_INITIALIZER;
++
+ typedef struct {
+ int id;
+ char *name;
+@@ -20,14 +34,10 @@ typedef struct {
+ int count;
+ } Pros;
+
+-void error(char *t,char *m,...){
+- va_list args;
+- va_start(args,m);
+- fprintf(stderr, "\033[1;31m[E]\033[0m \033[1;33m%s\033[0m:", t);
+- vfprintf(stderr, m,args);
+- fprintf(stderr, "\n");
+- va_end(args);
+-}
++typedef struct {
++ int id2;
++ Pros *list;
++}Potato;
+
+ Pros *init(){
+ Pros *list = malloc(sizeof(Pros));
+@@ -48,21 +58,32 @@ void add_pro(Pros *list,int id,char *name){
+
+ list->count++;
+ list->process = realloc(list->process, sizeof(Pro) * list->count);
+- if (!list->process) error("Memory","memory allocation failed.");
++ if (!list->process) {
++ warn("Memory","memory allocation failed.");
++ exit(1);
++ }
+ list->process[list->count -1].name = strdup(name);
+ list->process[list->count -1].id = id;
+ }
+-
+ void show_pros(Pros *list)
+ {
++ for(int i = 0; i < list->count - 1; i++){
++ for(int j = i + 1; j < list->count; j++){
++ if(list->process[i].id > list->process[j].id){
++ Pro temp = list->process[i];
++ list->process[i] = list->process[j];
++ list->process[j] = temp;
++ }
++ }
++ }
+ for(int a = 0; a<list->count;++a){
+ printf("%s",list->process[a].name);
+ }
+- printf("\n");
++ printf("\n");
+ fflush(stdout);
+ }
+
+-void show_help()
++void usage()
+ {
+ printf("Usage:\n");
+ printf("\t-id <number> => process id (id >= 1)\n");
+@@ -72,26 +93,36 @@ void show_help()
+ exit(1);
+ }
+
+-void args(int *id,const char **name,int argc, char const* argv[])
++void args(int *id,int argc, char const* argv[])
+ {
+ for (int i = 1; i < argc; i += 2) {
+ if (!strcmp("-h", argv[i]) ||!strcmp("-help", argv[i]))
+- show_help();
+-
+- if (i + 1 >= argc || argv[i+1][0] == '-')
+- error("Args", "missing value for %s\nrun: sta -h", argv[i]);
++ usage();
+
+ if (!strcmp("-id", argv[i]))
+ *id = atoi(argv[i + 1]);
++ }
+
+- else if (!strcmp("-name", argv[i]))
+- *name = argv[i + 1];
++ if (*id <= 0)
++ usage();
+
+- }
++}
+
+- if (*id <= 0 || !*name)
+- show_help();
++char *temp_spf(const char *cmd,char *fmt)
++{
++ char *buf = malloc(512);
++ sprintf(buf, fmt,cmd);
++ return buf;
++}
+
++void append(Args *command,Pros *list)
++{
++ const char *cmd = command->func(command->parm);
++ if (!cmd) cmd = strdup("N/A");
++ char *tmp =temp_spf(cmd,command->fmt);
++ add_pro(list, command->id, tmp);
++ free(tmp);
++ show_pros(list);
+ }
+
+ void clean_up(){
+@@ -99,6 +130,19 @@ void clean_up(){
+ exit(0);
+ }
+
++void *worker(void* arg){
++ Potato* data = arg;
++ Args command = commands[data->id2];
++ while (1){
++ pthread_mutex_lock(&list_mutex);
++ append(&command, data->list);
++ pthread_mutex_unlock(&list_mutex);
++
++ usleep(command.delay * 1000);
++ };
++}
++
++
+ int main(int argc, char const* argv[]){
+
+ struct sockaddr_un addr;
+@@ -106,19 +150,26 @@ int main(int argc, char const* argv[]){
+ addr.sun_family = AF_UNIX;
+ strcpy(addr.sun_path, SOCKET_PATH);
+ int sock = socket(AF_UNIX, SOCK_STREAM , 0);
+- if (sock < 0) error("Socket","failed to create socket: %s", strerror(errno));
++ if (sock < 0) warn("Socket","failed to create socket: %s", strerror(errno));
+
+ Pros *list = init();
+
+ if (access(SOCKET_PATH, F_OK) == 0) {
+ int id;
+- const char *name;
+ char buf[256];
+- args(&id, &name,argc, argv);
+- snprintf(buf,sizeof(buf),"%d|+|%s",id,name);
++ args(&id,argc, argv);
++ for (int i = 0;i<sizeof(commands)/sizeof(commands[0]);++i){
++ if (id == commands[i].id){
++ const char *cmd = commands[i].func(commands[i].parm);
++ if (!cmd) cmd = strdup("N/A");
++ char *tmp = temp_spf(cmd,commands[i].fmt);
++ snprintf(buf,sizeof(buf),"%d|+|%s",id,tmp);
++ free(tmp);
++ }
++ }
+
+ if (connect(sock, (struct sockaddr*)&addr , sizeof(addr)) < 0)
+- error("Connect","failed: %s", strerror(errno));
++ warn("Connect","failed: %s", strerror(errno));
+
+ write(sock, buf, strlen(buf));
+ close(sock);
+@@ -126,13 +177,28 @@ int main(int argc, char const* argv[]){
+ } else {
+ signal(SIGTERM, clean_up);
+ signal(SIGINT, clean_up);
++ unlink(SOCKET_PATH);
++
++ int cmds = sizeof(commands)/sizeof(commands[0]);
++
++ pthread_t tids[cmds];
++ for (int i = 0; i<cmds;++i){
++ if(commands[i].delay){
++ Potato *info = malloc(sizeof(Potato));
++ info->list = list;
++ info->id2 =i;
++ pthread_create(&tids[i], NULL,worker,info);
++
++ }else{
++ append(&commands[i], list);
++ }
++ }
+
+- unlink(SOCKET_PATH);
+ if (bind(sock, (struct sockaddr*)&addr , sizeof(addr)) < 0)
+- error("Bind","failed: %s", strerror(errno));
++ warn("Bind","failed: %s", strerror(errno));
+
+ if (listen(sock, 5) < 0)
+- error("Listen","failed: %s", strerror(errno));
++ warn("Listen","failed: %s", strerror(errno));
+
+ while (1) {
+ int client = accept(sock, NULL, NULL);
+diff --git a/sta b/sta
+new file mode 100755
+index 0000000..6b91afc
+Binary files /dev/null and b/sta differ
+diff --git a/util.h b/util.h
+new file mode 100644
+index 0000000..b26f07d
+--- /dev/null
++++ b/util.h
+@@ -0,0 +1,99 @@
++#include <stdint.h>
++
++
++/* 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);
++
++/* settings */
++#define LEN(x) (sizeof(x) / sizeof((x)[0]))
++
++extern char *argv0;
++
++void warn(const char *, ...);
++void die(const char *, ...);
++
++int esnprintf(const char *buf, char *str, size_t size, const char *fmt, ...);
++char *bprintf(const char *buf, const char *fmt, ...);
++const char *fmt_human(const char *buf, uintmax_t num, int base);
++int pscanf(const char *buf, const char *path, const char *fmt, ...);
++