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