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