xref: /openbsd-src/usr.sbin/apm/apm.c (revision b2ea75c1b17e1a9a339660e7ed45cd24946b230e)
1 /*	$OpenBSD: apm.c,v 1.5 2001/07/06 21:08:00 mickey 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,
76 	     struct apm_command *cmd,
77 	     struct apm_reply *reply)
78 {
79 	/* send a command to the apm daemon */
80 	cmd->vno = APMD_VNO;
81 
82 	if (send(fd, cmd, sizeof(*cmd), 0) == sizeof(*cmd)) {
83 		if (recv(fd, reply, sizeof(*reply), 0) != sizeof(*reply)) {
84 			warn("invalid reply from APM daemon");
85 		return 1;
86 		}
87 	} else {
88 		warn("invalid send to APM daemon");
89 		return 1;
90 	}
91 
92 	return 0;
93 }
94 
95 int
96 do_zzz(int fd, enum apm_action action)
97 {
98 	struct apm_command command;
99 	struct apm_reply reply;
100 
101 	switch (action) {
102 	case NONE:
103 	case SUSPEND:
104 		command.action = SUSPEND;
105 		break;
106 	case STANDBY:
107 		command.action = STANDBY;
108 		break;
109 	default:
110 		zzusage();
111 	}
112 
113 	printf("Suspending system...\n");
114 	exit(send_command(fd, &command, &reply));
115 }
116 
117 int
118 open_socket(const char *sockname)
119 {
120 	int sock, errr;
121 	struct sockaddr_un s_un;
122 
123 	sock = socket(AF_UNIX, SOCK_STREAM, 0);
124 	if (sock == -1)
125 		err(1, "cannot create local socket");
126 
127 	s_un.sun_family = AF_UNIX;
128 	strncpy(s_un.sun_path, sockname, sizeof(s_un.sun_path));
129 	s_un.sun_len = SUN_LEN(&s_un);
130 	if (connect(sock, (struct sockaddr *)&s_un, s_un.sun_len) == -1) {
131 		errr = errno;
132 		close(sock);
133 		errno = errr;
134 		err(1, "cannot open connection to APM daemon");
135 	}
136 
137 	return sock;
138 }
139 
140 int
141 main(int argc, char *argv[])
142 {
143 	const char *sockname = _PATH_APM_SOCKET;
144 	int dostatus = FALSE;
145 	int doac = FALSE;
146 	int dopct = FALSE;
147 	int dobstate = FALSE;
148 	int domin = FALSE;
149 	int verbose = FALSE;
150 	int ch, fd, rval;
151 	enum apm_action action = NONE;
152 	struct apm_command command;
153 	struct apm_reply reply;
154 
155 	while ((ch = getopt(argc, argv, "lmbvasSzf:")) != -1)
156 		switch(ch) {
157 		case 'v':
158 			verbose = TRUE;
159 			break;
160 		case 'f':
161 			sockname = optarg;
162 			break;
163 		case 'z':
164 			if (action != NONE)
165 				usage();
166 			action = SUSPEND;
167 			break;
168 		case 'S':
169 			if (action != NONE)
170 				usage();
171 			action = STANDBY;
172 			break;
173 		case 's':
174 			if (action != NONE && action != GETSTATUS)
175 				usage();
176 			dostatus = TRUE;
177 			action = GETSTATUS;
178 			break;
179 		case 'b':
180 			if (action != NONE && action != GETSTATUS)
181 				usage();
182 			dobstate = TRUE;
183 			action = GETSTATUS;
184 			break;
185 		case 'l':
186 			if (action != NONE && action != GETSTATUS)
187 				usage();
188 			dopct = TRUE;
189 			action = GETSTATUS;
190 			break;
191 		case 'm':
192 			if (action != NONE && action != GETSTATUS)
193 				usage();
194 			domin = TRUE;
195 			action = GETSTATUS;
196 			break;
197 		case 'a':
198 			if (action != NONE && action != GETSTATUS)
199 				usage();
200 			doac = TRUE;
201 			action = GETSTATUS;
202 			break;
203 		case '?':
204 		default:
205 			usage();
206 		}
207 
208 		fd = open_socket(sockname);
209 
210 		if (!strcmp(__progname, "zzz"))
211 			return (do_zzz(fd, action));
212 
213 		switch (action) {
214 		case NONE:
215 			action = GETSTATUS;
216 			verbose = doac = dopct = dobstate = dostatus = domin =
217 			    TRUE;
218 			/* fallthrough */
219 		case GETSTATUS:
220 			if (fd == -1) {
221 				/* open the device directly and get status */
222 				fd = open(_PATH_APM_NORMAL, O_RDONLY);
223 				if (ioctl(fd, APM_IOC_GETPOWER,
224 				    &reply.batterystate) == 0)
225 					goto printval;
226 			}
227 		case SUSPEND:
228 		case STANDBY:
229 			command.action = action;
230 			break;
231 		default:
232 			usage();
233 		}
234 
235 		if ((rval = send_command(fd, &command, &reply)) == 0) {
236 			switch (action) {
237 			case GETSTATUS:
238 			printval:
239 				if (verbose) {
240 					if (dobstate)
241 						printf("Battery state: %s\n",
242 						    battstate(reply.batterystate.battery_state));
243 					if (dopct)
244 						printf("Battery remaining: %d percent\n",
245 						    reply.batterystate.battery_life);
246 					if (domin)
247 						printf("Battery life estimate: %d minutes\n",
248 						    reply.batterystate.minutes_left);
249 					if (doac)
250 						printf("A/C adapter state: %s\n",
251 						    ac_state(reply.batterystate.ac_state));
252 					if (dostatus)
253 						printf("Power management enabled\n");
254 				} else {
255 					if (dobstate)
256 						printf("%d\n",
257 						    reply.batterystate.battery_state);
258 					if (dopct)
259 						printf("%d\n",
260 						    reply.batterystate.battery_life);
261 					if (domin)
262 						printf("%d\n",
263 						    reply.batterystate.minutes_left);
264 					if (doac)
265 						printf("%d\n",
266 						    reply.batterystate.ac_state);
267 					if (dostatus)
268 						printf("1\n");
269 				}
270 				break;
271 			default:
272 		}
273 		switch (reply.newstate) {
274 		case SUSPEND:
275 			printf("System will enter suspend mode momentarily.\n");
276 			break;
277 		case STANDBY:
278 			printf("System will enter standby mode momentarily.\n");
279 			break;
280 		default:
281 		}
282 	} else
283 		errx(rval, "cannot get reply from APM daemon");
284 	return (0);
285 }
286