changeset 1519:bb4cae772039

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.
author Isaac Dunham <ibid.ag@gmail.com>
date Fri, 10 Oct 2014 09:47:35 -0500
parents 4bfbd8b96f66
children dfd6b3404c16
files toys/other/acpi.c
diffstat 1 files changed, 71 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/toys/other/acpi.c	Thu Oct 09 13:43:32 2014 -0500
+++ b/toys/other/acpi.c	Fri Oct 10 09:47:35 2014 -0500
@@ -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 @@
 GLOBALS(
   int ac;
   int bat;
+  int therm;
+  int cool;
+  char *cpath;
 )
 
 int read_int_at(int dirfd, char *name)
@@ -46,10 +52,10 @@
 
   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 @@
 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);
+
 }