1 /* $NetBSD: apm.c,v 1.12 2001/09/13 11:05:58 enami 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 39 #include <sys/types.h> 40 #include <sys/ioctl.h> 41 #include <sys/socket.h> 42 #include <sys/time.h> 43 #include <sys/un.h> 44 45 #include <machine/apmvar.h> 46 47 #include <err.h> 48 #include <errno.h> 49 #include <fcntl.h> 50 #include <stdio.h> 51 #include <stdlib.h> 52 #include <string.h> 53 #include <unistd.h> 54 55 #include "pathnames.h" 56 #include "apm-proto.h" 57 58 #define FALSE 0 59 #define TRUE 1 60 61 void usage(void); 62 void zzusage(void); 63 int do_zzz(const char *, enum apm_action); 64 int open_socket(const char *); 65 int send_command(int, struct apm_command *, struct apm_reply *); 66 67 void 68 usage(void) 69 { 70 71 fprintf(stderr,"usage: %s [-v] [-z | -S] [-slmba] [-f socket]\n", 72 getprogname()); 73 exit(1); 74 } 75 76 void 77 zzusage(void) 78 { 79 80 fprintf(stderr,"usage: %s [-z | -S] [-f socket]\n", 81 getprogname()); 82 exit(1); 83 } 84 85 int 86 send_command(int fd, 87 struct apm_command *cmd, 88 struct apm_reply *reply) 89 { 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 125 fd = open_socket(pn); 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 struct sockaddr_un s_un; 136 int sock, errr; 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 struct apm_command command; 158 struct apm_reply reply; 159 struct apm_power_info *api = &reply.batterystate; 160 char *sockname = _PATH_APM_SOCKET; 161 enum apm_action action = NONE; 162 int ch, doac, dobstate, domin, dopct, dostatus, fd, nodaemon, 163 rval, verbose; 164 165 doac = dobstate = domin = dopct = dostatus = nodaemon = 166 verbose = FALSE; 167 while ((ch = getopt(argc, argv, "lmbvadsSzf:d")) != -1) 168 switch (ch) { 169 case 'v': 170 verbose = TRUE; 171 break; 172 case 'f': 173 sockname = optarg; 174 break; 175 case 'z': 176 if (action != NONE) 177 usage(); 178 action = SUSPEND; 179 break; 180 case 'S': 181 if (action != NONE) 182 usage(); 183 action = STANDBY; 184 break; 185 case 's': 186 if (action != NONE && action != GETSTATUS) 187 usage(); 188 dostatus = TRUE; 189 action = GETSTATUS; 190 break; 191 case 'b': 192 if (action != NONE && action != GETSTATUS) 193 usage(); 194 dobstate = TRUE; 195 action = GETSTATUS; 196 break; 197 case 'l': 198 if (action != NONE && action != GETSTATUS) 199 usage(); 200 dopct = TRUE; 201 action = GETSTATUS; 202 break; 203 case 'm': 204 if (action != NONE && action != GETSTATUS) 205 usage(); 206 domin = TRUE; 207 action = GETSTATUS; 208 break; 209 case 'a': 210 if (action != NONE && action != GETSTATUS) 211 usage(); 212 doac = TRUE; 213 action = GETSTATUS; 214 break; 215 case 'd': 216 nodaemon = TRUE; 217 break; 218 case '?': 219 default: 220 usage(); 221 } 222 223 if (strcmp(getprogname(), "zzz") == 0) 224 exit(do_zzz(sockname, action)); 225 226 if (nodaemon) 227 fd = -1; 228 else 229 fd = open_socket(sockname); 230 231 switch (action) { 232 case NONE: 233 verbose = doac = dopct = domin = dobstate = dostatus = TRUE; 234 action = GETSTATUS; 235 /* FALLTHROUGH */ 236 case GETSTATUS: 237 if (fd == -1) { 238 /* open the device directly and get status */ 239 fd = open(_PATH_APM_NORMAL, O_RDONLY); 240 if (fd == -1) { 241 err(1, "cannot contact APM daemon and " 242 "cannot open " 243 _PATH_APM_NORMAL); 244 } 245 memset(&reply, 0, sizeof(reply)); 246 if (ioctl(fd, APM_IOC_GETPOWER, 247 &reply.batterystate) == -1) 248 err(1, "ioctl(APM_IOC_GETPOWER)"); 249 goto printval; 250 } 251 /* FALLTHROUGH */ 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 " 258 _PATH_APM_CTLDEV); 259 sync(); 260 sync(); 261 sleep(1); 262 if (ioctl(fd, action == SUSPEND ? 263 APM_IOC_SUSPEND : APM_IOC_STANDBY, 0) == -1) 264 err(1, "cannot enter requested power state"); 265 printf("System will enter %s in a moment.\n", 266 action == SUSPEND ? "suspend mode" : 267 "standby mode"); 268 exit(0); 269 } else if (fd == -1) 270 err(1, "cannot contact APM daemon at socket " 271 _PATH_APM_SOCKET); 272 command.action = action; 273 break; 274 default: 275 usage(); 276 } 277 278 if ((rval = send_command(fd, &command, &reply)) == 0) { 279 switch (action) { 280 case GETSTATUS: 281 printval: 282 if (verbose) { 283 if (dobstate) 284 printf("Battery charge state: %s\n", 285 battstate(api->battery_state)); 286 if (dopct || domin) { 287 printf("Battery remaining: "); 288 if (dopct) 289 printf("%d percent", 290 api->battery_life); 291 if (dopct && domin) 292 printf(" ("); 293 if (domin) 294 printf("%d minutes", 295 api->minutes_left); 296 if (dopct && domin) 297 printf(")"); 298 printf("\n"); 299 } 300 if (doac) 301 printf("A/C adapter state: %s\n", 302 ac_state(api->ac_state)); 303 if (dostatus) 304 printf("Power management enabled\n"); 305 if (api->nbattery) { 306 printf("Number of batteries: %u\n", 307 api->nbattery); 308 } 309 } else { 310 if (dobstate) 311 printf("%d\n", api->battery_state); 312 if (dopct) 313 printf("%d\n", api->battery_life); 314 if (domin) 315 printf("%d\n", api->minutes_left); 316 if (doac) 317 printf("%d\n", api->ac_state); 318 if (dostatus) 319 printf("1\n"); 320 } 321 break; 322 default: 323 break; 324 } 325 switch (reply.newstate) { 326 case SUSPEND: 327 printf("System will enter suspend mode " 328 "in a moment.\n"); 329 break; 330 case STANDBY: 331 printf("System will enter standby mode " 332 "in a moment.\n"); 333 break; 334 default: 335 break; 336 } 337 } else 338 errx(rval, "cannot get reply from APM daemon\n"); 339 340 exit(0); 341 } 342