1/*
2 * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
3 * Use is subject to license terms.
4 */
5
6/*
7 * Copyright (c) 1983 Regents of the University of California.
8 * All rights reserved. The Berkeley software License Agreement
9 * specifies the terms and conditions for redistribution.
10 */
11
12#pragma ident	"%Z%%M%	%I%	%E% SMI"
13
14/*
15 * Stolen from ucb/lpr/printjob.c
16 */
17
18#include <string.h>
19#include "uucp.h"
20
21static struct termios termios_set;
22static struct termios termios_clear;
23
24static int parse_modes(char *modes);
25static void setty(int);
26
27int
28setmode(modes, fd)
29	char *modes;
30	int fd;
31{
32	if (parse_modes(modes))
33		setty(fd);
34	return (0);
35}
36
37struct mds {
38	char	*string;
39	unsigned long	set;
40	unsigned long	reset;
41};
42						/* Control Modes */
43static struct mds cmodes[] = {
44	"-parity", CS8, PARENB|CSIZE,
45	"-evenp", CS8, PARENB|CSIZE,
46	"-oddp", CS8, PARENB|PARODD|CSIZE,
47	"parity", PARENB|CS7, PARODD|CSIZE,
48	"evenp", PARENB|CS7, PARODD|CSIZE,
49	"oddp", PARENB|PARODD|CS7, CSIZE,
50	"parenb", PARENB, 0,
51	"-parenb", 0, PARENB,
52	"parodd", PARODD, 0,
53	"-parodd", 0, PARODD,
54	"cs8", CS8, CSIZE,
55	"cs7", CS7, CSIZE,
56	"cs6", CS6, CSIZE,
57	"cs5", CS5, CSIZE,
58	"cstopb", CSTOPB, 0,
59	"-cstopb", 0, CSTOPB,
60	"stopb", CSTOPB, 0,
61	"-stopb", 0, CSTOPB,
62	"hupcl", HUPCL, 0,
63	"hup", HUPCL, 0,
64	"-hupcl", 0, HUPCL,
65	"-hup", 0, HUPCL,
66	"clocal", CLOCAL, 0,
67	"-clocal", 0, CLOCAL,
68	"nohang", CLOCAL, 0,
69	"-nohang", 0, CLOCAL,
70#if 0		/* this bit isn't supported */
71	"loblk", LOBLK, 0,
72	"-loblk", 0, LOBLK,
73#endif
74	"cread", CREAD, 0,
75	"-cread", 0, CREAD,
76#ifndef CRTSCTS
77#define	CRTSCTS	0x80000000
78#endif
79	"crtscts", CRTSCTS, 0,
80	"-crtscts", 0, CRTSCTS,
81#ifndef CRTSXOFF
82#define	CRTSXOFF 0x40000000
83#endif
84	"crtsxoff", CRTSXOFF, 0,
85	"-crtsxoff", 0, CRTSXOFF,
86	"litout", CS8, (CSIZE|PARENB),
87	"-litout", (CS7|PARENB), CSIZE,
88	"pass8", CS8, (CSIZE|PARENB),
89	"-pass8", (CS7|PARENB), CSIZE,
90	"raw", CS8, (CSIZE|PARENB),
91	"-raw", (CS7|PARENB), CSIZE,
92	"cooked", (CS7|PARENB), CSIZE,
93	"sane", (CS7|PARENB|CREAD), (CSIZE|PARODD|CLOCAL),
94	0
95};
96						/* Input Modes */
97static struct mds imodes[] = {
98	"ignbrk", IGNBRK, 0,
99	"-ignbrk", 0, IGNBRK,
100	"brkint", BRKINT, 0,
101	"-brkint", 0, BRKINT,
102	"ignpar", IGNPAR, 0,
103	"-ignpar", 0, IGNPAR,
104	"parmrk", PARMRK, 0,
105	"-parmrk", 0, PARMRK,
106	"inpck", INPCK, 0,
107	"-inpck", 0, INPCK,
108	"istrip", ISTRIP, 0,
109	"-istrip", 0, ISTRIP,
110	"inlcr", INLCR, 0,
111	"-inlcr", 0, INLCR,
112	"igncr", IGNCR, 0,
113	"-igncr", 0, IGNCR,
114	"icrnl", ICRNL, 0,
115	"-icrnl", 0, ICRNL,
116	"-nl", ICRNL, (INLCR|IGNCR),
117	"nl", 0, ICRNL,
118	"iuclc", IUCLC, 0,
119	"-iuclc", 0, IUCLC,
120	"lcase", IUCLC, 0,
121	"-lcase", 0, IUCLC,
122	"LCASE", IUCLC, 0,
123	"-LCASE", 0, IUCLC,
124	"ixon", IXON, 0,
125	"-ixon", 0, IXON,
126	"ixany", IXANY, 0,
127	"-ixany", 0, IXANY,
128	"decctlq", 0, IXANY,
129	"-decctlq", IXANY, 0,
130	"ixoff", IXOFF, 0,
131	"-ixoff", 0, IXOFF,
132	"tandem", IXOFF, 0,
133	"-tandem", 0, IXOFF,
134	"imaxbel", IMAXBEL, 0,
135	"-imaxbel", 0, IMAXBEL,
136	"pass8", 0, ISTRIP,
137	"-pass8", ISTRIP, 0,
138	"raw", 0, (unsigned long)-1,
139	"-raw", (BRKINT|IGNPAR|ISTRIP|ICRNL|IXON|IMAXBEL), 0,
140	"cooked", (BRKINT|IGNPAR|ISTRIP|ICRNL|IXON), 0,
141	"sane", (BRKINT|IGNPAR|ISTRIP|ICRNL|IXON|IMAXBEL),
142		(IGNBRK|PARMRK|INPCK|INLCR|IGNCR|IUCLC|IXOFF),
143	0
144};
145						/* Local Modes */
146static struct mds lmodes[] = {
147	"isig", ISIG, 0,
148	"-isig", 0, ISIG,
149	"noisig", 0, ISIG,
150	"-noisig", ISIG, 0,
151	"iexten", IEXTEN, 0,
152	"-iexten", 0, IEXTEN,
153	"icanon", ICANON, 0,
154	"-icanon", 0, ICANON,
155	"cbreak", 0, ICANON,
156	"-cbreak", ICANON, 0,
157	"xcase", XCASE, 0,
158	"-xcase", 0, XCASE,
159	"lcase", XCASE, 0,
160	"-lcase", 0, XCASE,
161	"LCASE", XCASE, 0,
162	"-LCASE", 0, XCASE,
163	"echo", ECHO, 0,
164	"-echo", 0, ECHO,
165	"echoe", ECHOE, 0,
166	"-echoe", 0, ECHOE,
167	"crterase", ECHOE, 0,
168	"-crterase", 0, ECHOE,
169	"echok", ECHOK, 0,
170	"-echok", 0, ECHOK,
171	"lfkc", ECHOK, 0,
172	"-lfkc", 0, ECHOK,
173	"echonl", ECHONL, 0,
174	"-echonl", 0, ECHONL,
175	"noflsh", NOFLSH, 0,
176	"-noflsh", 0, NOFLSH,
177	"tostop", TOSTOP, 0,
178	"-tostop", 0, TOSTOP,
179	"echoctl", ECHOCTL, 0,
180	"-echoctl", 0, ECHOCTL,
181	"ctlecho", ECHOCTL, 0,
182	"-ctlecho", 0, ECHOCTL,
183	"echoprt", ECHOPRT, 0,
184	"-echoprt", 0, ECHOPRT,
185	"prterase", ECHOPRT, 0,
186	"-prterase", 0, ECHOPRT,
187	"echoke", ECHOKE, 0,
188	"-echoke", 0, ECHOKE,
189	"crtkill", ECHOKE, 0,
190	"-crtkill", 0, ECHOKE,
191#if 0		/* this bit isn't supported yet */
192	"defecho", DEFECHO, 0,
193	"-defecho", 0, DEFECHO,
194#endif
195	"raw", 0, (ISIG|ICANON|XCASE|IEXTEN),
196	"-raw", (ISIG|ICANON|IEXTEN), 0,
197	"cooked", (ISIG|ICANON), 0,
198	"sane", (ISIG|ICANON|ECHO|ECHOE|ECHOK|ECHOCTL|ECHOKE),
199		(XCASE|ECHOPRT|ECHONL|NOFLSH),
200	0,
201};
202						/* Output Modes */
203static struct mds omodes[] = {
204	"opost", OPOST, 0,
205	"-opost", 0, OPOST,
206	"nopost", 0, OPOST,
207	"-nopost", OPOST, 0,
208	"olcuc", OLCUC, 0,
209	"-olcuc", 0, OLCUC,
210	"lcase", OLCUC, 0,
211	"-lcase", 0, OLCUC,
212	"LCASE", OLCUC, 0,
213	"-LCASE", 0, OLCUC,
214	"onlcr", ONLCR, 0,
215	"-onlcr", 0, ONLCR,
216	"-nl", ONLCR, (OCRNL|ONLRET),
217	"nl", 0, ONLCR,
218	"ocrnl", OCRNL, 0,
219	"-ocrnl", 0, OCRNL,
220	"onocr", ONOCR, 0,
221	"-onocr", 0, ONOCR,
222	"onlret", ONLRET, 0,
223	"-onlret", 0, ONLRET,
224	"fill", OFILL, OFDEL,
225	"-fill", 0, OFILL|OFDEL,
226	"nul-fill", OFILL, OFDEL,
227	"del-fill", OFILL|OFDEL, 0,
228	"ofill", OFILL, 0,
229	"-ofill", 0, OFILL,
230	"ofdel", OFDEL, 0,
231	"-ofdel", 0, OFDEL,
232	"cr0", CR0, CRDLY,
233	"cr1", CR1, CRDLY,
234	"cr2", CR2, CRDLY,
235	"cr3", CR3, CRDLY,
236	"tab0", TAB0, TABDLY,
237	"tabs", TAB0, TABDLY,
238	"tab1", TAB1, TABDLY,
239	"tab2", TAB2, TABDLY,
240	"-tabs", XTABS, TABDLY,
241	"tab3", XTABS, TABDLY,
242	"nl0", NL0, NLDLY,
243	"nl1", NL1, NLDLY,
244	"ff0", FF0, FFDLY,
245	"ff1", FF1, FFDLY,
246	"vt0", VT0, VTDLY,
247	"vt1", VT1, VTDLY,
248	"bs0", BS0, BSDLY,
249	"bs1", BS1, BSDLY,
250#if 0		/* these bits aren't supported yet */
251	"pageout", PAGEOUT, 0,
252	"-pageout", 0, PAGEOUT,
253	"wrap", WRAP, 0,
254	"-wrap", 0, WRAP,
255#endif
256	"litout", 0, OPOST,
257	"-litout", OPOST, 0,
258	"raw", 0, OPOST,
259	"-raw", OPOST, 0,
260	"cooked", OPOST, 0,
261	"33", CR1, (CRDLY|TABDLY|NLDLY|FFDLY|VTDLY|BSDLY),
262	"tty33", CR1, (CRDLY|TABDLY|NLDLY|FFDLY|VTDLY|BSDLY),
263	"tn", CR1, (CRDLY|TABDLY|NLDLY|FFDLY|VTDLY|BSDLY),
264	"tn300", CR1, (CRDLY|TABDLY|NLDLY|FFDLY|VTDLY|BSDLY),
265	"ti", CR2, (CRDLY|TABDLY|NLDLY|FFDLY|VTDLY|BSDLY),
266	"ti700", CR2, (CRDLY|TABDLY|NLDLY|FFDLY|VTDLY|BSDLY),
267	"05", NL1, (CRDLY|TABDLY|NLDLY|FFDLY|VTDLY|BSDLY),
268	"vt05", NL1, (CRDLY|TABDLY|NLDLY|FFDLY|VTDLY|BSDLY),
269	"tek", FF1, (CRDLY|TABDLY|NLDLY|FFDLY|VTDLY|BSDLY),
270	"37", (FF1|VT1|CR2|TAB1|NL1), (NLDLY|CRDLY|TABDLY|BSDLY|VTDLY|FFDLY),
271	"tty37", (FF1|VT1|CR2|TAB1|NL1), (NLDLY|CRDLY|TABDLY|BSDLY|VTDLY|FFDLY),
272	"sane", (OPOST|ONLCR), (OLCUC|OCRNL|ONOCR|ONLRET|OFILL|OFDEL|
273			NLDLY|CRDLY|TABDLY|BSDLY|VTDLY|FFDLY),
274	0,
275};
276
277/*
278 * Parse a set of modes.
279 */
280static int
281parse_modes(modes)
282	char *modes;
283{
284	char *curtoken;
285	int match;
286	int i;
287
288	termios_clear.c_iflag = 0;
289	termios_clear.c_oflag = 0;
290	termios_clear.c_cflag = 0;
291	termios_clear.c_lflag = 0;
292	termios_set.c_iflag = 0;
293	termios_set.c_oflag = 0;
294	termios_set.c_cflag = 0;
295	termios_set.c_lflag = 0;
296
297	curtoken = strtok(modes, ",");
298	while (curtoken != NULL) {
299		match = 0;
300		for (i = 0; imodes[i].string != NULL; i++) {
301			if (strcmp(curtoken, imodes[i].string) == 0) {
302				match++;
303				termios_clear.c_iflag |= imodes[i].reset;
304				termios_set.c_iflag |= imodes[i].set;
305			}
306		}
307		for (i = 0; omodes[i].string != NULL; i++) {
308			if (strcmp(curtoken, omodes[i].string) == 0) {
309				match++;
310				termios_clear.c_oflag |= omodes[i].reset;
311				termios_set.c_oflag |= omodes[i].set;
312			}
313		}
314		for (i = 0; cmodes[i].string != NULL; i++) {
315			if (strcmp(curtoken, cmodes[i].string) == 0) {
316				match++;
317				termios_clear.c_cflag |= cmodes[i].reset;
318				termios_set.c_cflag |= cmodes[i].set;
319			}
320		}
321		for (i = 0; lmodes[i].string != NULL; i++) {
322			if (strcmp(curtoken, lmodes[i].string) == 0) {
323				match++;
324				termios_clear.c_lflag |= lmodes[i].reset;
325				termios_set.c_lflag |= lmodes[i].set;
326			}
327		}
328		if (!match) {
329			CDEBUG(5, "unknown mode %s in STTY= string", curtoken);
330			return (0);
331		}
332		curtoken = strtok((char *)NULL, ",");
333	}
334	return (1);
335}
336
337/*
338 * setup tty lines.
339 */
340static void
341setty(int fd)
342{
343	struct termios termios;
344
345	if ((*Ioctl)(fd, TCGETS, &termios) < 0) {
346		CDEBUG(5, "ioctl(TCGETS): %d", errno);
347		return;
348	}
349
350	termios.c_iflag &= ~termios_clear.c_iflag;
351	termios.c_iflag |= termios_set.c_iflag;
352	termios.c_oflag &= ~termios_clear.c_oflag;
353	termios.c_oflag |= termios_set.c_oflag;
354	termios.c_cflag &= ~termios_clear.c_cflag;
355	termios.c_cflag |= termios_set.c_cflag;
356	termios.c_lflag &= ~termios_clear.c_lflag;
357	termios.c_lflag |= termios_set.c_lflag;
358
359	if ((*Ioctl)(fd, TCSETSF, &termios) < 0) {
360		CDEBUG(5, "ioctl(TCSETSF): %d", errno);
361		return;
362	}
363}
364