// For nanosleep(), pread() #define _POSIX_C_SOURCE 200809L #include #include #include #include #include #include #include #include #include #include // 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; } }