toybox/toys/other/acpi.c
<<
>>
Prefs
   1/* acpi.c - show power state
   2 *
   3 * Written by Isaac Dunham, 2013
   4 *
   5 * No standard.
   6
   7USE_ACPI(NEWTOY(acpi, "abctV", TOYFLAG_USR|TOYFLAG_BIN))
   8
   9config 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
  27GLOBALS(
  28  int ac, bat, therm, cool;
  29  char *cpath;
  30)
  31
  32static 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
  44static 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    }
  78done:
  79    close(dfd);
  80  }
  81  free(TT.cpath);
  82  return 0;
  83}
  84
  85static 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
 108static 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
 135void 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