1 /* $OpenBSD: apm.c,v 1.37 2020/09/23 05:50:26 jca Exp $ */ 2 3 /* 4 * Copyright (c) 1996 John T. Kohl 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 22 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 27 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 * 30 */ 31 32 #include <sys/types.h> 33 #include <sys/sysctl.h> 34 #include <sys/socket.h> 35 #include <sys/un.h> 36 #include <sys/ioctl.h> 37 #include <machine/apmvar.h> 38 #include <stdio.h> 39 #include <stdlib.h> 40 #include <unistd.h> 41 #include <fcntl.h> 42 #include <errno.h> 43 #include <err.h> 44 #include <string.h> 45 #include "pathnames.h" 46 #include "apm-proto.h" 47 48 #define FALSE 0 49 #define TRUE 1 50 51 extern char *__progname; 52 53 static int do_zzz(int, enum apm_action); 54 static int open_socket(const char *); 55 static int send_command(int, struct apm_command *, 56 struct apm_reply *); 57 static __dead void usage(void); 58 static __dead void zzusage(void); 59 60 static __dead void 61 usage(void) 62 { 63 fprintf(stderr,"usage: %s [-AabHLlmPSvZz] [-f sockname]\n", 64 __progname); 65 exit(1); 66 } 67 68 static __dead void 69 zzusage(void) 70 { 71 fprintf(stderr,"usage: %s [-SZz] [-f sockname]\n", 72 __progname); 73 exit(1); 74 } 75 76 static int 77 send_command(int fd, struct apm_command *cmd, struct apm_reply *reply) 78 { 79 /* send a command to the apm daemon */ 80 cmd->vno = APMD_VNO; 81 82 if (send(fd, cmd, sizeof(*cmd), 0) == sizeof(*cmd)) { 83 if (recv(fd, reply, sizeof(*reply), 0) != sizeof(*reply)) { 84 warn("invalid reply from APM daemon"); 85 return (1); 86 } 87 } else { 88 warn("invalid send to APM daemon"); 89 return (1); 90 } 91 return (0); 92 } 93 94 static int 95 do_zzz(int fd, enum apm_action action) 96 { 97 struct apm_command command; 98 struct apm_reply reply; 99 char *msg; 100 101 switch (action) { 102 case NONE: 103 case SUSPEND: 104 command.action = SUSPEND; 105 msg = "Suspending system"; 106 break; 107 case STANDBY: 108 command.action = STANDBY; 109 msg = "System standing by"; 110 break; 111 case HIBERNATE: 112 command.action = HIBERNATE; 113 msg = "Hibernating system"; 114 break; 115 default: 116 zzusage(); 117 } 118 119 printf("%s...\n", msg); 120 exit(send_command(fd, &command, &reply)); 121 } 122 123 static int 124 open_socket(const char *sockname) 125 { 126 int sock, errr; 127 struct sockaddr_un s_un; 128 129 sock = socket(AF_UNIX, SOCK_STREAM, 0); 130 if (sock == -1) 131 err(1, "cannot create local socket"); 132 133 s_un.sun_family = AF_UNIX; 134 strlcpy(s_un.sun_path, sockname, sizeof(s_un.sun_path)); 135 if (connect(sock, (struct sockaddr *)&s_un, sizeof(s_un)) == -1) { 136 errr = errno; 137 close(sock); 138 errno = errr; 139 sock = -1; 140 } 141 return (sock); 142 } 143 144 int 145 main(int argc, char *argv[]) 146 { 147 const char *sockname = _PATH_APM_SOCKET; 148 int doac = FALSE; 149 int dopct = FALSE; 150 int dobstate = FALSE; 151 int domin = FALSE; 152 int doperf = FALSE; 153 int verbose = FALSE; 154 int ch, fd, rval; 155 enum apm_action action = NONE; 156 struct apm_command command; 157 struct apm_reply reply; 158 int cpuspeed_mib[] = { CTL_HW, HW_CPUSPEED }, cpuspeed; 159 size_t cpuspeed_sz = sizeof(cpuspeed); 160 161 if (sysctl(cpuspeed_mib, 2, &cpuspeed, &cpuspeed_sz, NULL, 0) == -1) 162 err(1, "sysctl hw.cpuspeed"); 163 164 while ((ch = getopt(argc, argv, "ACHLlmbvaPSzZf:")) != -1) { 165 switch (ch) { 166 case 'v': 167 verbose = TRUE; 168 break; 169 case 'f': 170 sockname = optarg; 171 break; 172 case 'z': 173 if (action != NONE) 174 usage(); 175 action = SUSPEND; 176 break; 177 case 'S': 178 if (action != NONE) 179 usage(); 180 action = STANDBY; 181 break; 182 case 'Z': 183 if (action != NONE) 184 usage(); 185 action = HIBERNATE; 186 break; 187 case 'A': 188 case 'C': 189 if (action != NONE) 190 usage(); 191 action = SETPERF_AUTO; 192 break; 193 case 'H': 194 if (action != NONE) 195 usage(); 196 action = SETPERF_HIGH; 197 break; 198 case 'L': 199 if (action != NONE) 200 usage(); 201 action = SETPERF_LOW; 202 break; 203 case 'b': 204 if (action != NONE && action != GETSTATUS) 205 usage(); 206 dobstate = TRUE; 207 action = GETSTATUS; 208 break; 209 case 'l': 210 if (action != NONE && action != GETSTATUS) 211 usage(); 212 dopct = TRUE; 213 action = GETSTATUS; 214 break; 215 case 'm': 216 if (action != NONE && action != GETSTATUS) 217 usage(); 218 domin = TRUE; 219 action = GETSTATUS; 220 break; 221 case 'a': 222 if (action != NONE && action != GETSTATUS) 223 usage(); 224 doac = TRUE; 225 action = GETSTATUS; 226 break; 227 case 'P': 228 if (action != NONE && action != GETSTATUS) 229 usage(); 230 doperf = TRUE; 231 action = GETSTATUS; 232 break; 233 default: 234 if (!strcmp(__progname, "zzz") || 235 !strcmp(__progname, "ZZZ")) 236 zzusage(); 237 else 238 usage(); 239 } 240 } 241 argc -= optind; 242 argv += optind; 243 if (argc) 244 usage(); 245 246 fd = open_socket(sockname); 247 248 if (fd != -1) { 249 if (pledge("stdio", NULL) == -1) 250 err(1, "pledge"); 251 } 252 253 if (!strcmp(__progname, "zzz")) { 254 if (fd < 0) 255 err(1, "cannot connect to apmd"); 256 else 257 return (do_zzz(fd, action)); 258 } else if (!strcmp(__progname, "ZZZ")) { 259 if (fd < 0) 260 err(1, "cannot connect to apmd"); 261 else 262 return (do_zzz(fd, HIBERNATE)); 263 } 264 265 266 bzero(&reply, sizeof reply); 267 reply.batterystate.battery_state = APM_BATT_UNKNOWN; 268 reply.batterystate.ac_state = APM_AC_UNKNOWN; 269 reply.perfmode = PERF_MANUAL; 270 reply.cpuspeed = cpuspeed; 271 272 switch (action) { 273 case SETPERF_LOW: 274 case SETPERF_HIGH: 275 case SETPERF_AUTO: 276 if (fd == -1) 277 errx(1, "cannot connect to apmd, " 278 "not changing performance adjustment mode"); 279 goto balony; 280 case NONE: 281 action = GETSTATUS; 282 verbose = doac = dopct = dobstate = domin = doperf = TRUE; 283 /* FALLTHROUGH */ 284 case GETSTATUS: 285 if (fd == -1) { 286 /* open the device directly and get status */ 287 fd = open(_PATH_APM_NORMAL, O_RDONLY); 288 if (ioctl(fd, APM_IOC_GETPOWER, 289 &reply.batterystate) == 0) { 290 if (pledge("stdio", NULL) == -1) 291 err(1, "pledge"); 292 293 goto printval; 294 } 295 } 296 /* FALLTHROUGH */ 297 balony: 298 case SUSPEND: 299 case STANDBY: 300 case HIBERNATE: 301 command.action = action; 302 break; 303 default: 304 usage(); 305 } 306 307 if (fd != -1 && (rval = send_command(fd, &command, &reply)) != 0) 308 errx(rval, "cannot get reply from APM daemon"); 309 310 switch (action) { 311 case GETSTATUS: 312 printval: 313 if (!verbose) { 314 if (dobstate) 315 printf("%d\n", 316 reply.batterystate.battery_state); 317 if (dopct) 318 printf("%d\n", 319 reply.batterystate.battery_life); 320 if (domin) { 321 if (reply.batterystate.minutes_left == 322 (u_int)-1) 323 printf("unknown\n"); 324 else 325 printf("%d\n", 326 reply.batterystate.minutes_left); 327 } 328 if (doac) 329 printf("%d\n", 330 reply.batterystate.ac_state); 331 if (doperf) 332 printf("%d\n", reply.perfmode); 333 break; 334 } 335 336 if (dobstate) { 337 printf("Battery state: %s", 338 battstate(reply.batterystate.battery_state)); 339 if (!dopct && !domin) 340 printf("\n"); 341 } 342 343 if (dopct && !dobstate) 344 printf("Battery remaining: %d percent", 345 reply.batterystate.battery_life); 346 else if (dopct) 347 printf(", %d%% remaining", 348 reply.batterystate.battery_life); 349 if (dopct && !domin) 350 printf("\n"); 351 352 if (domin && !dobstate && !dopct) { 353 #ifdef __powerpc__ 354 if (reply.batterystate.battery_state == 355 APM_BATT_CHARGING) 356 printf("Remaining battery recharge " 357 "time estimate: %d minutes\n", 358 reply.batterystate.minutes_left); 359 else if (reply.batterystate.minutes_left == 0 && 360 reply.batterystate.battery_life > 10) 361 printf("Battery life estimate: " 362 "not available\n"); 363 else 364 #endif 365 { 366 printf("Battery life estimate: "); 367 if (reply.batterystate.minutes_left == 368 (u_int)-1) 369 printf("unknown\n"); 370 else 371 printf("%d minutes\n", 372 reply.batterystate.minutes_left); 373 } 374 } else if (domin) { 375 #ifdef __powerpc__ 376 if (reply.batterystate.battery_state == 377 APM_BATT_CHARGING) 378 printf(", %d minutes recharge time estimate\n", 379 reply.batterystate.minutes_left); 380 else if (reply.batterystate.minutes_left == 0 && 381 reply.batterystate.battery_life > 10) 382 printf(", unknown life estimate\n"); 383 else 384 #endif 385 { 386 if (reply.batterystate.minutes_left == 387 (u_int)-1) 388 printf(", unknown"); 389 else 390 printf(", %d minutes", 391 reply.batterystate.minutes_left); 392 printf(" life estimate\n"); 393 } 394 } 395 396 if (doac) 397 printf("A/C adapter state: %s\n", 398 ac_state(reply.batterystate.ac_state)); 399 400 if (doperf) 401 printf("Performance adjustment mode: %s (%d MHz)\n", 402 perf_mode(reply.perfmode), reply.cpuspeed); 403 break; 404 default: 405 break; 406 } 407 408 switch (reply.newstate) { 409 case SUSPEND: 410 printf("System will enter suspend mode momentarily.\n"); 411 break; 412 case STANDBY: 413 printf("System will enter standby mode momentarily.\n"); 414 break; 415 case HIBERNATE: 416 printf("System will enter hibernate mode momentarily.\n"); 417 break; 418 default: 419 break; 420 } 421 return (0); 422 } 423