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;int bat;int therm;int cool;char * cpath;)27 GLOBALS(
28 int ac;
29 int bat;
30 int therm;
31 int cool;
32 char *cpath;
33 )
34
35 int read_int_at(int dirfd, char *name)
36 {
37 int fd, ret=0;
38 FILE *fil;
39
40 if ((fd = openat(dirfd, name, O_RDONLY)) < 0) return -1;
41 if (!fscanf(fil = xfdopen(fd, "r"), "%d", &ret)) perror_exit("%s", name);
42 fclose(fil);
43
44 return ret;
45 }
46
acpi_callback(struct dirtree * tree)47 int acpi_callback(struct dirtree *tree)
48 {
49 int dfd, fd, len, on;
50
51 errno = 0;
52
53 if (tree->name[0]=='.') return 0;
54
55 if (!tree->parent)
56 return DIRTREE_RECURSE|DIRTREE_SYMFOLLOW;
57
58 if (0 <= (dfd = open((TT.cpath=dirtree_path(tree, NULL)), O_RDONLY))) {
59 if ((fd = openat(dfd, "type", O_RDONLY)) < 0) goto done;
60 len = readall(fd, toybuf, sizeof(toybuf));
61 close(fd);
62 if (len < 1) goto done;
63
64 if (!strncmp(toybuf, "Battery", 7)) {
65 if ((toys.optflags & FLAG_b) || (!toys.optflags)) {
66 int cap = 0, curr = 0, max = 0;
67
68 if ((cap = read_int_at(dfd, "capacity")) < 0) {
69 if ((max = read_int_at(dfd, "charge_full")) > 0)
70 curr = read_int_at(dfd, "charge_now");
71 else if ((max = read_int_at(dfd, "energy_full")) > 0)
72 curr = read_int_at(dfd, "energy_now");
73 if (max > 0 && curr >= 0) cap = 100 * curr / max;
74 }
75 if (cap >= 0) printf("Battery %d: %d%%\n", TT.bat++, cap);
76 }
77 } else if (toys.optflags & FLAG_a) {
78 if ((on = read_int_at(dfd, "online")) >= 0)
79 printf("Adapter %d: %s-line\n", TT.ac++, (on ? "on" : "off"));
80 }
81 done:
82 close(dfd);
83 }
84 free(TT.cpath);
85 return 0;
86 }
87
temp_callback(struct dirtree * tree)88 int temp_callback(struct dirtree *tree)
89 {
90 int dfd, temp;
91
92 if (tree->name[0]=='.') return 0;
93 if (!tree->parent || !tree->parent->parent)
94 return DIRTREE_RECURSE|DIRTREE_SYMFOLLOW;
95 errno = 0;
96
97 if (0 <= (dfd = open((TT.cpath=dirtree_path(tree, NULL)), O_RDONLY))) {
98 if ((0 < (temp = read_int_at(dfd, "temp"))) || !errno) {
99 //some tempertures are in milli-C, some in deci-C
100 //reputedly some are in deci-K, but I have not seen them
101 if (((temp >= 1000) || (temp <= -1000)) && (temp%100 == 0))
102 temp /= 100;
103 printf("Thermal %d: %d.%d degrees C\n", TT.therm++, temp/10, temp%10);
104 }
105 close(dfd);
106 }
107 free(TT.cpath);
108 return 0;
109 }
110
cool_callback(struct dirtree * tree)111 int cool_callback(struct dirtree *tree)
112 {
113 int dfd=5, cur, max;
114
115 errno = 0;
116 memset(toybuf, 0, sizeof(toybuf));
117
118 if (*tree->name == '.') return 0;
119 if (!tree->parent) return DIRTREE_RECURSE|DIRTREE_SYMFOLLOW;
120
121
122 if (0 <= (dfd = open((TT.cpath=dirtree_path(tree, &dfd)), O_RDONLY))) {
123 TT.cpath = strcat(TT.cpath, "/type");
124 if (readfile(TT.cpath, toybuf, 256) && !errno) {
125 toybuf[strlen(toybuf) -1] = 0;
126 cur=read_int_at(dfd, "cur_state");
127 max=read_int_at(dfd, "max_state");
128 if (errno)
129 printf("Cooling %d: %s no state information\n", TT.cool++, toybuf);
130 else printf("Cooling %d: %s %d of %d\n", TT.cool++, toybuf, cur, max);
131 }
132 close(dfd);
133 }
134 free(TT.cpath);
135 return 0;
136 }
137
acpi_main(void)138 void acpi_main(void)
139 {
140 if (toys.optflags & FLAG_V) toys.optflags = FLAG_a|FLAG_b|FLAG_c|FLAG_t;
141 if (!toys.optflags) toys.optflags = FLAG_b;
142 if (toys.optflags & (FLAG_a|FLAG_b))
143 dirtree_read("/sys/class/power_supply", acpi_callback);
144 if (toys.optflags & FLAG_t) dirtree_read("/sys/class", temp_callback);
145 if (toys.optflags & FLAG_c) dirtree_read("/sys/class/thermal", cool_callback);
146
147 }
148