265 lines
6.3 KiB
C
265 lines
6.3 KiB
C
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <errno.h>
|
|
#include <unistd.h>
|
|
|
|
#ifdef USE_SYSLOG
|
|
#include <syslog.h>
|
|
#endif
|
|
|
|
#include "main.h"
|
|
|
|
#ifdef USE_LIBNOTIFY
|
|
#include <libnotify/notify.h>
|
|
#endif
|
|
|
|
int run_verbose = 0;
|
|
int run_terse = 0;
|
|
int run_continuously = 0;
|
|
int interval = DEFAULT_LOG_INTERVAL;
|
|
int run_unsafe = 0;
|
|
int force_print_parameters = 0;
|
|
|
|
int warn_level = 10;
|
|
|
|
int warned = 0; /* Set if already warned */
|
|
|
|
const char * delimiter = "\n";
|
|
|
|
void print_help(void){
|
|
printf("%s %s\n", TITLE, VERSION);
|
|
printf("%s %s %s\n", USAGE0, PROGNAME, USAGE1);
|
|
printf("%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
|
|
OPTIONS0, OPTIONS1, OPTIONS2, OPTIONS3, OPTIONS4,
|
|
OPTIONS5, OPTIONS6, OPTIONS7, OPTIONS8, OPTIONS9,
|
|
OPTIONS10);
|
|
}
|
|
|
|
int get_fds(FILE ** fd_now, FILE ** fd_full, const char * bat_path, const char * unit_now, const char * unit_full)
|
|
{
|
|
size_t bat_path_len = strlen(bat_path);
|
|
size_t unit_now_len = strlen(unit_now);
|
|
size_t unit_full_len = strlen(unit_full);
|
|
char * now_path = (char*)malloc(bat_path_len + unit_now_len + 1);
|
|
char * full_path = (char*)malloc(bat_path_len + unit_full_len + 1);
|
|
|
|
strncpy(now_path, bat_path, bat_path_len + 1);
|
|
strncpy(full_path, bat_path, bat_path_len + 1);
|
|
|
|
strncat(now_path, unit_now, unit_now_len);
|
|
strncat(full_path, unit_full, unit_full_len);
|
|
|
|
printf("Attempting to open:\n\t%s\n\t%s\n", now_path, full_path);
|
|
|
|
(*fd_now) = fopen(now_path, "r");
|
|
if(*fd_now == NULL){
|
|
perror("Error opening file for current charge level");
|
|
// if exiting here, no need to close fd_now because it is null
|
|
return 1;
|
|
}
|
|
(*fd_full) = fopen(full_path, "r");
|
|
if(*fd_full == NULL){
|
|
perror("Error opening file for maximum charge level");
|
|
// it just makes me feel safer, but this should be redundant
|
|
if((*fd_now) != NULL){
|
|
fclose(*fd_now);
|
|
}
|
|
return 1;
|
|
}
|
|
printf("Successfully found files at %p and %p\n", (void*)fd_now, (void*)fd_full);
|
|
return 0;
|
|
}
|
|
|
|
int get_percentage
|
|
(FILE * fd_now, FILE * fd_full, double * c_now, double * c_full, double * frac, int *pct)
|
|
{
|
|
int vals_read = fscanf(fd_now, "%lf", c_now);
|
|
if(vals_read != 1){
|
|
if(errno != 0){
|
|
perror("Error reading full battery charge: ");
|
|
} else if(vals_read == EOF){
|
|
printf("End-of-file reached while reading current battery charge(?)");
|
|
} else {
|
|
printf("Invalid number of arguments (%d) returned while reading full battery charge", vals_read);
|
|
}
|
|
return 1;
|
|
}
|
|
vals_read = fscanf(fd_full, "%lf", c_full);
|
|
if(vals_read != 1){
|
|
if(errno != 0){
|
|
perror("Error reading full battery charge: ");
|
|
} else if(vals_read == EOF){
|
|
printf("End-of-file reached while reading full battery charge(?)");
|
|
} else {
|
|
printf("Invalid number of arguments (%d) returned while reading full battery charge", vals_read);
|
|
}
|
|
return 1;
|
|
}
|
|
(*frac) = *c_now / *c_full;
|
|
(*pct) = (int)((*frac) * 100);
|
|
return 0;
|
|
}
|
|
|
|
void warn(int pct){
|
|
if(!warned){
|
|
|
|
printf("Battery Low\n");
|
|
|
|
#ifdef USE_SYSLOG
|
|
syslog(LOG_WARNING, "Battery Low");
|
|
#endif
|
|
|
|
#ifdef USE_LIBNOTIFY
|
|
char warnmesg[MESGLEN];
|
|
snprintf(warnmesg, MESGLEN, "Battery is at %d percent", pct);
|
|
notify_init(PROGNAME);
|
|
NotifyNotification * levelwarn = notify_notification_new("Battery Low", warnmesg, "dialog-information");
|
|
notify_notification_show(levelwarn, NULL);
|
|
g_object_unref(G_OBJECT(levelwarn));
|
|
notify_uninit();
|
|
#endif
|
|
}
|
|
warned = 1;
|
|
}
|
|
|
|
int main(int argc, char *const argv[]){
|
|
|
|
int opt;
|
|
while((opt = getopt(argc, argv, "vhtli:uw:p")) != -1) {
|
|
switch(opt){
|
|
case 'v':
|
|
run_verbose = 1;
|
|
break;
|
|
case 'h':
|
|
print_help();
|
|
return 0;
|
|
case 't':
|
|
run_terse = 1;
|
|
break;
|
|
case 'l':
|
|
run_continuously = 1;
|
|
break;
|
|
case 'i':
|
|
interval = atoi(optarg);
|
|
run_continuously = 1;
|
|
break;
|
|
case 'u':
|
|
run_unsafe = 1;
|
|
break;
|
|
case 'w':
|
|
warn_level = atoi(optarg);
|
|
break;
|
|
case 'p':
|
|
force_print_parameters = 1;
|
|
break;
|
|
default:
|
|
printf("Literally how could you pass an unspecified argument to this program");
|
|
}
|
|
}
|
|
|
|
/**
|
|
Print run parameters at startup
|
|
*/
|
|
if(force_print_parameters) {
|
|
if(run_terse && run_verbose){
|
|
printf(PROGNAME " called with arguments to run both tersely and verbosely, the author legitimately cannot tell what you want her to do\n");
|
|
} else if(run_terse) {
|
|
printf(PROGNAME " will run tersely\n");
|
|
} else if(run_verbose) {
|
|
printf(PROGNAME " will run verbosely\n");
|
|
}
|
|
printf(PROGNAME " will poll every %d seconds\n", interval);
|
|
if(!run_terse){
|
|
printf(PROGNAME " will warn at %d%% battery\n", warn_level);
|
|
}
|
|
|
|
|
|
}
|
|
|
|
if(warn_level <= 0 && !run_terse){
|
|
fprintf(stderr, "Warn level set to %d. " PROGNAME " will not send warning on low battery.\n", warn_level);
|
|
}
|
|
|
|
if(interval < 15 && !run_unsafe){
|
|
fprintf(stderr, "Update interval less than 15 seconds, refusing to run. Specify -u to override this check.\n");
|
|
return 1;
|
|
}
|
|
|
|
|
|
#ifdef USE_SYSLOG
|
|
openlog(PROGNAME, 0, LOG_USER);
|
|
#endif
|
|
|
|
FILE * fd_now;
|
|
FILE * fd_full;
|
|
|
|
|
|
if(get_fds(&fd_now, &fd_full, BAT_PATH, CHARGE_NOW_PATH, CHARGE_FULL_PATH)){
|
|
printf("Charge unavailable, attempting to use energy\n");
|
|
if(get_fds(&fd_now, &fd_full, BAT_PATH, ENERGY_NOW_PATH, ENERGY_FULL_PATH)){
|
|
printf("Could not find a charge unit that works.\n");
|
|
exit(1);
|
|
} else {
|
|
printf("Unit is energy");
|
|
}
|
|
}
|
|
fflush(stdout);
|
|
double c_now;
|
|
double c_full;
|
|
double frac;
|
|
int pct;
|
|
|
|
do{
|
|
int rval = get_percentage(fd_now, fd_full, &c_now, &c_full, &frac, &pct);
|
|
if (rval){
|
|
printf("Um, problem\n");
|
|
return 1;
|
|
}
|
|
if(run_verbose){
|
|
printf("Current charge: %lf\n microampere-hours\n", c_now);
|
|
printf("Full charge: %lf\n microampere-hours\n", c_full);
|
|
}
|
|
|
|
if(!run_terse) {
|
|
printf("Battery percentage: ");
|
|
}
|
|
|
|
if(pct > warn_level){
|
|
warned = 0;
|
|
}
|
|
|
|
if(pct <= warn_level && !warned){
|
|
warn(pct);
|
|
}
|
|
printf("%d%s", pct, delimiter);
|
|
#ifdef USE_SYSLOG
|
|
syslog(LOG_INFO, "%d%%%s", pct, delimiter);
|
|
#endif
|
|
if(run_continuously){
|
|
sleep(interval);
|
|
errno = 0;
|
|
rewind(fd_now);
|
|
if(errno != 0){
|
|
perror("Error rewinding " CHARGE_NOW_PATH);
|
|
return 1;
|
|
}
|
|
rewind(fd_full); //just for the hecc of it
|
|
if(errno != 0){
|
|
perror("Error rewinding " CHARGE_FULL_PATH);
|
|
return 1;
|
|
}/*
|
|
fclose(fd_now);
|
|
fclose(fd_full);
|
|
fd_now = fopen(CHARGE_NOW_PATH, "r");
|
|
fd_full = fopen(CHARGE_FULL_PATH, "r");*/
|
|
}
|
|
} while (run_continuously);
|
|
|
|
|
|
#ifdef USE_SYSLOG
|
|
closelog();
|
|
#endif
|
|
|
|
return 0;
|
|
}
|