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