[Toybox] [PATCH] acpi: implement -ctV, fix recursion

Isaac Dunham ibid.ag at gmail.com
Thu Oct 9 23:04:38 PDT 2014


acpi: implement -ctV, fix recursion, plug a small leak

* acpi_callback had blindly assumed that a path of 26 chars or more was
  the right depth; rely on depth from dirtree root

* acpi -c shows cooling device state
  some backlights are set up so that they will report dimmer as higher,
  but that's a hardware issue that can't be sanely worked around.

* acpi -t shows temperatures
  this implementation will pick up fan, battery temperatures, etc. 
  (but currently not hwmon-type temperatures, or hdd temps; 
  acpi 1.7 does not measure these either)
  we handle milli-C (typical) and deci-C (I've seen this on Qualcomm 
  batteries, and not yet anywhere else)
  we do *not* handle deci-K yet

* acpi -V shows all sensors

* without saving the result of dirtree_path() to free later, we had 
  a slow leak.
  all callbacks call this once, so save it in GLOBALS()
  acpi -t happens to need this anyhow, though using openat()/readall()
  instead of readfile() would work.

--
If you're reluctant to apply some of it, *please* go ahead and tell me
to redo the patch or break it up. I can afford to rewrite it till it's
good.

The leak mainly got noticed due to the need to modify the path
for cool_callback; I don't think it's really significant on most systems.
If there were a "readfileat()", I wouldn't have bothered.

hwmon-style temperatures would take a bit of thought; I could theoretically
call dirtree_read() within temp_callback()...
Here's the relevant layout of hwmon-style stuff:

/sys/class/thermal/<name>: #or /sys/class/hwmon/...
temp1_input
temp2_input
temp3_input
temp4_input

(the number is unspecified; it could be 8 or more.)
Each file contains temperature in milli-C.

I could modify acpi to work with tests, if I implement -d:
in acpi-1.7, -d allows specifying a directory corresponding to /sys/class.
I would do this by trying to chdir() to the string passed to -d (default
location of /sys/class, of course) and would make paths relative to 
/sys/class.

Thanks,
Isaac Dunham

-------------- next part --------------
diff --git a/toys/other/acpi.c b/toys/other/acpi.c
index 1b31f31..c293e84 100644
--- a/toys/other/acpi.c
+++ b/toys/other/acpi.c
@@ -4,18 +4,21 @@
  *
  * No standard.
 
-USE_ACPI(NEWTOY(acpi, "ab", TOYFLAG_USR|TOYFLAG_BIN))
+USE_ACPI(NEWTOY(acpi, "abctV", TOYFLAG_USR|TOYFLAG_BIN))
 
 config ACPI
   bool "acpi"
   default y
   help
-    usage: acpi [-ab]
+    usage: acpi [-abctV]
     
-    Show status of power sources.
+    Show status of power sources and thermal devices.
 
     -a	show power adapters
     -b	show batteries
+    -c	show cooling device state
+    -t	show temperatures
+    -V	show everything
 */
 
 #define FOR_acpi
@@ -24,6 +27,9 @@ config ACPI
 GLOBALS(
   int ac;
   int bat;
+  int therm;
+  int cool;
+  char *cpath;
 )
 
 int read_int_at(int dirfd, char *name)
@@ -46,10 +52,10 @@ int acpi_callback(struct dirtree *tree)
 
   if (tree->name[0]=='.') return 0;
 
-  if (strlen(dirtree_path(tree, NULL)) < 26)
-    return DIRTREE_RECURSE | DIRTREE_SYMFOLLOW;
+  if (!tree->parent)
+    return DIRTREE_RECURSE|DIRTREE_SYMFOLLOW;
 
-  if (0 <= (dfd = open(dirtree_path(tree, NULL), O_RDONLY))) {
+  if (0 <= (dfd = open((TT.cpath=dirtree_path(tree, NULL)), O_RDONLY))) {
     if ((fd = openat(dfd, "type", O_RDONLY)) < 0) goto done;
     len = readall(fd, toybuf, sizeof(toybuf));
     close(fd);
@@ -75,11 +81,69 @@ int acpi_callback(struct dirtree *tree)
 done:
     close(dfd);
   }
+  free(TT.cpath);
+  return 0;
+}
+
+int temp_callback(struct dirtree *tree)
+{
+  int dfd, temp;
 
+  if (tree->name[0]=='.') return 0;
+  if (!tree->parent || !tree->parent->parent)
+    return DIRTREE_RECURSE|DIRTREE_SYMFOLLOW;
+  errno = 0;
+
+  if (0 <= (dfd = open((TT.cpath=dirtree_path(tree, NULL)), O_RDONLY))) {
+    if ((0 < (temp = read_int_at(dfd, "temp"))) || !errno) {
+      //some tempertures are in milli-C, some in deci-C
+      //reputedly some are in deci-K, but I have not seen them
+      if (((temp >= 1000) || (temp <= -1000)) && (temp%100 == 0))
+        temp /= 100;
+      printf("Thermal %d: %d.%d degrees C\n", TT.therm++, temp/10, temp%10);
+    }
+    close(dfd);
+  }
+  free(TT.cpath);
+  return 0;
+}
+
+int cool_callback(struct dirtree *tree)
+{
+  int dfd=5, cur, max;
+  errno = 0;
+  memset(toybuf, 0, sizeof(toybuf));
+
+  if (tree->name[0]=='.') return 0;
+  if (!tree->parent) return DIRTREE_RECURSE|DIRTREE_SYMFOLLOW;
+
+
+  if (0 <= (dfd = open((TT.cpath=dirtree_path(tree, &dfd)), O_RDONLY))) {
+    TT.cpath = strcat(TT.cpath, "/type");
+    if (readfile(TT.cpath, toybuf, 256) && !errno) {
+      toybuf[strlen(toybuf) -1] = 0;
+      cur=read_int_at(dfd, "cur_state");
+      max=read_int_at(dfd, "max_state");
+      if (errno)
+        printf("Cooling %d: %s no state information\n", TT.cool++, toybuf);
+      else printf("Cooling %d: %s %d of %d\n", TT.cool++, toybuf, cur, max);
+    }
+    close(dfd);
+  }
+  free(TT.cpath);
   return 0;
 }
 
 void acpi_main(void)
 {
-  dirtree_read("/sys/class/power_supply", acpi_callback);
+  if (toys.optflags & FLAG_V)
+    toys.optflags = FLAG_a|FLAG_b|FLAG_c|FLAG_t;
+  if (!toys.optflags) toys.optflags = FLAG_b;
+  if (toys.optflags & (FLAG_a|FLAG_b))
+    dirtree_read("/sys/class/power_supply", acpi_callback);
+  if (toys.optflags & FLAG_t)
+    dirtree_read("/sys/class", temp_callback);
+  if (toys.optflags & FLAG_c)
+    dirtree_read("/sys/class/thermal", cool_callback);
+
 }


More information about the Toybox mailing list