Skip to content

Commit

Permalink
Restructure source files
Browse files Browse the repository at this point in the history
  • Loading branch information
electrickite committed Jan 13, 2024
1 parent 32e37f1 commit 77e34ce
Show file tree
Hide file tree
Showing 10 changed files with 421 additions and 307 deletions.
48 changes: 26 additions & 22 deletions Makefile
@@ -1,6 +1,6 @@
.POSIX:

NAME = batsignal
TARGET = batsignal

CC.$(CC)=$(CC)
CC.=cc
Expand All @@ -13,9 +13,9 @@ SED = sed
GREP = grep
CUT = cut

VERSION != $(GREP) VERSION defs.h | $(CUT) -d \" -f2
PROGNAME != $(GREP) PROGNAME defs.h | $(CUT) -d \" -f2
PROGUPPER != $(GREP) PROGUPPER defs.h | $(CUT) -d \" -f2
VERSION != $(GREP) VERSION main.h | $(CUT) -d \" -f2
PROGNAME != $(GREP) PROGNAME main.h | $(CUT) -d \" -f2
PROGUPPER != $(GREP) PROGUPPER main.h | $(CUT) -d \" -f2

PREFIX = /usr/local

Expand All @@ -33,47 +33,51 @@ LIBS := $(LIBS) -lm
LDFLAGS_EXTRA = -s
LDFLAGS := $(LDFLAGS_EXTRA) $(LDFLAGS)

OBJ = main.o options.o
SRC = main.c options.c battery.c notify.c
OBJ = $(SRC:.c=.o)
HDR = $(SRC:.c=.h)

all: $(NAME) $(NAME).1
.PHONY: all install install-service clean test compile-test

%.o: defs.h
all: $(TARGET) $(TARGET).1

$(NAME): $(OBJ)
$(CC) -o $(NAME) $(LDFLAGS) $(OBJ) $(LIBS)
$(TARGET): $(OBJ)
$(CC) -o $(TARGET) $(LDFLAGS) $(OBJ) $(LIBS)

$(NAME).1: $(NAME).1.in defs.h
$(SED) "s/VERSION/$(VERSION)/g" < $(NAME).1.in | $(SED) "s/PROGNAME/$(PROGNAME)/g" | $(SED) "s/PROGUPPER/$(PROGUPPER)/g" > $@
%.o: $(HDR)

$(TARGET).1: $(TARGET).1.in main.h
$(SED) "s/VERSION/$(VERSION)/g" < $(TARGET).1.in | $(SED) "s/PROGNAME/$(PROGNAME)/g" | $(SED) "s/PROGUPPER/$(PROGUPPER)/g" > $@

install: all
@echo Installing in $(DESTDIR)$(PREFIX)
$(INSTALL) -d $(DESTDIR)$(PREFIX)/bin
$(INSTALL) -d $(DESTDIR)$(MANPREFIX)/man1
$(INSTALL) -m 0755 $(NAME) $(DESTDIR)$(PREFIX)/bin/
$(INSTALL) -m 0644 $(NAME).1 $(DESTDIR)$(MANPREFIX)/man1/
$(INSTALL) -m 0755 $(TARGET) $(DESTDIR)$(PREFIX)/bin/
$(INSTALL) -m 0644 $(TARGET).1 $(DESTDIR)$(MANPREFIX)/man1/

install-service: install
$(INSTALL) -d $(DESTDIR)$(PREFIX)/lib/systemd/user
$(INSTALL) -m 0644 $(NAME).service $(DESTDIR)$(PREFIX)/lib/systemd/user/
$(INSTALL) -m 0644 $(TARGET).service $(DESTDIR)$(PREFIX)/lib/systemd/user/

uninstall:
@echo Removing files from $(DESTDIR)$(PREFIX)
$(RM) $(DESTDIR)$(PREFIX)/bin/$(NAME)
$(RM) $(DESTDIR)$(MANPREFIX)/man1/$(NAME).1
$(RM) $(DESTDIR)$(PREFIX)/lib/systemd/user/$(NAME).service
$(RM) $(DESTDIR)$(PREFIX)/bin/$(TARGET)
$(RM) $(DESTDIR)$(MANPREFIX)/man1/$(TARGET).1
$(RM) $(DESTDIR)$(PREFIX)/lib/systemd/user/$(TARGET).service

clean-all: clean clean-images

clean:
@echo Cleaning build files
$(RM) $(NAME) $(OBJ) $(NAME).1
$(RM) $(TARGET) $(OBJ) $(TARGET).1

