battery.c (4803B)
1 /* See LICENSE file for copyright and license details. */ 2 #include <stdio.h> 3 #include <string.h> 4 5 #include "../util.h" 6 7 #if defined(__linux__) 8 #include <limits.h> 9 #include <stdint.h> 10 #include <unistd.h> 11 12 static const char * 13 pick(const char *bat, const char *f1, const char *f2, char *path, 14 size_t length) 15 { 16 if (esnprintf(path, length, f1, bat) > 0 && 17 access(path, R_OK) == 0) { 18 return f1; 19 } 20 21 if (esnprintf(path, length, f2, bat) > 0 && 22 access(path, R_OK) == 0) { 23 return f2; 24 } 25 26 return NULL; 27 } 28 29 const char * 30 battery_perc(const char *bat) 31 { 32 int perc; 33 char path[PATH_MAX]; 34 35 if (esnprintf(path, sizeof(path), 36 "/sys/class/power_supply/%s/capacity", bat) < 0) { 37 return NULL; 38 } 39 if (pscanf(path, "%d", &perc) != 1) { 40 return NULL; 41 } 42 43 return bprintf("%d", perc); 44 } 45 46 const char * 47 battery_state(const char *bat) 48 { 49 static struct { 50 char *state; 51 char *symbol; 52 } map[] = { 53 { "Charging", "+" }, 54 { "Discharging", "-" }, 55 }; 56 size_t i; 57 char path[PATH_MAX], state[12]; 58 59 if (esnprintf(path, sizeof(path), 60 "/sys/class/power_supply/%s/status", bat) < 0) { 61 return NULL; 62 } 63 if (pscanf(path, "%12s", state) != 1) { 64 return NULL; 65 } 66 67 for (i = 0; i < LEN(map); i++) { 68 if (!strcmp(map[i].state, state)) { 69 break; 70 } 71 } 72 return (i == LEN(map)) ? "?" : map[i].symbol; 73 } 74 75 const char * 76 battery_remaining(const char *bat) 77 { 78 uintmax_t charge_now, current_now, m, h; 79 double timeleft; 80 char path[PATH_MAX], state[12]; 81 82 if (esnprintf(path, sizeof(path), 83 "/sys/class/power_supply/%s/status", bat) < 0) { 84 return NULL; 85 } 86 if (pscanf(path, "%12s", state) != 1) { 87 return NULL; 88 } 89 90 if (!pick(bat, "/sys/class/power_supply/%s/charge_now", 91 "/sys/class/power_supply/%s/energy_now", path, 92 sizeof(path)) || 93 pscanf(path, "%ju", &charge_now) < 0) { 94 return NULL; 95 } 96 97 if (!strcmp(state, "Discharging")) { 98 if (!pick(bat, "/sys/class/power_supply/%s/current_now", 99 "/sys/class/power_supply/%s/power_now", path, 100 sizeof(path)) || 101 pscanf(path, "%ju", ¤t_now) < 0) { 102 return NULL; 103 } 104 105 if (current_now == 0) { 106 return NULL; 107 } 108 109 timeleft = (double)charge_now / (double)current_now; 110 h = timeleft; 111 m = (timeleft - (double)h) * 60; 112 113 return bprintf("%juh %jum", h, m); 114 } 115 116 return ""; 117 } 118 #elif defined(__OpenBSD__) 119 #include <fcntl.h> 120 #include <machine/apmvar.h> 121 #include <sys/ioctl.h> 122 #include <unistd.h> 123 124 static int 125 load_apm_power_info(struct apm_power_info *apm_info) 126 { 127 int fd; 128 129 fd = open("/dev/apm", O_RDONLY); 130 if (fd < 0) { 131 warn("open '/dev/apm':"); 132 return 0; 133 } 134 135 memset(apm_info, 0, sizeof(struct apm_power_info)); 136 if (ioctl(fd, APM_IOC_GETPOWER, apm_info) < 0) { 137 warn("ioctl 'APM_IOC_GETPOWER':"); 138 close(fd); 139 return 0; 140 } 141 return close(fd), 1; 142 } 143 144 const char * 145 battery_perc(const char *unused) 146 { 147 struct apm_power_info apm_info; 148 149 if (load_apm_power_info(&apm_info)) { 150 return bprintf("%d", apm_info.battery_life); 151 } 152 153 return NULL; 154 } 155 156 const char * 157 battery_state(const char *unused) 158 { 159 struct { 160 unsigned int state; 161 char *symbol; 162 } map[] = { 163 { APM_AC_ON, "+" }, 164 { APM_AC_OFF, "-" }, 165 }; 166 struct apm_power_info apm_info; 167 size_t i; 168 169 if (load_apm_power_info(&apm_info)) { 170 for (i = 0; i < LEN(map); i++) { 171 if (map[i].state == apm_info.ac_state) { 172 break; 173 } 174 } 175 return (i == LEN(map)) ? "?" : map[i].symbol; 176 } 177 178 return NULL; 179 } 180 181 const char * 182 battery_remaining(const char *unused) 183 { 184 struct apm_power_info apm_info; 185 186 if (load_apm_power_info(&apm_info)) { 187 if (apm_info.ac_state != APM_AC_ON) { 188 return bprintf("%uh %02um", 189 apm_info.minutes_left / 60, 190 apm_info.minutes_left % 60); 191 } else { 192 return ""; 193 } 194 } 195 196 return NULL; 197 } 198 #elif defined(__FreeBSD__) 199 #include <sys/sysctl.h> 200 201 const char * 202 battery_perc(const char *unused) 203 { 204 int cap; 205 size_t len; 206 207 len = sizeof(cap); 208 if (sysctlbyname("hw.acpi.battery.life", &cap, &len, NULL, 0) == -1 209 || !len) 210 return NULL; 211 212 return bprintf("%d", cap); 213 } 214 215 const char * 216 battery_state(const char *unused) 217 { 218 int state; 219 size_t len; 220 221 len = sizeof(state); 222 if (sysctlbyname("hw.acpi.battery.state", &state, &len, NULL, 0) == -1 223 || !len) 224 return NULL; 225 226 switch(state) { 227 case 0: 228 case 2: 229 return "+"; 230 case 1: 231 return "-"; 232 default: 233 return "?"; 234 } 235 } 236 237 const char * 238 battery_remaining(const char *unused) 239 { 240 int rem; 241 size_t len; 242 243 len = sizeof(rem); 244 if (sysctlbyname("hw.acpi.battery.time", &rem, &len, NULL, 0) == -1 245 || !len 246 || rem == -1) 247 return NULL; 248 249 return bprintf("%uh %02um", rem / 60, rem % 60); 250 } 251 #endif