/** rexbacklight Copyright (C) 2018 rexy712 This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include #include static const char* backlight_dir = "/sys/class/backlight/"; void usage(int exit_val){ fprintf(stderr, "Usage: rexbacklight [option]\n\n"); fprintf(stderr, "Options:\n"); fprintf(stderr, " =\n"); fprintf(stderr, " -\n"); fprintf(stderr, " +\n"); fprintf(stderr, " off\n"); fprintf(stderr, " max\n"); fprintf(stderr, " min\n"); if(!exit_val){ fprintf(stderr, "\nrexbacklight Copyright (C) 2018 rexy712\n"); fprintf(stderr, "This program comes with ABSOLUTELY NO WARRANTY.\n"); fprintf(stderr, "This is free software, and you are welcome to redistribute it\n"); fprintf(stderr, "under certain conditions; see the GNU GPLv3 for details.\n"); fprintf(stderr, "A copy of the GPLv3 is available with the source in the file 'LICENSE'\n"); } exit(exit_val); } int check_valid_files(const char* f1, const char* f2){ struct stat file1, file2; if(stat(f1, &file1)){ printf("failed to open '%s'\n", f1); return -1; } if(stat(f2, &file2)){ printf("failed to open '%s'\n", f2); return -1; } //Same device and same inode means same file //device id if(file1.st_dev != file2.st_dev) return -2; //inode number if(file1.st_ino != file2.st_ino) return -2; return 0; } struct string_array{ char** list; int size; }; //Get a list of backlight devices in sysfs struct string_array get_backlight_sources(void){ DIR* fd; struct dirent* dir; fd = opendir(backlight_dir); if(!fd){ fprintf(stderr, "Unable to open '%s' for reading!\n", backlight_dir); return (struct string_array){.list = NULL, .size = 0}; } char** list = malloc(sizeof(const char*) * 8); int i; for(i = 0;(dir = readdir(fd));){ if(!strcmp(dir->d_name, ".") || !strcmp(dir->d_name, "..")){ continue; } list[i] = malloc(strlen(dir->d_name) + 1); strcpy(list[i], dir->d_name); i++; } closedir(fd); return (struct string_array){.list = list, .size = i}; } void free_string_array(struct string_array* s){ for(int i = 0;i < s->size;i++) free(s->list[i]); free(s->list); } int get_brightness(const char* file){ FILE* bright = fopen(file, "r"); char buff[127]; if(!bright){ fprintf(stderr, "Unable to open brightness file \"%s\"!\n", file); return 0; } if(!fgets(buff, sizeof(buff), bright)){ fprintf(stderr, "Unable to read file \"%s\"!\n", file); fclose(bright); return 0; } fclose(bright); return atof(buff); } int process_arg(char* arg, float min, float current, float max){ //Amount to inc/dec int delta = delta = max * atof(arg + 1) / 100.0; //Increment if(arg[0] == '+'){ delta = delta + current; if(delta >= max) return max; else{ return delta; } //Decrement }else if(arg[0] == '-'){ delta = current - delta; if(delta <= min) return min; else return delta; //Directly set }else if(arg[0] == '='){ if(delta >= max) return max; else if(delta <= min) return min; else return delta; //Set to minimum plus one (so backlight is actually on!) }else if(!strcmp("min", arg)){ return min + 1; //Turn off backlight }else if(!strcmp("off", arg)){ return min; //Set to maximum }else if(!strcmp("max", arg)){ return max; //Unknown option }else{ usage(-1); } return current; } //argv[1] shall be [+-=]|min|max|off int main(int argc, char** argv){ const char* backlight_file = "brightness"; const char* max_backlight_file = "max_brightness"; //Make sure we have an argument and it is at least 2 characters long if(argc < 2 || !strcmp(argv[1], "--help")) usage(0); else if(strlen(argv[1]) < 2) usage(-1); //Gain access to sysfs files if(setuid(0)){ fprintf(stderr, "Unable to setuid to 0!\n"); return -3; } //Make sure we aren't in a chroot environment (prevents writing to a file we don't want to!) if(check_valid_files("/", "/proc/1/root")){ fprintf(stderr, "No chroot today\n"); return -4; } //Now that we've verified we're in a safe environment to do the work, //Let's get everything set up! //Acquire a list of backlight devices in sysfs struct string_array backlight_names = get_backlight_sources(); if(backlight_names.size == 0){ fprintf(stderr, "No backlights devices found!\n"); return -1; } //save our starting directory so we can change to each backlight directory const char* starting_dir = getcwd(NULL, 0); if(chdir(backlight_dir)){ fprintf(stderr, "Unable to read backlight sysfs directory!\n"); return -2; } //Set all backlight sources to the requested percentage for(int i = 0;i < backlight_names.size;i++){ if(chdir(backlight_names.list[i])){ fprintf(stderr, "Unable to open backlight directory \"%s%s\"!\n", backlight_dir, backlight_names.list[i]); continue; } //Open brightness file for writing int out = process_arg(argv[1], 0, get_brightness(backlight_file), get_brightness(max_backlight_file)); FILE* bright = fopen(backlight_file, "w+"); if(!bright){ fprintf(stderr, "Unable to open brightness file \"%s\" for writing!\n", backlight_file); continue; } fprintf(bright, "%d", out); fclose(bright); } free_string_array(&backlight_names); if(chdir(starting_dir)){ fprintf(stderr, "Could not return to starting directory!\nWas the directory moved/deleted?\n"); if(chdir(getenv("HOME")) || chdir("/")){ return -5; } } return 0; }