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