• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
GLOBALS(int ac,bat,therm,cool;char * cpath;)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 
acpi_callback(struct dirtree * tree)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 
temp_callback(struct dirtree * tree)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 
cool_callback(struct dirtree * tree)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 
acpi_main(void)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