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.
378 lines
7.5 KiB
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);
|
|
}
|
|
|