1 /* $NetBSD: apm.c,v 1.2 1996/09/25 00:53:46 jtc 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 REGENTS OR CONTRIBUTORS BE 30 * 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 39 #include <stdio.h> 40 #include <errno.h> 41 #include <stdlib.h> 42 #include <unistd.h> 43 #include <fcntl.h> 44 #include <err.h> 45 #include <string.h> 46 #include <sys/types.h> 47 #include <sys/time.h> 48 #include <sys/socket.h> 49 #include <sys/un.h> 50 #include <sys/ioctl.h> 51 #include <machine/apmvar.h> 52 #include "pathnames.h" 53 #include "apm-proto.h" 54 55 #define FALSE 0 56 #define TRUE 1 57 58 extern char *__progname; 59 extern char *optarg; 60 extern int optind; 61 extern int optopt; 62 extern int opterr; 63 extern int optreset; 64 65 void usage(void); 66 void zzusage(void); 67 int do_zzz(const char *pn, enum apm_action action); 68 int open_socket(const char *pn); 69 int send_command(int fd, 70 struct apm_command *cmd, 71 struct apm_reply *reply); 72 73 void 74 usage(void) 75 { 76 fprintf(stderr,"usage: %s [-v] [-z | -S] [-slba] [-f socket]\n", 77 __progname); 78 exit(1); 79 } 80 81 void 82 zzusage(void) 83 { 84 fprintf(stderr,"usage: %s [-z | -S] [-f socket]\n", 85 __progname); 86 exit(1); 87 } 88 89 int 90 send_command(int fd, 91 struct apm_command *cmd, 92 struct apm_reply *reply) 93 { 94 /* send a command to the apm daemon */ 95 cmd->vno = APMD_VNO; 96 97 if (send(fd, cmd, sizeof(*cmd), 0) == sizeof(*cmd)) { 98 if (recv(fd, reply, sizeof(*reply), 0) != sizeof(*reply)) { 99 warn("invalid reply from APM daemon\n"); 100 return 1; 101 } 102 } else { 103 warn("invalid send to APM daemon"); 104 return 1; 105 } 106 return 0; 107 } 108 109 int 110 do_zzz(const char *pn, enum apm_action action) 111 { 112 struct apm_command command; 113 struct apm_reply reply; 114 int fd; 115 116 switch (action) { 117 case NONE: 118 case SUSPEND: 119 command.action = SUSPEND; 120 break; 121 case STANDBY: 122 command.action = STANDBY; 123 break; 124 default: 125 zzusage(); 126 } 127 fd = open_socket(pn); 128 129 if (fd == -1) 130 err(1, "cannot open connection to APM daemon"); 131 printf("Suspending system...\n"); 132 exit(send_command(fd, &command, &reply)); 133 } 134 135 int 136 open_socket(const char *sockname) 137 { 138 int sock, errr; 139 struct sockaddr_un s_un; 140 141 sock = socket(AF_UNIX, SOCK_STREAM, 0); 142 if (sock == -1) 143 err(1, "cannot create local socket"); 144 145 s_un.sun_family = AF_UNIX; 146 strncpy(s_un.sun_path, sockname, sizeof(s_un.sun_path)); 147 s_un.sun_len = SUN_LEN(&s_un); 148 if (connect(sock, (struct sockaddr *)&s_un, s_un.sun_len) == -1) { 149 errr = errno; 150 close(sock); 151 errno = errr; 152 return -1; 153 } 154 return sock; 155 } 156 157 void 158 main(int argc, char *argv[]) 159 { 160 char *sockname = _PATH_APM_SOCKET; 161 int ch; 162 int dostatus = FALSE; 163 int doac = FALSE; 164 int dopct = FALSE; 165 int dobstate = FALSE; 166 int nodaemon = FALSE; 167 int fd; 168 int rval; 169 int verbose = FALSE; 170 enum apm_action action = NONE; 171 struct apm_command command; 172 struct apm_reply reply; 173 174 while ((ch = getopt(argc, argv, "lbvadsSzf:d")) != -1) 175 switch(ch) { 176 case 'v': 177 verbose = TRUE; 178 break; 179 case 'f': 180 sockname = optarg; 181 break; 182 case 'z': 183 if (action != NONE) 184 usage(); 185 action = SUSPEND; 186 break; 187 case 'S': 188 if (action != NONE) 189 usage(); 190 action = STANDBY; 191 break; 192 case 's': 193 if (action != NONE && action != GETSTATUS) 194 usage(); 195 dostatus = TRUE; 196 action = GETSTATUS; 197 break; 198 case 'b': 199 if (action != NONE && action != GETSTATUS) 200 usage(); 201 dobstate = TRUE; 202 action = GETSTATUS; 203 break; 204 case 'l': 205 if (action != NONE && action != GETSTATUS) 206 usage(); 207 dopct = 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 'd': 217 nodaemon = TRUE; 218 break; 219 case '?': 220 default: 221 usage(); 222 } 223 224 if (!strcmp(__progname, "zzz")) { 225 exit(do_zzz(sockname, action)); 226 } 227 228 if (nodaemon) 229 fd = -1; 230 else 231 fd = open_socket(sockname); 232 233 switch (action) { 234 case NONE: 235 verbose = doac = dopct = dobstate = dostatus = TRUE; 236 action = GETSTATUS; 237 /* fallthrough */ 238 case GETSTATUS: 239 if (fd == -1) { 240 /* open the device directly and get status */ 241 fd = open(_PATH_APM_NORMAL, O_RDONLY); 242 if (fd == -1) { 243 err(1, "cannot contact APM daemon and cannot open " _PATH_APM_NORMAL); 244 } 245 if (ioctl(fd, APM_IOC_GETPOWER, &reply.batterystate) == 0) 246 goto printval; 247 } 248 case SUSPEND: 249 case STANDBY: 250 if (nodaemon && fd == -1) { 251 fd = open(_PATH_APM_CTLDEV, O_RDWR); 252 if (fd == -1) 253 err(1, "cannot open APM control device " _PATH_APM_CTLDEV); 254 sync(); 255 sync(); 256 sleep(1); 257 if (ioctl(fd, action == SUSPEND ? 258 APM_IOC_SUSPEND : APM_IOC_STANDBY, 0) == -1) 259 err(1, "cannot enter requested power state"); 260 if (action == SUSPEND) 261 printf("System will enter suspend mode momentarily.\n"); 262 else 263 printf("System will enter standby mode momentarily.\n"); 264 exit(0); 265 } else if (fd == -1) 266 err(1, "cannot contact APM daemon at socket " _PATH_APM_SOCKET); 267 command.action = action; 268 break; 269 default: 270 usage(); 271 } 272 273 if ((rval = send_command(fd, &command, &reply)) == 0) { 274 switch (action) { 275 case GETSTATUS: 276 printval: 277 if (verbose) { 278 if (dobstate) 279 printf("Battery charge state: %s\n", 280 battstate(reply.batterystate.battery_state)); 281 if (dopct) 282 printf("Battery remaining: %d percent\n", 283 reply.batterystate.battery_life); 284 if (doac) 285 printf("A/C adapter state: %s\n", ac_state(reply.batterystate.ac_state)); 286 if (dostatus) 287 printf("Power management enabled\n"); 288 } else { 289 if (dobstate) 290 printf("%d\n", reply.batterystate.battery_state); 291 if (dopct) 292 printf("%d\n", reply.batterystate.battery_life); 293 if (doac) 294 printf("%d\n", reply.batterystate.ac_state); 295 if (dostatus) 296 printf("1\n"); 297 } 298 break; 299 default: 300 break; 301 } 302 switch (reply.newstate) { 303 case SUSPEND: 304 printf("System will enter suspend mode momentarily.\n"); 305 break; 306 case STANDBY: 307 printf("System will enter standby mode momentarily.\n"); 308 break; 309 default: 310 break; 311 } 312 } else 313 errx(rval, "cannot get reply from APM daemon\n"); 314 315 exit(0); 316 } 317