diff options
Diffstat (limited to 'batwarn_daemon.c')
-rw-r--r-- | batwarn_daemon.c | 85 |
1 files changed, 85 insertions, 0 deletions
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; + } +} |