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