xref: /openbsd-src/usr.sbin/apm/apm.c (revision db3296cf5c1dd9058ceecc3a29fe4aaa0bd26000)
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