Home | History | Annotate | Download | only in other
      1 /* acpi.c - show power state
      2  *
      3  * Written by Isaac Dunham, 2013
      4  *
      5  * No standard.
      6 
      7 USE_ACPI(NEWTOY(acpi, "abctV", TOYFLAG_USR|TOYFLAG_BIN))
      8 
      9 config ACPI
     10   bool "acpi"
     11   default y
     12   help
     13     usage: acpi [-abctV]
     14 
     15     Show status of power sources and thermal devices.
     16 
     17     -a	show power adapters
     18     -b	show batteries
     19     -c	show cooling device state
     20     -t	show temperatures
     21     -V	show everything
     22 */
     23 
     24 #define FOR_acpi
     25 #include "toys.h"
     26 
     27 GLOBALS(
     28   int ac, bat, therm, cool;
     29   char *cpath;
     30 )
     31 
     32 static int read_int_at(int dirfd, char *name)
     33 {
     34   int fd, ret=0;
     35   FILE *fil;
     36 
     37   if ((fd = openat(dirfd, name, O_RDONLY)) < 0) return -1;
     38   if (!fscanf(fil = xfdopen(fd, "r"), "%d", &ret)) perror_exit_raw(name);
     39   fclose(fil);
     40 
     41   return ret;
     42 }
     43 
     44 static int acpi_callback(struct dirtree *tree)
     45 {
     46   int dfd, fd, len, on;
     47 
     48   errno = 0;
     49 
     50   if (tree->name[0]=='.') return 0;
     51 
     52   if (!tree->parent)
     53     return DIRTREE_RECURSE|DIRTREE_SYMFOLLOW;
     54 
     55   if (0 <= (dfd = open((TT.cpath=dirtree_path(tree, NULL)), O_RDONLY))) {
     56     if ((fd = openat(dfd, "type", O_RDONLY)) < 0) goto done;
     57     len = readall(fd, toybuf, sizeof(toybuf));
     58     close(fd);
     59     if (len < 1) goto done;
     60 
     61     if (!strncmp(toybuf, "Battery", 7)) {
     62       if ((toys.optflags & FLAG_b) || (!toys.optflags)) {
     63         int cap = 0, curr = 0, max = 0;
     64 
     65         if ((cap = read_int_at(dfd, "capacity")) < 0) {
     66           if ((max = read_int_at(dfd, "charge_full")) > 0)
     67             curr = read_int_at(dfd, "charge_now");
     68           else if ((max = read_int_at(dfd, "energy_full")) > 0)
     69             curr = read_int_at(dfd, "energy_now");
     70           if (max > 0 && curr >= 0) cap = 100 * curr / max;
     71         }
     72         if (cap >= 0) printf("Battery %d: %d%%\n", TT.bat++, cap);
     73       }
     74     } else if (toys.optflags & FLAG_a) {
     75       if ((on = read_int_at(dfd, "online")) >= 0)
     76         printf("Adapter %d: %s-line\n", TT.ac++, (on ? "on" : "off"));
     77     }
     78 done:
     79     close(dfd);
     80   }
     81   free(TT.cpath);
     82   return 0;
     83 }
     84 
     85 static int temp_callback(struct dirtree *tree)
     86 {
     87   int dfd, temp;
     88 
     89   if (*tree->name=='.') return 0;
     90   if (!tree->parent || !tree->parent->parent)
     91     return DIRTREE_RECURSE|DIRTREE_SYMFOLLOW;
     92   errno = 0;
     93 
     94   if (0 <= (dfd = open((TT.cpath=dirtree_path(tree, NULL)), O_RDONLY))) {
     95     if ((0 < (temp = read_int_at(dfd, "temp"))) || !errno) {
     96       //some tempertures are in milli-C, some in deci-C
     97       //reputedly some are in deci-K, but I have not seen them
     98       if (((temp >= 1000) || (temp <= -1000)) && (temp%100 == 0)) temp /= 100;
     99       printf("Thermal %d: %d.%d degrees C\n", TT.therm++, temp/10, temp%10);
    100     }
    101     close(dfd);
    102   }
    103   free(TT.cpath);
    104 
    105   return 0;
    106 }
    107 
    108 static int cool_callback(struct dirtree *tree)
    109 {
    110   int dfd=5, cur, max;
    111 
    112   errno = 0;
    113   memset(toybuf, 0, sizeof(toybuf));
    114 
    115   if (*tree->name == '.') return 0;
    116   if (!tree->parent) return DIRTREE_RECURSE|DIRTREE_SYMFOLLOW;
    117 
    118 
    119   if (0 <= (dfd = open((TT.cpath=dirtree_path(tree, &dfd)), O_RDONLY))) {
    120     TT.cpath = strcat(TT.cpath, "/type");
    121     if (readfile(TT.cpath, toybuf, 256) && !errno) {
    122       toybuf[strlen(toybuf) -1] = 0;
    123       cur=read_int_at(dfd, "cur_state");
    124       max=read_int_at(dfd, "max_state");
    125       if (errno)
    126         printf("Cooling %d: %s no state information\n", TT.cool++, toybuf);
    127       else printf("Cooling %d: %s %d of %d\n", TT.cool++, toybuf, cur, max);
    128     }
    129     close(dfd);
    130   }
    131   free(TT.cpath);
    132   return 0;
    133 }
    134 
    135 void acpi_main(void)
    136 {
    137   if (toys.optflags & FLAG_V) toys.optflags = FLAG_a|FLAG_b|FLAG_c|FLAG_t;
    138   if (!toys.optflags) toys.optflags = FLAG_b;
    139   if (toys.optflags & (FLAG_a|FLAG_b))
    140     dirtree_read("/sys/class/power_supply", acpi_callback);
    141   if (toys.optflags & FLAG_t) dirtree_read("/sys/class", temp_callback);
    142   if (toys.optflags & FLAG_c) dirtree_read("/sys/class/thermal", cool_callback);
    143 }
    144