1 /**********************************************************
2  * tty/tio routines.
3  *
4  * Most part of this code is taken from mgetty package
5  * copyrighted by 1993 Gert Doering.
6  *
7  * I don't intend to make mgetty competent software based
8  * on the mgetty's source but just to use the well
9  * working code.
10  **********************************************************/
11 
12 /*
13  * $Id: tty.c,v 1.27 2005/08/16 20:23:23 mitry Exp $
14  *
15  * $Log: tty.c,v $
16  * Revision 1.27  2005/08/16 20:23:23  mitry
17  * Pre 0.57.1: minor changes
18  *
19  * Revision 1.26  2005/08/16 10:32:19  mitry
20  * Fixed broken calls of loginscript
21  *
22  * Revision 1.25  2005/06/10 20:57:28  mitry
23  * Changed tty_bufblock()
24  *
25  * Revision 1.24  2005/05/17 19:51:11  mitry
26  * Code cleaning
27  *
28  * Revision 1.23  2005/05/17 18:17:43  mitry
29  * Removed system basename() usage.
30  * Added qbasename() implementation.
31  *
32  * Revision 1.22  2005/05/16 20:33:46  mitry
33  * Code cleaning
34  *
35  * Revision 1.21  2005/05/06 20:53:06  mitry
36  * Changed misc code
37  *
38  * Revision 1.20  2005/04/14 14:48:11  mitry
39  * Misc changes
40  *
41  * Revision 1.19  2005/04/08 18:15:05  mitry
42  * More proper sighup handling
43  *
44  * Revision 1.18  2005/04/04 19:43:56  mitry
45  * Added timeout arg to BUFFLUSH() - tty_bufflush()
46  *
47  * Revision 1.17  2005/03/31 20:39:20  mitry
48  * Added support for HUP_XXX and removed old code
49  *
50  * Revision 1.16  2005/03/29 20:41:27  mitry
51  * Restore saved tio settings before closing port
52  *
53  * Revision 1.15  2005/03/28 17:02:53  mitry
54  * Pre non-blocking i/o update. Mostly non working.
55  *
56  * Revision 1.14  2005/02/25 16:41:55  mitry
57  * Adding proper tio calls in progress
58  * Changed some code
59  *
60  * Revision 1.13  2005/02/23 21:56:26  mitry
61  * Changed tty_carrier() code. To be rewritten
62  *
63  * Revision 1.12  2005/02/22 16:15:39  mitry
64  * Code rewrite
65  *
66  * Revision 1.11  2005/02/21 18:14:15  mitry
67  * One more tty_hangedup rename
68  *
69  * Revision 1.10  2005/02/21 16:33:42  mitry
70  * Changed tty_hangedup to tty_online
71  *
72  * Revision 1.9  2005/02/18 20:39:34  mitry
73  * tty_block() commented out
74  * tty_close() now has parameter (may be temporarily) and rewritten
75  * Added debug messages
76  *
77  */
78 
79 #include "headers.h"
80 #ifdef HAVE_SYS_IOCTL_H
81 #include <sys/ioctl.h>
82 #endif
83 #include "tty.h"
84 
85 
86 #ifdef POSIX_TERMIOS
87 static char tio_compilation_type[]="@(#)tty.c compiled with POSIX_TERMIOS";
88 #endif
89 #ifdef SYSV_TERMIO
90 static char tio_compilation_type[]="@(#)tty.c compiled with SYSV_TERMIO";
91 #endif
92 #ifdef BSD_SGTTY
93 static char tio_compilation_type[]="@(#)tty.c compiled with BSD_SGTTY";
94 #endif
95 
96 
97 #ifdef BSD
98 # ifndef IUCLC
99 # define IUCLC 0
100 # endif
101 # ifndef TAB3
102 #  ifdef NeXT
103 #   define TAB3 XTABS
104 #  else
105 #   define TAB3 OXTABS
106 #  endif	/* !NeXT */
107 # endif
108 #endif
109 
110 
111 #define DEBUG_SLEEP 0
112 
113 #define IFGOTHUP \
114     if ( tty_gothup || (!is_ip && tty_online && !tty_dcd( tty_fd ))) \
115         { tty_status = TTY_HANGUP; return RCDO; }
116 
117 #define	IFLESSZERO \
118     if ( rc < 0 ) {        \
119         IFGOTHUP;          \
120         else return ERROR; \
121     }
122 
123 
124 char *tty_errs[] = {
125     "Ok",                    /* ME_OK        0 */
126     "tcget/setattr error",   /* ME_ATTRS     1 */
127     "bad speed",             /* ME_SPEED     2 */
128     "open error",            /* ME_OPEN      3 */
129     "read error",            /* ME_READ      4 */
130     "write error",           /* ME_WRITE     5 */
131     "timeout",               /* ME_TIMEOUT   6 */
132     "close error",           /* ME_CLOSE     7 */
133     "can't lock port",       /* ME_CANTLOCK  8 */
134     "can't set/get flags",   /* ME_FLAGS     9 */
135     "not a tty",             /* ME_NOTATT   10 */
136     "no DSR/CTS signals"     /* ME_NODSR    11 */
137 };
138 
139 
140 /* baud rate table */
141 static struct	speedtab {
142 #ifdef POSIX_TERMIOS
143     speed_t	cbaud;
144 #else
145     unsigned short cbaud;	/* baud rate, e.g. B9600 */
146 #endif
147     int	 nspeed;		/* speed in numeric format */
148     char *speed;		/* speed in display format */
149 } speedtab[] = {
150 	{ B50,	  50,	 "50"	 },
151 	{ B75,	  75,	 "75"	 },
152 	{ B110,	  110,	 "110"	 },
153 	{ B134,	  134,	 "134"	 },
154 	{ B150,	  150,	 "150"	 },
155 	{ B200,	  200,	 "200"	 },
156 	{ B300,	  300,	 "300"	 },
157 	{ B600,	  600,	 "600"	 },
158 #ifdef	B900
159 	{ B900,	  900,	 "900"	},
160 #endif
161 	{ B1200,  1200,	 "1200"	 },
162 	{ B1800,  1800,	 "1800"	 },
163 	{ B2400,  2400,	 "2400"	 },
164 #ifdef	B3600
165 	{ B3600,  3600,	 "3600"	},
166 #endif
167 	{ B4800,  4800,	 "4800"	 },
168 #ifdef	B7200
169 	{ B7200,  7200,  "7200"	},
170 #endif
171 	{ B9600,  9600,	 "9600"	 },
172 #ifdef	B14400
173 	{ B14400, 14400, "14400" },
174 #endif
175 #ifdef	B19200
176 	{ B19200, 19200, "19200" },
177 #endif	/* B19200 */
178 #ifdef	B28800
179 	{ B28800, 28800, "28800" },
180 #endif
181 #ifdef	B38400
182 	{ B38400, 38400, "38400" },
183 #endif	/* B38400 */
184 #ifdef	EXTA
185 	{ EXTA,	  19200, "EXTA"	 },
186 #endif
187 #ifdef	EXTB
188 	{ EXTB,	  38400, "EXTB"	 },
189 #endif
190 #ifdef	B57600
191 	{ B57600, 57600, "57600" },
192 #endif
193 #ifdef	B76800
194 	{ B76800, 76800, "76800" },
195 #endif
196 #ifdef	B115200
197 	{ B115200,115200,"115200"},
198 #endif
199 #ifdef B230400
200 	{ B230400,230400,"230400"},
201 #endif
202 #ifdef B460800
203 	{ B460800,460800,"460800"},
204 #endif
205 	{ 0,	  0,	 ""	 }
206 };
207 
208 
209 TIO tty_stio;
210 
211 #if 0
212 #ifdef HYDRA8K16K
213 #define RX_BUF_SIZE (16384 + 1024)
214 #define TX_BUF_SIZE (16384 + 1024)
215 #else
216 #define RX_BUF_SIZE (4096 + 1024)
217 #define TX_BUF_SIZE (4096 + 1024)
218 #endif
219 #endif /* 0 */
220 
221 #define RX_BUF_SIZE (0x8100)
222 #define TX_BUF_SIZE (0x8100)
223 
224 static unsigned char tty_rx_buf[RX_BUF_SIZE];
225 static unsigned char tty_tx_buf[TX_BUF_SIZE];
226 
227 /* tty_rx_left - number of bytes in receive buffer
228  * tty_rx_ptr  - pointer to next byte in receive buffer
229  * tty_tx_ptr  - pointer to next byte to send out in transmit buffer
230  * tty_tx_free - number of byte left in transmit buffer
231  *
232  *                             |  <- tty_rx_left ->  |
233  * +---------------------------+*********************+--------------------+
234  * |read data//  tty_rx_ptr <- |       new data      |                    | RX_BUF_SIZE
235  * +---------------------------+*********************+--------------------+
236  *
237  *                                                   | <- tty_tx_free ->  |
238  * +---------------------------+*********************+--------------------+
239  * |sent data//  tty_tx_ptr -> |     unsent data     | <-   new data      | TX_BUF_SIZE
240  * +---------------------------+*********************+--------------------+
241  */
242 static int tty_rx_ptr = 0;
243 static int tty_rx_left = 0;
244 static int tty_tx_ptr = 0;
245 static int tty_tx_free = TX_BUF_SIZE;
246 
247 int tty_fd = -1;
248 int tty_error = 0;
249 int tty_status = TTY_SUCCESS;
250 
251 
252 #define FDS(f) ( (f) ? ( *(f) ? "true" : "false" ) : "not set" )
253 
254 /*
255  * Checks out whether or not stdin and/or stdout are ready to receive/send data
256  *
257  * Parameters:
258  *    rd   - if not NULL & TRUE - check read (stdin) fd
259  *    wd   - if not NULL & TRUE - check write (stdout) fd
260  *    tval - a pointer to struct timeval to wait for event. If tval:
261  *           NULL  - wait for at least one fd is ready or forever
262  *           {0,0} - do not wait at all, just return fds state
263  *           other - wait for specified time
264  *
265  * Return values: number of fds are ready or -1 on error (errno in tty_error).
266  *    rd - true if stdin is ready
267  *    wd - true if stdout is ready
268  */
tty_select(boolean * rd,boolean * wd,struct timeval * tval)269 int tty_select(boolean *rd, boolean *wd, struct timeval *tval)
270 {
271 	fd_set	rfd, wfd;
272 	int rc;
273 
274 	DEBUG(('T',2,"tty_select"));
275 
276 	FD_ZERO( &rfd );
277 	FD_ZERO( &wfd );
278 	if ( rd && *rd ) {
279 		FD_SET( tty_fd, &rfd );
280 		*rd = FALSE;
281 	}
282 	if ( wd && *wd ) {
283 		FD_SET( tty_fd, &wfd );
284 		*wd = FALSE;
285 	}
286 
287 	tty_error = 0;
288 	rc = select( tty_fd + 1, &rfd, &wfd, NULL, ( tval ? tval : NULL ));
289 
290 	tty_error = errno;
291 	tty_status = TTY_SUCCESS;
292 	if ( rc < 0 ) {
293 		if ( EWBOEA() ) {
294 			tty_status = TTY_TIMEOUT;
295 		} else if ( errno == EINTR ) {
296 			tty_status = ( tty_online && tty_gothup ) ? TTY_HANGUP : TTY_TIMEOUT;
297         } else if ( errno == EPIPE ) {
298 		tty_gothup = HUP_LINE;
299 		tty_status = TTY_HANGUP;
300         } else
301 		tty_status = TTY_ERROR;
302 	} else if ( rc == 0 )
303 		tty_status = TTY_TIMEOUT;
304 	else {
305 		if ( rd && FD_ISSET( tty_fd, &rfd ))
306 			*rd = TRUE;
307 		if ( wd && FD_ISSET( tty_fd, &wfd ))
308 			*wd = TRUE;
309 	}
310 
311 	DEBUG(('T',2,"tty_select: fd=%d rc=%i (rd=%s, wd=%s)", tty_fd, rc, FDS( rd ), FDS( wd )));
312 
313 	return rc;
314 }
315 
316 
317 /*
318  * Returns whether the rx_buf has data.
319  */
tty_hasinbuf(void)320 int tty_hasinbuf(void)
321 {
322 	return ( tty_rx_left > 0 );
323 }
324 
325 
326 /*
327  * Returns whether the in stream has data.
328  */
tty_hasdata(int sec,int usec)329 int tty_hasdata(int sec, int usec)
330 {
331 	boolean		rd = TRUE;
332 	struct timeval	tv;
333 
334 	DEBUG(('T',5,"tty_hasdata"));
335 
336 	if ( tty_hasinbuf() )
337 		return 1;
338 
339 	tv.tv_sec = sec;
340 	tv.tv_usec = usec;
341 	return ( tty_select( &rd, NULL, &tv ) > 0 && rd );
342 }
343 
344 
tty_hasdata_timed(int * timeout)345 int tty_hasdata_timed(int *timeout)
346 {
347 	int	rc;
348 	time_t	t = time( NULL );
349 
350 	rc = tty_hasdata( *timeout, 0 );
351 	*timeout -= (time( NULL ) - t);
352 
353 	return rc;
354 }
355 
356 
357 
358 /*
359  * Attempts to write nbytes of data from the buffer pointed to by buf to stdout.
360  *
361  * Return values:
362  *    Upon successful completion the number of bytes which were written is
363  *    returned. Otherwise a value < 0 is returned and the tty_error and tty_status
364  *    are set to indicate the error.
365  */
tty_write(const void * buf,size_t nbytes)366 int tty_write(const void *buf, size_t nbytes)
367 {
368 	int	rc;
369 
370 #ifdef NEED_DEBUG
371 	byte	*bbuf = (byte *) buf;
372 	int	i;
373 #endif
374 
375 	DEBUG(('T',5,"tty_write"));
376 
377 	IFGOTHUP;
378 
379 	if ( nbytes == 0 )
380 		return 0;
381 
382 	rc = write( tty_fd, buf, nbytes );
383 
384 	tty_error = errno;
385 	IFGOTHUP;
386 
387 	if ( rc < 0 ) {
388 		if ( EWBOEA() ) {
389 			tty_status = TTY_TIMEOUT;
390 		} else if ( errno == EINTR ) {
391 			if ( tty_online && tty_gothup )
392 				tty_status = TTY_HANGUP;
393 			else
394 				tty_status = TTY_TIMEOUT;
395 		} else if ( errno == EPIPE ) {
396 			tty_gothup = HUP_LINE;
397 			tty_status = TTY_HANGUP;
398 		} else
399 			tty_status = TTY_ERROR;
400 	} else if ( rc == 0 ) {
401 		tty_status = TTY_ERROR;
402 	} else /* rc > 0 */
403 		tty_status = TTY_SUCCESS;
404 
405 	DEBUG(('T',6,"tty_write: rc = %d", rc));
406 
407 #ifdef NEED_DEBUG
408 	if ( rc > 0 )
409 		for( i = 0; i < rc; i++ )
410 			DEBUG(('T',9,"tty_write: '%c' (%d)", C0(bbuf[i]), bbuf[i]));
411 #endif
412 
413 	return ( tty_status == TTY_SUCCESS ? rc : tty_status );
414 }
415 
416 
417 /*
418  * Attempts to read nbytes of data from the stdin into the buffer pointed to
419  * by buf.
420  *
421  * Return values:
422  *    Upon successful completion the number of bytes which were read is
423  *    returned. Otherwise a value < 0 is returned and the tty_error and tty_status
424  *    are set to indicate the error.
425  */
tty_read(void * buf,size_t nbytes)426 int tty_read(void *buf, size_t nbytes)
427 {
428 	int	rc;
429 
430 #ifdef NEED_DEBUG
431 	byte	*bbuf = (byte *) buf;
432 	int	i;
433 #endif
434 
435 	DEBUG(('T',5,"tty_read"));
436 
437 	IFGOTHUP;
438 
439 	rc = read( tty_fd, buf, nbytes );
440 	IFGOTHUP;
441 
442 	tty_error = errno;
443 	if ( rc < 0 ) {
444 		if ( EWBOEA() ) {
445 			tty_status = TTY_TIMEOUT;
446 		} else if ( errno == EINTR ) {
447 			if ( tty_online && tty_gothup )
448 				tty_status = TTY_HANGUP;
449 			else
450 				tty_status = TTY_TIMEOUT;
451 		} else if ( errno == EPIPE ) {
452 			tty_gothup = HUP_LINE;
453 			tty_status = TTY_HANGUP;
454 		} else
455 			tty_status = TTY_ERROR;
456 	} else if ( rc == 0 ) {
457 		tty_status = TTY_ERROR;
458 	} else /* rc > 0 */
459 		tty_status = TTY_SUCCESS;
460 
461 	DEBUG(('T',6,"tty_read: rc = %d", rc));
462 
463 #ifdef NEED_DEBUG
464 	if ( rc > 0 )
465 		for( i = 0; i < rc; i++ )
466 			DEBUG(('T',9,"tty_read: '%c' (%d)", C0(bbuf[i]), bbuf[i]));
467 #endif
468 
469 	return ( tty_status == TTY_SUCCESS ? rc : tty_status );
470 }
471 
472 
tty_sighup(int sig)473 RETSIGTYPE tty_sighup(int sig)
474 {
475 	DEBUG(('T',1,"tty_sighup: got SIG%s signal, %d", sigs[sig], tty_gothup));
476 
477 	getevt();
478 	DEBUG(('T',2,"tty_sighup: %d", tty_gothup));
479 	if (( is_ip && sig == SIGPIPE ) || ( !is_ip && !tty_dcd( tty_fd )))
480 		tty_gothup = HUP_LINE;
481 	else
482 		tty_gothup = HUP_OPERATOR;
483 }
484 
485 
baseport(const char * p)486 char *baseport(const char *p)
487 {
488 	char		*q;
489 	static char	pn[MAX_PATH + 5];
490 
491 	q = qbasename( p );
492 	if ( !q || !*q )
493 		return NULL;
494 
495 	xstrcpy( pn, q, MAX_PATH );
496 	if (( q = strrchr( pn, ':' )))
497 		*q = 0;
498 	return pn;
499 }
500 
501 
tty_isfree(const char * port,const char * nodial)502 int tty_isfree(const char *port, const char *nodial)
503 {
504 	int		pid = 0;
505 	FILE		*f;
506 	struct stat	s;
507 	char		lckname[MAX_PATH + 5];
508 
509 	if ( !port )
510 		return 0;
511 
512 	if ( nodial ) {
513 		snprintf( lckname, MAX_PATH, "%s.%s", nodial, port );
514 		if ( !stat( lckname, &s ))
515 			return 0;
516 	}
517 
518 	LCK_NAME(lckname, port);
519 	if (( f = fopen( lckname, "r" ))) {
520 		fscanf( f, "%d", &pid );
521 		fclose( f );
522 		if ( pid && kill( pid, 0 ) && ( errno == ESRCH )) {
523 			lunlink( lckname );
524 			return 1;
525 		}
526 		return 0;
527 	}
528 	return 1;
529 }
530 
531 
tty_findport(slist_t * ports,const char * nodial)532 char *tty_findport(slist_t *ports, const char *nodial)
533 {
534 	for(; ports; ports = ports->next )
535 		if( tty_isfree( baseport( ports->str ), nodial ))
536 			return ports->str;
537 	return NULL;
538 }
539 
540 
tty_lock(const char * port)541 int tty_lock(const char *port)
542 {
543 	int		rc = -1;
544 	char		lckname[MAX_PATH + 5];
545 	const char	*p;
546 
547 	DEBUG(('M',1,"tty_lock"));
548 	if ( !( p = strrchr( port, '/' )))
549 		p = port;
550 	else
551 		p++;
552 
553 	LCK_NAME(lckname, p);
554 	rc = lockpid( lckname );
555 	return rc ? 0 : -1;
556 }
557 
558 
tty_unlock(const char * port)559 void tty_unlock(const char *port)
560 {
561 	long		pid;
562 	char		lckname[MAX_PATH + 5];
563 	const char	*p;
564 	FILE		*f;
565 
566 	DEBUG(('M',1,"tty_unlock"));
567 	if ( !( p = strrchr( port, '/' )))
568 		p = port;
569 	else
570 		p++;
571 
572 	LCK_NAME(lckname, p);
573 	if (( f = fopen( lckname, "r" ))) {
574 		fscanf( f, "%ld", &pid );
575 		fclose( f );
576 	}
577 
578 	if ( pid == getpid())
579 		lunlink( lckname );
580 }
581 
582 
tty_close(void)583 int tty_close(void)
584 {
585 	if ( !tty_port )
586 		return ME_CLOSE;
587 
588 	DEBUG(('M',2,"tty_close"));
589 
590 	tio_flush_queue( tty_fd, TIO_Q_BOTH );
591 	tio_set( tty_fd, &tty_stio );
592 
593 	(void) close( tty_fd );
594 
595 	tty_unlock( tty_port );
596 	xfree( tty_port );
597 	tty_online = FALSE;
598 
599 	return ME_OK;
600 }
601 
602 
tty_local(TIO * tio,int local)603 int tty_local(TIO *tio, int local)
604 {
605 	signal( SIGHUP, local ? SIG_IGN : tty_sighup );
606 	signal( SIGPIPE, local ? SIG_IGN : tty_sighup );
607 
608 	if ( !isatty( tty_fd ))
609 		return ME_NOTATT;
610 
611 	tio_local_mode( tio, local );
612 	tio_set_flow_control( tty_fd, tio, local ? FLOW_NONE : FLOW_HARD );
613 
614 	if ( local )
615 		tty_gothup = FALSE;
616 	return 1;
617 }
618 
619 
tty_bufclear(void)620 void tty_bufclear(void)
621 {
622 	tty_tx_ptr = 0;
623 	tty_tx_free = TX_BUF_SIZE;
624 }
625 
626 
tty_bufflush(int tsec)627 int tty_bufflush(int tsec)
628 {
629 	int		rc = OK, restsize = TX_BUF_SIZE - tty_tx_free - tty_tx_ptr;
630 	boolean		wd;
631 	struct timeval	tv;
632 	time_t		tm;
633 
634 	tm = timer_set( tsec );
635 	while( TX_BUF_SIZE != tty_tx_free ) {
636 		wd = true;
637 		tv.tv_sec = timer_rest( tm );
638 		tv.tv_usec = 0;
639 
640 		if (( rc = tty_select( NULL, &wd, &tv )) > 0 && wd ) {
641 			rc = tty_write( tty_tx_buf + tty_tx_ptr, restsize );
642 
643 			if ( rc == restsize ) {
644 				tty_bufclear();
645 			} else if ( rc > 0 ) {
646 				tty_tx_ptr += rc;
647 				restsize -= rc;
648 			} else if ( rc < 0 && tty_status != TTY_TIMEOUT )
649 				return ERROR;
650 		} else
651 			return rc;
652 
653 		if ( timer_expired( tm ))
654 			return ERROR;
655 	}
656 	return rc;
657 }
658 
659 
tty_bufblock(const void * data,size_t nbytes)660 int tty_bufblock(const void *data, size_t nbytes)
661 {
662 	int rc = OK, txptr = TX_BUF_SIZE - tty_tx_free;
663 	char *nptr = (char *)data;
664 
665 	DEBUG(('T',8,"tty_bufblock: tty_tx_ptr=%d, tty_tx_free=%d, need2buf=%d",
666 		tty_tx_ptr,tty_tx_free,nbytes));
667 
668 	tty_status = TTY_SUCCESS;
669 
670 	while ( nbytes ) {
671 		if ( nbytes > (size_t) tty_tx_free ) {
672 			do {
673 				tty_bufflush( 5 );
674 				if ( tty_status == TTY_SUCCESS ) {
675 					size_t n = MIN( (size_t) tty_tx_free, nbytes);
676 					memcpy( tty_tx_buf, nptr, n );
677 					tty_tx_free -= n;
678 					nbytes -= n;
679 					nptr += n;
680 				}
681 			} while ( tty_status != TTY_SUCCESS );
682 		} else {
683 			memcpy( (void *) (tty_tx_buf + txptr), nptr, nbytes );
684 			tty_tx_free -= nbytes;
685 			nbytes = 0;
686 		}
687 	}
688 	return rc;
689 }
690 
691 
tty_bufc(char ch)692 int tty_bufc(char ch)
693 {
694 	return tty_bufblock( &ch, 1 );
695 }
696 
697 
tty_putc(char ch)698 int tty_putc(char ch)
699 {
700 	tty_bufblock( &ch, 1 );
701 	return tty_bufflush( 5 );
702 }
703 
704 
tty_getc(int timeout)705 int tty_getc(int timeout)
706 {
707 
708 	DEBUG(('T',8,"tty_getc: tty_rx_ptr=%d, tty_rx_left=%d",tty_rx_ptr,tty_rx_left));
709 	if ( tty_rx_left == 0 ) {
710 		int rc = tty_hasdata( timeout, 0 );
711 		/*
712 		int rc = ( timeout > 0 ) ? tty_hasdata( timeout, 0 ) : 1;
713                 */
714 
715 		IFGOTHUP;
716 
717 		if ( rc > 0 ) {
718 			if (( rc = tty_read( tty_rx_buf, RX_BUF_SIZE )) < 0 ) {
719 				IFGOTHUP;
720 				return ( EWBOEA()) ? TTY_TIMEOUT : ERROR;
721 			} else if ( rc == 0 )
722 				return ERROR;
723 			tty_rx_ptr = 0;
724 			tty_rx_left = rc;
725 		} else
726 			return ( tty_gothup ? TTY_HANGUP : TTY_TIMEOUT );
727 	}
728 
729 	tty_rx_left--;
730 	return tty_rx_buf[tty_rx_ptr++];
731 }
732 
733 
tty_getc_timed(int * timeout)734 int tty_getc_timed(int *timeout)
735 {
736 	int	rc;
737 	time_t	t = time( NULL );
738 
739 	rc = tty_getc( *timeout );
740 	*timeout -= (time( NULL ) - t);
741 	return rc;
742 }
743 
744 
tty_purge(void)745 void tty_purge(void) {
746 	DEBUG(('M',3,"tty_purge"));
747 
748 	tty_rx_ptr = tty_rx_left = 0;
749 	if ( isatty( tty_fd ))
750 		tio_flush_queue( tty_fd, TIO_Q_IN );
751 }
752 
753 
tty_purgeout(void)754 void tty_purgeout(void) {
755 	DEBUG(('M',3,"tty_purgeout"));
756 
757 	tty_bufclear();
758 	if ( isatty( tty_fd ))
759 		tio_flush_queue( tty_fd, TIO_Q_OUT );
760 }
761 
762 
tty_send_break(void)763 int tty_send_break(void)
764 {
765 #ifdef POSIX_TERMIOS
766 	if ( tcsendbreak( tty_fd, 0 ) < 0 ) {
767 		DEBUG(('M',3,"tcsendbreak() failed"));
768 		return -1;
769 	}
770 #endif
771 #ifdef SYSV_TERMIO
772 	if ( ioctl( tty_fd, TCSBRK, 0 ) < 0 ) {
773 		DEBUG(('M',3,"ioctl( TCSBRK ) failed"));
774 		return -1;
775 	}
776 #endif
777 #ifdef BSD_SGTTY
778 	if ( ioctl( tty_fd, TIOCSBRK, 0 ) < 0 ) {
779 		DEBUG(('M',3,"ioctl( TIOCSBRK ) failed"));
780 		return -1;
781 	}
782 	qsleep( 1000 );
783 	if ( ioctl( tty_fd, TIOCCBRK, 0 ) < 0 ) {
784 		DEBUG(('M',3,"ioctl( TIOCCBRK ) failed"));
785 		return -1;
786 	}
787 #endif
788 
789 	return 0;
790 }
791 
792 
793 /* Return the amount of remaining bytes to be transmitted */
tty_hasout(void)794 int tty_hasout(void)
795 {
796 	return (tty_tx_free != TX_BUF_SIZE);
797 }
798 
799 
800 /*
801  * Returns whether CD line of given tty is on or off
802  */
tty_dcd(int fd)803 int tty_dcd(int fd)
804 {
805 	int rs_lines = tio_get_rs232_lines( fd );
806 
807 	DEBUG(('M',2,"tty_dcd: CD is %s",(rs_lines & TIO_F_DCD ? "On" : "Off")));
808 
809 	return ( rs_lines & TIO_F_DCD );
810 }
811 
812 
813 /*
814  * Close all FDs >= a specified value
815  */
fd_close_all(int startfd)816 static void fd_close_all(int startfd)
817 {
818 	int fdlimit = sysconf(_SC_OPEN_MAX);
819 
820 	while( startfd < fdlimit )
821 		close( startfd++ );
822 }
823 
824 
825 /*
826  * Make file descriptor stdin/stdout/stderr
827  */
fd_make_stddev(int fd)828 int fd_make_stddev(int fd)
829 {
830 
831 	fflush( stdin );
832 	fflush( stdout );
833 	fflush( stderr );
834 
835 	if ( fd > 0 ) {
836 		(void) close( 0 );
837 		if ( dup( fd ) != 0 ) {
838 			DEBUG(('T',2,"fd_make_stddev: can't dup(fd=%d) to stdin", fd));
839 			return ERROR;
840 		}
841 		close( fd );
842 	}
843 
844 	(void) close( 1 );
845 	if ( dup( 0 ) != 1 ) {
846 		DEBUG(('T',2,"fd_make_stddev: can't dup(fd=%d) to stdout", fd));
847 		return ERROR;
848 	}
849 
850 	(void) close( 2 );
851 	if ( dup( 0 ) != 2 ) {
852 		DEBUG(('T',2,"fd_make_stddev: can't dup(0) to stderr"));
853 		return ERROR;
854 	}
855 
856 	setbuf( stdin,  (char *) NULL );
857 	setbuf( stdout, (char *) NULL );
858 	setbuf( stderr, (char *) NULL );
859 
860 	clearerr( stdin );
861 	clearerr( stdout );
862 	clearerr( stderr );
863 
864 	return OK;
865 }
866 
867 
868 /*
869  * Set the O_NONBLOCK flag of desc if value is nonzero,
870  * or clear the flag if value is 0.
871  * Return 0 on success, or -1 on error with errno set.
872  */
fd_set_nonblock(int fd,int mode)873 int fd_set_nonblock(int fd, int mode)
874 {
875 	int misc;
876 
877 #if defined(FIONBIO)
878 
879 	/*
880 	 * Set non-blocking I/O mode on sockets
881 	 */
882 	misc = 1;
883 	if ( ioctl( fd, FIONBIO, &misc, sizeof( misc )) == -1 ) {
884 		DEBUG(('T',1,"ioctl: can't set %sblocking mode on fd %d: %s",
885 			(mode ? "non-" : ""), fd, strerror( errno )));
886 		return -1;
887 	}
888 #endif
889 
890 	misc = fcntl( fd, F_GETFL, 0);
891 	if ( misc == -1 ) {
892 		DEBUG(('T',1,"fnctl: can't get flags on fd %d: %s",
893 			fd, strerror( errno )));
894 		return -1;
895 	}
896 
897 	if ( mode )
898 		misc |= O_NONBLOCK;
899 	else
900 		misc &= ~O_NONBLOCK;
901 
902 	if (( misc = fcntl( fd, F_SETFL, misc )) == -1 ) {
903 		DEBUG(('T',1,"fnctl: can't set %sblocking mode on fd %d: %s",
904 			(mode ? "non-" : ""), fd, strerror( errno )));
905 	}
906 	return misc;
907 }
908 
909 
910 
911 /*
912  * tio part
913  */
914 
915 /* get current tio settings for given filedescriptor */
tio_get(int fd,TIO * t)916 int tio_get(int fd, TIO *t)
917 {
918 #ifdef SYSV_TERMIO
919     if ( ioctl( fd, TCGETA, t ) < 0 )
920     {
921         DEBUG(('T',3,"TCGETA failed"));
922         return ERROR;
923     }
924 #endif
925 #ifdef POSIX_TERMIOS
926     if ( tcgetattr( fd, t ) < 0 )
927     {
928         DEBUG(('T',3,"tcgetattr failed"));
929         return ERROR;
930     }
931 #endif
932 #ifdef BSD_SGTTY
933     if ( gtty( fd, t ) < 0 )
934     {
935         DEBUG(('T',3,"gtty failed"));
936         return ERROR;
937     }
938 #endif
939     DEBUG(('T',4,"tio_get: c_iflag=%08x, c_oflag=%08x, c_cflag=%08x, c_lflag=%08x",
940         t->c_iflag, t->c_oflag, t->c_cflag, t->c_lflag));
941     return OK;
942 }
943 
944 
945 /* set current tio settings for given filedescriptor */
tio_set(int fd,TIO * t)946 int tio_set(int fd, TIO *t)
947 {
948 #ifdef SYSV_TERMIO
949     if ( ioctl( fd, TCSETA, t ) < 0 )
950     {
951         DEBUG(('T',3,"ioctl TCSETA failed"));
952         return ERROR;
953     }
954 #endif
955 #ifdef POSIX_TERMIOS
956     if ( tcsetattr( fd, TCSANOW, t ) < 0 )
957     {
958         DEBUG(('T',3,"tcsetattr failed"));
959         return ERROR;
960     }
961 #endif /* posix_termios */
962 
963 #ifdef BSD_SGTTY
964     if ( stty( fd, t ) < 0 )
965     {
966         DEBUG(('T',3,"stty failed"));
967         return ERROR;
968     }
969 #endif
970     DEBUG(('T',4,"tio_set: c_iflag=%08x, c_oflag=%08x, c_cflag=%08x, c_lflag=%08x",
971         t->c_iflag, t->c_oflag, t->c_cflag, t->c_lflag));
972     return OK;
973 }
974 
975 
976 /*
977  * Set speed, do not touch the other flags
978  * "speed" is given as numeric baud rate, not as Bxxx constant
979  */
tio_set_speed(TIO * t,unsigned int speed)980 int tio_set_speed(TIO *t, unsigned int speed)
981 {
982     int i, symspeed = 0;
983 
984     for( i = 0; speedtab[i].cbaud != 0; i++ )
985     {
986 	if ( speedtab[i].nspeed == speed )
987 		{ symspeed = speedtab[i].cbaud; break; }
988     }
989 
990     if ( symspeed == 0 ) {
991         errno = EINVAL;
992         DEBUG(('T',2,"tss: unknown/unsupported bit rate: %d", speed));
993         return ERROR;
994     }
995 
996     DEBUG(('T',2,"tss: set speed to %d (%03o)", speed, symspeed));
997 
998 #ifdef SYSV_TERMIO
999     t->c_cflag = ( t->c_cflag & ~CBAUD) | symspeed;
1000 #endif
1001 #ifdef POSIX_TERMIOS
1002     cfsetospeed( t, symspeed );
1003     cfsetispeed( t, symspeed );
1004 #endif
1005 #ifdef BSD_SGTTY
1006     t->sg_ispeed = t->sg_ospeed = symspeed;
1007 #endif
1008     return OK;
1009 }
1010 
1011 /*
1012  * Get port speed. Return integer value, not symbolic constant
1013  */
tio_get_speed(TIO * t)1014 int tio_get_speed(TIO *t)
1015 {
1016 #ifdef SYSV_TERMIO
1017     ushort cbaud = t->c_cflag & CBAUD;
1018 #endif
1019 #ifdef POSIX_TERMIOS
1020     speed_t cbaud = cfgetospeed( t );
1021 #endif
1022 #ifdef BSD_SGTTY
1023     int cbaud = t->sg_ospeed;
1024 #endif
1025     struct speedtab *st;
1026 
1027     for( st = speedtab; st->nspeed != 0; st++ ) {
1028         if ( st->cbaud == cbaud )
1029 	    break;
1030     }
1031     return st->nspeed;
1032 }
1033 
1034 
1035 /* set "sane" mode, usable for login, ...
1036  * unlike the other tio_mode_* functions, this function initializes
1037  * all flags, and should be called before calling any other function
1038  */
tio_local_mode(TIO * t,int local)1039 void tio_local_mode(TIO * t, int local)
1040 {
1041 	if ( local )
1042 #if defined(SYSV_TERMIO) || defined( POSIX_TERMIOS )
1043 		t->c_cflag |= CLOCAL;
1044 	else
1045 		t->c_cflag &= ~CLOCAL;
1046 #else		/* BSD_SGTTY (tested only on NeXT yet, but should work) */
1047 		t->sg_flags &= ~LNOHANG;
1048 	else
1049 		t->sg_flags |= LNOHANG ;
1050 #endif
1051 }
1052 
1053 
1054 /*
1055  */
1056 
1057 #define CFLAGS_TO_SET (CREAD | HUPCL)
1058 #define CFLAGS_TO_CLEAR (CSTOPB | PARENB | PARODD | CLOCAL)
1059 
tio_raw_mode(TIO * t)1060 void tio_raw_mode(TIO * t)
1061 {
1062 #if defined(SYSV_TERMIO) || defined( POSIX_TERMIOS)
1063 #if 0
1064     t->c_iflag &= ( IXON | IXOFF | IXANY );	/* clear all flags except */
1065 						/* xon / xoff handshake */
1066     t->c_oflag  = 0;				/* no output processing */
1067     t->c_lflag  = 0;				/* no signals, no echo */
1068 #endif /* 0 */
1069     t->c_cc[VMIN]  = 1;				/* disable line buffering */
1070     t->c_cc[VTIME] = 0;
1071 
1072     /*
1073     t->c_iflag &= ~( IGNBRK | BRKINT | PARMRK | ISTRIP
1074                             | INLCR | IGNCR | ICRNL | IXON );
1075     */
1076     t->c_iflag = 0;
1077     t->c_oflag = 0;
1078     t->c_lflag = 0;
1079     t->c_cflag &= ~( CSIZE | CFLAGS_TO_CLEAR );
1080     t->c_cflag |= ( CS8 | CFLAGS_TO_SET );
1081 
1082 #else
1083     t->sg_flags = RAW;
1084 #endif
1085 }
1086 
1087 
1088 /*
1089  * initialize all c_cc fields (for POSIX and SYSV) to proper start
1090  * values (normally, the serial driver should do this, but there are
1091  * numerous systems where some of the more esoteric (VDSUSP...) flags
1092  * are plain wrong (e.g. set to "m" or so)
1093  *
1094  * do /not/ initialize VERASE and VINTR, since some systems use
1095  * ^H / DEL here, others DEL / ^C.
1096  */
tio_default_cc(TIO * t)1097 void tio_default_cc(TIO *t)
1098 {
1099 #ifdef BSD_SGTTY
1100     t->sg_erase = 0x7f;            /* erase character */
1101     t->sg_kill  = 0x25;            /* kill character, ^u */
1102 
1103 #else /* posix or sysv */
1104     t->c_cc[VQUIT]  = CQUIT;
1105     t->c_cc[VKILL]  = CKILL;
1106     t->c_cc[VEOF]   = CEOF;
1107 #if defined(VEOL) && VEOL < TIONCC
1108     t->c_cc[VEOL] = CEOL;
1109 #endif
1110 #if defined(VSTART) && VSTART < TIONCC
1111     t->c_cc[VSTART] = CSTART;
1112 #endif
1113 #if defined(VSTOP) && VSTOP < TIONCC
1114     t->c_cc[VSTOP] = CSTOP;
1115 #endif
1116 #if defined(VSUSP) && VSUSP < TIONCC
1117     t->c_cc[VSUSP] = CSUSP;
1118 #endif
1119 #if defined(VSWTCH) && VSWTCH < TIONCC
1120     t->c_cc[VSWTCH] = CSWTCH;
1121 #endif
1122     /* the following are for SVR4.2 (and higher) */
1123 #if defined(VDSUSP) && VDSUSP < TIONCC
1124     t->c_cc[VDSUSP] = CDSUSP;
1125 #endif
1126 #if defined(VREPRINT) && VREPRINT < TIONCC
1127     t->c_cc[VREPRINT] = CRPRNT;
1128 #endif
1129 #if defined(VDISCARD) && VDISCARD < TIONCC
1130     t->c_cc[VDISCARD] = CFLUSH;
1131 #endif
1132 #if defined(VWERASE) && VWERASE < TIONCC
1133     t->c_cc[VWERASE] = CWERASE;
1134 #endif
1135 #if defined(VLNEXT) && VLNEXT < TIONCC
1136     t->c_cc[VLNEXT] = CLNEXT;
1137 #endif
1138 
1139 #endif /* bsd <-> posix + sysv */
1140 }
1141 
1142 
1143 /*
1144  * set flow control according to the <type> parameter. It can be any
1145  * combination of
1146  *   FLOW_XON_IN - use Xon/Xoff on incoming data
1147  *   FLOW_XON_OUT- respect Xon/Xoff on outgoing data
1148  *   FLOW_HARD   - use RTS/respect CTS line for hardware handshake
1149  * (not every combination will work on every system)
1150  *
1151  * WARNING: for most systems, this function will not touch the tty
1152  *          settings, only modify the TIO structure.
1153  */
tio_set_flow_control(int fd,TIO * t,int type)1154 int tio_set_flow_control(int fd, TIO *t, int type)
1155 {
1156 #ifdef USE_TERMIOX
1157     struct termiox tix;
1158 #endif
1159 
1160     DEBUG(('T',2,"tio_set_flow_control(%s%s%s%s )",
1161         type & FLOW_HARD   ? " HARD": "",
1162         type & FLOW_XON_IN ? " XON_IN": "",
1163         type & FLOW_XON_OUT? " XON_OUT": "",
1164         type == FLOW_NONE ? " NONE" : "" ));
1165 
1166 #if defined( SYSV_TERMIO ) || defined( POSIX_TERMIOS )
1167     t->c_cflag &= ~HARDW_HS;
1168     t->c_iflag &= ~( IXON | IXOFF | IXANY );
1169 
1170     if ( type & FLOW_HARD )
1171         t->c_cflag |= HARDW_HS;
1172     if ( type & FLOW_XON_IN )
1173         t->c_iflag |= IXOFF;
1174     if ( type & FLOW_XON_OUT ) {
1175         t->c_iflag |= IXON;
1176         if ( type & FLOW_XON_IXANY )
1177             t->c_iflag |= IXANY;
1178     }
1179 #else
1180 # ifdef NEXTSGTTY
1181     DEBUG(('T',3,"tio_set_flow_control: not yet implemented"));
1182 # else
1183 #  error "not yet implemented"
1184 # endif
1185 #endif
1186 
1187     /* SVR4 came up with a new method of setting h/w flow control */
1188 #ifdef USE_TERMIOX
1189     DEBUG(('T',3,"tio_set_flow_control: using termiox"));
1190 
1191     if ( ioctl(fd, TCGETX, &tix ) < 0) {
1192         DEBUG(('T',3,"ioctl TCGETX"));
1193         return ERROR;
1194     }
1195     if ( type & FLOW_HARD )
1196         tix.x_hflag |= (RTSXOFF | CTSXON);
1197     else
1198         tix.x_hflag &= ~(RTSXOFF | CTSXON);
1199 
1200     if ( ioctl( fd, TCSETX, &tix ) < 0 ) {
1201         DEBUG(('T',3,"ioctl TCSETX" ));
1202 	return ERROR;
1203     }
1204 #endif
1205 
1206     return OK;
1207 }
1208 
1209 
1210 /*
1211  * Returns 0 if `speed' was not found in speedtab[] or
1212  * symbolic speed otherwise.
1213  */
tio_trans_speed(unsigned int speed)1214 int tio_trans_speed(unsigned int speed)
1215 {
1216     struct speedtab *st;
1217 
1218     for( st = speedtab; st->nspeed != 0; st++ ) {
1219         if ( st->nspeed == speed )
1220             break;
1221     }
1222     return st->cbaud;
1223 }
1224 
1225 
1226 /*
1227  * Toggle dtr with delay for msec milliseconds
1228  */
tio_toggle_dtr(int fd,int msec)1229 int tio_toggle_dtr(int fd, int msec)
1230 {
1231 #if defined(TIOCMBIS) && \
1232     ( defined(sun) || defined(SVR4) || defined(NeXT) || defined(linux) )
1233 
1234     int mctl = TIOCM_DTR;
1235 
1236     DEBUG(('T',2,"tio_toggle_dtr: %d msec", msec));
1237 #if !defined( TIOCM_VALUE )
1238     if ( ioctl( fd, TIOCMBIC, &mctl ) < 0 )
1239 #else
1240     if ( ioctl( fd, TIOCMBIC, (char *) mctl ) < 0 )
1241 #endif
1242     {
1243         DEBUG(('T',2,"tio_toggle_dtr: TIOCMBIC failed"));
1244         return ERROR;
1245     }
1246 
1247     qsleep( msec );
1248 
1249 #if !defined( TIOCM_VALUE)
1250     if ( ioctl( fd, TIOCMBIS, &mctl ) < 0 )
1251 #else
1252     if ( ioctl( fd, TIOCMBIS, (char *) mctl ) < 0 )
1253 #endif
1254     {
1255         DEBUG(('T',2,"tio_toggle_dtr: TIOCMBIS failed"));
1256         return ERROR;
1257     }
1258     return OK;
1259 #else						/* !TIOCMBI* */
1260 
1261     /* On HP/UX, lowering DTR by setting the port speed to B0 will
1262      * leave it there. So, do it via HP/UX's special ioctl()'s...
1263      */
1264 #if defined(_HPUX_SOURCE) || defined(MCGETA)
1265     unsigned long mflag = 0L;
1266 
1267     DEBUG(('T',2,"tio_toggle_dtr: %d msec", msec));
1268     if ( ioctl( fd, MCSETAF, &mflag ) < 0 ) {
1269         DEBUG(('T',2,"tio_toggle_dtr: MCSETAF failed"));
1270         return ERROR;
1271     }
1272 
1273     qsleep( msec );
1274 
1275     if ( ioctl( fd, MCGETA, &mflag ) < 0 ) {
1276         DEBUG(('T',2,"tio_toggle_dtr: MCGETA failed"));
1277         return ERROR;
1278     }
1279     mflag = MRTS | MDTR;
1280     if ( ioctl( fd, MCSETAF, &mflag ) < 0 ) {
1281         DEBUG(('T',2,"tio_toggle_dtr: MCSETAF failed"));
1282         return ERROR;
1283     }
1284     return OK;
1285 
1286 #else /* !MCGETA */
1287 
1288     /* The "standard" way of doing things - via speed = B0
1289      */
1290     TIO t, save_t;
1291     int result;
1292 
1293     DEBUG(('T',2,"tio_toggle_dtr: %d msec", msec));
1294     if ( tio_get( fd, &t ) == ERROR ) {
1295          DEBUG(('T',2,"tio_toggle_dtr: tio_get failed"));
1296          return ERROR;
1297     }
1298 
1299     save_t = t;
1300 
1301 #ifdef SYSV_TERMIO
1302     t.c_cflag = ( t.c_cflag & ~CBAUD ) | B0;		/* speed = 0 */
1303 #endif
1304 #ifdef POSIX_TERMIOS
1305     cfsetospeed( &t, B0 );
1306     cfsetispeed( &t, B0 );
1307 #endif
1308 #ifdef BSD_SGTTY
1309     t.sg_ispeed = t.sg_ospeed = B0
1310 #endif
1311 
1312     tio_set( fd, &t );
1313     qsleep( msec );
1314     result = tio_set( fd, &save_t );
1315 
1316     DEBUG(('T',2,"tio_toggle_dtr: result %d", result));
1317     return result;
1318 #endif					/* !MCSETA */
1319 #endif					/* !SVR4 */
1320 }
1321 
1322 
1323 /*
1324  * Flush input or output data queue
1325  *
1326  * "queue" is one of the TIO_Q* values from tio.h
1327  */
tio_flush_queue(int fd,int queue)1328 int tio_flush_queue(int fd, int queue)
1329 {
1330     int r = OK;
1331 #ifdef POSIX_TERMIOS
1332     switch( queue ) {
1333         case TIO_Q_IN:   r = tcflush( fd, TCIFLUSH ); break;
1334         case TIO_Q_OUT:  r = tcflush( fd, TCOFLUSH ); break;
1335         case TIO_Q_BOTH: r = tcflush( fd, TCIOFLUSH );break;
1336         default:
1337             DEBUG(('T',2,"tio_flush_queue: invalid ``queue'' argument (%d)", queue ));
1338             return ERROR;
1339     }
1340 #endif
1341 #ifdef SYSV_TERMIO
1342     switch ( queue ) {
1343         case TIO_Q_IN:   r = ioctl( fd, TCFLSH, 0 ); break;
1344         case TIO_Q_OUT:  r = ioctl( fd, TCFLSH, 1 ); break;
1345         case TIO_Q_BOTH: r = ioctl( fd, TCFLSH, 2 ); break;
1346         default:
1347             DEBUG(('T',2,"tio_flush_queue: invalid ``queue'' argument (%d)", queue ));
1348             return ERROR;
1349     }
1350 #endif
1351 #ifdef BSD_SGTTY
1352     int arg;
1353 
1354     switch ( queue ) {
1355         case TIO_Q_IN:   arg = FREAD; break;
1356         case TIO_Q_OUT:  arg = FWRITE; break;
1357         case TIO_Q_BOTH: arg = FREAD | FWRITE; break;
1358         default:
1359             DEBUG(('T',2,"tio_flush_queue: invalid ``queue'' argument (%d)", queue ));
1360             return ERROR;
1361     }
1362     r = ioctl( fd, TIOCFLUSH, (char *) &arg );
1363 #endif
1364     if ( r != 0 )
1365         DEBUG(('T',2,"tio: cannot flush queue" ));
1366 
1367     return r;
1368 }
1369 
1370 
1371 /*
1372  * tio_drain(fd): wait for output queue to drain
1373  */
tio_drain_output(int fd)1374 int tio_drain_output(int fd)
1375 {
1376 #ifdef POSIX_TERMIOS
1377     if ( tcdrain( fd ) == ERROR ) {
1378         DEBUG(('T',2,"tio_drain: tcdrain" ));
1379         return ERROR;
1380     }
1381 #else
1382 # ifdef SYSV_TERMIO
1383     if ( ioctl( fd, TCSBRK, 1 ) == ERROR ) {
1384         DEBUG(('T',2,"tio_drain: TCSBRK/1" ));
1385         return ERROR;
1386     }
1387 # else	/* no way to wait for data to drain with BSD_SGTTY */
1388     DEBUG(('T',2,"tio_drain: expect spurious failures" ));
1389 # endif
1390 #endif
1391     return OK;
1392 }
1393 
1394 
1395 /* tio_get_rs232_lines()
1396  *
1397  * get the status of all RS232 status lines
1398  * (coded by the TIO_F_* flags. On systems that have the BSD TIOCM_*
1399  * flags, we use them, on others we may have to do some other tricks)
1400  *
1401  * "-1" can mean "error" or "not supported on this system" (e.g. SCO).
1402  */
tio_get_rs232_lines(int fd)1403 int tio_get_rs232_lines(int fd)
1404 {
1405     int flags;
1406 #ifdef TIO_F_SYSTEM_DEFS
1407     if ( ioctl(fd, TIOCMGET, &flags ) < 0 )
1408         DEBUG(('M',3,"tio_get_rs232_lines: TIOCMGET failed"));
1409 
1410 #else /* !TIO_F_SYSTEM_DEFS */
1411     flags=-1;
1412 #endif
1413 
1414     if ( flags != -1 )
1415     {
1416         DEBUG(('M',3,"tio_get_rs232_lines: status: [%s][%s][%s][%s][%s][%s]",
1417             ( flags & TIO_F_RTS ) ? "RTS" : "rts",
1418             ( flags & TIO_F_CTS ) ? "CTS" : "cts",
1419             ( flags & TIO_F_DSR ) ? "DSR" : "dsr",
1420             ( flags & TIO_F_DTR ) ? "DTR" : "dtr",
1421             ( flags & TIO_F_DCD ) ? "DCD" : "dcd",
1422             ( flags & TIO_F_RI  ) ? "RI" : "ri" ));
1423     }
1424     return flags;
1425 }
1426 
1427