#define _DEFAULT_SOURCE #define _POSIX_C_SOURCE 200809L #include #include #include #include #include #include #include #include #include #include #include #include #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); }