| /* acpi.c - show power state |
| * |
| * Written by Isaac Dunham, 2013 |
| * |
| * No standard. |
| |
| USE_ACPI(NEWTOY(acpi, "abctV", TOYFLAG_USR|TOYFLAG_BIN)) |
| |
| config ACPI |
| bool "acpi" |
| default y |
| help |
| usage: acpi [-abctV] |
| |
| 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 |
| #include "toys.h" |
| |
| GLOBALS( |
| int ac, bat, therm, cool; |
| char *cpath; |
| ) |
| |
| static int read_int_at(int dirfd, char *name) |
| { |
| int fd, ret=0; |
| FILE *fil; |
| |
| if ((fd = openat(dirfd, name, O_RDONLY)) < 0) return -1; |
| if (!fscanf(fil = xfdopen(fd, "r"), "%d", &ret)) perror_exit_raw(name); |
| fclose(fil); |
| |
| return ret; |
| } |
| |
| static int acpi_callback(struct dirtree *tree) |
| { |
| int dfd, fd, len, on; |
| |
| errno = 0; |
| |
| if (tree->name[0]=='.') return 0; |
| |
| if (!tree->parent) |
| return DIRTREE_RECURSE|DIRTREE_SYMFOLLOW; |
| |
| 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); |
| if (len < 1) goto done; |
| |
| if (!strncmp(toybuf, "Battery", 7)) { |
| if ((toys.optflags & FLAG_b) || (!toys.optflags)) { |
| int cap = 0, curr = 0, max = 0; |
| |
| if ((cap = read_int_at(dfd, "capacity")) < 0) { |
| if ((max = read_int_at(dfd, "charge_full")) > 0) |
| curr = read_int_at(dfd, "charge_now"); |
| else if ((max = read_int_at(dfd, "energy_full")) > 0) |
| curr = read_int_at(dfd, "energy_now"); |
| if (max > 0 && curr >= 0) cap = 100 * curr / max; |
| } |
| if (cap >= 0) printf("Battery %d: %d%%\n", TT.bat++, cap); |
| } |
| } else if (toys.optflags & FLAG_a) { |
| if ((on = read_int_at(dfd, "online")) >= 0) |
| printf("Adapter %d: %s-line\n", TT.ac++, (on ? "on" : "off")); |
| } |
| done: |
| close(dfd); |
| } |
| free(TT.cpath); |
| return 0; |
| } |
| |
| static int temp_callback(struct dirtree *tree) |
| { |
| int dfd, temp; |
| |
| if (*tree->name=='.') 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; |
| } |
| |
| static int cool_callback(struct dirtree *tree) |
| { |
| int dfd=5, cur, max; |
| |
| errno = 0; |
| memset(toybuf, 0, sizeof(toybuf)); |
| |
| if (*tree->name == '.') 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) |
| { |
| 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); |
| } |