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 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 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 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 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 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