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