xref: /openbsd/sbin/wsconsctl/wsconsctl.c (revision 3e5f9209)
1 /*	$OpenBSD: wsconsctl.c,v 1.27 2012/07/14 08:25:12 shadchin Exp $	*/
2 /*	$NetBSD: wsconsctl.c,v 1.2 1998/12/29 22:40:20 hannken Exp $ */
3 
4 /*-
5  * Copyright (c) 1998 The NetBSD Foundation, Inc.
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to The NetBSD Foundation
9  * by Juergen Hannken-Illjes.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include <fcntl.h>
34 #include <err.h>
35 #include <errno.h>
36 #include <string.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <unistd.h>
40 #include "wsconsctl.h"
41 
42 extern const char *__progname;		/* from crt0.o */
43 
44 extern struct field keyboard_field_tab[];
45 extern struct field mouse_field_tab[];
46 extern struct field display_field_tab[];
47 
48 void	usage(void);
49 
50 struct vartypesw {
51 	const	char *name;
52 	struct field *field_tab;
53 	void	(*getval)(int);
54 	int	(*putval)(int);
55 	char *	(*nextdev)(int);
56 } typesw[] = {
57 	{ "keyboard", keyboard_field_tab,
58 	  keyboard_get_values, keyboard_put_values, keyboard_next_device },
59 	{ "mouse", mouse_field_tab,
60 	  mouse_get_values, mouse_put_values, mouse_next_device },
61 	{ "display", display_field_tab,
62 	  display_get_values, display_put_values, display_next_device },
63 	{ NULL }
64 };
65 
66 struct vartypesw *tab_by_name(const char *, int *);
67 
68 void
69 usage()
70 {
71 	fprintf(stderr,
72 	    "usage: %s [-an]\n"
73 	    "       %s [-n] [-f file] name ...\n"
74 	    "       %s [-n] [-f file] name=value ...\n"
75 	    "       %s [-n] [-f file] name+=value ...\n",
76 	    __progname, __progname, __progname, __progname);
77 	exit(1);
78 }
79 
80 int
81 main(int argc, char *argv[])
82 {
83 	int i, ch, error = 0, aflag = 0, do_merge, putval, devidx, devfd;
84 	struct vartypesw *sw = NULL;
85 	char *getsep = "=", *setsep = " -> ", *p;
86 	char *wdev = NULL;
87 	char *device;
88 	struct field *f;
89 	char devname[20];
90 
91 	while ((ch = getopt(argc, argv, "af:nw")) != -1) {
92 		switch(ch) {
93 		case 'a':
94 			aflag = 1;
95 			break;
96 		case 'f':
97 			wdev = optarg;
98 			break;
99 		case 'n':
100 			getsep = setsep = NULL;
101 			break;
102 		case 'w':
103 			/* compat */
104 			break;
105 		default:
106 			usage();
107 		}
108 	}
109 
110 	argc -= optind;
111 	argv += optind;
112 
113 	if (argc > 0 && aflag != 0)
114 		errx(1, "excess arguments after -a");
115 	if (argc == 0)
116 		aflag = 1;
117 
118 	if (aflag != 0) {
119 		for (sw = typesw; sw->name; sw++) {
120 			for (devidx = 0;; devidx++) {
121 				device = (*sw->nextdev)(devidx);
122 				if (!device ||
123 				    ((devfd = open(device, O_WRONLY)) < 0 &&
124 				     (devfd = open(device, O_RDONLY)) < 0)) {
125 					if (!device || errno != ENXIO) {
126 						if (device && errno != ENOENT) {
127 							warn("%s", device);
128 							error = 1;
129 						}
130 						break;
131 					} else
132 						continue;
133 				}
134 
135 				if (devidx == 0)
136 					snprintf(devname, sizeof(devname),
137 					    "%s", sw->name);
138 				else
139 					snprintf(devname, sizeof(devname),
140 					    "%s%d", sw->name, devidx);
141 
142 				for (f = sw->field_tab; f->name; f++)
143 					if (!(f->flags &
144 					    (FLG_NOAUTO|FLG_WRONLY)))
145 						f->flags |= FLG_GET;
146 				(*sw->getval)(devfd);
147 				for (f = sw->field_tab; f->name; f++)
148 					if (f->flags & FLG_DEAD)
149 						continue;
150 					else if (f->flags & FLG_NOAUTO)
151 						warnx("Use explicit arg to "
152 						    "view %s.%s.",
153 						    devname, f->name);
154 					else if (f->flags & FLG_GET)
155 						pr_field(devname, f, getsep);
156 			}
157 		}
158 	} else if (argc > 0) {
159 		for (i = 0; i < argc; i++) {
160 			sw = tab_by_name(argv[i], &devidx);
161 			if (!sw)
162 				continue;
163 
164 			if (!wdev)
165 				device = (*sw->nextdev)(devidx);
166 			else
167 				device = wdev;
168 
169 			if (!device ||
170 			    ((devfd = open(device, O_WRONLY)) < 0 &&
171 			     (devfd = open(device, O_RDONLY)) < 0)) {
172 				if (!device) {
173 					const char *c = strchr(argv[i], '.');
174 					int k;
175 					if (!c)
176 						c = strchr(argv[i], '\0');
177 					k = c - argv[i];
178 					warnx("%*.*s: no such variable",
179 					    k, k, argv[i]);
180 				} else
181 					warn("%s", device);
182 				error = 1;
183 				continue;
184 			}
185 
186 			if (devidx == 0)
187 				snprintf(devname, sizeof(devname),
188 				    "%s", sw->name);
189 			else
190 				snprintf(devname, sizeof(devname),
191 				    "%s%d", sw->name, devidx);
192 
193 			p = strchr(argv[i], '=');
194 			if (p == NULL) {
195 				if (!strchr(argv[i], '.')) {
196 					for (f = sw->field_tab; f->name; f++)
197 						if (!(f->flags &
198 						    (FLG_NOAUTO|FLG_WRONLY)))
199 							f->flags |= FLG_GET;
200 					(*sw->getval)(devfd);
201 					for (f = sw->field_tab; f->name; f++)
202 						if (f->flags & FLG_DEAD)
203 							continue;
204 						else if (f->flags & FLG_NOAUTO)
205 							warnx("Use explicit "
206 							    "arg to view "
207 							    "%s.%s.",
208 							    devname, f->name);
209 						else if (f->flags & FLG_GET)
210 							pr_field(devname, f,
211 							    getsep);
212 					continue;
213 				}
214 
215 				f = field_by_name(sw->field_tab, argv[i]);
216 				if (f->flags & FLG_DEAD)
217 					continue;
218 				if ((f->flags & FLG_WRONLY)) {
219 					warnx("%s: write only", argv[i]);
220 					continue;
221 				}
222 				f->flags |= FLG_GET;
223 				(*sw->getval)(devfd);
224 				if (f->flags & FLG_DEAD)
225 					continue;
226 				pr_field(devname, f, getsep);
227 			} else {
228 				if (!strchr(argv[i], '.') ||
229 				    (strchr(argv[i], '.') > p)) {
230 					warnx("%s: illegal variable name",
231 					    argv[i]);
232 					continue;
233 				}
234 				if (p > argv[i] &&
235 				    (*(p - 1) == '+' || *(p - 1) == '-')) {
236 					do_merge = *(p - 1);
237 					*(p - 1) = '\0';
238 				} else
239 					do_merge = 0;
240 				*p++ = '\0';
241 
242 				f = field_by_name(sw->field_tab, argv[i]);
243 				if (f->flags & FLG_DEAD)
244 					continue;
245 				if (f->flags & FLG_RDONLY) {
246 					warnx("%s: read only", argv[i]);
247 					continue;
248 				}
249 				if (do_merge || f->flags & FLG_INIT) {
250 					if (!(f->flags & FLG_MODIFY))
251 						errx(1, "%s: can only be set",
252 						    argv[i]);
253 					f->flags |= FLG_GET;
254 					(*sw->getval)(devfd);
255 					f->flags &= ~FLG_GET;
256 				}
257 				rd_field(f, p, do_merge);
258 				f->flags |= FLG_SET;
259 				putval = (*sw->putval)(devfd);
260 				f->flags &= ~FLG_SET;
261 				if (putval != 0 ||
262 				    f->flags & (FLG_DEAD|FLG_NOAUTO))
263 					continue;
264 				if (f->flags & FLG_WRONLY) {
265 					pr_field(devname, f, setsep);
266 				} else {
267 					f->flags |= FLG_GET;
268 					(*sw->getval)(devfd);
269 					if (f->flags & FLG_DEAD)
270 						continue;
271 					pr_field(devname, f, setsep);
272 				}
273 			}
274 
275 			close(devfd);
276 		}
277 	} else
278 		usage();
279 
280 	exit(error);
281 }
282 
283 struct vartypesw *
284 tab_by_name(const char *var, int *idx)
285 {
286 	struct vartypesw *sw;
287 	const char *p = strchr(var, '.');
288 	char *c;
289 	int i;
290 
291 	for (sw = typesw; sw->name; sw++)
292 		if (!strncmp(sw->name, var, strlen(sw->name)))
293 			break;
294 
295 	if (!p)
296 		p = strchr(var, '\0');
297 
298 	if (!sw->name) {
299 		i = p - var;
300 		warnx("%*.*s: no such variable", i, i, var);
301 		return (NULL);
302 	}
303 
304 	if ((p - var) > strlen(sw->name)) {
305 		c = (char *)var;
306 		c = c + strlen(sw->name);
307 		i = 0;
308 		while (c < p) {
309 			if (*c >= '0' && *c <= '9')
310 				i = i * 10 + *c - '0';
311 			else
312 				i = -1;
313 			c++;
314 		}
315 		if (i < 0 || i > 32) {
316 			i = p - var;
317 			warnx("%*.*s: no such variable", i, i, var);
318 			return (NULL);
319 		}
320 	} else
321 		i = 0;
322 
323 	*idx = i;
324 
325 	return (sw);
326 }
327