123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478
  1. /*
  2. * Licensed under the GNU Public License version 3.
  3. * Read attached LICENSE
  4. * Copyright (C) 2012 - Fredrik Haikarainen
  5. * Fredrik.haikarainen@gmail.com
  6. */
  7. #define _GNU_SOURCE
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <dirent.h>
  11. #include <string.h>
  12. #include <unistd.h>
  13. #include <limits.h>
  14. typedef enum LBOOL{
  15. TRUE = 0,
  16. FALSE = 1
  17. } LBOOL;
  18. typedef enum LOPTYPE{
  19. SET = 0,
  20. ADD = 1,
  21. SUB = 2
  22. } LOPTYPE;
  23. /* Flags */
  24. LBOOL q; /* Quiet, supresses output */
  25. LBOOL c; /* print unprecise current value in percentage */
  26. LBOOL m; /* read max value*/
  27. LBOOL p; /* precision read current value */
  28. int wbright;
  29. LOPTYPE ot;
  30. LBOOL readint(const char* f, unsigned int *i){
  31. FILE* ff = fopen(f, "r");
  32. if(ff){
  33. fscanf(ff, "%u", i);
  34. fclose(ff);
  35. return TRUE;
  36. }else{
  37. return FALSE;
  38. }
  39. }
  40. LBOOL readchar(const char* f, char *c){
  41. FILE* ff = fopen(f, "r");
  42. /*c = malloc(sz+1);*/
  43. if(ff){
  44. unsigned int sz;
  45. fseek(ff, 0L, SEEK_END);
  46. sz = ftell(ff);
  47. fseek(ff, 0L, SEEK_SET);
  48. fgets(c,sz,ff);
  49. fclose(ff);
  50. return TRUE;
  51. }else{
  52. return FALSE;
  53. }
  54. }
  55. LBOOL writeint(const char* f, unsigned int i){
  56. FILE* ff = fopen(f, "w");
  57. if(ff){
  58. fprintf(ff, "%u", i);
  59. fclose(ff);
  60. return TRUE;
  61. }else{
  62. return FALSE;
  63. }
  64. }
  65. LBOOL is_dir(const char* d){
  66. DIR* dd = opendir(d);
  67. if(dd){
  68. closedir(dd);
  69. return TRUE;
  70. }else{
  71. return FALSE;
  72. }
  73. }
  74. LBOOL is_writable(const char* f){
  75. FILE* dd = fopen(f, "w");
  76. if(dd){
  77. fclose(dd);
  78. return TRUE;
  79. }else{
  80. return FALSE;
  81. }
  82. }
  83. typedef struct {
  84. char name[256];
  85. unsigned int current_brightness;
  86. unsigned int max_brightness;
  87. char c_path[256]; /* Controller-path */
  88. char cb_path[256]; /* Current brightness-path */
  89. char mb_path[256]; /* Max brightness-path */
  90. char b_path[256]; /* Brightness-path */
  91. enum LBOOL is_ok;
  92. unsigned int guide_id;
  93. } controller;
  94. typedef struct {
  95. controller controllers[256];
  96. unsigned int num_controllers;
  97. } fetch_result;
  98. fetch_result fetch_controllers(const char* ctrldir){
  99. fetch_result returner;
  100. struct dirent* ep;
  101. DIR* lcdir = opendir(ctrldir);
  102. returner.num_controllers = 0;
  103. if(!lcdir){
  104. if(q == FALSE)
  105. printf("Error: Could not open directory '%s'!\n", ctrldir);
  106. }else{
  107. while( ( ep = readdir(lcdir) ) ){
  108. char* currctrldir = "";
  109. char* currctrldir_curr = "";
  110. char* currctrldir_max = "";
  111. char* currctrldir_f = "";
  112. if( ep->d_name[0] != '.'){
  113. strncpy(returner.controllers[returner.num_controllers].name, ep->d_name, sizeof(returner.controllers[returner.num_controllers].name));
  114. /* Set some default values, in case something fails we dont just get null */
  115. returner.controllers[returner.num_controllers].current_brightness = 0;
  116. returner.controllers[returner.num_controllers].max_brightness = 0;
  117. returner.controllers[returner.num_controllers].is_ok = TRUE;
  118. /*
  119. returner.controllers[returner.num_controllers].c_path = NULL;
  120. returner.controllers[returner.num_controllers].cb_path = NULL;
  121. returner.controllers[returner.num_controllers].b_path = NULL;
  122. returner.controllers[returner.num_controllers].mb_path = NULL;
  123. */
  124. /* Get path to the current controller dir */
  125. asprintf(&currctrldir, "%s/%s", ctrldir, ep->d_name);
  126. strncpy(returner.controllers[returner.num_controllers].c_path, currctrldir, sizeof(returner.controllers[returner.num_controllers].c_path));
  127. if(is_dir(currctrldir) == FALSE){
  128. if(q == FALSE)
  129. printf("Warning: '%s' is not a directory, check your system.\n", currctrldir);
  130. returner.controllers[returner.num_controllers].is_ok = FALSE;
  131. }
  132. /* Get path to current actual_brightness-file */
  133. asprintf(&currctrldir_curr, "%s/%s", currctrldir, "actual_brightness");
  134. strncpy(returner.controllers[returner.num_controllers].cb_path, currctrldir_curr, sizeof(returner.controllers[returner.num_controllers].cb_path));
  135. if( readint(currctrldir_curr, &returner.controllers[returner.num_controllers].current_brightness) == FALSE ){
  136. if(q == FALSE)
  137. printf("Warning: Can't read actual_brightness-file of '%s'. Will ignore this controller.\n", ep->d_name);
  138. returner.controllers[returner.num_controllers].is_ok = FALSE;
  139. }
  140. /* Get path to current max_brightness-file*/
  141. asprintf(&currctrldir_max, "%s/%s", currctrldir, "max_brightness");
  142. strncpy(returner.controllers[returner.num_controllers].mb_path, currctrldir_max, sizeof(returner.controllers[returner.num_controllers].mb_path));
  143. if( readint(currctrldir_max, &returner.controllers[returner.num_controllers].max_brightness) == FALSE ){
  144. if(q == FALSE)
  145. printf("Warning: Can't read max_brightness-file of '%s'. Will ignore this controller.\n", ep->d_name);
  146. returner.controllers[returner.num_controllers].is_ok = FALSE;
  147. }
  148. /* Get path to current brightness-file */
  149. asprintf(&currctrldir_f, "%s/%s", currctrldir, "brightness");
  150. strncpy(returner.controllers[returner.num_controllers].b_path, currctrldir_f, sizeof(returner.controllers[returner.num_controllers].b_path));
  151. if( is_writable(currctrldir_f) == FALSE){
  152. if(q == FALSE)
  153. printf("Warning: Controllerfile of '%s' is not writable. Will ignore this controller.\n", ep->d_name);
  154. returner.controllers[returner.num_controllers].is_ok = FALSE;
  155. }
  156. returner.num_controllers++;
  157. }
  158. }
  159. closedir(lcdir);
  160. }
  161. return returner;
  162. }
  163. controller* get_best_controller(fetch_result* res){
  164. unsigned int it;
  165. unsigned int cmax;
  166. LBOOL foundokctrl;
  167. controller* returner;
  168. it = 0;
  169. cmax = 0;
  170. foundokctrl = FALSE;
  171. returner = NULL;
  172. while(it < res->num_controllers){
  173. if(res->controllers[it].is_ok == TRUE){
  174. if(foundokctrl != TRUE){
  175. foundokctrl = TRUE;
  176. returner = &res->controllers[it];
  177. }
  178. if(res->controllers[it].max_brightness > cmax){
  179. cmax = res->controllers[it].max_brightness;
  180. returner = &res->controllers[it];
  181. }
  182. }
  183. it++;
  184. }
  185. return returner;
  186. }
  187. controller* get_controller_by_name(fetch_result* res, const char* name){
  188. unsigned int it;
  189. controller* returner;
  190. it = 0;
  191. returner = NULL;
  192. while(it < res->num_controllers){
  193. if(strcmp(res->controllers[it].name, name) == 0){
  194. returner = &res->controllers[it];
  195. }
  196. it++;
  197. }
  198. return returner;
  199. }
  200. void usage(){
  201. printf("Usage: light [-qcaspmfh] [--options] <value>\n\n\tFlags:\n\t-q:\t Run quiet, supresses output.\n\t-c:\t Prints the current brightness in percent and exits.(Not precise)\n\t-p:\t Prints the current brightness directly from controller and exits. (Precise)\n\t-m:\t Prints the max brightness directly from controller and exits. \n\t-a:\t Add the value instead of setting it.\n\t-s:\t Subtract the value instead of setting it.\n\t-h:\t Shows this help and exits.\n");
  202. printf("\n\tOptions:\n\t--help:\t Shows this help and exits.\n\n\t<value>\t Brightness wanted in percent.\n\n");
  203. }
  204. int main(int argc, char **argv) {
  205. unsigned int argsit;
  206. fetch_result res;
  207. controller* best_ctrl;
  208. unsigned int citr;
  209. uid_t uid;
  210. unsigned int minlight;
  211. LBOOL given;
  212. unsigned int real_wbright;
  213. unsigned int minlight_nonp;
  214. unsigned int curr_bright;
  215. unsigned int curr_brightp;
  216. LBOOL useforce;
  217. char* useforce_name;
  218. /* Get UID */
  219. uid = getuid();
  220. useforce = FALSE;
  221. useforce_name = malloc(256*sizeof(char));
  222. /* Parse arguments */
  223. q=FALSE;
  224. c=FALSE;
  225. m=FALSE;
  226. p=FALSE;
  227. ot=SET;
  228. wbright=0;
  229. argsit = 1;
  230. given=FALSE;
  231. while(argsit < argc){
  232. char* carg = argv[argsit];
  233. if(carg[0] == '-'){
  234. LBOOL argdone;
  235. argdone = FALSE;
  236. if(strlen(carg) > 2){
  237. if(carg[1] == '-'){
  238. int longargs = strlen(carg) -2;
  239. char *longarg = (char*) malloc(longargs);
  240. strncpy(longarg, carg+2, longargs);
  241. if(strcmp(longarg, "help") == 0){
  242. usage();
  243. return 0;
  244. }else{
  245. printf("Unknown option: \"%s\".\n", longarg);
  246. return 0;
  247. }
  248. argdone = TRUE;
  249. }
  250. }
  251. if(argdone == FALSE){
  252. unsigned int cargit = 1;
  253. while(cargit < strlen(carg)){
  254. switch(carg[cargit]){
  255. case 'q':
  256. q = TRUE;
  257. break;
  258. case 'a':
  259. ot = ADD;
  260. break;
  261. case 's':
  262. ot = SUB;
  263. break;
  264. case 'c':
  265. c = TRUE;
  266. break;
  267. case 'p':
  268. p = TRUE;
  269. break;
  270. case 'm':
  271. m = TRUE;
  272. break;
  273. case 'h':
  274. usage();
  275. return 0;
  276. break;
  277. default:
  278. printf("Unknown flag: %c\n", carg[cargit]);
  279. return 1;
  280. break;
  281. }
  282. cargit++;
  283. }
  284. }
  285. }else{
  286. wbright = atoi(carg);
  287. given=TRUE;
  288. }
  289. argsit++;
  290. }
  291. if(c == TRUE || m == TRUE || p == TRUE){
  292. q = TRUE;
  293. }
  294. if(given == FALSE && c == FALSE && m == FALSE && p == FALSE){
  295. usage();
  296. return 0;
  297. }
  298. if(q == FALSE)
  299. printf("Light 0.7 - Fredrik Haikarainen\n");
  300. /* Get and check minlight */
  301. if(readint("/etc/light/minlight", &minlight) == FALSE){
  302. minlight = 5;
  303. if(q == FALSE)
  304. printf("Warning: Couldn't read /etc/light/minlight, using 5 as default.\n");
  305. }
  306. /* Fetch controllers */
  307. if(q == FALSE)
  308. printf("Fetching controllers..\n");
  309. res = fetch_controllers("/sys/class/backlight");
  310. citr = 0;
  311. while(citr < res.num_controllers){
  312. controller* currc = &res.controllers[citr];
  313. if(currc->is_ok == TRUE){
  314. if(q == FALSE)
  315. printf("\tFound '%s' (%u/%u)\n", currc->name, currc->current_brightness, currc->max_brightness);
  316. }else{
  317. if(q == FALSE)
  318. printf("\tFound '%s', but ignoring\n", currc->name);
  319. }
  320. citr++;
  321. }
  322. if(q == FALSE)
  323. printf("\n");
  324. /* Read override-file if exists*/
  325. if(readchar("/etc/light/override",useforce_name) == TRUE){
  326. printf("Overriding controller '%s' !\n", useforce_name);
  327. useforce=TRUE;
  328. }
  329. if(useforce == TRUE){
  330. best_ctrl = get_controller_by_name(&res, useforce_name);
  331. if(best_ctrl == NULL){
  332. if(q == FALSE)
  333. printf("Can't override, no such controller. Check/remove your override-file!\n");
  334. return 1;
  335. }
  336. }else{
  337. /* Get the best controller */
  338. best_ctrl = get_best_controller(&res);
  339. if(best_ctrl == NULL){
  340. if(uid == 0){
  341. if(q == FALSE)
  342. printf("No okay controller found, even though you are root! Check your system.\n");
  343. }else{
  344. if(q == FALSE)
  345. printf("No okay controller found, check your permissions or try to run as root.\n");
  346. }
  347. return 1;
  348. }
  349. }
  350. if(p == TRUE){
  351. printf("%u\n", best_ctrl->current_brightness);
  352. return 0;
  353. }
  354. if(m == TRUE){
  355. printf("%u\n", best_ctrl->max_brightness);
  356. return 0;
  357. }
  358. if(q == FALSE)
  359. printf("Using controller '%s' ..\n", best_ctrl->name);
  360. if(wbright < 0){ wbright = 0;}
  361. if(wbright > 100){wbright=100;}
  362. curr_bright = best_ctrl->current_brightness;
  363. curr_brightp = (float)((float)curr_bright / (float)best_ctrl->max_brightness) * 100;
  364. if(c == TRUE){
  365. printf("%u\n", curr_brightp);
  366. return 0;
  367. }
  368. minlight_nonp = best_ctrl->max_brightness * ( (float)minlight / 100) + 1;
  369. switch(ot){
  370. case SET:
  371. real_wbright = best_ctrl->max_brightness * ( (float)wbright / 100 );
  372. break;
  373. case ADD:
  374. real_wbright = ( best_ctrl->max_brightness * ( (float)( curr_brightp + wbright +1) / 100 ));
  375. break;
  376. case SUB:
  377. if(curr_brightp <= wbright){
  378. real_wbright = minlight_nonp;
  379. }else{
  380. real_wbright = ( best_ctrl->max_brightness * ( (float)( curr_brightp - wbright + 1) / 100 ));
  381. }
  382. break;
  383. default:
  384. break;
  385. }
  386. /* FIXME<- SHOULD BE FIXED NOW, LETS STAY HERE ANYWAY JUST IN CASE
  387. Line below makes sure the value never wraps around and gets higher. Puts a (high) limit on max brightness.
  388. Not sure if safe for portabilities sake.
  389. if(real_wbright > ((UINT_MAX/2) - best_ctrl->max_brightness)){ real_wbright = minlight_nonp; }
  390. */
  391. if(real_wbright > best_ctrl->max_brightness){real_wbright = best_ctrl->max_brightness;}
  392. if(real_wbright < minlight_nonp){real_wbright = minlight_nonp;}
  393. if(q == FALSE)
  394. printf("Writing %u to file '%s'..\n", real_wbright, best_ctrl->b_path);
  395. if(writeint(best_ctrl->b_path, real_wbright) == FALSE){
  396. if(q == FALSE){
  397. printf("Error: Could not write to file %s, check your permissions!\n", best_ctrl->b_path);
  398. }
  399. return 1;
  400. }
  401. return 0;
  402. }