diff options
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | Makefile | 10 | ||||
-rw-r--r-- | batwarn_daemon.c | 85 | ||||
-rwxr-xr-x | old/batwarn.sh | 26 | ||||
-rw-r--r-- | old/syscalls_per_iteration.txt | 126 |
5 files changed, 249 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..cbf6ab9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +batwarn_daemon +compile_commands.json diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..206a678 --- /dev/null +++ b/Makefile @@ -0,0 +1,10 @@ +CC = gcc +CFLAGS = -Wall -Wextra -std=c11 -O3 -fwrapv +TARGET = batwarn_daemon + +.PHONY: all clean + +all: $(TARGET) + +clean: + rm -f $(TARGET) diff --git a/batwarn_daemon.c b/batwarn_daemon.c new file mode 100644 index 0000000..1cd1d17 --- /dev/null +++ b/batwarn_daemon.c @@ -0,0 +1,85 @@ +// For nanosleep(), pread() +#define _POSIX_C_SOURCE 200809L + +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> +#include <string.h> +#include <time.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> +#include <sys/wait.h> +#include <assert.h> + + +// Warning when battery percentage is <= this +static const int WARN_PERC = 10; + +// Time to sleep between checks +static const struct timespec SLEEP_SPEC = {60, 0}; + +// Format string with percentage %d +static const char *MESSAGE_FORMAT = "Battery at %d%%!"; + + +static inline void parse(const char *buffer, bool *discharging, int *charge, int *full) { + while (true) { + if (memcmp(buffer, "POWER_SUPPLY_STATUS", 19) == 0) { + *discharging = memcmp(buffer + 20, "Discharging", 11) == 0; + } else if (memcmp(buffer, "POWER_SUPPLY_CHARGE_NOW", 23) == 0) { + *charge = strtol(buffer + 24, NULL, 10); + } else if (memcmp(buffer, "POWER_SUPPLY_CHARGE_FULL_DESIGN", 31) == 0) { + *full = strtol(buffer + 32, NULL, 10); + } + buffer = strchr(buffer, '\n'); + if (buffer != NULL) buffer++; + else break; + } +} + +int main(void) { + int fd = open("/sys/class/power_supply/BAT1/uevent", O_RDONLY); + if (fd < 0) { + perror("open"); + return 1; + } + + char buffer[1024]; + + while (true) { + ssize_t nr = pread(fd, buffer, sizeof buffer, 0); + if (nr < 0) { + perror("pread"); + break; + } + + bool discharging = false; + int charge = 1, full = 1; + parse(buffer, &discharging, &charge, &full); + + if (full > 0 && discharging && charge * 100 / full <= WARN_PERC) { + pid_t pid = fork(); + if (pid < 0) perror("fork"); + else if (pid == 0) { + char msg[strlen(MESSAGE_FORMAT) + 16]; + snprintf(msg, sizeof msg, MESSAGE_FORMAT, charge * 100 / full); + char *argv[4] = {"i3-nagbar", "-m", msg, NULL}; + execv("/usr/bin/i3-nagbar", argv); + perror("execv"); + exit(255); + } else { + int status; + do if (waitpid(pid, &status, 0) < 0 && errno == ECHILD) break; + while (!WIFEXITED(status) && !WIFSIGNALED(status)); + } + } + + (void)nanosleep(&SLEEP_SPEC, NULL); + } + + if (close(fd) < 0) { + perror("close"); + return 1; + } +} diff --git a/old/batwarn.sh b/old/batwarn.sh new file mode 100755 index 0000000..2556a70 --- /dev/null +++ b/old/batwarn.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +function get_props_key() { + local v="$(grep "$1" <<<"$props")" + echo "${v/*=}" +} + +function do_check() { + while read line; do + key="${line/=*}" + value="${line/*=}" + [[ $key = "POWER_SUPPLY_STATUS" ]] && status="$value" + [[ $key = "POWER_SUPPLY_CHARGE_NOW" ]] && charge="$value" + [[ $key = "POWER_SUPPLY_CHARGE_FULL_DESIGN" ]] && full="$value" + done </sys/class/power_supply/BAT1/uevent + + percent="$(( charge * 100 / full ))" + + if [[ $status = "Discharging" && $percent -le 30 ]]; then + i3-nagbar -m "Battery is at $percent%!" + fi +} + +while true; do + do_check + sleep 30 +done diff --git a/old/syscalls_per_iteration.txt b/old/syscalls_per_iteration.txt new file mode 100644 index 0000000..12e0a33 --- /dev/null +++ b/old/syscalls_per_iteration.txt @@ -0,0 +1,126 @@ +[{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0, NULL) = 5448 +rt_sigaction(SIGINT, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f5eea52b8e0}, {sa_handler=0x5625a3152150, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f5eea52b8e0}, 8) = 0 +rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 +--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=5448, si_uid=1000, si_status=0, si_utime=0, si_stime=0} --- +wait4(-1, 0x7fffb461e7d0, WNOHANG, NULL) = -1 ECHILD (No child processes) +rt_sigreturn({mask=[]}) = 0 +rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0 +rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 +openat(AT_FDCWD, "/sys/class/power_supply/BAT1/uevent", O_RDONLY) = 3 +fcntl(0, F_GETFD) = 0 +fcntl(0, F_DUPFD, 10) = 10 +fcntl(0, F_GETFD) = 0 +fcntl(10, F_SETFD, FD_CLOEXEC) = 0 +dup2(3, 0) = 0 +close(3) = 0 +ioctl(0, TCGETS, 0x7fffb461e5c0) = -1 ENOTTY (Inappropriate ioctl for device) +lseek(0, 0, SEEK_CUR) = 0 +read(0, "POWER_SUPPLY_NAME=BAT1\nPOWER_SUP"..., 128) = 128 +lseek(0, -105, SEEK_CUR) = 23 +rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0 +rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 +ioctl(0, TCGETS, 0x7fffb461e5c0) = -1 ENOTTY (Inappropriate ioctl for device) +lseek(0, 0, SEEK_CUR) = 23 +read(0, "POWER_SUPPLY_STATUS=Charging\nPOW"..., 128) = 128 +lseek(0, -99, SEEK_CUR) = 52 +rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0 +rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 +ioctl(0, TCGETS, 0x7fffb461e5c0) = -1 ENOTTY (Inappropriate ioctl for device) +lseek(0, 0, SEEK_CUR) = 52 +read(0, "POWER_SUPPLY_PRESENT=1\nPOWER_SUP"..., 128) = 128 +lseek(0, -105, SEEK_CUR) = 75 +rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0 +rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 +ioctl(0, TCGETS, 0x7fffb461e5c0) = -1 ENOTTY (Inappropriate ioctl for device) +lseek(0, 0, SEEK_CUR) = 75 +read(0, "POWER_SUPPLY_TECHNOLOGY=Li-ion\nP"..., 128) = 128 +lseek(0, -97, SEEK_CUR) = 106 +rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0 +rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 +ioctl(0, TCGETS, 0x7fffb461e5c0) = -1 ENOTTY (Inappropriate ioctl for device) +lseek(0, 0, SEEK_CUR) = 106 +read(0, "POWER_SUPPLY_CYCLE_COUNT=0\nPOWER"..., 128) = 128 +lseek(0, -101, SEEK_CUR) = 133 +rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0 +rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 +ioctl(0, TCGETS, 0x7fffb461e5c0) = -1 ENOTTY (Inappropriate ioctl for device) +lseek(0, 0, SEEK_CUR) = 133 +read(0, "POWER_SUPPLY_VOLTAGE_MIN_DESIGN="..., 128) = 128 +lseek(0, -87, SEEK_CUR) = 174 +rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0 +rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 +ioctl(0, TCGETS, 0x7fffb461e5c0) = -1 ENOTTY (Inappropriate ioctl for device) +lseek(0, 0, SEEK_CUR) = 174 +read(0, "POWER_SUPPLY_VOLTAGE_NOW=1575300"..., 128) = 128 +lseek(0, -94, SEEK_CUR) = 208 +rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0 +rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 +ioctl(0, TCGETS, 0x7fffb461e5c0) = -1 ENOTTY (Inappropriate ioctl for device) +lseek(0, 0, SEEK_CUR) = 208 +read(0, "POWER_SUPPLY_CURRENT_NOW=1541000"..., 128) = 128 +lseek(0, -95, SEEK_CUR) = 241 +rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0 +rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 +ioctl(0, TCGETS, 0x7fffb461e5c0) = -1 ENOTTY (Inappropriate ioctl for device) +lseek(0, 0, SEEK_CUR) = 241 +read(0, "POWER_SUPPLY_CHARGE_FULL_DESIGN="..., 128) = 128 +lseek(0, -88, SEEK_CUR) = 281 +rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0 +rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 +ioctl(0, TCGETS, 0x7fffb461e5c0) = -1 ENOTTY (Inappropriate ioctl for device) +lseek(0, 0, SEEK_CUR) = 281 +read(0, "POWER_SUPPLY_CHARGE_FULL=3107000"..., 128) = 128 +lseek(0, -95, SEEK_CUR) = 314 +rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0 +rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 +ioctl(0, TCGETS, 0x7fffb461e5c0) = -1 ENOTTY (Inappropriate ioctl for device) +lseek(0, 0, SEEK_CUR) = 314 +read(0, "POWER_SUPPLY_CHARGE_NOW=895000\nP"..., 128) = 128 +lseek(0, -97, SEEK_CUR) = 345 +rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0 +rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 +ioctl(0, TCGETS, 0x7fffb461e5c0) = -1 ENOTTY (Inappropriate ioctl for device) +lseek(0, 0, SEEK_CUR) = 345 +read(0, "POWER_SUPPLY_CAPACITY=28\nPOWER_S"..., 128) = 128 +lseek(0, -103, SEEK_CUR) = 370 +rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0 +rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 +ioctl(0, TCGETS, 0x7fffb461e5c0) = -1 ENOTTY (Inappropriate ioctl for device) +lseek(0, 0, SEEK_CUR) = 370 +read(0, "POWER_SUPPLY_CAPACITY_LEVEL=Norm"..., 128) = 128 +lseek(0, -93, SEEK_CUR) = 405 +rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0 +rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 +ioctl(0, TCGETS, 0x7fffb461e5c0) = -1 ENOTTY (Inappropriate ioctl for device) +lseek(0, 0, SEEK_CUR) = 405 +read(0, "POWER_SUPPLY_MODEL_NAME=PABAS024"..., 128) = 104 +lseek(0, -67, SEEK_CUR) = 442 +rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0 +rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 +ioctl(0, TCGETS, 0x7fffb461e5c0) = -1 ENOTTY (Inappropriate ioctl for device) +lseek(0, 0, SEEK_CUR) = 442 +read(0, "POWER_SUPPLY_MANUFACTURER=COMPAL"..., 128) = 67 +lseek(0, -33, SEEK_CUR) = 476 +rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0 +rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 +ioctl(0, TCGETS, 0x7fffb461e5c0) = -1 ENOTTY (Inappropriate ioctl for device) +lseek(0, 0, SEEK_CUR) = 476 +read(0, "POWER_SUPPLY_SERIAL_NUMBER=41167"..., 128) = 33 +rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0 +rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 +ioctl(0, TCGETS, 0x7fffb461e5c0) = -1 ENOTTY (Inappropriate ioctl for device) +lseek(0, 0, SEEK_CUR) = 509 +read(0, "", 128) = 0 +rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0 +rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 +dup2(10, 0) = 0 +fcntl(10, F_GETFD) = 0x1 (flags FD_CLOEXEC) +close(10) = 0 +rt_sigprocmask(SIG_BLOCK, [INT CHLD], [], 8) = 0 +clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f5eeaeede50) = 5450 +rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 +rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0 +rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 +rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0 +rt_sigaction(SIGINT, {sa_handler=0x5625a3152150, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f5eea52b8e0}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f5eea52b8e0}, 8) = 0 +wait4(-1, |