1 /* $OpenBSD: apm.c,v 1.36 2019/06/28 13:32:46 deraadt 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 if (action != NONE) 189 usage(); 190 action = SETPERF_AUTO; 191 break; 192 case 'C': 193 if (action != NONE) 194 usage(); 195 action = SETPERF_COOL; 196 break; 197 case 'H': 198 if (action != NONE) 199 usage(); 200 action = SETPERF_HIGH; 201 break; 202 case 'L': 203 if (action != NONE) 204 usage(); 205 action = SETPERF_LOW; 206 break; 207 case 'b': 208 if (action != NONE && action != GETSTATUS) 209 usage(); 210 dobstate = TRUE; 211 action = GETSTATUS; 212 break; 213 case 'l': 214 if (action != NONE && action != GETSTATUS) 215 usage(); 216 dopct = TRUE; 217 action = GETSTATUS; 218 break; 219 case 'm': 220 if (action != NONE && action != GETSTATUS) 221 usage(); 222 domin = TRUE; 223 action = GETSTATUS; 224 break; 225 case 'a': 226 if (action != NONE && action != GETSTATUS) 227 usage(); 228 doac = TRUE; 229 action = GETSTATUS; 230 break; 231 case 'P': 232 if (action != NONE && action != GETSTATUS) 233 usage(); 234 doperf = TRUE; 235 action = GETSTATUS; 236 break; 237 default: 238 if (!strcmp(__progname, "zzz") || 239 !strcmp(__progname, "ZZZ")) 240 zzusage(); 241 else 242 usage(); 243 } 244 } 245 argc -= optind; 246 argv += optind; 247 if (argc) 248 usage(); 249 250 fd = open_socket(sockname); 251 252 if (fd != -1) { 253 if (pledge("stdio", NULL) == -1) 254 err(1, "pledge"); 255 } 256 257 if (!strcmp(__progname, "zzz")) { 258 if (fd < 0) 259 err(1, "cannot connect to apmd"); 260 else 261 return (do_zzz(fd, action)); 262 } else if (!strcmp(__progname, "ZZZ")) { 263 if (fd < 0) 264 err(1, "cannot connect to apmd"); 265 else 266 return (do_zzz(fd, HIBERNATE)); 267 } 268 269 270 bzero(&reply, sizeof reply); 271 reply.batterystate.battery_state = APM_BATT_UNKNOWN; 272 reply.batterystate.ac_state = APM_AC_UNKNOWN; 273 reply.perfmode = PERF_MANUAL; 274 reply.cpuspeed = cpuspeed; 275 276 switch (action) { 277 case SETPERF_LOW: 278 case SETPERF_HIGH: 279 case SETPERF_AUTO: 280 case SETPERF_COOL: 281 if (fd == -1) 282 errx(1, "cannot connect to apmd, " 283 "not changing performance adjustment mode"); 284 goto balony; 285 case NONE: 286 action = GETSTATUS; 287 verbose = doac = dopct = dobstate = domin = doperf = TRUE; 288 /* FALLTHROUGH */ 289 case GETSTATUS: 290 if (fd == -1) { 291 /* open the device directly and get status */ 292 fd = open(_PATH_APM_NORMAL, O_RDONLY); 293 if (ioctl(fd, APM_IOC_GETPOWER, 294 &reply.batterystate) == 0) { 295 if (pledge("stdio", NULL) == -1) 296 err(1, "pledge"); 297 298 goto printval; 299 } 300 } 301 /* FALLTHROUGH */ 302 balony: 303 case SUSPEND: 304 case STANDBY: 305 case HIBERNATE: 306 command.action = action; 307 break; 308 default: 309 usage(); 310 } 311 312 if (fd != -1 && (rval = send_command(fd, &command, &reply)) != 0) 313 errx(rval, "cannot get reply from APM daemon"); 314 315 switch (action) { 316 case GETSTATUS: 317 printval: 318 if (!verbose) { 319 if (dobstate) 320 printf("%d\n", 321 reply.batterystate.battery_state); 322 if (dopct) 323 printf("%d\n", 324 reply.batterystate.battery_life); 325 if (domin) { 326 if (reply.batterystate.minutes_left == 327 (u_int)-1) 328 printf("unknown\n"); 329 else 330 printf("%d\n", 331 reply.batterystate.minutes_left); 332 } 333 if (doac) 334 printf("%d\n", 335 reply.batterystate.ac_state); 336 if (doperf) 337 printf("%d\n", reply.perfmode); 338 break; 339 } 340 341 if (dobstate) { 342 printf("Battery state: %s", 343 battstate(reply.batterystate.battery_state)); 344 if (!dopct && !domin) 345 printf("\n"); 346 } 347 348 if (dopct && !dobstate) 349 printf("Battery remaining: %d percent", 350 reply.batterystate.battery_life); 351 else if (dopct) 352 printf(", %d%% remaining", 353 reply.batterystate.battery_life); 354 if (dopct && !domin) 355 printf("\n"); 356 357 if (domin && !dobstate && !dopct) { 358 #ifdef __powerpc__ 359 if (reply.batterystate.battery_state == 360 APM_BATT_CHARGING) 361 printf("Remaining battery recharge " 362 "time estimate: %d minutes\n", 363 reply.batterystate.minutes_left); 364 else if (reply.batterystate.minutes_left == 0 && 365 reply.batterystate.battery_life > 10) 366 printf("Battery life estimate: " 367 "not available\n"); 368 else 369 #endif 370 { 371 printf("Battery life estimate: "); 372 if (reply.batterystate.minutes_left == 373 (u_int)-1) 374 printf("unknown\n"); 375 else 376 printf("%d minutes\n", 377 reply.batterystate.minutes_left); 378 } 379 } else if (domin) { 380 #ifdef __powerpc__ 381 if (reply.batterystate.battery_state == 382 APM_BATT_CHARGING) 383 printf(", %d minutes recharge time estimate\n", 384 reply.batterystate.minutes_left); 385 else if (reply.batterystate.minutes_left == 0 && 386 reply.batterystate.battery_life > 10) 387 printf(", unknown life estimate\n"); 388 else 389 #endif 390 { 391 if (reply.batterystate.minutes_left == 392 (u_int)-1) 393 printf(", unknown"); 394 else 395 printf(", %d minutes", 396 reply.batterystate.minutes_left); 397 printf(" life estimate\n"); 398 } 399 } 400 401 if (doac) 402 printf("A/C adapter state: %s\n", 403 ac_state(reply.batterystate.ac_state)); 404 405 if (doperf) 406 printf("Performance adjustment mode: %s (%d MHz)\n", 407 perf_mode(reply.perfmode), reply.cpuspeed); 408 break; 409 default: 410 break; 411 } 412 413 switch (reply.newstate) { 414 case SUSPEND: 415 printf("System will enter suspend mode momentarily.\n"); 416 break; 417 case STANDBY: 418 printf("System will enter standby mode momentarily.\n"); 419 break; 420 case HIBERNATE: 421 printf("System will enter hibernate mode momentarily.\n"); 422 break; 423 default: 424 break; 425 } 426 return (0); 427 } 428