clean-images: arch-clean debian-stable-clean debian-testing-clean ubuntu-latest-clean fedora-latest-clean

%-clean: test/Dockerfile.%
@echo Removing images for $*
-docker container prune --force --filter="label=$(NAME)-$*"
-docker rmi -f $(NAME)-$*
-docker container prune --force --filter="label=$(TARGET)-$*"
-docker rmi -f $(TARGET)-$*

test: compile-test

Expand All @@ -82,5 +86,5 @@ compile-test: arch-test debian-stable-test debian-testing-test ubuntu-latest-tes

%-test: test/Dockerfile.%
@echo Starting compile test for $*
docker build --label=$(NAME)-$* --tag=$(NAME)-$* --file=$< .
docker run -it $(NAME)-$*
docker build --label=$(TARGET)-$* --tag=$(TARGET)-$* --file=$< .
docker run -it $(TARGET)-$*
4 changes: 2 additions & 2 deletions batsignal.1.in
Expand Up @@ -80,7 +80,7 @@ App name used in notifications (default: PROGNAME)
.B \-I ICON
Display specified ICON in notifications
.SH CONFIGURATION
The options described above can be passed as program arguments or placed in an options configuration file.
Options can be passed to PROGNAME as command arguments or placed in a configuration file.
Options from the configuration file will be applied first and then may be overridden by command line as arguments.
.P
The configuration file should include option arguments as documented above, one argument per line.
Expand All @@ -99,7 +99,7 @@ For example, to specify a warning level of 30 and run as a background daemon, th
30
.RE
.P
Tthe following paths are checked in sequence for a configuration file:
The following paths are checked in sequence for a configuration file:
.IP \[bu]
.B PROGUPPER_CONFIG
environment variable (if present)
Expand Down
198 changes: 198 additions & 0 deletions battery.c
@@ -0,0 +1,198 @@
/*
* Copyright (c) 2018-2024 Corey Hinshaw
*/

#define _DEFAULT_SOURCE
#include <dirent.h>
#include <err.h>
#include <errno.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "battery.h"

static char *attr_path = NULL;

static void set_attributes(char *battery_name, char **now_attribute, char **full_attribute)
{
sprintf(attr_path, POWER_SUPPLY_SUBSYSTEM "/%s/charge_now", battery_name);
if (access(attr_path, F_OK) == 0) {
*now_attribute = "charge_now";
*full_attribute = "charge_full";
} else {
sprintf(attr_path, POWER_SUPPLY_SUBSYSTEM "/%s/energy_now", battery_name);
if (access(attr_path, F_OK) == 0) {
*now_attribute = "energy_now";
*full_attribute = "energy_full";
} else {
*now_attribute = "capacity";
*full_attribute = NULL;
}
}
}

static bool is_type_battery(char *name)
{
FILE *file;
char type[11] = "";

sprintf(attr_path, POWER_SUPPLY_SUBSYSTEM "/%s/type", name);
file = fopen(attr_path, "r");
if (file != NULL) {
if (fscanf(file, "%10s", type) == 0) { /* Continue... */ }
fclose(file);
}
return strcmp(type, "Battery") == 0;
}

static bool has_capacity_field(char *name)
{
FILE *file;
int capacity = -1;
char *now_attribute;
char *full_attribute;

set_attributes(name, &now_attribute, &full_attribute);

if (strcmp(now_attribute, "capacity") == 0) {
sprintf(attr_path, POWER_SUPPLY_SUBSYSTEM "/%s/capacity", name);
file = fopen(attr_path, "r");
if (file != NULL) {
if (fscanf(file, "%d", &capacity) == 0) { /* Continue... */ }
fclose(file);
}
} else {
capacity = 1;
}
return capacity >= 0;
}

static bool is_battery(char *name)
{
return is_type_battery(name) && has_capacity_field(name);
}

int find_batteries(char ***battery_names)
{
unsigned int path_len = strlen(POWER_SUPPLY_SUBSYSTEM) + POWER_SUPPLY_ATTR_LENGTH;
unsigned int entry_name_len = 5;
int battery_count = 0;
DIR *dir;
struct dirent *entry;

attr_path = realloc(attr_path, path_len + entry_name_len);

dir = opendir(POWER_SUPPLY_SUBSYSTEM);
if (dir) {
while ((entry = readdir(dir)) != NULL) {
if (strlen(entry->d_name) > entry_name_len) {
entry_name_len = strlen(entry->d_name);
attr_path = realloc(attr_path, path_len + entry_name_len);
if (attr_path == NULL)
err(EXIT_FAILURE, "Memory allocation failed");
}

if (is_battery(entry->d_name)) {
*battery_names = realloc(*battery_names, sizeof(char *) * (battery_count+1));
if (*battery_names == NULL)
err(EXIT_FAILURE, "Memory allocation failed");
(*battery_names)[battery_count] = strdup(entry->d_name);
if ((*battery_names)[battery_count] == NULL)
err(EXIT_FAILURE, "Memory allocation failed");
battery_count++;
}
}
closedir(dir);
}

return battery_count;
}

