1 /* $MirOS: src/usr.sbin/wsconfig/wsconfig.c,v 1.16 2007/05/10 13:02:21 tg Exp $ */
2 
3 /*-
4  * Copyright (c) 2006, 2007
5  *	Thorsten Glaser <tg@mirbsd.de>
6  *
7  * Provided that these terms and disclaimer and all copyright notices
8  * are retained or reproduced in an accompanying document, permission
9  * is granted to deal in this work without restriction, including un-
10  * limited rights to use, publicly perform, distribute, sell, modify,
11  * merge, give away, or sublicence.
12  *
13  * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
14  * the utmost extent permitted by applicable law, neither express nor
15  * implied; without malicious intent or gross negligence. In no event
16  * may a licensor, author or contributor be held liable for indirect,
17  * direct, other damage, loss, or other issues arising in any way out
18  * of dealing in the work, even if advised of the possibility of such
19  * damage or existence of a defect, except proven that it results out
20  * of said person's immediate fault when using the work as intended.
21  */
22 
23 #include <sys/param.h>
24 #include <sys/ioctl.h>
25 #include <dev/wscons/wsconsio.h>
26 #include <dev/wscons/wsdisplay_usl_io.h>
27 #include <dev/wscons/wsdisplayvar.h>
28 #include <ctype.h>
29 #include <err.h>
30 #include <errno.h>
31 #include <fcntl.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <termios.h>
36 #include <unistd.h>
37 
38 __RCSID("$MirOS: src/usr.sbin/wsconfig/wsconfig.c,v 1.16 2007/05/10 13:02:21 tg Exp $");
39 __RCSID("$miros: ports/sysutils/chkuterm/dist/chkuterm.c,v 1.11 2007/05/10 13:02:22 tg Exp $");
40 __RCSID("$miros: ports/misc/screen/patches/patch-screen_c,v 1.12 2007/05/10 13:02:23 tg Exp $");
41 
42 #define DEFDEV	"/dev/ttyCcfg"
43 
44 /* query string sent to the terminal for LC_CTYPE detection */
45 /* XXX is U+20AC U+002E ok or some other char better? Think EUC, SJIS, etc. */
46 const char ctype_qstr[] = "\030\032\r\xE2\x82\xAC.\033[6n";
47 
48 #ifndef SMALL
49 __dead void usage(void);
50 #endif
51 
52 /*
53  * common options:
54  * -f <device>		select device on which to operate
55  * -q			be more quiet
56  * -?			help
57  *
58  *
59  * operation modes:
60  *
61  * === default device: /dev/ttyCcfg ===
62  * -I <number>		dump info about font in slot #number
63  * -S			print out active VT number
64  * -s <number>		activate VT #number
65  *
66  * === default device: ttyname(stdin) ===
67  * -o <name>		select font #name
68  * -U			return true and print (unless -q) if VT is UTF-8
69  */
70 
71 int
72 #ifdef SMALL
main(void)73 main(void)		/* like -U -q */
74 #else
75 main(int argc, char **argv)
76 #endif
77 {
78 	const char *wsdev, *est;
79 	char ch;
80 	int wsfd, c, rv = 0;
81 	int action = 0, nr = 0;
82 	struct termios tio, otio;
83 	fd_set fds;
84 	struct timeval tv;
85 	FILE *wsf;
86 #ifndef SMALL
87 	struct wsdisplay_font f;
88 	int q = 0;
89 
90 	wsdev = DEFDEV;
91 	while ((c = getopt(argc, argv, "f:I:o:qSs:U")) != -1)
92 		switch (c) {
93 		case 'f':
94 			wsdev = optarg;
95 			break;
96 		case 'I':
97 			if (action)
98 				usage();
99 			else
100 				action = 5;
101 			nr = strtonum(optarg, 0, WSDISPLAY_MAXFONT - 1, &est);
102 			if (est)
103 				errx(1, "slot number %s is %s", optarg, est);
104 			f.index = nr;
105 			break;
106 		case 'o':
107 			if (action)
108 				usage();
109 			else
110 				action = 4;
111 			strlcpy(f.name, optarg, WSFONT_NAME_SIZE);
112 			break;
113 		case 'q':
114 			q = 1;
115 			break;
116 		case 'S':
117 			if (action)
118 				usage();
119 			else
120 				action = 2;
121 			break;
122 		case 's':
123 			if (action)
124 				usage();
125 			else
126 				action = 1;
127 			nr = strtonum(optarg, 1, 255, &est);
128 			if (est)
129 				errx(1, "console number %s is %s", optarg, est);
130 			break;
131 		case 'U':
132 			if (action)
133 				usage();
134 			else
135 #endif
136 				action = 6;
137 #ifndef SMALL
138 			break;
139 		default:
140 			usage();
141 		}
142 	argc -= optind;
143 	argv += optind;
144 
145 	if (!action)
146 		usage();
147 
148 	if (wsdev == DEFDEV && (action == 4 || action == 6))
149 #endif
150 		if ((wsdev = ttyname(STDIN_FILENO)) == NULL)
151 			wsdev = "/dev/tty";
152 
153 	/* apparently O_RDONLY wouldn't matter but we stay safe */
154 	if ((est = ttyname(STDIN_FILENO)) != NULL && !strcmp(wsdev, est))
155 		wsfd = STDIN_FILENO;
156 	else if ((est = ttyname(STDOUT_FILENO)) != NULL && !strcmp(wsdev, est))
157 		wsfd = STDOUT_FILENO;
158 	else
159 		if ((wsfd = open(wsdev, O_RDWR, 0)) < 0)
160 			err(2, "open %s", wsdev);
161 	wsf = fdopen(wsfd, "rb+");
162 
163 #ifndef SMALL
164 	switch (action) {
165 	case 1:
166 		if (argc)
167 			usage();
168 		if (ioctl(wsfd, VT_ACTIVATE, nr) == -1)
169 			err(3, "ioctl VT_ACTIVATE %d", nr);
170 		break;
171 	case 2:
172 		if (argc)
173 			usage();
174 		if (ioctl(wsfd, VT_GETACTIVE, &nr) == -1)
175 			err(3, "ioctl VT_GETACTIVE");
176 		printf("%d\n", nr);
177 		break;
178 	case 4:
179 		if (ioctl(wsfd, WSDISPLAYIO_USEFONT, &f) == -1)
180 			err(3, "ioctl WSDISPLAYIO_USEFONT");
181 		if (!q)
182 			printf("selected font \"%s\"\n", f.name);
183 		break;
184 	case 5:
185 		if (ioctl(wsfd, WSDISPLAYIO_LSFONT, &f) == -1)
186 			err(3, "ioctl WSDISPLAYIO_LSFONT");
187 		if (q)
188 			printf("%s\n", f.name);
189 		else {
190 			printf("%32s%s\n", "Name:", f.name);
191 			printf("%32s%d\n", "Index:", f.index);
192 			printf("%32s%d\n", "First Character:", f.firstchar);
193 			printf("%32s%d\n", "Number of Characters:", f.numchars);
194 			printf("%32s%d\n", "Last Character:",
195 			    f.firstchar + f.numchars);
196 			if ((unsigned)f.encoding < 5)
197 				printf("%32s%s\n", "Encoding:",
198 				    (f.encoding == 0) ? "ISO (latin1)" :
199 				    (f.encoding == 1) ? "IBM (437)" :
200 				    (f.encoding == 2) ? "PCVT (special)" :
201 				    (f.encoding == 3) ? "ISO7 (greek)" :
202 				    "SONY");
203 			else
204 				printf("%32sUNKNOWN (%d)\n",
205 				    "Encoding:", f.encoding);
206 			printf("%32s%u\n", "Font Width:", f.fontwidth);
207 			printf("%32s%u\n", "Font Height:", f.fontheight);
208 			printf("%32s%u\n", "Font Stride:", f.stride);
209 			if ((unsigned)f.bitorder < 3)
210 				printf("%32s%s\n", "Bit Order:",
211 				    (f.bitorder == 0) ? "KNOWN (host)" :
212 				    (f.bitorder == 1) ? "L2R" : "R2L");
213 			else
214 				printf("%32sUNKNOWN (%d)\n",
215 				    "Bit Order:", f.bitorder);
216 			if ((unsigned)f.byteorder < 3)
217 				printf("%32s%s\n", "Byte Order:",
218 				    (f.byteorder == 0) ? "KNOWN (host)" :
219 				    (f.byteorder == 1) ? "L2R" : "R2L");
220 			else
221 				printf("%32sUNKNOWN (%d)\n",
222 				    "Byte Order:", f.byteorder);
223 		}
224 		break;
225 	case 6:
226 #endif
227 		if (tcgetattr(wsfd, &otio))
228 			err(3, "tcgetattr");
229 		tio = otio;
230 		cfmakeraw(&tio);
231 		if (tcflush(wsfd, TCIOFLUSH))
232 			warn("tcflush");
233 		rv = /* error */ 3;
234 		if (tcsetattr(wsfd, TCSANOW, &tio)) {
235 			warn("tcsetattr\r");
236 			goto tios_err;
237 		}
238 		tv.tv_sec = 0;
239 		tv.tv_usec = 75;
240 		select(0, NULL, NULL, NULL, &tv);	/* sleep 75 msec */
241 		if ((size_t)write(wsfd, ctype_qstr, strlen(ctype_qstr)) !=
242 		    strlen(ctype_qstr)) {
243 			warn("write\r");
244 			goto noin;
245 		}
246 		select(0, NULL, NULL, NULL, &tv);	/* sleep 75 msec */
247 		FD_ZERO(&fds);
248 		FD_SET(wsfd, &fds);
249 		tv.tv_sec = 2;
250 		tv.tv_usec = 0;
251 		if (select(wsfd + 1, &fds, NULL, NULL, &tv) <= 0)
252 			goto noin;
253 		nr = read(wsfd, &ch, 1);
254 		rv = /* unknown */ 1;
255 		if (wsf != NULL && nr == 1 && ch == 033) {
256 			unsigned zeile, spalte;
257 
258 			if (fscanf(wsf, "[%u;%u", &zeile, &spalte) == 2)
259 				switch (spalte) {
260 				case 1:	/* EUC-JP, EUC-KR kterm */
261 				case 5:	/* Shift-JIS kterm */
262 					break;
263 				case 3:	/* UTF-8 xterm, screen */
264 					rv = 0;
265 					break;
266 				case 4:	/* ISO-8859-1 xterm, screen */
267 					rv = 2;
268 					break;
269 				default:
270 					rv = 0x1000 | spalte;
271 					break;
272 				}
273 		}
274  noin:
275 		write(wsfd, "\r      \r", 8);
276  tios_err:
277 		if (tcflush(wsfd, TCIOFLUSH))
278 			warn("tcflush");
279 		if (tcsetattr(wsfd, TCSANOW, &otio))
280 			err(3, "tcsetattr");
281 #ifndef SMALL
282 		if (rv & 0x1000) {
283 			/* unknown charset */
284 			if (!q)
285 				printf("# unknown column %d\n", rv & 0xFFF);
286 			rv = 1;
287 		}
288 		if (!q)
289 			printf("LC_CTYPE=%s; export LC_CTYPE\n",
290 			    rv == 0 ? "en_US.UTF-8" : "C");
291 		if (!q && rv > 2)
292 			puts("# warning: problems occured!\n");
293 		break;
294 	default:
295 		usage();
296 	}
297 #endif
298 
299 	if (wsf == NULL)
300 		close(wsfd);
301 	else
302 		fclose(wsf);
303 	return (rv);
304 }
305 
306 #ifndef SMALL
307 void
usage(void)308 usage(void)
309 {
310 	extern const char *__progname;
311 
312 	fprintf(stderr, "Usage:\t%s -U\n"
313 	    "\t%s [-f ctldev] -s screen\n"
314 	    "\t%s [-q] [-f wsdev] { -I slot | -o name }\n",
315 	    __progname, __progname, __progname);
316 	exit(1);
317 }
318 #endif
319