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