int validate_batteries(char **battery_names, int battery_count)
{
unsigned int path_len = strlen(POWER_SUPPLY_SUBSYSTEM) + POWER_SUPPLY_ATTR_LENGTH;
unsigned int name_len = 5;
int return_value = -1;

attr_path = realloc(attr_path, path_len + name_len);

for (int i = 0; i < battery_count; i++) {
if (strlen(battery_names[i]) > name_len) {
name_len = strlen(battery_names[i]);
attr_path = realloc(attr_path, path_len + name_len);
if (attr_path == NULL)
err(EXIT_FAILURE, "Memory allocation failed");
}
if (!is_battery(battery_names[i]) && return_value < 0) {
return_value = i;
}
}
return return_value;
}

void update_battery_state(BatteryState *battery, bool required)
{
char state[15];
char *now_attribute;
char *full_attribute;
unsigned int tmp_now;
unsigned int tmp_full;
FILE *file;

battery->discharging = false;
battery->full = true;
battery->energy_now = 0;
battery->energy_full = 0;
set_attributes(battery->names[0], &now_attribute, &full_attribute);

/* iterate through all batteries */
for (int i = 0; i < battery->count; i++) {
sprintf(attr_path, POWER_SUPPLY_SUBSYSTEM "/%s/status", battery->names[i]);
file = fopen(attr_path, "r");
if (file == NULL || fscanf(file, "%12s", state) == 0) {
if (required)
err(EXIT_FAILURE, "Could not read %s", attr_path);
battery->discharging |= 0;
if (file)
fclose(file);
continue;
}
fclose(file);

battery->discharging |= strcmp(state, POWER_SUPPLY_DISCHARGING) == 0;
battery->full &= strcmp(state, POWER_SUPPLY_FULL) == 0;

sprintf(attr_path, POWER_SUPPLY_SUBSYSTEM "/%s/%s", battery->names[i], now_attribute);
file = fopen(attr_path, "r");
if (file == NULL || fscanf(file, "%u", &tmp_now) == 0) {
if (required)
err(EXIT_FAILURE, "Could not read %s", attr_path);
if (file)
fclose(file);
continue;
}
fclose(file);

if (full_attribute != NULL) {
sprintf(attr_path, POWER_SUPPLY_SUBSYSTEM "/%s/%s", battery->names[i], full_attribute);
file = fopen(attr_path, "r");
if (file == NULL || fscanf(file, "%u", &tmp_full) == 0) {
if (required)
err(EXIT_FAILURE, "Could not read %s", attr_path);
if (file)
fclose(file);
continue;
}
fclose(file);
} else {
tmp_full = 100;
}

battery->energy_now += tmp_now;
battery->energy_full += tmp_full;
}

battery->level = round(100.0 * battery->energy_now / battery->energy_full);
}
43 changes: 43 additions & 0 deletions battery.h
@@ -0,0 +1,43 @@
/*
* Copyright (c) 2018-2024 Corey Hinshaw
*/

#ifndef BATTERY_H
#define BATTERY_H

#include <stdbool.h>

/* battery states */
#define STATE_AC 0
#define STATE_DISCHARGING 1
#define STATE_WARNING 2
#define STATE_CRITICAL 3
#define STATE_DANGER 4
#define STATE_FULL 5

/* system paths */
#define POWER_SUPPLY_SUBSYSTEM "/sys/class/power_supply"

/* Battery state strings */
#define POWER_SUPPLY_FULL "Full"
#define POWER_SUPPLY_DISCHARGING "Discharging"

#define POWER_SUPPLY_ATTR_LENGTH 15

/* battery information */
typedef struct BatteryState {
char **names;
int count;
bool discharging;
bool full;
char state;
int level;
int energy_full;
int energy_now;
} BatteryState;

int find_batteries(char ***battery_names);
int validate_batteries(char **battery_names, int battery_count);
void update_battery_state(BatteryState *battery, bool required);

#endif

0 comments on commit 77e34ce

Please sign in to comment.