You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
sbl/sbl.c

378 lines
7.5 KiB

#define _DEFAULT_SOURCE
#define _POSIX_C_SOURCE 200809L
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <stdarg.h>
#include <errno.h>
#include <string.h>
#include <wordexp.h>
#include <limits.h>
#include <getopt.h>
#include <unistd.h>
#define BACKLIGHT_ROOT_PATH "/sys/class/backlight/"
#define BL_MIN 5
#define const_arr_size(val) ((int)(sizeof(val)/sizeof(val[0])))
const char *savefile_paths[] = {
NULL, /* reserved for external savefile path */
"/etc/sblsave"
};
enum action {
DISPLAY, INCREASE, DECREASE, SET, RESTORE
};
static uid_t ruid;
static int device_index = 0;
static const char *savefile;
static int max_brightness;
static const char *device_path;
static void die (const char *, ...);
static void usage (void);
static void list_cards (void);
static void set_brightness (float);
static void change_permissions (const char *);
static void restore_permissions (void);
static int save_value (float);
static int get_max_brightness (void);
static float get_saved_value (void);
static float get_current_brightness (void);
static const char * get_device_path (int);
static const char * get_savefile (void);
int main (int argc, char *argv[])
{
int opc = 0, store = 0;
enum action act = DISPLAY;
float value = BL_MIN;
char *extfile = NULL;
/* Parse command line arguments */
while ((opc = getopt(argc, argv, "c:hI:li:d:s:Sr")) != -1) {
switch (opc) {
case 'l':
list_cards();
break;
case 'h':
usage();
break;
case 'c':
extfile = malloc(strlen(optarg) + 1);
if (!extfile)
die("malloc in main():");
strcpy(extfile, optarg);
savefile_paths[0] = extfile;
break;
case 'I':
device_index = atoi(optarg);
break;
case 'i':
act = INCREASE;
value = atof(optarg);
break;
case 'd':
act = DECREASE;
value = atof(optarg);
break;
case 's':
act = SET;
value = atof(optarg);
break;
case 'r':
act = RESTORE;
break;
case 'S':
store = 1;
break;
default:
exit(EXIT_FAILURE);
break;
}
}
ruid = getuid ();
if (!(device_path = get_device_path(device_index)))
die("invalid device index");
max_brightness = get_max_brightness();
savefile = get_savefile();
switch (act) {
case DISPLAY:
printf("%.2f\n", get_current_brightness());
break;
case SET:
set_brightness(value);
break;
case INCREASE:
value += get_current_brightness();
set_brightness(value);
break;
case DECREASE:
value = get_current_brightness() - value;
set_brightness(value);
break;
case RESTORE:
set_brightness(get_saved_value());
break;
default:
break;
}
if (store)
save_value(get_current_brightness());
if (extfile)
free(extfile);
return 0;
}
int save_value (float value)
{
FILE *fd;
change_permissions(savefile);
fd = fopen(savefile, "w");
if (!fd)
die("could not open savefile");
fprintf(fd, "%f\n", value);
fclose(fd);
restore_permissions();
return 1;
}
float get_saved_value (void)
{
FILE *fd;
float rtf = -1;
fd = fopen(savefile, "r");
if (!fd)
die("could not open savefile");
fscanf(fd, "%f", &rtf);
fclose(fd);
return rtf;
}
float get_current_brightness (void)
{
FILE *fd;
char buf[PATH_MAX] = {0};
int cb = -1;
strcpy(buf, device_path);
strcat(buf, "/brightness");
fd = fopen(buf, "r");
if (!fd)
die("could not open %s", buf);
fscanf(fd, "%d", &cb);
fclose(fd);
return ((float)cb / (float)max_brightness) * 100.0;;
}
int get_max_brightness (void)
{
FILE *fd;
char buf[PATH_MAX] = {0};
int rti = -1;
strcpy(buf, device_path);
strcat(buf, "/max_brightness");
fd = fopen(buf, "r");
if (!fd)
die("could not open %s", buf);
fscanf(fd, "%d", &rti);
fclose(fd);
return rti;
}
/* Return the correct savefile path, creating it if it does not exist */
const char * get_savefile (void)
{
static char buf[PATH_MAX];
wordexp_t result = {0};
FILE *fd;
for (int i = 0; i < const_arr_size(savefile_paths); i++) {
if (!savefile_paths[i])
continue;
switch (wordexp(savefile_paths[i], &result, 0)) {
case 0:
break;
case WRDE_NOSPACE:
wordfree (&result);
die("Not enough space");
default:
die("Path not valid");
}
strcpy(buf, result.we_wordv[0]);
if ((fd = fopen(result.we_wordv[0], "r")))
break;
}
/* Create a savefile */
if (!fd) {
wordfree(&result);
for (int i = 0; i < const_arr_size(savefile_paths); i++) {
if (!savefile_paths[i])
continue;
switch (wordexp(savefile_paths[i], &result, 0)) {
case 0:
break;
case WRDE_NOSPACE:
wordfree (&result);
die("Not enough space");
default:
die("Path not valid");
}
strcpy(buf, result.we_wordv[0]);
change_permissions(buf);
if ((fd = fopen(result.we_wordv[0], "w")))
break;
}
}
restore_permissions();
wordfree(&result);
if (!fd)
die("could not open or create a savefile");
fclose(fd);
return buf;
}
const char * get_device_path (int index)
{
DIR *dp;
struct dirent *de;
static char buf[PATH_MAX];
memset(buf, 0, PATH_MAX);
if (index < 0)
die("%d is not a valid index", index);
if (!(dp = opendir(BACKLIGHT_ROOT_PATH)))
die("error opening " BACKLIGHT_ROOT_PATH);
errno = 0;
while ((de = readdir(dp))) {
if (!(de->d_type & DT_LNK))
continue;
if (index) {
index--;
continue;
} else {
strcpy(buf, BACKLIGHT_ROOT_PATH);
strcat(buf, de->d_name);
break;
}
}
closedir(dp);
if (errno)
die("error reading " BACKLIGHT_ROOT_PATH);
// FIXME: actually check return value of this
if (!buf[0])
return NULL;
return buf;
}
void list_cards (void)
{
int i = 0;
const char *s;
for (; (s = get_device_path(i)); i++)
printf("%d: %s\n", i, s);
exit(EXIT_SUCCESS);
}
void set_brightness (float value)
{
int set;
char buf[PATH_MAX] = {0};
FILE *fd;
if (value > 100)
value = 100;
if (value < BL_MIN)
value = BL_MIN;
set = (value/100.0) * max_brightness;
if (set < 0)
return;
strcpy(buf, device_path);
strcat(buf, "/brightness");
change_permissions(buf);
fd = fopen(buf, "w");
if (!fd)
die("could not open %s", buf);
fprintf(fd, "%d", set);
fclose(fd);
restore_permissions();
}
/* Change the process permissions matching the ones pointed by path */
void change_permissions (const char *path)
{
int status;
struct stat st;
static char buf[PATH_MAX];
char *p;
if (stat(path, &st) == -1) {
if (errno != ENOENT)
die("stat error");
strcpy(buf, path);
for (p = &buf[strlen(buf) - 1]; *p && p != buf; p--) {
if (*p == '/') {
*p = '\0';
if (stat(buf, &st) != -1)
break;
}
}
if (p == buf)
die("stat error, invalid path");
}
status = seteuid(st.st_uid);
if (status < 0)
die("could not setuid");
}
static void restore_permissions (void)
{
int status;
status = seteuid(ruid);
if (status < 0)
die("could not setuid");
}
void die(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
if (fmt[0] && fmt[strlen(fmt) - 1] == ':') {
fputc(' ', stderr);
perror(NULL);
} else {
fputc('\n', stderr);
}
va_end(ap);
exit(errno ? errno : 1);
}
static void usage (void)
{
puts("Usage: sbl [-hlrS] [-c savefile] [-I index] [-i/d/s percent]\n"
"-h print this message\n"
"-l list devices by index\n"
"-r restore saved value\n"
"-S save value\n"
"-c savefile specify savefile\n"
"-I index specify device by index\n"
"-i percent increase backlight by percent\n"
"-d percent decrease backlight by percent\n"
"-s percent set backlight to percent\n");
exit(EXIT_SUCCESS);
}