1/* $NetBSD: apm.c,v 1.20 2008/05/02 19:59:19 xtraeme Exp $ */ 2 3/*- 4 * Copyright (c) 1996 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by John Kohl. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32#include <sys/types.h> 33#include <sys/ioctl.h> 34#include <sys/socket.h> 35#include <sys/time.h> 36#include <sys/un.h> 37 38#include <machine/apmvar.h> 39 40#include <err.h> 41#include <errno.h> 42#include <fcntl.h> 43#include <stdio.h> 44#include <stdlib.h> 45#include <string.h> 46#include <unistd.h> 47 48#include "pathnames.h" 49#include "apm-proto.h" 50 51#define FALSE 0 52#define TRUE 1 53 54__dead static void usage(void); 55__dead static void zzusage(void); 56static int do_zzz(const char *, enum apm_action); 57static int open_socket(const char *); 58static int send_command(int, struct apm_command *, struct apm_reply *); 59 60static void 61usage(void) 62{ 63 64 fprintf(stderr,"usage: %s [-v] [-z | -S] [-abdlms] [-f socket]\n", 65 getprogname()); 66 exit(1); 67} 68 69static void 70zzusage(void) 71{ 72 73 fprintf(stderr,"usage: %s [-z | -S] [-f socket]\n", 74 getprogname()); 75 exit(1); 76} 77 78static int 79send_command(int fd, 80 struct apm_command *cmd, 81 struct apm_reply *reply) 82{ 83 84 /* send a command to the apm daemon */ 85 cmd->vno = APMD_VNO; 86 87 if (send(fd, cmd, sizeof(*cmd), 0) == sizeof(*cmd)) { 88 if (recv(fd, reply, sizeof(*reply), 0) != sizeof(*reply)) { 89 warn("invalid reply from APM daemon"); 90 return (1); 91 } 92 } else { 93 warn("invalid send to APM daemon"); 94 return (1); 95 } 96 return (0); 97} 98 99static int 100do_zzz(const char *pn, enum apm_action action) 101{ 102 struct apm_command command; 103 struct apm_reply reply; 104 int fd; 105 106 switch (action) { 107 case NONE: 108 case SUSPEND: 109 command.action = SUSPEND; 110 break; 111 case STANDBY: 112 command.action = STANDBY; 113 break; 114 default: 115 zzusage(); 116 } 117 118 fd = open_socket(pn); 119 if (fd == -1) 120 err(1, "cannot open connection to APM daemon"); 121 printf("Suspending system...\n"); 122 exit(send_command(fd, &command, &reply)); 123} 124 125static int 126open_socket(const char *sockname) 127{ 128 struct sockaddr_un s_un; 129 int sock, errr; 130 131 sock = socket(AF_LOCAL, SOCK_STREAM, 0); 132 if (sock == -1) 133 err(1, "cannot create local socket"); 134 135 s_un.sun_family = AF_LOCAL; 136 strncpy(s_un.sun_path, sockname, sizeof(s_un.sun_path)); 137 s_un.sun_len = SUN_LEN(&s_un); 138 if (connect(sock, (struct sockaddr *)&s_un, s_un.sun_len) == -1) { 139 errr = errno; 140 close(sock); 141 errno = errr; 142 return (-1); 143 } 144 return (sock); 145} 146 147int 148main(int argc, char *argv[]) 149{ 150 struct apm_command command; 151 struct apm_reply reply; 152 struct apm_power_info *api = &reply.batterystate; 153 const char *sockname = _PATH_APM_SOCKET; 154 enum apm_action action = NONE; 155 int ch, doac, dobstate, domin, dopct, dostatus, fd, nodaemon, 156 rval, verbose; 157 158 doac = dobstate = domin = dopct = dostatus = nodaemon = 159 verbose = FALSE; 160 while ((ch = getopt(argc, argv, "Sabdf:lmsvz")) != -1) 161 switch (ch) { 162 case 'v': 163 verbose = TRUE; 164 break; 165 case 'f': 166 sockname = optarg; 167 break; 168 case 'z': 169 if (action != NONE) 170 usage(); 171 action = SUSPEND; 172 break; 173 case 'S': 174 if (action != NONE) 175 usage(); 176 action = STANDBY; 177 break; 178 case 's': 179 if (action != NONE && action != GETSTATUS) 180 usage(); 181 dostatus = TRUE; 182 action = GETSTATUS; 183 break; 184 case 'b': 185 if (action != NONE && action != GETSTATUS) 186 usage(); 187 dobstate = TRUE; 188 action = GETSTATUS; 189 break; 190 case 'l': 191 if (action != NONE && action != GETSTATUS) 192 usage(); 193 dopct = TRUE; 194 action = GETSTATUS; 195 break; 196 case 'm': 197 if (action != NONE && action != GETSTATUS) 198 usage(); 199 domin = TRUE; 200 action = GETSTATUS; 201 break; 202 case 'a': 203 if (action != NONE && action != GETSTATUS) 204 usage(); 205 doac = TRUE; 206 action = GETSTATUS; 207 break; 208 case 'd': 209 nodaemon = TRUE; 210 break; 211 case '?': 212 default: 213 usage(); 214 } 215 216 if (strcmp(getprogname(), "zzz") == 0) 217 exit(do_zzz(sockname, action)); 218 219 if (nodaemon) 220 fd = -1; 221 else 222 fd = open_socket(sockname); 223 224 switch (action) { 225 case NONE: 226 verbose = doac = dopct = domin = dobstate = dostatus = TRUE; 227 action = GETSTATUS; 228 /* FALLTHROUGH */ 229 case GETSTATUS: 230 if (fd == -1) { 231 /* open the device directly and get status */ 232 fd = open(_PATH_APM_NORMAL, O_RDONLY); 233 if (fd == -1) { 234 err(1, "cannot contact APM daemon and " 235 "cannot open " 236 _PATH_APM_NORMAL); 237 } 238 memset(&reply, 0, sizeof(reply)); 239 if (ioctl(fd, APM_IOC_GETPOWER, 240 &reply.batterystate) == -1) 241 err(1, "ioctl(APM_IOC_GETPOWER)"); 242 goto printval; 243 } 244 /* FALLTHROUGH */ 245 case SUSPEND: 246 case STANDBY: 247 if (nodaemon && fd == -1) { 248 fd = open(_PATH_APM_CTLDEV, O_RDWR); 249 if (fd == -1) 250 err(1, "cannot open APM control device " 251 _PATH_APM_CTLDEV); 252 sync(); 253 sync(); 254 sleep(1); 255 if (ioctl(fd, action == SUSPEND ? 256 APM_IOC_SUSPEND : APM_IOC_STANDBY, 0) == -1) 257 err(1, "cannot enter requested power state"); 258 printf("System will enter %s in a moment.\n", 259 action == SUSPEND ? "suspend mode" : 260 "standby mode"); 261 exit(0); 262 } else if (fd == -1) 263 err(1, "cannot contact APM daemon at socket " 264 _PATH_APM_SOCKET); 265 command.action = action; 266 break; 267 default: 268 usage(); 269 } 270 271 if ((rval = send_command(fd, &command, &reply)) == 0) { 272 switch (action) { 273 case GETSTATUS: 274printval: 275 if (verbose) { 276 if (dobstate) 277 printf("Battery charge state: %s\n", 278 battstate(api->battery_state)); 279 280 if (dopct && domin && api->minutes_left == 0) 281 domin = FALSE; 282 283 if (dopct || domin) { 284 printf("Battery remaining: "); 285 if (dopct) 286 printf("%d percent", 287 api->battery_life); 288 if (dopct && domin) 289 printf(" ("); 290 if (domin) 291 printf("%d minutes", 292 api->minutes_left); 293 if (dopct && domin) 294 printf(")"); 295 printf("\n"); 296 } 297 if (doac) 298 printf("A/C adapter state: %s\n", 299 ac_state(api->ac_state)); 300 if (dostatus) 301 printf("Power management enabled\n"); 302 if (api->nbattery) { 303 printf("Number of batteries: %u\n", 304 api->nbattery); 305 } 306 } else { 307 if (dobstate) 308 printf("%d\n", api->battery_state); 309 if (dopct) 310 printf("%d\n", api->battery_life); 311 if (domin) 312 printf("%d\n", api->minutes_left); 313 if (doac) 314 printf("%d\n", api->ac_state); 315 if (dostatus) 316 printf("1\n"); 317 } 318 break; 319 default: 320 break; 321 } 322 switch (reply.newstate) { 323 case SUSPEND: 324 printf("System will enter suspend mode " 325 "in a moment.\n"); 326 break; 327 case STANDBY: 328 printf("System will enter standby mode " 329 "in a moment.\n"); 330 break; 331 default: 332 break; 333 } 334 } else 335 errx(rval, "cannot get reply from APM daemon"); 336 337 exit(0); 338} 339