1 /* $OpenBSD: apm.c,v 1.23 2006/06/11 17:45:54 sturm 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 usage(); 224 } 225 } 226 227 fd = open_socket(sockname); 228 229 if (!strcmp(__progname, "zzz")) { 230 if (fd < 0) 231 err(1, "cannot connect to apmd"); 232 else 233 return (do_zzz(fd, action)); 234 } 235 236 bzero(&reply, sizeof reply); 237 reply.batterystate.battery_state = APM_BATT_UNKNOWN; 238 reply.batterystate.ac_state = APM_AC_UNKNOWN; 239 reply.perfmode = PERF_MANUAL; 240 if (sysctl(cpuspeed_mib, 2, &cpuspeed, &cpuspeed_sz, NULL, 0) < 0) 241 reply.cpuspeed = 0; 242 else 243 reply.cpuspeed = cpuspeed; 244 245 switch (action) { 246 case SETPERF_LOW: 247 case SETPERF_HIGH: 248 case SETPERF_AUTO: 249 case SETPERF_COOL: 250 if (fd == -1) 251 errx(1, "cannot connect to apmd, " 252 "not changing performance adjustment mode"); 253 goto balony; 254 case NONE: 255 action = GETSTATUS; 256 verbose = doac = dopct = dobstate = domin = doperf = TRUE; 257 /* FALLTHROUGH */ 258 case GETSTATUS: 259 if (fd == -1) { 260 /* open the device directly and get status */ 261 fd = open(_PATH_APM_NORMAL, O_RDONLY); 262 if (ioctl(fd, APM_IOC_GETPOWER, 263 &reply.batterystate) == 0) 264 goto printval; 265 } 266 /* FALLTHROUGH */ 267 balony: 268 case SUSPEND: 269 case STANDBY: 270 command.action = action; 271 break; 272 default: 273 usage(); 274 } 275 276 if (fd != -1 && (rval = send_command(fd, &command, &reply)) != 0) 277 errx(rval, "cannot get reply from APM daemon"); 278 279 switch (action) { 280 case GETSTATUS: 281 printval: 282 if (!verbose) { 283 if (dobstate) 284 printf("%d\n", 285 reply.batterystate.battery_state); 286 if (dopct) 287 printf("%d\n", 288 reply.batterystate.battery_life); 289 if (domin) { 290 if (reply.batterystate.minutes_left == 291 (u_int)-1) 292 printf("unknown\n"); 293 else 294 printf("%d\n", 295 reply.batterystate.minutes_left); 296 } 297 if (doac) 298 printf("%d\n", 299 reply.batterystate.ac_state); 300 if (doperf) 301 printf("%d\n", reply.perfmode); 302 break; 303 } 304 305 if (dobstate) { 306 printf("Battery state: %s", 307 battstate(reply.batterystate.battery_state)); 308 if (!dopct && !domin) 309 printf("\n"); 310 } 311 312 if (dopct && !dobstate) 313 printf("Battery remaining: %d percent", 314 reply.batterystate.battery_life); 315 else if (dopct) 316 printf(", %d%% remaining", 317 reply.batterystate.battery_life); 318 if (dopct && !domin) 319 printf("\n"); 320 321 if (domin && !dobstate && !dopct) { 322 #ifdef __powerpc__ 323 if (reply.batterystate.battery_state == 324 APM_BATT_CHARGING) 325 printf("Remaining battery recharge " 326 "time estimate: %d minutes\n", 327 reply.batterystate.minutes_left); 328 else if (reply.batterystate.minutes_left == 0 && 329 reply.batterystate.battery_life > 10) 330 printf("Battery life estimate: " 331 "not available\n"); 332 else 333 #endif 334 { 335 printf("Battery life estimate: "); 336 if (reply.batterystate.minutes_left == 337 (u_int)-1) 338 printf("unknown\n"); 339 else 340 printf("%d minutes\n", 341 reply.batterystate.minutes_left); 342 } 343 } else if (domin) { 344 #ifdef __powerpc__ 345 if (reply.batterystate.battery_state == 346 APM_BATT_CHARGING) 347 printf(", %d minutes recharge time estimate\n", 348 reply.batterystate.minutes_left); 349 else if (reply.batterystate.minutes_left == 0 && 350 reply.batterystate.battery_life > 10) 351 printf(", unknown life estimate\n"); 352 else 353 #endif 354 { 355 if (reply.batterystate.minutes_left == 356 (u_int)-1) 357 printf(", unknown"); 358 else 359 printf(", %d minutes", 360 reply.batterystate.minutes_left); 361 printf(" life estimate\n"); 362 } 363 } 364 365 if (doac) 366 printf("A/C adapter state: %s\n", 367 ac_state(reply.batterystate.ac_state)); 368 369 if (doperf) 370 printf("Performance adjustment mode: %s (%d MHz)\n", 371 perf_mode(reply.perfmode), reply.cpuspeed); 372 break; 373 default: 374 break; 375 } 376 377 switch (reply.newstate) { 378 case SUSPEND: 379 printf("System will enter suspend mode momentarily.\n"); 380 break; 381 case STANDBY: 382 printf("System will enter standby mode momentarily.\n"); 383 break; 384 default: 385 break; 386 } 387 return (0); 388 } 389