xref: /netbsd-src/usr.sbin/apm/apm.c (revision dc9f50680cb6c911169f3477fb7dcd9fa091b292)
1 /*	$NetBSD: apm.c,v 1.21 2011/11/25 12:51:28 joerg 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  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <sys/types.h>
33 #include <sys/ioctl.h>
34 #include <sys/socket.h>
35 #include <sys/time.h>
36 #include <sys/un.h>
37 
38 #include <machine/apmvar.h>
39 
40 #include <err.h>
41 #include <errno.h>
42 #include <fcntl.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <unistd.h>
47 
48 #include "pathnames.h"
49 #include "apm-proto.h"
50 
51 #define	FALSE 0
52 #define	TRUE 1
53 
54 __dead static void	usage(void);
55 __dead static void	zzusage(void);
56 static int	do_zzz(const char *, enum apm_action);
57 static int	open_socket(const char *);
58 static int	send_command(int, struct apm_command *, struct apm_reply *);
59 
60 static void
usage(void)61 usage(void)
62 {
63 
64 	fprintf(stderr,"usage: %s [-v] [-z | -S] [-abdlms] [-f socket]\n",
65 	    getprogname());
66 	exit(1);
67 }
68 
69 static void
zzusage(void)70 zzusage(void)
71 {
72 
73 	fprintf(stderr,"usage: %s [-z | -S] [-f socket]\n",
74 	    getprogname());
75 	exit(1);
76 }
77 
78 static int
send_command(int fd,struct apm_command * cmd,struct apm_reply * reply)79 send_command(int fd,
80     struct apm_command *cmd,
81     struct apm_reply *reply)
82 {
83 
84 	/* send a command to the apm daemon */
85 	cmd->vno = APMD_VNO;
86 
87 	if (send(fd, cmd, sizeof(*cmd), 0) == sizeof(*cmd)) {
88 		if (recv(fd, reply, sizeof(*reply), 0) != sizeof(*reply)) {
89 			warn("invalid reply from APM daemon");
90 			return (1);
91 		}
92 	} else {
93 		warn("invalid send to APM daemon");
94 		return (1);
95 	}
96 	return (0);
97 }
98 
99 static int
do_zzz(const char * pn,enum apm_action action)100 do_zzz(const char *pn, enum apm_action action)
101 {
102 	struct apm_command command;
103 	struct apm_reply reply;
104 	int fd;
105 
106 	switch (action) {
107 	case NONE:
108 	case SUSPEND:
109 		command.action = SUSPEND;
110 		break;
111 	case STANDBY:
112 		command.action = STANDBY;
113 		break;
114 	default:
115 		zzusage();
116 	}
117 
118 	fd = open_socket(pn);
119 	if (fd == -1)
120 		err(1, "cannot open connection to APM daemon");
121 	printf("Suspending system...\n");
122 	exit(send_command(fd, &command, &reply));
123 }
124 
125 static int
open_socket(const char * sockname)126 open_socket(const char *sockname)
127 {
128 	struct sockaddr_un s_un;
129 	int sock, errr;
130 
131 	sock = socket(AF_LOCAL, SOCK_STREAM, 0);
132 	if (sock == -1)
133 		err(1, "cannot create local socket");
134 
135 	s_un.sun_family = AF_LOCAL;
136 	strncpy(s_un.sun_path, sockname, sizeof(s_un.sun_path));
137 	s_un.sun_len = SUN_LEN(&s_un);
138 	if (connect(sock, (struct sockaddr *)&s_un, s_un.sun_len) == -1) {
139 		errr = errno;
140 		close(sock);
141 		errno = errr;
142 		return (-1);
143 	}
144 	return (sock);
145 }
146 
147 int
main(int argc,char * argv[])148 main(int argc, char *argv[])
149 {
150 	struct apm_command command;
151 	struct apm_reply reply;
152 	struct apm_power_info *api = &reply.batterystate;
153 	const char *sockname = _PATH_APM_SOCKET;
154 	enum apm_action action = NONE;
155 	int ch, doac, dobstate, domin, dopct, dostatus, fd, nodaemon,
156 	    rval, verbose;
157 
158 	doac = dobstate = domin = dopct = dostatus = nodaemon =
159 	    verbose = FALSE;
160 	while ((ch = getopt(argc, argv, "Sabdf:lmsvz")) != -1)
161 		switch (ch) {
162 		case 'v':
163 			verbose = TRUE;
164 			break;
165 		case 'f':
166 			sockname = optarg;
167 			break;
168 		case 'z':
169 			if (action != NONE)
170 				usage();
171 			action = SUSPEND;
172 			break;
173 		case 'S':
174 			if (action != NONE)
175 				usage();
176 			action = STANDBY;
177 			break;
178 		case 's':
179 			if (action != NONE && action != GETSTATUS)
180 				usage();
181 			dostatus = TRUE;
182 			action = GETSTATUS;
183 			break;
184 		case 'b':
185 			if (action != NONE && action != GETSTATUS)
186 				usage();
187 			dobstate = TRUE;
188 			action = GETSTATUS;
189 			break;
190 		case 'l':
191 			if (action != NONE && action != GETSTATUS)
192 				usage();
193 			dopct = TRUE;
194 			action = GETSTATUS;
195 			break;
196 		case 'm':
197 			if (action != NONE && action != GETSTATUS)
198 				usage();
199 			domin = TRUE;
200 			action = GETSTATUS;
201 			break;
202 		case 'a':
203 			if (action != NONE && action != GETSTATUS)
204 				usage();
205 			doac = TRUE;
206 			action = GETSTATUS;
207 			break;
208 		case 'd':
209 			nodaemon = TRUE;
210 			break;
211 		case '?':
212 		default:
213 			usage();
214 		}
215 
216 	if (strcmp(getprogname(), "zzz") == 0)
217 		exit(do_zzz(sockname, action));
218 
219 	if (nodaemon)
220 		fd = -1;
221 	else
222 		fd = open_socket(sockname);
223 
224 	switch (action) {
225 	case NONE:
226 		verbose = doac = dopct = domin = dobstate = dostatus = TRUE;
227 		action = GETSTATUS;
228 		/* FALLTHROUGH */
229 	case GETSTATUS:
230 		if (fd == -1) {
231 			/* open the device directly and get status */
232 			fd = open(_PATH_APM_NORMAL, O_RDONLY);
233 			if (fd == -1) {
234 				err(1, "cannot contact APM daemon and "
235 				    "cannot open "
236 				    _PATH_APM_NORMAL);
237 			}
238 			memset(&reply, 0, sizeof(reply));
239 			if (ioctl(fd, APM_IOC_GETPOWER,
240 			    &reply.batterystate) == -1)
241 				err(1, "ioctl(APM_IOC_GETPOWER)");
242 			goto printval;
243 		}
244 		/* FALLTHROUGH */
245 	case SUSPEND:
246 	case STANDBY:
247 		if (nodaemon && fd == -1) {
248 			fd = open(_PATH_APM_CTLDEV, O_RDWR);
249 			if (fd == -1)
250 				err(1, "cannot open APM control device "
251 				    _PATH_APM_CTLDEV);
252 			sync();
253 			sync();
254 			sleep(1);
255 			if (ioctl(fd, action == SUSPEND ?
256 			    APM_IOC_SUSPEND : APM_IOC_STANDBY, 0) == -1)
257 				err(1, "cannot enter requested power state");
258 			printf("System will enter %s in a moment.\n",
259 			    action == SUSPEND ? "suspend mode" :
260 			    "standby mode");
261 			exit(0);
262 		} else if (fd == -1)
263 			err(1, "cannot contact APM daemon at socket "
264 			    _PATH_APM_SOCKET);
265 		command.action = action;
266 		break;
267 	default:
268 		usage();
269 	}
270 
271 	if ((rval = send_command(fd, &command, &reply)) == 0) {
272 		switch (action) {
273 		case GETSTATUS:
274 printval:
275 			if (verbose) {
276 				if (dobstate)
277 					printf("Battery charge state: %s\n",
278 					    battstate(api->battery_state));
279 
280 				if (dopct && domin && api->minutes_left == 0)
281 					domin = FALSE;
282 
283 				if (dopct || domin) {
284 					printf("Battery remaining: ");
285 					if (dopct)
286 						printf("%d percent",
287 						    api->battery_life);
288 					if (dopct && domin)
289 						printf(" (");
290 					if (domin)
291 						printf("%d minutes",
292 						    api->minutes_left);
293 					if (dopct && domin)
294 						printf(")");
295 					printf("\n");
296 				}
297 				if (doac)
298 					printf("A/C adapter state: %s\n",
299 					    ac_state(api->ac_state));
300 				if (dostatus)
301 					printf("Power management enabled\n");
302 				if (api->nbattery) {
303 					printf("Number of batteries: %u\n",
304 					    api->nbattery);
305 				}
306 			} else {
307 				if (dobstate)
308 					printf("%d\n", api->battery_state);
309 				if (dopct)
310 					printf("%d\n", api->battery_life);
311 				if (domin)
312 					printf("%d\n", api->minutes_left);
313 				if (doac)
314 					printf("%d\n", api->ac_state);
315 				if (dostatus)
316 					printf("1\n");
317 			}
318 			break;
319 		default:
320 			break;
321 		}
322 		switch (reply.newstate) {
323 		case SUSPEND:
324 			printf("System will enter suspend mode "
325 			    "in a moment.\n");
326 			break;
327 		case STANDBY:
328 			printf("System will enter standby mode "
329 			    "in a moment.\n");
330 			break;
331 		default:
332 			break;
333 		}
334 	} else
335 		errx(rval, "cannot get reply from APM daemon");
336 
337 	exit(0);
338 }
339