1 /* $OpenBSD: apm.c,v 1.32 2015/11/01 14:13:30 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 void usage(void); 54 void zzusage(void); 55 int do_zzz(int, enum apm_action action); 56 int open_socket(const char *pn); 57 int send_command(int fd, struct apm_command *cmd, struct apm_reply *reply); 58 59 void 60 usage(void) 61 { 62 fprintf(stderr,"usage: %s [-AabHLlmPSvZz] [-f sockname]\n", 63 __progname); 64 exit(1); 65 } 66 67 void 68 zzusage(void) 69 { 70 fprintf(stderr,"usage: %s [-SZz] [-f sockname]\n", 71 __progname); 72 exit(1); 73 } 74 75 int 76 send_command(int fd, struct apm_command *cmd, struct apm_reply *reply) 77 { 78 /* send a command to the apm daemon */ 79 cmd->vno = APMD_VNO; 80 81 if (send(fd, cmd, sizeof(*cmd), 0) == sizeof(*cmd)) { 82 if (recv(fd, reply, sizeof(*reply), 0) != sizeof(*reply)) { 83 warn("invalid reply from APM daemon"); 84 return (1); 85 } 86 } else { 87 warn("invalid send to APM daemon"); 88 return (1); 89 } 90 return (0); 91 } 92 93 int 94 do_zzz(int fd, enum apm_action action) 95 { 96 struct apm_command command; 97 struct apm_reply reply; 98 char *msg; 99 100 switch (action) { 101 case NONE: 102 case SUSPEND: 103 command.action = SUSPEND; 104 msg = "Suspending system"; 105 break; 106 case STANDBY: 107 command.action = STANDBY; 108 msg = "System standing by"; 109 break; 110 case HIBERNATE: 111 command.action = HIBERNATE; 112 msg = "Hibernating system"; 113 break; 114 default: 115 zzusage(); 116 } 117 118 printf("%s...\n", msg); 119 exit(send_command(fd, &command, &reply)); 120 } 121 122 int 123 open_socket(const char *sockname) 124 { 125 int sock, errr; 126 struct sockaddr_un s_un; 127 128 sock = socket(AF_UNIX, SOCK_STREAM, 0); 129 if (sock == -1) 130 err(1, "cannot create local socket"); 131 132 s_un.sun_family = AF_UNIX; 133 strlcpy(s_un.sun_path, sockname, sizeof(s_un.sun_path)); 134 if (connect(sock, (struct sockaddr *)&s_un, sizeof(s_un)) == -1) { 135 errr = errno; 136 close(sock); 137 errno = errr; 138 sock = -1; 139 } 140 return (sock); 141 } 142 143 int 144 main(int argc, char *argv[]) 145 { 146 const char *sockname = _PATH_APM_SOCKET; 147 int doac = FALSE; 148 int dopct = FALSE; 149 int dobstate = FALSE; 150 int domin = FALSE; 151 int doperf = FALSE; 152 int verbose = FALSE; 153 int ch, fd, rval; 154 enum apm_action action = NONE; 155 struct apm_command command; 156 struct apm_reply reply; 157 int cpuspeed_mib[] = { CTL_HW, HW_CPUSPEED }, cpuspeed; 158 size_t cpuspeed_sz = sizeof(cpuspeed); 159 160 if (sysctl(cpuspeed_mib, 2, &cpuspeed, &cpuspeed_sz, NULL, 0) < 0) 161 err(1, "sysctl hw.cpuspeed"); 162 163 while ((ch = getopt(argc, argv, "ACHLlmbvaPSzZf:")) != -1) { 164 switch (ch) { 165 case 'v': 166 verbose = TRUE; 167 break; 168 case 'f': 169 sockname = optarg; 170 break; 171 case 'z': 172 if (action != NONE) 173 usage(); 174 action = SUSPEND; 175 break; 176 case 'S': 177 if (action != NONE) 178 usage(); 179 action = STANDBY; 180 break; 181 case 'Z': 182 if (action != NONE) 183 usage(); 184 action = HIBERNATE; 185 break; 186 case 'A': 187 if (action != NONE) 188 usage(); 189 action = SETPERF_AUTO; 190 break; 191 case 'C': 192 if (action != NONE) 193 usage(); 194 action = SETPERF_COOL; 195 break; 196 case 'H': 197 if (action != NONE) 198 usage(); 199 action = SETPERF_HIGH; 200 break; 201 case 'L': 202 if (action != NONE) 203 usage(); 204 action = SETPERF_LOW; 205 break; 206 case 'b': 207 if (action != NONE && action != GETSTATUS) 208 usage(); 209 dobstate = TRUE; 210 action = GETSTATUS; 211 break; 212 case 'l': 213 if (action != NONE && action != GETSTATUS) 214 usage(); 215 dopct = TRUE; 216 action = GETSTATUS; 217 break; 218 case 'm': 219 if (action != NONE && action != GETSTATUS) 220 usage(); 221 domin = TRUE; 222 action = GETSTATUS; 223 break; 224 case 'a': 225 if (action != NONE && action != GETSTATUS) 226 usage(); 227 doac = TRUE; 228 action = GETSTATUS; 229 break; 230 case 'P': 231 if (action != NONE && action != GETSTATUS) 232 usage(); 233 doperf = TRUE; 234 action = GETSTATUS; 235 break; 236 default: 237 if (!strcmp(__progname, "zzz") || !strcmp(__progname, "ZZZ")) 238 zzusage(); 239 else 240 usage(); 241 } 242 } 243 244 fd = open_socket(sockname); 245 246 if (fd != -1) { 247 if (pledge("stdio rpath wpath cpath", NULL) == -1) 248 err(1, "pledge"); 249 } 250 251 if (!strcmp(__progname, "zzz")) { 252 if (fd < 0) 253 err(1, "cannot connect to apmd"); 254 else 255 return (do_zzz(fd, action)); 256 } else if (!strcmp(__progname, "ZZZ")) { 257 if (fd < 0) 258 err(1, "cannot connect to apmd"); 259 else 260 return (do_zzz(fd, HIBERNATE)); 261 } 262 263 264 bzero(&reply, sizeof reply); 265 reply.batterystate.battery_state = APM_BATT_UNKNOWN; 266 reply.batterystate.ac_state = APM_AC_UNKNOWN; 267 reply.perfmode = PERF_MANUAL; 268 reply.cpuspeed = cpuspeed; 269 270 switch (action) { 271 case SETPERF_LOW: 272 case SETPERF_HIGH: 273 case SETPERF_AUTO: 274 case SETPERF_COOL: 275 if (fd == -1) 276 errx(1, "cannot connect to apmd, " 277 "not changing performance adjustment mode"); 278 goto balony; 279 case NONE: 280 action = GETSTATUS; 281 verbose = doac = dopct = dobstate = domin = doperf = TRUE; 282 /* FALLTHROUGH */ 283 case GETSTATUS: 284 if (fd == -1) { 285 /* open the device directly and get status */ 286 fd = open(_PATH_APM_NORMAL, O_RDONLY); 287 if (ioctl(fd, APM_IOC_GETPOWER, 288 &reply.batterystate) == 0) 289 goto printval; 290 } 291 /* FALLTHROUGH */ 292 balony: 293 case SUSPEND: 294 case STANDBY: 295 case HIBERNATE: 296 command.action = action; 297 break; 298 default: 299 usage(); 300 } 301 302 if (fd != -1 && (rval = send_command(fd, &command, &reply)) != 0) 303 errx(rval, "cannot get reply from APM daemon"); 304 305 switch (action) { 306 case GETSTATUS: 307 printval: 308 if (!verbose) { 309 if (dobstate) 310 printf("%d\n", 311 reply.batterystate.battery_state); 312 if (dopct) 313 printf("%d\n", 314 reply.batterystate.battery_life); 315 if (domin) { 316 if (reply.batterystate.minutes_left == 317 (u_int)-1) 318 printf("unknown\n"); 319 else 320 printf("%d\n", 321 reply.batterystate.minutes_left); 322 } 323 if (doac) 324 printf("%d\n", 325 reply.batterystate.ac_state); 326 if (doperf) 327 printf("%d\n", reply.perfmode); 328 break; 329 } 330 331 if (dobstate) { 332 printf("Battery state: %s", 333 battstate(reply.batterystate.battery_state)); 334 if (!dopct && !domin) 335 printf("\n"); 336 } 337 338 if (dopct && !dobstate) 339 printf("Battery remaining: %d percent", 340 reply.batterystate.battery_life); 341 else if (dopct) 342 printf(", %d%% remaining", 343 reply.batterystate.battery_life); 344 if (dopct && !domin) 345 printf("\n"); 346 347 if (domin && !dobstate && !dopct) { 348 #ifdef __powerpc__ 349 if (reply.batterystate.battery_state == 350 APM_BATT_CHARGING) 351 printf("Remaining battery recharge " 352 "time estimate: %d minutes\n", 353 reply.batterystate.minutes_left); 354 else if (reply.batterystate.minutes_left == 0 && 355 reply.batterystate.battery_life > 10) 356 printf("Battery life estimate: " 357 "not available\n"); 358 else 359 #endif 360 { 361 printf("Battery life estimate: "); 362 if (reply.batterystate.minutes_left == 363 (u_int)-1) 364 printf("unknown\n"); 365 else 366 printf("%d minutes\n", 367 reply.batterystate.minutes_left); 368 } 369 } else if (domin) { 370 #ifdef __powerpc__ 371 if (reply.batterystate.battery_state == 372 APM_BATT_CHARGING) 373 printf(", %d minutes recharge time estimate\n", 374 reply.batterystate.minutes_left); 375 else if (reply.batterystate.minutes_left == 0 && 376 reply.batterystate.battery_life > 10) 377 printf(", unknown life estimate\n"); 378 else 379 #endif 380 { 381 if (reply.batterystate.minutes_left == 382 (u_int)-1) 383 printf(", unknown"); 384 else 385 printf(", %d minutes", 386 reply.batterystate.minutes_left); 387 printf(" life estimate\n"); 388 } 389 } 390 391 if (doac) 392 printf("A/C adapter state: %s\n", 393 ac_state(reply.batterystate.ac_state)); 394 395 if (doperf) 396 printf("Performance adjustment mode: %s (%d MHz)\n", 397 perf_mode(reply.perfmode), reply.cpuspeed); 398 break; 399 default: 400 break; 401 } 402 403 switch (reply.newstate) { 404 case SUSPEND: 405 printf("System will enter suspend mode momentarily.\n"); 406 break; 407 case STANDBY: 408 printf("System will enter standby mode momentarily.\n"); 409 break; 410 case HIBERNATE: 411 printf("System will enter hibernate mode momentarily.\n"); 412 break; 413 default: 414 break; 415 } 416 return (0); 417 } 418