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