xref: /openbsd/sbin/wsconsctl/wsconsctl.c (revision df69c215)
1 /*	$OpenBSD: wsconsctl.c,v 1.32 2019/06/28 13:32:46 deraadt 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	(*init)(int,int);
54 	void	(*getval)(int);
55 	int	(*putval)(int);
56 	char *	(*nextdev)(int);
57 } typesw[] = {
58 	{ "keyboard", keyboard_field_tab, NULL,
59 	  keyboard_get_values, keyboard_put_values, keyboard_next_device },
60 	{ "mouse", mouse_field_tab, mouse_init,
61 	  mouse_get_values, mouse_put_values, mouse_next_device },
62 	{ "display", display_field_tab, NULL,
63 	  display_get_values, display_put_values, display_next_device },
64 	{ NULL }
65 };
66 
67 struct vartypesw *tab_by_name(const char *, int *);
68 
69 void
usage(void)70 usage(void)
71 {
72 	fprintf(stderr,
73 	    "usage: %s [-an]\n"
74 	    "       %s [-n] [-f file] name ...\n"
75 	    "       %s [-n] [-f file] name=value ...\n",
76 	    __progname, __progname, __progname);
77 	exit(1);
78 }
79 
80 int
main(int argc,char * argv[])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)) == -1 &&
124 				     (devfd = open(device, O_RDONLY)) == -1)) {
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 				if (sw->init != NULL)
143 					(*sw->init)(devfd, devidx);
144 
145 				for (f = sw->field_tab; f->name; f++)
146 					if (!(f->flags &
147 					    (FLG_NOAUTO|FLG_WRONLY)))
148 						f->flags |= FLG_GET;
149 				(*sw->getval)(devfd);
150 				for (f = sw->field_tab; f->name; f++)
151 					if (f->flags & FLG_DEAD)
152 						continue;
153 					else if (f->flags & FLG_NOAUTO)
154 						warnx("Use explicit arg to "
155 						    "view %s.%s.",
156 						    devname, f->name);
157 					else if (f->flags & FLG_GET)
158 						pr_field(devname, f, getsep);
159 			}
160 		}
161 	} else if (argc > 0) {
162 		for (i = 0; i < argc; i++) {
163 			sw = tab_by_name(argv[i], &devidx);
164 			if (!sw)
165 				continue;
166 
167 			if (!wdev)
168 				device = (*sw->nextdev)(devidx);
169 			else
170 				device = wdev;
171 
172 			if (!device ||
173 			    ((devfd = open(device, O_WRONLY)) == -1 &&
174 			     (devfd = open(device, O_RDONLY)) == -1)) {
175 				if (!device) {
176 					const char *c = strchr(argv[i], '.');
177 					int k;
178 					if (!c)
179 						c = strchr(argv[i], '\0');
180 					k = c - argv[i];
181 					warnx("%*.*s: no such variable",
182 					    k, k, argv[i]);
183 				} else
184 					warn("%s", device);
185 				error = 1;
186 				continue;
187 			}
188 
189 			if (devidx == 0)
190 				snprintf(devname, sizeof(devname),
191 				    "%s", sw->name);
192 			else
193 				snprintf(devname, sizeof(devname),
194 				    "%s%d", sw->name, devidx);
195 
196 			if (sw->init != NULL)
197 				(*sw->init)(devfd, devidx);
198 
199 			p = strchr(argv[i], '=');
200 			if (p == NULL) {
201 				if (!strchr(argv[i], '.')) {
202 					for (f = sw->field_tab; f->name; f++)
203 						if (!(f->flags &
204 						    (FLG_NOAUTO|FLG_WRONLY)))
205 							f->flags |= FLG_GET;
206 					(*sw->getval)(devfd);
207 					for (f = sw->field_tab; f->name; f++)
208 						if (f->flags & FLG_DEAD)
209 							continue;
210 						else if (f->flags & FLG_NOAUTO)
211 							warnx("Use explicit "
212 							    "arg to view "
213 							    "%s.%s.",
214 							    devname, f->name);
215 						else if (f->flags & FLG_GET)
216 							pr_field(devname, f,
217 							    getsep);
218 					continue;
219 				}
220 
221 				f = field_by_name(sw->field_tab, argv[i]);
222 				if (f->flags & FLG_DEAD)
223 					continue;
224 				if ((f->flags & FLG_WRONLY)) {
225 					warnx("%s: write only", argv[i]);
226 					continue;
227 				}
228 				f->flags |= FLG_GET;
229 				(*sw->getval)(devfd);
230 				if (f->flags & FLG_DEAD)
231 					continue;
232 				pr_field(devname, f, getsep);
233 			} else {
234 				if (!strchr(argv[i], '.') ||
235 				    (strchr(argv[i], '.') > p)) {
236 					warnx("%s: illegal variable name",
237 					    argv[i]);
238 					continue;
239 				}
240 				if (p > argv[i] &&
241 				    (*(p - 1) == '+' || *(p - 1) == '-')) {
242 					do_merge = *(p - 1);
243 					*(p - 1) = '\0';
244 				} else
245 					do_merge = 0;
246 				*p++ = '\0';
247 
248 				f = field_by_name(sw->field_tab, argv[i]);
249 				if (f->flags & FLG_DEAD)
250 					continue;
251 				if (f->flags & FLG_RDONLY) {
252 					warnx("%s: read only", argv[i]);
253 					continue;
254 				}
255 				if (do_merge || f->flags & FLG_INIT) {
256 					if (!(f->flags & FLG_MODIFY))
257 						errx(1, "%s: can only be set",
258 						    argv[i]);
259 					f->flags |= FLG_GET;
260 					(*sw->getval)(devfd);
261 					f->flags &= ~FLG_GET;
262 				}
263 				rd_field(f, p, do_merge);
264 				f->flags |= FLG_SET;
265 				putval = (*sw->putval)(devfd);
266 				f->flags &= ~FLG_SET;
267 				if (putval != 0 ||
268 				    f->flags & (FLG_DEAD|FLG_NOAUTO))
269 					continue;
270 				if (f->flags & FLG_WRONLY) {
271 					pr_field(devname, f, setsep);
272 				} else {
273 					if (!(f->flags & FLG_NORDBACK)) {
274 						f->flags |= FLG_GET;
275 						(*sw->getval)(devfd);
276 					}
277 					if (f->flags & FLG_DEAD)
278 						continue;
279 					pr_field(devname, f, setsep);
280 				}
281 			}
282 
283 			close(devfd);
284 		}
285 	} else
286 		usage();
287 
288 	exit(error);
289 }
290 
291 struct vartypesw *
tab_by_name(const char * var,int * idx)292 tab_by_name(const char *var, int *idx)
293 {
294 	struct vartypesw *sw;
295 	const char *p = strchr(var, '.');
296 	char *c;
297 	int i;
298 
299 	for (sw = typesw; sw->name; sw++)
300 		if (!strncmp(sw->name, var, strlen(sw->name)))
301 			break;
302 
303 	if (!p)
304 		p = strchr(var, '\0');
305 
306 	if (!sw->name) {
307 		i = p - var;
308 		warnx("%*.*s: no such variable", i, i, var);
309 		return (NULL);
310 	}
311 
312 	if ((p - var) > strlen(sw->name)) {
313 		c = (char *)var;
314 		c = c + strlen(sw->name);
315 		i = 0;
316 		while (c < p) {
317 			if (*c >= '0' && *c <= '9')
318 				i = i * 10 + *c - '0';
319 			else
320 				i = -1;
321 			c++;
322 		}
323 		if (i < 0 || i > 32) {
324 			i = p - var;
325 			warnx("%*.*s: no such variable", i, i, var);
326 			return (NULL);
327 		}
328 	} else
329 		i = 0;
330 
331 	*idx = i;
332 
333 	return (sw);
334 }
335