1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057
  1. #include "light.h"
  2. #include <stdlib.h>
  3. #include <stdio.h>
  4. #include <string.h>
  5. #include <unistd.h>
  6. #include <getopt.h>
  7. #include <sys/stat.h>
  8. #include <errno.h>
  9. void light_defaultConfig()
  10. {
  11. light_Configuration.controllerMode = LIGHT_AUTO;
  12. memset(&light_Configuration.specifiedController, '\0', NAME_MAX + 1);
  13. light_Configuration.operationMode = LIGHT_GET;
  14. light_Configuration.valueMode = LIGHT_PERCENT;
  15. light_Configuration.specifiedValueRaw = 0;
  16. light_Configuration.specifiedValuePercent = 0.0;
  17. light_Configuration.target = LIGHT_BACKLIGHT;
  18. light_Configuration.field = LIGHT_BRIGHTNESS;
  19. light_Configuration.hasCachedMaxBrightness = FALSE;
  20. light_Configuration.cachedMaxBrightness = 0;
  21. light_verbosity = 0;
  22. }
  23. LIGHT_BOOL light_checkOperations()
  24. {
  25. LIGHT_BOOL valid = TRUE;
  26. LIGHT_OP_MODE op = light_Configuration.operationMode;
  27. /* Nothing to check if we just print info */
  28. if(op == LIGHT_PRINT_HELP || op == LIGHT_PRINT_VERSION || op == LIGHT_LIST_CTRL)
  29. {
  30. return TRUE;
  31. }
  32. switch (light_Configuration.field) {
  33. case LIGHT_BRIGHTNESS:
  34. if(op != LIGHT_GET && op != LIGHT_SET &&
  35. op != LIGHT_ADD && op != LIGHT_SUB &&
  36. op != LIGHT_SAVE && op != LIGHT_RESTORE)
  37. {
  38. valid = FALSE;
  39. fprintf(stderr, "Wrong operation specified for brightness. You can use only -G -S -A or -U\n\n");
  40. }
  41. break;
  42. case LIGHT_MAX_BRIGHTNESS:
  43. if(op != LIGHT_GET)
  44. {
  45. valid = FALSE;
  46. fprintf(stderr, "Wrong operation specified for max brightness. You can only use -G\n\n");
  47. }
  48. break;
  49. case LIGHT_MIN_CAP:
  50. if(op != LIGHT_GET && op != LIGHT_SET)
  51. {
  52. valid = FALSE;
  53. fprintf(stderr, "Wrong operation specified for min cap. You can only use -G or -S\n\n");
  54. }
  55. default:
  56. break;
  57. }
  58. return valid;
  59. }
  60. LIGHT_BOOL light_parseArguments(int argc, char** argv)
  61. {
  62. int currFlag;
  63. int verbosity;
  64. LIGHT_BOOL opSet = FALSE;
  65. LIGHT_BOOL targetSet = FALSE;
  66. LIGHT_BOOL fieldSet = FALSE;
  67. LIGHT_BOOL ctrlSet = FALSE;
  68. LIGHT_BOOL valSet = FALSE;
  69. while((currFlag = getopt(argc, argv, "HhVGSAULIObmclkas:prv:")) != -1)
  70. {
  71. switch(currFlag)
  72. {
  73. /* -- Operations -- */
  74. case 'H':
  75. case 'h':
  76. ASSERT_OPSET();
  77. light_Configuration.operationMode = LIGHT_PRINT_HELP;
  78. break;
  79. case 'V':
  80. ASSERT_OPSET();
  81. light_Configuration.operationMode = LIGHT_PRINT_VERSION;
  82. break;
  83. case 'G':
  84. ASSERT_OPSET();
  85. light_Configuration.operationMode = LIGHT_GET;
  86. break;
  87. case 'S':
  88. ASSERT_OPSET();
  89. light_Configuration.operationMode = LIGHT_SET;
  90. break;
  91. case 'A':
  92. ASSERT_OPSET();
  93. light_Configuration.operationMode = LIGHT_ADD;
  94. break;
  95. case 'U':
  96. ASSERT_OPSET();
  97. light_Configuration.operationMode = LIGHT_SUB;
  98. break;
  99. case 'L':
  100. ASSERT_OPSET();
  101. light_Configuration.operationMode = LIGHT_LIST_CTRL;
  102. break;
  103. case 'I':
  104. ASSERT_OPSET();
  105. light_Configuration.operationMode = LIGHT_RESTORE;
  106. break;
  107. case 'O':
  108. ASSERT_OPSET();
  109. light_Configuration.operationMode = LIGHT_SAVE;
  110. break;
  111. /* -- Targets -- */
  112. case 'l':
  113. ASSERT_TARGETSET();
  114. light_Configuration.target = LIGHT_BACKLIGHT;
  115. break;
  116. case 'k':
  117. ASSERT_TARGETSET();
  118. light_Configuration.target = LIGHT_KEYBOARD;
  119. break;
  120. /* -- Fields -- */
  121. case 'b':
  122. ASSERT_FIELDSET();
  123. light_Configuration.field = LIGHT_BRIGHTNESS;
  124. break;
  125. case 'm':
  126. ASSERT_FIELDSET();
  127. light_Configuration.field = LIGHT_MAX_BRIGHTNESS;
  128. break;
  129. case 'c':
  130. ASSERT_FIELDSET();
  131. light_Configuration.field = LIGHT_MIN_CAP;
  132. break;
  133. /* -- Controller selection -- */
  134. case 'a':
  135. ASSERT_CTRLSET();
  136. light_Configuration.controllerMode = LIGHT_AUTO;
  137. break;;
  138. case 's':
  139. ASSERT_CTRLSET();
  140. light_Configuration.controllerMode = LIGHT_SPECIFY;
  141. if(optarg == NULL)
  142. {
  143. fprintf(stderr, "-s NEEDS an argument.\n\n");
  144. light_printHelp();
  145. }
  146. if(!light_validControllerName(optarg))
  147. {
  148. fprintf(stderr, "can't handle controller '%s'\n", optarg);
  149. return FALSE;
  150. }
  151. strncpy(light_Configuration.specifiedController, optarg, NAME_MAX);
  152. light_Configuration.specifiedController[NAME_MAX] = '\0';
  153. break;
  154. /* -- Value modes -- */
  155. case 'p':
  156. ASSERT_VALSET();
  157. light_Configuration.valueMode = LIGHT_PERCENT;
  158. break;
  159. case 'r':
  160. ASSERT_VALSET();
  161. light_Configuration.valueMode = LIGHT_RAW;
  162. break;
  163. /* -- Other -- */
  164. case 'v':
  165. if(optarg == NULL)
  166. {
  167. fprintf(stderr, "-v NEEDS an argument.\n\n");
  168. light_printHelp();
  169. return FALSE;
  170. }
  171. if(sscanf(optarg, "%i", &verbosity) != 1)
  172. {
  173. fprintf(stderr, "-v Verbosity is not specified in a recognizable format.\n\n");
  174. light_printHelp();
  175. return FALSE;
  176. }
  177. if(verbosity < 0 || verbosity > 3)
  178. {
  179. fprintf(stderr, "-v Verbosity has to be between 0 and 3.\n\n");
  180. light_printHelp();
  181. return FALSE;
  182. }
  183. light_verbosity = (LIGHT_LOG_LEVEL)verbosity;
  184. break;
  185. }
  186. }
  187. if(!light_checkOperations())
  188. {
  189. light_printHelp();
  190. return FALSE;
  191. }
  192. /* If we need a <value> (for writing), make sure we have it! */
  193. if(light_Configuration.operationMode == LIGHT_SET ||
  194. light_Configuration.operationMode == LIGHT_ADD ||
  195. light_Configuration.operationMode == LIGHT_SUB)
  196. {
  197. if(argc - optind != 1)
  198. {
  199. fprintf(stderr, "Light needs an argument for <value>.\n\n");
  200. light_printHelp();
  201. return FALSE;
  202. }
  203. if(light_Configuration.valueMode == LIGHT_PERCENT)
  204. {
  205. if(sscanf(argv[optind], "%lf", &light_Configuration.specifiedValuePercent) != 1){
  206. fprintf(stderr, "<value> is not specified in a recognizable format.\n\n");
  207. light_printHelp();
  208. return FALSE;
  209. }
  210. light_Configuration.specifiedValuePercent = light_clampPercent(light_Configuration.specifiedValuePercent);
  211. }else{
  212. if(sscanf(argv[optind], "%lu", &light_Configuration.specifiedValueRaw) != 1){
  213. fprintf(stderr, "<value> is not specified in a recognizable format.\n\n");
  214. light_printHelp();
  215. return FALSE;
  216. }
  217. }
  218. }
  219. return TRUE;
  220. }
  221. void light_printVersion(){
  222. printf("Light %u.%u (%s)\n", LIGHT_VER_MAJOR, LIGHT_VER_MINOR, LIGHT_VER_TYPE);
  223. printf("Copyright (C) %u %s\n", LIGHT_YEAR, LIGHT_AUTHOR);
  224. printf("This is free software, see the source for copying conditions. There is NO\n");
  225. printf("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE\n\n");
  226. }
  227. void light_printHelp(){
  228. printf("Usage: light <options> <value>\n");
  229. printf("<value> has to be either integral(raw mode) or decimal(percent mode) depending on the specified value mode.\n");
  230. printf("<options> can be any of the following:\n\n");
  231. printf("Operations (can not be used in conjunction):\n");
  232. printf(" -H -h:\tPrints this help and exits\n");
  233. printf(" -V:\t\tPrints version info and exits\n");
  234. printf(" -G:\t\tGet value (default)\n");
  235. printf(" -S:\t\tSet value\n");
  236. printf(" -A:\t\tAdd value\n");
  237. printf(" -U:\t\tSubtract value\n");
  238. printf(" -L:\t\tList controllers\n");
  239. printf(" -I:\t\tRestore brightness\n");
  240. printf(" -O:\t\tSave brightness\n\n");
  241. printf("Targets (can not be used in conjunction):\n");
  242. printf(" -l:\t\tAct on screen backlight (default)\n");
  243. printf(" -k:\t\tAct on keyboard backlight\n\n");
  244. printf("Fields (can not be used in conjunction):\n");
  245. printf(" -b:\t\tBrightness (default)\n \t\tUsed with [GSAU]\n\n");
  246. printf(" -m:\t\tMaximum brightness\n \t\tUsed with [G]\n\n");
  247. printf(" -c:\t\tMinimum cap\n \t\tUsed with [GS]\n");
  248. printf(" \t\tG returns null if no minimum cap is set.\n\n");
  249. printf("Controller selection (can not be used in conjunction):\n");
  250. printf(" -a:\t\tSelects controller automatically (default).\n");
  251. printf(" -s:\t\tSpecify controller to use. (needs argument)\n\n");
  252. printf("Value modes (can not be used in conjunction):\n");
  253. printf(" -p:\t\tInterpret <value> as, and output values in, percent. (default)\n");
  254. printf(" -r:\t\tInterpret <value> as, and output values in, raw mode.\n\n");
  255. printf("Other:\n");
  256. printf(" -v:\t\tSets the verbosity level, (needs argument).\n \t\t0: Only outputs read values.\n \t\t1: Read values, Errors.\n \t\t2: Read values, Errors, Warnings.\n \t\t3: Read values, Errors, Warnings, Notices.\n\n");
  257. }
  258. LIGHT_BOOL light_initialize(int argc, char** argv)
  259. {
  260. int mkdirVal;
  261. LIGHT_OP_MODE mode;
  262. light_defaultConfig();
  263. if(!light_parseArguments(argc, argv))
  264. {
  265. LIGHT_ERR("could not parse arguments");
  266. return FALSE;
  267. }
  268. mode = light_Configuration.operationMode;
  269. /* Just return true for operation modes that do not need initialization */
  270. if(mode == LIGHT_PRINT_HELP ||
  271. mode == LIGHT_PRINT_VERSION ||
  272. mode == LIGHT_LIST_CTRL)
  273. {
  274. return TRUE;
  275. }
  276. if(mode == LIGHT_SAVE ||
  277. (mode == LIGHT_SET && light_Configuration.field == LIGHT_MIN_CAP))
  278. {
  279. /* Make sure we have a valid /etc/light directory, as well as mincap and save */
  280. char const * const dirs[5] = {"/etc/light", "/etc/light/mincap", "/etc/light/save", "/etc/light/mincap/kbd", "/etc/light/save/kbd"};
  281. char const * const *dir = dirs;
  282. char const * const direrr = "'%s' does not exist and could not be created, make sure this application is run as root.";
  283. while (dir < dirs + 5)
  284. {
  285. mkdirVal = mkdir(*dir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
  286. if(mkdirVal != 0 && errno != EEXIST)
  287. {
  288. LIGHT_ERR_FMT(direrr, *dir);
  289. return FALSE;
  290. }
  291. ++dir;
  292. }
  293. }
  294. /* Make sure we have a valid controller before we proceed */
  295. if(light_Configuration.controllerMode == LIGHT_AUTO)
  296. {
  297. LIGHT_NOTE("Automatic mode -- finding best controller");
  298. if(!light_getBestController(light_Configuration.specifiedController))
  299. {
  300. LIGHT_ERR("could not find suitable controller");
  301. return FALSE;
  302. }
  303. }
  304. else if(!light_controllerAccessible(light_Configuration.specifiedController))
  305. {
  306. LIGHT_ERR_FMT("selected controller '%s' is not valid",
  307. light_Configuration.specifiedController);
  308. return FALSE;
  309. }
  310. return TRUE;
  311. }
  312. /* Print help and version info */
  313. LIGHT_BOOL light_handleInfo()
  314. {
  315. if(light_Configuration.operationMode == LIGHT_PRINT_HELP)
  316. {
  317. light_printHelp();
  318. return TRUE;
  319. }
  320. if(light_Configuration.operationMode == LIGHT_PRINT_VERSION)
  321. {
  322. light_printVersion();
  323. return TRUE;
  324. }
  325. if(light_Configuration.operationMode == LIGHT_LIST_CTRL)
  326. {
  327. /* listControllers() can return FALSE, but only if it does not find any controllers. That is not enough for an unsuccessfull run. */
  328. light_listControllers();
  329. return TRUE;
  330. }
  331. return FALSE;
  332. }
  333. LIGHT_BOOL light_initExecution(unsigned long *rawCurr, unsigned long *rawMax, LIGHT_BOOL *hasMinCap, unsigned long *minCap)
  334. {
  335. if(light_Configuration.hasCachedMaxBrightness)
  336. {
  337. *rawMax = light_Configuration.cachedMaxBrightness;
  338. }
  339. else if(!light_getMaxBrightness(light_Configuration.specifiedController, rawMax))
  340. {
  341. LIGHT_ERR("could not get max brightness");
  342. return FALSE;
  343. }
  344. /* No need to go further if targetting mincap */
  345. if(light_Configuration.field == LIGHT_MIN_CAP ||
  346. light_Configuration.field == LIGHT_MAX_BRIGHTNESS)
  347. {
  348. /* Init other values to 0 */
  349. *rawCurr = *minCap = 0;
  350. *hasMinCap = FALSE;
  351. return TRUE;
  352. }
  353. if(!light_getBrightness(light_Configuration.specifiedController, rawCurr))
  354. {
  355. LIGHT_ERR("could not get brightness");
  356. return FALSE;
  357. }
  358. if(!light_getMinCap(light_Configuration.specifiedController, hasMinCap, minCap))
  359. {
  360. LIGHT_ERR("could not get min brightness");
  361. return FALSE;
  362. }
  363. if( *hasMinCap && *minCap > *rawMax )
  364. {
  365. LIGHT_WARN_FMT("invalid minimum cap (raw) value of '%lu' for controller, ignoring and using 0", *minCap);
  366. LIGHT_WARN_FMT("minimum cap must be inferior to '%lu'", *rawMax);
  367. minCap = 0;
  368. }
  369. return TRUE;
  370. }
  371. LIGHT_BOOL light_execute()
  372. {
  373. unsigned long rawCurr; /* The current brightness, in raw units */
  374. double percentCurr; /* The current brightness, in percent */
  375. unsigned long rawMax; /* The max brightness, in percent */
  376. unsigned long minCap; /* The minimum cap, in raw units */
  377. double percentMinCap; /* The minimum cap, in percent */
  378. LIGHT_BOOL hasMinCap; /* If we have a minimum cap */
  379. LIGHT_VAL_MODE valueMode;
  380. if(light_handleInfo())
  381. {
  382. return TRUE;
  383. }
  384. if(!light_initExecution(&rawCurr, &rawMax, &hasMinCap, &minCap))
  385. {
  386. return FALSE;
  387. }
  388. valueMode = light_Configuration.valueMode;
  389. percentCurr = light_clampPercent(((double)rawCurr) / ((double)rawMax) * 100);
  390. percentMinCap = light_clampPercent(((double)minCap) / ((double)rawMax) * 100);
  391. LIGHT_NOTE_FMT("executing light on '%s' controller", light_Configuration.specifiedController);
  392. /* Handle get operations */
  393. if(light_Configuration.operationMode == LIGHT_GET)
  394. {
  395. switch(light_Configuration.field){
  396. case LIGHT_BRIGHTNESS:
  397. (valueMode == LIGHT_RAW) ? printf("%lu\n", rawCurr) : printf("%.2f\n", percentCurr);
  398. break;
  399. case LIGHT_MAX_BRIGHTNESS:
  400. (valueMode == LIGHT_RAW) ? printf("%lu\n", rawMax) : printf("100.00\n"); /* <- I know how stupid it is but it might just make someones life easier */
  401. break;
  402. case LIGHT_MIN_CAP:
  403. (valueMode == LIGHT_RAW) ? printf("%lu\n", minCap) : printf("%.2f\n", percentMinCap);
  404. break;
  405. case LIGHT_SAVERESTORE:
  406. break;
  407. }
  408. return TRUE;
  409. }
  410. /* Handle saves and restores*/
  411. if(light_Configuration.operationMode == LIGHT_SAVE){
  412. if(!light_saveBrightness(light_Configuration.specifiedController, rawCurr))
  413. {
  414. LIGHT_ERR("could not save brightness");
  415. return FALSE;
  416. }
  417. return TRUE;
  418. }
  419. if(light_Configuration.operationMode == LIGHT_RESTORE){
  420. if(!light_restoreBrightness(light_Configuration.specifiedController)){
  421. LIGHT_ERR("could not restore brightness");
  422. return FALSE;
  423. }
  424. return TRUE;
  425. }
  426. /* Handle set/add/sub operations */
  427. if(light_Configuration.operationMode == LIGHT_SET ||
  428. light_Configuration.operationMode == LIGHT_ADD ||
  429. light_Configuration.operationMode == LIGHT_SUB)
  430. {
  431. unsigned long specValueRaw = valueMode == LIGHT_RAW ?
  432. light_Configuration.specifiedValueRaw :
  433. (unsigned long) ( (light_Configuration.specifiedValuePercent * ((double)rawMax)) / 100.0);
  434. if(light_Configuration.field == LIGHT_MIN_CAP)
  435. {
  436. /* Handle minimum cap files */
  437. if(!light_setMinCap(light_Configuration.specifiedController, LIGHT_CLAMP(specValueRaw, 0, rawMax)))
  438. {
  439. LIGHT_ERR("could not set minimum cap");
  440. return FALSE;
  441. }
  442. /* All good? Return true. */
  443. return TRUE;
  444. }else if(light_Configuration.field == LIGHT_BRIGHTNESS){
  445. /* Handle brightness writing */
  446. unsigned long writeVal;
  447. switch(light_Configuration.operationMode)
  448. {
  449. case LIGHT_SET:
  450. writeVal = LIGHT_CLAMP(specValueRaw, minCap, rawMax);
  451. break;
  452. case LIGHT_ADD:
  453. writeVal = LIGHT_CLAMP(rawCurr + specValueRaw, minCap, rawMax);
  454. break;
  455. case LIGHT_SUB:
  456. /* check if we're going below 0, which wouldn't work with unsigned values */
  457. if(rawCurr < specValueRaw)
  458. {
  459. light_logInfClamp(minCap);
  460. writeVal = minCap;
  461. break;
  462. }
  463. writeVal = LIGHT_CLAMP(rawCurr - specValueRaw, minCap, rawMax);
  464. break;
  465. /* we have already taken other possibilities, so we shouldn't get here */
  466. default:
  467. return FALSE;
  468. }
  469. /* Attempt to write */
  470. if(!light_setBrightness(light_Configuration.specifiedController, writeVal))
  471. {
  472. LIGHT_ERR("could not set brightness");
  473. return FALSE;
  474. }
  475. /* All good? return true. */
  476. return TRUE;
  477. }
  478. }
  479. /* Handle saves and restores*/
  480. if(light_Configuration.operationMode == LIGHT_SAVE){
  481. if(!light_saveBrightness(light_Configuration.specifiedController, rawCurr))
  482. {
  483. LIGHT_ERR("could not save brightness");
  484. return FALSE;
  485. }
  486. return TRUE;
  487. }
  488. if(light_Configuration.operationMode == LIGHT_RESTORE){
  489. if(!light_restoreBrightness(light_Configuration.specifiedController)){
  490. LIGHT_ERR("could not restore brightness");
  491. return FALSE;
  492. }
  493. return TRUE;
  494. }
  495. fprintf(stderr, "Controller: %s\nValueRaw: %lu\nValuePercent: %.2f\nOpMode: %u\nValMode: %u\nField: %u\n\n", light_Configuration.specifiedController, light_Configuration.specifiedValueRaw, light_Configuration.specifiedValuePercent, light_Configuration.operationMode, valueMode, light_Configuration.field);
  496. fprintf(stderr, "You did not specify a valid combination of commandline arguments. Have some help: \n");
  497. light_printHelp();
  498. return FALSE;
  499. }
  500. void light_free()
  501. {
  502. }
  503. LIGHT_BOOL light_validControllerName(char const *controller)
  504. {
  505. if(!controller)
  506. {
  507. return FALSE;
  508. }
  509. if(strlen(controller) > NAME_MAX)
  510. {
  511. LIGHT_WARN_FMT("controller \"%s\"'s name is too long", controller);
  512. return FALSE;
  513. }
  514. return TRUE;
  515. }
  516. LIGHT_BOOL light_genPath(char const *controller, LIGHT_TARGET target, LIGHT_FIELD type, char **buffer)
  517. {
  518. char* returner;
  519. int spfVal = -1;
  520. if(!light_validControllerName(controller))
  521. {
  522. LIGHT_ERR("invalid controller, couldn't generate path");
  523. return FALSE;
  524. }
  525. if(!buffer)
  526. {
  527. LIGHT_ERR("a valid buffer is required");
  528. return FALSE;
  529. }
  530. *buffer = NULL;
  531. /* PATH_MAX define includes the '\0' character, so no + 1 here*/
  532. if((returner = malloc(PATH_MAX)) == NULL)
  533. {
  534. LIGHT_MEMERR();
  535. return FALSE;
  536. }
  537. if(target == LIGHT_BACKLIGHT)
  538. {
  539. switch(type)
  540. {
  541. case LIGHT_BRIGHTNESS:
  542. spfVal = snprintf(returner, PATH_MAX, "/sys/class/backlight/%s/brightness", controller);
  543. break;
  544. case LIGHT_MAX_BRIGHTNESS:
  545. spfVal = snprintf(returner, PATH_MAX, "/sys/class/backlight/%s/max_brightness", controller);
  546. break;
  547. case LIGHT_MIN_CAP:
  548. spfVal = snprintf(returner, PATH_MAX, "/etc/light/mincap/%s", controller);
  549. break;
  550. case LIGHT_SAVERESTORE:
  551. spfVal = snprintf(returner, PATH_MAX, "/etc/light/save/%s", controller);
  552. break;
  553. }
  554. }else{
  555. switch(type)
  556. {
  557. case LIGHT_BRIGHTNESS:
  558. spfVal = snprintf(returner, PATH_MAX, "/sys/class/leds/%s/brightness", controller);
  559. break;
  560. case LIGHT_MAX_BRIGHTNESS:
  561. spfVal = snprintf(returner, PATH_MAX, "/sys/class/leds/%s/max_brightness", controller);
  562. break;
  563. case LIGHT_MIN_CAP:
  564. spfVal = snprintf(returner, PATH_MAX, "/etc/light/mincap/kbd/%s", controller);
  565. break;
  566. case LIGHT_SAVERESTORE:
  567. spfVal = snprintf(returner, PATH_MAX, "/etc/light/save/kbd/%s", controller);
  568. break;
  569. }
  570. }
  571. if(spfVal < 0)
  572. {
  573. LIGHT_ERR("snprintf failed");
  574. free(returner);
  575. return FALSE;
  576. }
  577. /* PATH_MAX define includes the '\0' character, so - 1 here*/
  578. if(spfVal > PATH_MAX - 1)
  579. {
  580. LIGHT_ERR("generated path is too long to be handled");
  581. return FALSE;
  582. }
  583. *buffer = returner;
  584. return TRUE;
  585. }
  586. LIGHT_BOOL light_getBrightnessPath(char const *controller, char **path)
  587. {
  588. if(!light_genPath(controller, light_Configuration.target, LIGHT_BRIGHTNESS, path))
  589. {
  590. LIGHT_ERR("could not generate path to brightness file");
  591. return FALSE;
  592. }
  593. return TRUE;
  594. }
  595. LIGHT_BOOL light_getBrightness(char const *controller, unsigned long *v)
  596. {
  597. char *brightnessPath = NULL;
  598. LIGHT_BOOL readVal = FALSE;
  599. if(!light_getBrightnessPath(controller, &brightnessPath))
  600. {
  601. return FALSE;
  602. }
  603. readVal = light_readULong( brightnessPath , v);
  604. free(brightnessPath);
  605. if(!readVal)
  606. {
  607. LIGHT_ERR("could not read value from brightness file");
  608. return FALSE;
  609. }
  610. return TRUE;
  611. }
  612. LIGHT_BOOL light_getMaxBrightnessPath(char const *controller, char **path)
  613. {
  614. if(!light_genPath(controller, light_Configuration.target, LIGHT_MAX_BRIGHTNESS, path))
  615. {
  616. LIGHT_ERR("could not generate path to maximum brightness file");
  617. return FALSE;
  618. }
  619. return TRUE;
  620. }
  621. LIGHT_BOOL light_getMaxBrightness(char const *controller, unsigned long *v)
  622. {
  623. char *maxPath = NULL;
  624. LIGHT_BOOL readVal = FALSE;
  625. if (!light_getMaxBrightnessPath(controller, &maxPath))
  626. {
  627. return FALSE;
  628. }
  629. readVal = light_readULong(maxPath , v);
  630. free(maxPath);
  631. if(!readVal)
  632. {
  633. LIGHT_ERR("could not read value from max brightness file");
  634. return FALSE;
  635. }
  636. if(*v == 0)
  637. {
  638. LIGHT_ERR("max brightness is 0, so controller is not valid");
  639. return FALSE;
  640. }
  641. return TRUE;
  642. }
  643. LIGHT_BOOL light_setBrightness(char const *controller, unsigned long v)
  644. {
  645. char *brightnessPath = NULL;
  646. LIGHT_BOOL writeVal = FALSE;
  647. if(!light_genPath(controller, light_Configuration.target, light_Configuration.field, &brightnessPath))
  648. {
  649. LIGHT_ERR("could not generate path to brightness file");
  650. return FALSE;
  651. }
  652. LIGHT_NOTE_FMT("setting brightness %lu (raw) to controller", v);
  653. writeVal = light_writeULong(brightnessPath, v);
  654. if(!writeVal)
  655. {
  656. LIGHT_ERR("could not write value to brightness file");
  657. }
  658. free(brightnessPath);
  659. return writeVal;
  660. }
  661. LIGHT_BOOL light_controllerAccessible(char const *controller)
  662. {
  663. char *brightnessPath = NULL;
  664. /* On auto mode, we need to check if we can read the max brightness value
  665. of the controller for later computation */
  666. if(light_Configuration.controllerMode == LIGHT_AUTO ||
  667. light_Configuration.field == LIGHT_MAX_BRIGHTNESS)
  668. {
  669. if(!light_getMaxBrightnessPath(controller, &brightnessPath))
  670. {
  671. return FALSE;
  672. }
  673. if(!light_isReadable(brightnessPath))
  674. {
  675. LIGHT_WARN("could not open controller max brightness file for reading, so controller is not accessible");
  676. free(brightnessPath);
  677. return FALSE;
  678. }
  679. free(brightnessPath);
  680. }
  681. if(!light_getBrightnessPath(controller, &brightnessPath))
  682. {
  683. return FALSE;
  684. }
  685. if(light_Configuration.operationMode != LIGHT_GET &&
  686. light_Configuration.field != LIGHT_MIN_CAP &&
  687. !light_isWritable(brightnessPath))
  688. {
  689. LIGHT_WARN("could not open controller brightness file for writing, so controller is not accessible");
  690. free(brightnessPath);
  691. return FALSE;
  692. }
  693. else if (!light_isReadable(brightnessPath))
  694. {
  695. LIGHT_WARN("could not open controller brightness file for reading, so controller is not accessible");
  696. free(brightnessPath);
  697. return FALSE;
  698. }
  699. free(brightnessPath);
  700. return TRUE;
  701. }
  702. LIGHT_BOOL light_prepareControllerIteration(DIR **dir)
  703. {
  704. if(!dir)
  705. {
  706. LIGHT_ERR("specified dir was NULL");
  707. return FALSE;
  708. }
  709. if(light_Configuration.target == LIGHT_KEYBOARD)
  710. {
  711. *dir = opendir("/sys/class/leds");
  712. }
  713. else
  714. {
  715. *dir = opendir("/sys/class/backlight");
  716. }
  717. if(dir == NULL)
  718. {
  719. LIGHT_ERR("could not open backlight or leds directory in /sys/class");
  720. return FALSE;
  721. }
  722. return TRUE;
  723. }
  724. LIGHT_BOOL light_iterateControllers(DIR *dir, char *currentController)
  725. {
  726. struct dirent *file;
  727. LIGHT_BOOL controllerFound = FALSE;
  728. if(!dir || !currentController)
  729. {
  730. LIGHT_ERR("one of the arguments was NULL");
  731. return FALSE;
  732. }
  733. while(!controllerFound)
  734. {
  735. file = readdir(dir);
  736. if(file == NULL)
  737. {
  738. return FALSE;
  739. }
  740. if(file->d_name[0] != '.')
  741. {
  742. if(!light_validControllerName(file->d_name))
  743. {
  744. LIGHT_WARN_FMT("invalid controller '%s' found, continuing...", file->d_name);
  745. continue;
  746. }
  747. controllerFound = TRUE;
  748. }
  749. }
  750. strncpy(currentController, file->d_name, NAME_MAX);
  751. currentController[NAME_MAX] = '\0';
  752. return TRUE;
  753. }
  754. LIGHT_BOOL light_getBestController(char *controller)
  755. {
  756. DIR *dir;
  757. unsigned long bestValYet = 0;
  758. LIGHT_BOOL foundOkController = FALSE;
  759. char bestYet[NAME_MAX + 1];
  760. char currentController[NAME_MAX + 1];
  761. if(!controller)
  762. {
  763. LIGHT_ERR("controller buffer was NULL");
  764. return FALSE;
  765. }
  766. if(!light_prepareControllerIteration(&dir))
  767. {
  768. LIGHT_ERR("can't list controllers");
  769. return FALSE;
  770. }
  771. while(light_iterateControllers(dir, currentController))
  772. {
  773. unsigned long currVal = 0;
  774. LIGHT_NOTE_FMT("found '%s' controller", currentController);
  775. if(light_controllerAccessible(currentController))
  776. {
  777. if(light_getMaxBrightness(currentController, &currVal))
  778. {
  779. if(currVal > bestValYet)
  780. {
  781. foundOkController = TRUE;
  782. bestValYet = currVal;
  783. strncpy(bestYet, currentController, NAME_MAX);
  784. bestYet[NAME_MAX] = '\0';
  785. light_Configuration.hasCachedMaxBrightness = TRUE;
  786. light_Configuration.cachedMaxBrightness = currVal;
  787. }else{
  788. LIGHT_NOTE("ignoring controller as better one already found");
  789. }
  790. }else{
  791. LIGHT_WARN("could not read max brightness from file");
  792. }
  793. }else{
  794. LIGHT_WARN("controller not accessible");
  795. }
  796. }
  797. closedir(dir);
  798. if(!foundOkController)
  799. {
  800. LIGHT_ERR("could not find an accessible controller");
  801. return FALSE;
  802. }
  803. if(bestValYet == 0)
  804. {
  805. LIGHT_ERR("found accessible controller but it's useless/corrupt");
  806. return FALSE;
  807. }
  808. strncpy(controller, bestYet, NAME_MAX);
  809. controller[NAME_MAX] = '\0';
  810. return TRUE;
  811. }
  812. LIGHT_BOOL light_getMinCap(char const * controller, LIGHT_BOOL * hasMinCap, unsigned long * minCap)
  813. {
  814. char * mincapPath = NULL;
  815. if(!light_genPath(controller, light_Configuration.target, LIGHT_MIN_CAP, &mincapPath))
  816. {
  817. LIGHT_ERR("could not generate path to minimum cap file");
  818. return FALSE;
  819. }
  820. if(!light_isReadable(mincapPath)){
  821. *hasMinCap = FALSE;
  822. *minCap = 0;
  823. free(mincapPath);
  824. LIGHT_NOTE("cap file doesn't exist or can't read from it, so assuming a minimum brightness of 0");
  825. return TRUE;
  826. }
  827. if(!light_readULong(mincapPath, minCap))
  828. {
  829. LIGHT_ERR("could not read minimum cap from file");
  830. free(mincapPath);
  831. return FALSE;
  832. }
  833. *hasMinCap = TRUE;
  834. free(mincapPath);
  835. return TRUE;
  836. }
  837. LIGHT_BOOL light_setMinCap(char const * controller, unsigned long v)
  838. {
  839. char * mincapPath = NULL;
  840. if(!light_genPath(controller, light_Configuration.target, LIGHT_MIN_CAP, &mincapPath))
  841. {
  842. LIGHT_ERR("could not generate path to minimum cap file");
  843. return FALSE;
  844. }
  845. LIGHT_NOTE_FMT("setting minimum cap to %lu (raw)", v);
  846. if(!light_writeULong(mincapPath, v))
  847. {
  848. LIGHT_ERR("could not write to minimum cap file");
  849. free(mincapPath);
  850. return FALSE;
  851. }
  852. free(mincapPath);
  853. return TRUE;
  854. }
  855. LIGHT_BOOL light_listControllers()
  856. {
  857. DIR *dir;
  858. char controller[NAME_MAX + 1];
  859. LIGHT_BOOL foundController = FALSE;
  860. if(!light_prepareControllerIteration(&dir))
  861. {
  862. LIGHT_ERR("can't list controllers");
  863. return FALSE;
  864. }
  865. while(light_iterateControllers(dir, controller))
  866. {
  867. printf("%s\n", controller);
  868. foundController = TRUE;
  869. }
  870. if(!foundController)
  871. {
  872. LIGHT_WARN("no controllers found, either check your system or your permissions");
  873. return FALSE;
  874. }
  875. return TRUE;
  876. }
  877. LIGHT_BOOL light_saveBrightness(char const *controller, unsigned long v){
  878. char *savePath = NULL;
  879. if(!light_genPath(controller, light_Configuration.target, LIGHT_SAVERESTORE, &savePath))
  880. {
  881. LIGHT_ERR("could not generate path to save/restore file");
  882. return FALSE;
  883. }
  884. LIGHT_NOTE_FMT("saving brightness %lu (raw) to save file\n", v);
  885. if(!light_writeULong(savePath, v))
  886. {
  887. LIGHT_ERR("could not write to save/restore file");
  888. free(savePath);
  889. return FALSE;
  890. }
  891. free(savePath);
  892. return TRUE;
  893. }
  894. LIGHT_BOOL light_restoreBrightness(char const *controller){
  895. char *restorePath = NULL;
  896. unsigned long v = 0;
  897. if(!light_genPath(controller, light_Configuration.target, LIGHT_SAVERESTORE, &restorePath))
  898. {
  899. LIGHT_ERR("could not generate path to save/restore file");
  900. return FALSE;
  901. }
  902. LIGHT_NOTE("restoring brightness from saved file");
  903. if(!light_readULong(restorePath, &v))
  904. {
  905. LIGHT_ERR("could not read saved value");
  906. free(restorePath);
  907. return FALSE;
  908. }
  909. if(!light_setBrightness(controller, v))
  910. {
  911. LIGHT_ERR("could not set restored brightness");
  912. free(restorePath);
  913. return FALSE;
  914. }
  915. free(restorePath);
  916. return TRUE;
  917. }