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