xref: /illumos-gate/usr/src/cmd/bnu/line.c (revision 56e2cc86321ec889bf83a888d902c60d6fb2ef8d)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 /*
31  * This is a new line.c, which consists of line.c and culine.c
32  * merged together.
33  */
34 
35 #include "uucp.h"
36 
37 static struct sg_spds {
38 	int	sp_val,
39 		sp_name;
40 } spds[] = {
41 	{  50,   B50},
42 	{  75,   B75},
43 	{ 110,  B110},
44 	{ 134,  B134},
45 	{ 150,  B150},
46 	{ 200,  B200},
47 	{ 300,  B300},
48 	{ 600,  B600},
49 	{1200, B1200},
50 	{1800, B1800},
51 	{2400, B2400},
52 	{4800, B4800},
53 	{9600, B9600},
54 #ifdef EXTA
55 	{19200,	EXTA},
56 #endif
57 #ifdef B19200
58 	{19200,	B19200},
59 #endif
60 #ifdef B38400
61 	{38400,	B38400},
62 #endif
63 	{57600, B57600},
64 	{76800, B76800},
65 	{115200, B115200},
66 	{153600, B153600},
67 	{230400, B230400},
68 	{307200, B307200},
69 	{460800, B460800},
70 	{921600, B921600},
71 	{0,    0}
72 };
73 
74 #define	PACKSIZE	64
75 #define	HEADERSIZE	6
76 
77 GLOBAL int
78 	packsize = PACKSIZE,
79 	xpacksize = PACKSIZE;
80 
81 #define	SNDFILE	'S'
82 #define	RCVFILE 'R'
83 #define	RESET	'X'
84 
85 #ifdef PKSPEEDUP
86 GLOBAL int linebaudrate;	/* for speedup hook in pk1.c */
87 #endif /*  PKSPEEDUP  */
88 static int Saved_line;		/* was savline() successful?	*/
89 static int Saved_termios;	/* was termios saved?	*/
90 GLOBAL int
91 	Oddflag = 0,	/* Default is no parity */
92 	Evenflag = 0,	/* Default is no parity */
93 	Duplex = 1,	/* Default is full duplex */
94 	Terminal = 0,	/* Default is no terminal */
95 	term_8bit = -1,	/* Default to terminal setting or 8 bit */
96 	line_8bit = -1;	/* Default is same as terminal */
97 
98 static char *P_PARITY  = "Parity option error\r\n";
99 
100 #ifdef ATTSVTTY
101 
102 static struct termio Savettyb;
103 static struct termios Savettybs;
104 /*
105  * set speed/echo/mode...
106  *	tty 	-> terminal name
107  *	spwant 	-> speed
108  *	type	-> type
109  *
110  *	if spwant == 0, speed is untouched
111  *	type is unused, but needed for compatibility
112  *
113  * return:
114  *	none
115  */
116 /*ARGSUSED*/
117 GLOBAL void
118 fixline(tty, spwant, type)
119 int	tty, spwant, type;
120 {
121 	register struct sg_spds	*ps;
122 	struct termio		ttbuf;
123 	struct termios		ttbufs;
124 	int			speed = -1;
125 	int			i, istermios, ospeed;
126 
127 	DEBUG(6, "fixline(%d, ", tty);
128 	DEBUG(6, "%d)\n", spwant);
129 	if ((istermios = (*Ioctl)(tty, TCGETS, &ttbufs)) < 0) {
130 		if ((*Ioctl)(tty, TCGETA, &ttbuf) != 0) {
131 			return;
132 		} else {
133 			ttbufs.c_lflag = ttbuf.c_lflag;
134 			ttbufs.c_oflag = ttbuf.c_oflag;
135 			ttbufs.c_iflag = ttbuf.c_iflag;
136 			ttbufs.c_cflag = ttbuf.c_cflag;
137 			for (i = 0; i < NCC; i++)
138 				ttbufs.c_cc[i] = ttbuf.c_cc[i];
139 		}
140 	}
141 	if (spwant > 0) {
142 		for (ps = spds; ps->sp_val; ps++)
143 			if (ps->sp_val == spwant) {
144 				speed = ps->sp_name;
145 				break;
146 			}
147 		if (speed < 0)
148 			DEBUG(5, "speed (%d) not supported\n", spwant);
149 		ASSERT(speed >= 0, "BAD SPEED", "", spwant);
150 		ttbufs.c_cflag &= 0xffff0000;
151 		cfsetospeed(&ttbufs, speed);
152 	} else { /* determine the current speed setting */
153 		ospeed = cfgetospeed(&ttbufs);
154 		ttbufs.c_cflag &= 0xffff0000;
155 		cfsetospeed(&ttbufs, ospeed);
156 		for (ps = spds; ps->sp_val; ps++)
157 			if (ps->sp_name == ospeed) {
158 				spwant = ps->sp_val;
159 				break;
160 			}
161 	}
162 	/*
163 	 * In order to prevent attempts at split speed, all baud rate
164 	 * bitfields should be cleared. Thus cfsetispeed is used to
165 	 * set the speed to zero.
166 	 */
167 	(void) cfsetispeed(&ttbufs, 0);
168 	ttbufs.c_iflag &= 0xffff0000;
169 	ttbufs.c_oflag &= 0xffff0000;
170 	ttbufs.c_lflag &= 0xffff0000;
171 #ifdef PKSPEEDUP
172 	linebaudrate = spwant;
173 #endif /*  PKSPEEDUP  */
174 
175 #ifdef NO_MODEM_CTRL
176 	/*   CLOCAL may cause problems on pdp11s with DHs */
177 	if (type == D_DIRECT) {
178 		DEBUG(4, "fixline - direct\n%s", "");
179 		ttbufs.c_cflag |= CLOCAL;
180 	} else
181 #endif /* NO_MODEM_CTRL */
182 		ttbufs.c_cflag &= ~CLOCAL;
183 
184 	if (!EQUALS(Progname, "uucico")) {
185 
186 		/* set attributes associated with -h, -t, -e, and -o options */
187 
188 		ttbufs.c_iflag = (IGNPAR | IGNBRK | IXON | IXOFF);
189 		ttbufs.c_cc[VEOF] = '\1';
190 		ttbufs.c_cflag |= (CREAD | (speed ? HUPCL : 0));
191 
192 		if (line_8bit) {
193 			ttbufs.c_cflag |= CS8;
194 			ttbufs.c_iflag &= ~ISTRIP;
195 		} else {
196 			if (Evenflag) {			/* even parity -e */
197 				ttbufs.c_cflag &= ~PARODD;
198 			} else if (Oddflag) {		/* odd parity -o */
199 				ttbufs.c_cflag |= PARODD;
200 			}
201 			ttbufs.c_cflag |= CS7|PARENB;
202 			ttbufs.c_iflag |= ISTRIP;
203 		}
204 
205 		if (!Duplex)				/* half duplex -h */
206 			ttbufs.c_iflag &= ~(IXON | IXOFF);
207 		if (Terminal)				/* -t */
208 			ttbufs.c_oflag |= (OPOST | ONLCR);
209 
210 	} else { /* non-uucico */
211 		ttbufs.c_cflag |= (CS8 | CREAD | (speed ? HUPCL : 0));
212 		ttbufs.c_cc[VMIN] = HEADERSIZE;
213 		ttbufs.c_cc[VTIME] = 1;
214 	}
215 
216 	if (istermios < 0) {
217 		ttbuf.c_lflag = ttbufs.c_lflag;
218 		ttbuf.c_oflag = ttbufs.c_oflag;
219 		ttbuf.c_iflag = ttbufs.c_iflag;
220 		ttbuf.c_cflag = ttbufs.c_cflag;
221 		for (i = 0; i < NCC; i++)
222 			ttbuf.c_cc[i] = ttbufs.c_cc[i];
223 		ASSERT((*Ioctl)(tty, TCSETAW, &ttbuf) >= 0,
224 		    "RETURN FROM fixline ioctl", "", errno);
225 	} else {
226 		ASSERT((*Ioctl)(tty, TCSETSW, &ttbufs) >= 0,
227 		    "RETURN FROM fixline ioctl", "", errno);
228 	}
229 }
230 
231 GLOBAL void
232 sethup(dcf)
233 int	dcf;
234 {
235 	struct termio ttbuf;
236 
237 	if ((*Ioctl)(dcf, TCGETA, &ttbuf) != 0)
238 		return;
239 	if (!(ttbuf.c_cflag & HUPCL)) {
240 		ttbuf.c_cflag |= HUPCL;
241 		(void) (*Ioctl)(dcf, TCSETAW, &ttbuf);
242 	}
243 }
244 
245 GLOBAL void
246 ttygenbrk(fn)
247 register int	fn;
248 {
249 	if (isatty(fn))
250 		(void) (*Ioctl)(fn, TCSBRK, 0);
251 }
252 
253 
254 /*
255  * optimize line setting for sending or receiving files
256  * return:
257  *	none
258  */
259 GLOBAL void
260 setline(type)
261 register char	type;
262 {
263 	static struct termio tbuf;
264 	static struct termios tbufs;
265 	int i, vtime, istermios, ospeed;
266 
267 	DEBUG(2, "setline - %c\n", type);
268 
269 	if ((istermios = (*Ioctl)(Ifn, TCGETS, &tbufs)) < 0) {
270 		if ((*Ioctl)(Ifn, TCGETA, &tbuf) != 0) {
271 			return;
272 		} else {
273 			tbufs.c_lflag = tbuf.c_lflag;
274 			tbufs.c_oflag = tbuf.c_oflag;
275 			tbufs.c_iflag = tbuf.c_iflag;
276 			tbufs.c_cflag = tbuf.c_cflag;
277 			for (i = 0; i < NCC; i++)
278 				tbufs.c_cc[i] = tbuf.c_cc[i];
279 		}
280 	}
281 	switch (type) {
282 	case RCVFILE:
283 		ospeed = cfgetospeed(&tbufs);
284 		switch (ospeed) {
285 #ifdef B19200
286 		case B19200:
287 #else
288 #ifdef EXTA
289 		case EXTA:
290 #endif
291 #endif
292 #ifdef B38400
293 		case B38400:
294 #endif
295 		case B57600:
296 		case B76800:
297 		case B115200:
298 		case B153600:
299 		case B230400:
300 		case B307200:
301 		case B460800:
302 		case B921600:
303 		case B9600:
304 			vtime = 1;
305 			break;
306 		case B4800:
307 			vtime = 4;
308 			break;
309 		default:
310 			vtime = 8;
311 			break;
312 		}
313 		if (tbufs.c_cc[VMIN] != packsize ||
314 		    tbufs.c_cc[VTIME] != vtime) {
315 		    tbufs.c_cc[VMIN] = packsize;
316 		    tbufs.c_cc[VTIME] = vtime;
317 		    if (istermios < 0) {
318 			tbuf.c_lflag = tbufs.c_lflag;
319 			tbuf.c_oflag = tbufs.c_oflag;
320 			tbuf.c_iflag = tbufs.c_iflag;
321 			tbuf.c_cflag = tbufs.c_cflag;
322 			for (i = 0; i < NCC; i++)
323 				tbuf.c_cc[i] = tbufs.c_cc[i];
324 			if ((*Ioctl)(Ifn, TCSETAW, &tbuf) != 0)
325 				DEBUG(4, "setline Ioctl failed errno=%d\n",
326 				    errno);
327 			} else {
328 				if ((*Ioctl)(Ifn, TCSETSW, &tbufs) != 0)
329 					DEBUG(4,
330 					    "setline Ioctl failed errno=%d\n",
331 					    errno);
332 			}
333 		}
334 		break;
335 
336 	case SNDFILE:
337 	case RESET:
338 		if (tbufs.c_cc[VMIN] != HEADERSIZE) {
339 			tbufs.c_cc[VMIN] = HEADERSIZE;
340 			if (istermios < 0) {
341 				tbuf.c_lflag = tbufs.c_lflag;
342 				tbuf.c_oflag = tbufs.c_oflag;
343 				tbuf.c_iflag = tbufs.c_iflag;
344 				tbuf.c_cflag = tbufs.c_cflag;
345 				for (i = 0; i < NCC; i++)
346 					tbuf.c_cc[i] = tbufs.c_cc[i];
347 				if ((*Ioctl)(Ifn, TCSETAW, &tbuf) != 0)
348 					DEBUG(4,
349 					    "setline Ioctl failed errno=%d\n",
350 					    errno);
351 			} else {
352 				if ((*Ioctl)(Ifn, TCSETSW, &tbufs) != 0)
353 					DEBUG(4,
354 					    "setline Ioctl failed errno=%d\n",
355 					    errno);
356 			}
357 		}
358 		break;
359 	}
360 }
361 
362 GLOBAL int
363 savline()
364 {
365 	if ((Saved_termios = (*Ioctl)(0, TCGETS, &Savettybs)) < 0) {
366 		if ((*Ioctl)(0, TCGETA, &Savettyb) != 0) {
367 			Saved_line = FALSE;
368 		} else {
369 			Saved_line = TRUE;
370 			Savettyb.c_cflag =
371 			    (Savettyb.c_cflag & ~CS8) | CS7 | PARENB;
372 			Savettyb.c_oflag |= OPOST;
373 			Savettyb.c_lflag |= (ISIG|ICANON|ECHO);
374 		}
375 	} else {
376 		Saved_line = TRUE;
377 		Savettybs.c_cflag = (Savettybs.c_cflag & ~CS8) | CS7 | PARENB;
378 		Savettybs.c_oflag |= OPOST;
379 		Savettybs.c_lflag |= (ISIG|ICANON|ECHO);
380 	}
381 	return (0);
382 }
383 
384 #ifdef SYTEK
385 
386 /*
387  *	sytfixline(tty, spwant)	set speed/echo/mode...
388  *	int tty, spwant;
389  *
390  *	return codes:  none
391  */
392 
393 GLOBAL void
394 sytfixline(tty, spwant)
395 int tty, spwant;
396 {
397 	struct termio ttbuf;
398 	struct termios ttbufs;
399 	struct sg_spds *ps;
400 	int speed = -1;
401 	int i, ret, istermios;
402 
403 	if ((istermios = (*Ioctl)(tty, TCGETS, &ttbufs)) < 0) {
404 		if ((*Ioctl)(tty, TCGETA, &ttbuf) != 0) {
405 			return;
406 		} else {
407 			ttbufs.c_lflag = ttbuf.c_lflag;
408 			ttbufs.c_oflag = ttbuf.c_oflag;
409 			ttbufs.c_iflag = ttbuf.c_iflag;
410 			ttbufs.c_cflag = ttbuf.c_cflag;
411 			for (i = 0; i < NCC; i++)
412 				ttbufs.c_cc[i] = ttbuf.c_cc[i];
413 		}
414 	}
415 	for (ps = spds; ps->sp_val >= 0; ps++)
416 		if (ps->sp_val == spwant)
417 			speed = ps->sp_name;
418 	DEBUG(4, "sytfixline - speed= %d\n", speed);
419 	ASSERT(speed >= 0, "BAD SPEED", "", spwant);
420 	ttbufs.c_iflag &= 0xffff0000;
421 	ttbufs.c_oflag &= 0xffff0000;
422 	ttbufs.c_lflag &= 0xffff0000;
423 	ttbufs.c_cflag &= 0xffff0000;
424 	cfsetospeed(&ttbufs, speed);
425 	ttbufs.c_cflag |= (CS8|CLOCAL);
426 	ttbufs.c_cc[VMIN] = 6;
427 	ttbufs.c_cc[VTIME] = 1;
428 	if (istermios < 0) {
429 		ttbuf.c_lflag = ttbufs.c_lflag;
430 		ttbuf.c_oflag = ttbufs.c_oflag;
431 		ttbuf.c_iflag = ttbufs.c_iflag;
432 		ttbuf.c_cflag = ttbufs.c_cflag;
433 		for (i = 0; i < NCC; i++)
434 			ttbuf.c_cc[i] = ttbufs.c_cc[i];
435 		ret = (*Ioctl)(tty, TCSETAW, &ttbuf);
436 	} else
437 		ret = (*Ioctl)(tty, TCSETAWS &ttbufs);
438 	ASSERT(ret >= 0, "RETURN FROM sytfixline", "", ret);
439 }
440 
441 GLOBAL void
442 sytfix2line(tty)
443 int tty;
444 {
445 	struct termio ttbuf;
446 	int ret;
447 
448 	if ((*Ioctl)(tty, TCGETA, &ttbuf) != 0)
449 		return;
450 	ttbuf.c_cflag &= ~CLOCAL;
451 	ttbuf.c_cflag |= CREAD|HUPCL;
452 	ret = (*Ioctl)(tty, TCSETAW, &ttbuf);
453 	ASSERT(ret >= 0, "RETURN FROM sytfix2line", "", ret);
454 }
455 
456 #endif /* SYTEK */
457 
458 GLOBAL int
459 restline()
460 {
461 	if (Saved_line == TRUE) {
462 		if (Saved_termios < 0)
463 			return ((*Ioctl)(0, TCSETAW, &Savettyb));
464 		else
465 			return ((*Ioctl)(0, TCSETSW, &Savettybs));
466 	}
467 	return (0);
468 }
469 
470 #else /* !ATTSVTTY */
471 
472 static struct sgttyb Savettyb;
473 
474 /*
475  *	fixline(tty, spwant, type)	set speed/echo/mode...
476  *	int tty, spwant;
477  *
478  *	if spwant == 0, speed is untouched
479  *	type is unused, but needed for compatibility
480  *
481  *	return codes:  none
482  */
483 
484 /*ARGSUSED*/
485 GLOBAL void
486 fixline(tty, spwant, type)
487 int tty, spwant, type;
488 {
489 	struct sgttyb	ttbuf;
490 	struct sg_spds	*ps;
491 	int		 speed = -1;
492 
493 	DEBUG(6, "fixline(%d, ", tty);
494 	DEBUG(6, "%d)\n", spwant);
495 
496 	if ((*Ioctl)(tty, TIOCGETP, &ttbuf) != 0)
497 		return;
498 	if (spwant > 0) {
499 		for (ps = spds; ps->sp_val; ps++)
500 			if (ps->sp_val == spwant) {
501 				speed = ps->sp_name;
502 				break;
503 			}
504 		ASSERT(speed >= 0, "BAD SPEED", "", spwant);
505 		ttbuf.sg_ispeed = ttbuf.sg_ospeed = speed;
506 	} else {
507 		for (ps = spds; ps->sp_val; ps++)
508 			if (ps->sp_name == ttbuf.sg_ispeed) {
509 				spwant = ps->sp_val;
510 				break;
511 			}
512 		ASSERT(spwant >= 0, "BAD SPEED", "", ttbuf.sg_ispeed);
513 	}
514 	ttbuf.sg_flags = (ANYP | RAW);
515 #ifdef PKSPEEDUP
516 	linebaudrate = spwant;
517 #endif /*  PKSPEEDUP  */
518 	(void) (*Ioctl)(tty, TIOCSETP, &ttbuf);
519 	(void) (*Ioctl)(tty, TIOCHPCL, STBNULL);
520 	(void) (*Ioctl)(tty, TIOCEXCL, STBNULL);
521 }
522 
523 GLOBAL void
524 sethup(dcf)
525 int	dcf;
526 {
527 	if (isatty(dcf))
528 		(void) (*Ioctl)(dcf, TIOCHPCL, STBNULL);
529 }
530 
531 /*
532  *	genbrk		send a break
533  *
534  *	return codes;  none
535  */
536 
537 GLOBAL void
538 ttygenbrk(fn)
539 {
540 	if (isatty(fn)) {
541 		(void) (*Ioctl)(fn, TIOCSBRK, 0);
542 #ifndef V8
543 		nap(HZ/10);				/* 0.1 second break */
544 		(void) (*Ioctl)(fn, TIOCCBRK, 0);
545 #endif
546 	}
547 }
548 
549 /*
550  * V7 and RT aren't smart enough for this -- linebaudrate is the best
551  * they can do.
552  */
553 /*ARGSUSED*/
554 GLOBAL void
555 setline(dummy) { }
556 
557 GLOBAL int
558 savline()
559 {
560 	if ((*Ioctl)(0, TIOCGETP, &Savettyb) != 0)
561 		Saved_line = FALSE;
562 	else {
563 		Saved_line = TRUE;
564 		Savettyb.sg_flags |= ECHO;
565 		Savettyb.sg_flags &= ~RAW;
566 	}
567 	return (0);
568 }
569 
570 GLOBAL int
571 restline()
572 {
573 	if (Saved_line == TRUE)
574 		return ((*Ioctl)(0, TIOCSETP, &Savettyb));
575 	return (0);
576 }
577 #endif
578