1/* vi: set sw=4 ts=4:
2 *
3 * term.c
4 *
5 * General purpose terminal handling library.
6 *
7 * Nick Patavalis (npat@inaccessnetworks.com)
8 *
9 * originaly by Pantelis Antoniou (panto@intranet.gr), Nick Patavalis
10 *
11 * Documentation can be found in the header file "term.h".
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License as
15 * published by the Free Software Foundation; either version 2 of the
16 * License, or (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21 * General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
26 * USA
27 *
28 * $Id$
29 */
30
31#include <stdlib.h>
32#include <stdio.h>
33#include <string.h>
34#include <errno.h>
35#include <unistd.h>
36#ifdef __linux__
37#include <termio.h>
38#else
39#include <termios.h>
40#endif /* of __linux__ */
41
42#include "term.h"
43
44/***************************************************************************/
45
46static struct term_s {
47	int init;
48	int fd[MAX_TERMS];
49	struct termios origtermios[MAX_TERMS];
50	struct termios currtermios[MAX_TERMS];
51	struct termios nexttermios[MAX_TERMS];
52} term;
53
54/***************************************************************************/
55
56int term_errno;
57
58static const char * const term_err_str[] = {
59	[TERM_EOK]        = "No error",
60	[TERM_ENOINIT]    = "Framework is uninitialized",
61	[TERM_EFULL]      = "Framework is full",
62    [TERM_ENOTFOUND]  = "Filedes not in the framework",
63    [TERM_EEXISTS]    = "Filedes already in the framework",
64    [TERM_EATEXIT]    = "Cannot install atexit handler",
65    [TERM_EISATTY]    = "Filedes is not a tty",
66    [TERM_EFLUSH]     = "Cannot flush the device",
67	[TERM_EGETATTR]   = "Cannot get the device attributes",
68	[TERM_ESETATTR]   = "Cannot set the device attributes",
69	[TERM_EBAUD]      = "Invalid baud rate",
70	[TERM_ESETOSPEED] = "Cannot set the output speed",
71	[TERM_ESETISPEED] = "Cannot set the input speed",
72	[TERM_EPARITY]    = "Invalid parity mode",
73	[TERM_EDATABITS]  = "Invalid number of databits",
74	[TERM_EFLOW]      = "Invalid flowcontrol mode",
75    [TERM_EDTRDOWN]   = "Cannot lower DTR",
76    [TERM_EDTRUP]     = "Cannot raise DTR",
77	[TERM_EDRAIN]     = "Cannot drain the device",
78	[TERM_EBREAK]     = "Cannot send break sequence"
79};
80
81static char term_err_buff[1024];
82
83const char *
84term_strerror (int terrnum, int errnum)
85{
86	const char *rval;
87
88	switch(terrnum) {
89	case TERM_EFLUSH:
90	case TERM_EGETATTR:
91	case TERM_ESETATTR:
92	case TERM_ESETOSPEED:
93	case TERM_ESETISPEED:
94	case TERM_EDRAIN:
95	case TERM_EBREAK:
96		snprintf(term_err_buff, sizeof(term_err_buff),
97				 "%s: %s", term_err_str[terrnum], strerror(errnum));
98		rval = term_err_buff;
99		break;
100	case TERM_EOK:
101	case TERM_ENOINIT:
102	case TERM_EFULL:
103	case TERM_ENOTFOUND:
104	case TERM_EEXISTS:
105	case TERM_EATEXIT:
106	case TERM_EISATTY:
107	case TERM_EBAUD:
108	case TERM_EPARITY:
109	case TERM_EDATABITS:
110	case TERM_EFLOW:
111	case TERM_EDTRDOWN:
112	case TERM_EDTRUP:
113		snprintf(term_err_buff, sizeof(term_err_buff),
114				 "%s", term_err_str[terrnum]);
115		rval = term_err_buff;
116		break;
117	default:
118		rval = NULL;
119		break;
120	}
121
122	return rval;
123}
124
125int
126term_perror (const char *prefix)
127{
128	return fprintf(stderr, "%s %s\n",
129				   prefix, term_strerror(term_errno, errno));
130}
131
132/***************************************************************************/
133
134static int
135term_find_next_free (void)
136{
137	int rval, i;
138
139	do { /* dummy */
140		if ( ! term.init ) {
141			term_errno = TERM_ENOINIT;
142			rval = -1;
143			break;
144		}
145
146		for (i = 0; i < MAX_TERMS; i++)
147			if ( term.fd[i] == -1 ) break;
148
149		if ( i == MAX_TERMS ) {
150			term_errno = TERM_EFULL;
151			rval = -1;
152			break;
153		}
154
155		rval = i;
156	} while (0);
157
158	return rval;
159}
160
161/***************************************************************************/
162
163static int
164term_find (int fd)
165{
166	int rval, i;
167
168	do { /* dummy */
169		if ( ! term.init ) {
170			term_errno = TERM_ENOINIT;
171			rval = -1;
172			break;
173		}
174
175		for (i = 0; i < MAX_TERMS; i++)
176			if (term.fd[i] == fd) break;
177
178		if ( i == MAX_TERMS ) {
179			term_errno = TERM_ENOTFOUND;
180			rval = -1;
181			break;
182		}
183
184		rval = i;
185	} while (0);
186
187	return rval;
188}
189
190/***************************************************************************/
191
192static void
193term_exitfunc (void)
194{
195	int r, i;
196
197	do { /* dummy */
198		if ( ! term.init )
199			break;
200
201		for (i = 0; i < MAX_TERMS; i++) {
202			if (term.fd[i] == -1)
203				continue;
204			do { /* dummy */
205				r = tcflush(term.fd[i], TCIOFLUSH);
206				if ( r < 0 ) break;
207				r = tcsetattr(term.fd[i], TCSAFLUSH, &term.origtermios[i]);
208				if ( r < 0 ) break;
209			} while (0);
210			if ( r < 0 ) {
211				char *tname;
212
213				tname = ttyname(term.fd[i]);
214				if ( ! tname ) tname = "UNKNOWN";
215				fprintf(stderr, "%s: reset failed for dev %s: %s\n",
216						__FUNCTION__, tname, strerror(errno));
217			}
218			term.fd[i] = -1;
219		}
220	} while (0);
221}
222
223/***************************************************************************/
224
225int
226term_lib_init (void)
227{
228	int rval, r, i;
229
230	rval = 0;
231
232	do { /* dummy */
233		if ( term.init ) {
234			/* reset all terms back to their original settings */
235			for (i = 0; i < MAX_TERMS; i++) {
236				if (term.fd[i] == -1)
237					continue;
238				do {
239					r = tcflush(term.fd[i], TCIOFLUSH);
240					if ( r < 0 ) break;
241					r = tcsetattr(term.fd[i], TCSAFLUSH, &term.origtermios[i]);
242					if ( r < 0 ) break;
243				} while (0);
244				if ( r < 0 ) {
245					char *tname;
246
247					tname = ttyname(term.fd[i]);
248					if ( ! tname ) tname = "UNKNOWN";
249					fprintf(stderr, "%s: reset failed for dev %s: %s\n",
250							__FUNCTION__, tname, strerror(errno));
251				}
252				term.fd[i] = -1;
253			}
254		} else {
255			/* initialize term structure. */
256			for (i = 0; i < MAX_TERMS; i++)
257				term.fd[i] = -1;
258			if ( atexit(term_exitfunc) != 0 ) {
259				term_errno = TERM_EATEXIT;
260				rval = -1;
261				break;
262			}
263			/* ok. term struct is now initialized. */
264			term.init = 1;
265		}
266	} while(0);
267
268	return rval;
269}
270
271/***************************************************************************/
272
273int
274term_add (int fd)
275{
276	int rval, r, i;
277
278	rval = 0;
279
280	do { /* dummy */
281		i = term_find(fd);
282		if ( i >= 0 ) {
283			term_errno = TERM_EEXISTS;
284			rval = -1;
285			break;
286		}
287
288		if ( ! isatty(fd) ) {
289			term_errno = TERM_EISATTY;
290			rval = -1;
291			break;
292		}
293
294		i = term_find_next_free();
295		if ( i < 0 ) {
296			rval = -1;
297			break;
298		}
299
300		r = tcgetattr(fd, &term.origtermios[i]);
301		if ( r < 0 ) {
302			term_errno = TERM_EGETATTR;
303			rval = -1;
304			break;
305		}
306
307		term.currtermios[i] = term.origtermios[i];
308		term.nexttermios[i] = term.origtermios[i];
309		term.fd[i] = fd;
310	} while (0);
311
312	return rval;
313}
314
315/***************************************************************************/
316
317int
318term_remove(int fd)
319{
320	int rval, r, i;
321
322	rval = 0;
323
324	do { /* dummy */
325		i = term_find(fd);
326		if ( i < 0 ) {
327			rval = -1;
328			break;
329		}
330
331		do { /* dummy */
332			r = tcflush(term.fd[i], TCIOFLUSH);
333			if ( r < 0 ) {
334				term_errno = TERM_EFLUSH;
335				rval = -1;
336				break;
337			}
338			r = tcsetattr(term.fd[i], TCSAFLUSH, &term.origtermios[i]);
339			if ( r < 0 ) {
340				term_errno = TERM_ESETATTR;
341				rval = -1;
342				break;
343			}
344		} while (0);
345
346		term.fd[i] = -1;
347	} while (0);
348
349	return rval;
350}
351
352/***************************************************************************/
353
354int
355term_erase(int fd)
356{
357	int rval, i;
358
359	rval = 0;
360
361	do { /* dummy */
362		i = term_find(fd);
363		if ( i < 0 ) {
364			rval = -1;
365			break;
366		}
367
368		term.fd[i] = -1;
369	} while (0);
370
371	return rval;
372}
373
374/***************************************************************************/
375
376int
377term_replace (int oldfd, int newfd)
378{
379	int rval, r, i;
380
381	rval = 0;
382
383	do { /* dummy */
384
385		i = term_find(oldfd);
386		if ( i < 0 ) {
387			rval = -1;
388			break;
389		}
390
391		r = tcsetattr(newfd, TCSAFLUSH, &term.currtermios[i]);
392		if ( r < 0 ) {
393			term_errno = TERM_ESETATTR;
394			rval = -1;
395			break;
396		}
397
398		term.fd[i] = newfd;
399
400	} while (0);
401
402	return rval;
403}
404
405/***************************************************************************/
406
407int
408term_reset (int fd)
409{
410	int rval, r, i;
411
412	rval = 0;
413
414	do { /* dummy */
415
416		i = term_find(fd);
417		if ( i < 0 ) {
418			rval = -1;
419			break;
420		}
421
422		r = tcflush(term.fd[i], TCIOFLUSH);
423		if ( r < 0 ) {
424			term_errno = TERM_EFLUSH;
425			rval = -1;
426			break;
427		}
428		r = tcsetattr(term.fd[i], TCSAFLUSH, &term.origtermios[i]);
429		if ( r < 0 ) {
430			term_errno = TERM_ESETATTR;
431			rval = -1;
432			break;
433		}
434
435		term.currtermios[i] = term.origtermios[i];
436		term.nexttermios[i] = term.origtermios[i];
437	} while (0);
438
439	return rval;
440}
441
442/***************************************************************************/
443
444int
445term_revert (int fd)
446{
447	int rval, i;
448
449	rval = 0;
450
451	do { /* dummy */
452
453		i = term_find(fd);
454		if ( i < 0 ) {
455			rval = -1;
456			break;
457		}
458
459		term.nexttermios[i] = term.currtermios[i];
460
461	} while (0);
462
463	return rval;
464}
465
466/***************************************************************************/
467
468int
469term_refresh (int fd)
470{
471	int rval, r, i;
472
473	rval = 0;
474
475	do { /* dummy */
476
477		i = term_find(fd);
478		if ( i < 0 ) {
479			rval = -1;
480			break;
481		}
482
483		r = tcgetattr(fd, &term.currtermios[i]);
484		if ( r < 0 ) {
485			term_errno = TERM_EGETATTR;
486			rval = -1;
487			break;
488		}
489
490	} while (0);
491
492	return rval;
493}
494
495/***************************************************************************/
496
497int
498term_apply (int fd)
499{
500	int rval, r, i;
501
502	rval = 0;
503
504	do { /* dummy */
505
506		i = term_find(fd);
507		if ( i < 0 ) {
508			rval = -1;
509			break;
510		}
511
512		r = tcsetattr(term.fd[i], TCSAFLUSH, &term.nexttermios[i]);
513		if ( r < 0 ) {
514			term_errno = TERM_ESETATTR;
515			rval = -1;
516			break;
517		}
518
519		term.currtermios[i] = term.nexttermios[i];
520
521	} while (0);
522
523	return rval;
524}
525
526/***************************************************************************/
527
528int
529term_set_raw (int fd)
530{
531	int rval, i;
532
533	rval = 0;
534
535	do { /* dummy */
536
537		i = term_find(fd);
538		if ( i < 0 ) {
539			rval = -1;
540			break;
541		}
542
543		/* BSD raw mode */
544		cfmakeraw(&term.nexttermios[i]);
545		/* one byte at a time, no timer */
546		term.nexttermios[i].c_cc[VMIN] = 1;
547		term.nexttermios[i].c_cc[VTIME] = 0;
548
549	} while (0);
550
551	return rval;
552}
553
554/***************************************************************************/
555
556int
557term_set_baudrate (int fd, int baudrate)
558{
559	int rval, r, i;
560	speed_t spd;
561	struct termios tio;
562
563	rval = 0;
564
565	do { /* dummy */
566
567		i = term_find(fd);
568		if ( i < 0 ) {
569			rval = -1;
570			break;
571		}
572
573		tio = term.nexttermios[i];
574
575		switch (baudrate) {
576		case 0:
577			spd = B0;
578			break;
579		case 50:
580			spd = B50;
581			break;
582		case 75:
583			spd = B75;
584			break;
585		case 110:
586			spd = B110;
587			break;
588		case 134:
589			spd = B134;
590			break;
591		case 150:
592			spd = B150;
593			break;
594		case 200:
595			spd = B200;
596			break;
597		case 300:
598			spd = B300;
599			break;
600		case 600:
601			spd = B600;
602			break;
603		case 1200:
604			spd = B1200;
605			break;
606		case 1800:
607			spd = B1800;
608			break;
609		case 2400:
610			spd = B2400;
611			break;
612		case 4800:
613			spd = B4800;
614			break;
615		case 9600:
616			spd = B9600;
617			break;
618		case 19200:
619			spd = B19200;
620			break;
621		case 38400:
622			spd = B38400;
623			break;
624		case 57600:
625			spd = B57600;
626			break;
627		case 115200:
628			spd = B115200;
629			break;
630		case 230400:
631			spd = B230400;
632			break;
633		default:
634			term_errno = TERM_EBAUD;
635			rval = -1;
636			break;
637		}
638		if ( rval < 0 ) break;
639
640		r = cfsetospeed(&tio, spd);
641		if ( r < 0 ) {
642			term_errno = TERM_ESETOSPEED;
643			rval = -1;
644			break;
645		}
646
647		r = cfsetispeed(&tio, spd);
648		if ( r < 0 ) {
649			term_errno = TERM_ESETISPEED;
650			rval = -1;
651			break;
652		}
653
654		term.nexttermios[i] = tio;
655
656	} while (0);
657
658	return rval;
659}
660
661/***************************************************************************/
662
663int
664term_set_parity (int fd, enum parity_e parity)
665{
666	int rval, i;
667	struct termios *tiop;
668
669	rval = 0;
670
671	do { /* dummy */
672
673		i = term_find(fd);
674		if ( i < 0 ) {
675			rval = -1;
676			break;
677		}
678
679		tiop = &term.nexttermios[i];
680
681		switch (parity) {
682		case P_EVEN:
683			tiop->c_cflag = (tiop->c_cflag & ~(PARENB | PARODD)) | PARENB;
684			break;
685		case P_ODD:
686			tiop->c_cflag = (tiop->c_cflag & ~(PARENB | PARODD)) | PARODD;
687			break;
688		case P_NONE:
689			tiop->c_cflag = (tiop->c_cflag & ~(PARENB | PARODD));
690			break;
691		default:
692			term_errno = TERM_EPARITY;
693			rval = -1;
694			break;
695		}
696		if ( rval < 0 ) break;
697
698	} while (0);
699
700	return rval;
701}
702
703/***************************************************************************/
704
705int
706term_set_databits (int fd, int databits)
707{
708	int rval, i;
709	struct termios *tiop;
710
711	rval = 0;
712
713	do { /* dummy */
714
715		i = term_find(fd);
716		if ( i < 0 ) {
717			rval = -1;
718			break;
719		}
720
721		tiop = &term.nexttermios[i];
722
723		switch (databits) {
724		case 5:
725			tiop->c_cflag = (tiop->c_cflag & ~CSIZE) | CS5;
726			break;
727		case 6:
728			tiop->c_cflag = (tiop->c_cflag & ~CSIZE) | CS6;
729			break;
730		case 7:
731			tiop->c_cflag = (tiop->c_cflag & ~CSIZE) | CS7;
732			break;
733		case 8:
734			tiop->c_cflag = (tiop->c_cflag & ~CSIZE) | CS8;
735			break;
736		default:
737			term_errno = TERM_EDATABITS;
738			rval = -1;
739			break;
740		}
741		if ( rval < 0 ) break;
742
743	} while (0);
744
745	return rval;
746}
747
748/***************************************************************************/
749
750int
751term_set_flowcntrl (int fd, enum flowcntrl_e flowcntl)
752{
753	int rval, i;
754	struct termios *tiop;
755
756	rval = 0;
757
758	do { /* dummy */
759
760		i = term_find(fd);
761		if ( i < 0 ) {
762			rval = -1;
763			break;
764		}
765
766		tiop = &term.nexttermios[i];
767
768		switch (flowcntl) {
769		case FC_RTSCTS:
770			tiop->c_cflag |= CRTSCTS;
771			tiop->c_iflag &= ~(IXON | IXOFF | IXANY);
772			break;
773		case FC_XONXOFF:
774			tiop->c_cflag &= ~(CRTSCTS);
775			tiop->c_iflag |= IXON | IXOFF;
776			break;
777		case FC_NONE:
778			tiop->c_cflag &= ~(CRTSCTS);
779			tiop->c_iflag &= ~(IXON | IXOFF | IXANY);
780			break;
781		default:
782			term_errno = TERM_EFLOW;
783			rval = -1;
784			break;
785		}
786		if ( rval < 0 ) break;
787
788	} while (0);
789
790	return rval;
791}
792
793/***************************************************************************/
794
795int
796term_set_local(int fd, int local)
797{
798	int rval, i;
799	struct termios *tiop;
800
801	rval = 0;
802
803	do { /* dummy */
804
805		i = term_find(fd);
806		if ( i < 0 ) {
807			rval = -1;
808			break;
809		}
810
811		tiop = &term.nexttermios[i];
812
813		if ( local )
814			tiop->c_cflag |= CLOCAL;
815		else
816			tiop->c_cflag &= ~CLOCAL;
817
818	} while (0);
819
820	return rval;
821}
822
823/***************************************************************************/
824
825int
826term_set_hupcl (int fd, int on)
827{
828	int rval, i;
829	struct termios *tiop;
830
831	rval = 0;
832
833	do { /* dummy */
834
835		i = term_find(fd);
836		if ( i < 0 ) {
837			rval = -1;
838			break;
839		}
840
841		tiop = &term.nexttermios[i];
842
843		if ( on )
844			tiop->c_cflag |= HUPCL;
845		else
846			tiop->c_cflag &= ~HUPCL;
847
848	} while (0);
849
850	return rval;
851}
852
853/***************************************************************************/
854
855int
856term_set(int fd,
857		 int raw,
858		 int baud, enum parity_e parity, int bits, enum flowcntrl_e fc,
859		 int local, int hup_close)
860{
861	int rval, r, i, ni;
862	struct termios tio;
863
864	rval = 0;
865
866	do { /* dummy */
867
868		i = term_find(fd);
869		if ( i < 0 ) {
870			ni = term_add(fd);
871			if ( ni < 0 ) {
872				rval = -1;
873				break;
874			}
875		} else {
876			ni = i;
877		}
878
879		tio = term.nexttermios[ni];
880
881		do { /* dummy */
882
883			if (raw) {
884				r = term_set_raw(fd);
885				if ( r < 0 ) { rval = -1; break; }
886			}
887
888			r = term_set_baudrate(fd, baud);
889			if ( r < 0 ) { rval = -1; break; }
890
891			r = term_set_parity(fd, parity);
892			if ( r < 0 ) { rval = -1; break; }
893
894			r = term_set_databits(fd, bits);
895			if ( r < 0 ) { rval = -1; break; }
896
897			r = term_set_flowcntrl(fd, fc);
898			if ( r < 0 ) { rval = -1; break; }
899
900			r = term_set_local(fd, local);
901			if ( r < 0 ) { rval = -1; break; }
902
903			r = term_set_hupcl(fd, hup_close);
904			if ( r < 0 ) { rval = -1; break; }
905
906		} while (0);
907
908		if ( rval < 0 ) {
909			if ( i < 0 )
910				/* new addition. must be removed */
911				term.fd[ni] = -1;
912			else
913				/* just revert to previous settings */
914				term.nexttermios[ni] = tio;
915		}
916
917	} while (0);
918
919	return rval;
920}
921
922/***************************************************************************/
923
924int
925term_pulse_dtr (int fd)
926{
927	int rval, r, i;
928
929	rval = 0;
930
931	do { /* dummy */
932
933		i = term_find(fd);
934		if ( i < 0 ) {
935			rval = -1;
936			break;
937		}
938
939#ifdef __linux__
940		{
941			int opins = TIOCM_DTR;
942
943			r = ioctl(fd, TIOCMBIC, &opins);
944			if ( r < 0 ) {
945				term_errno = TERM_EDTRDOWN;
946				rval = -1;
947				break;
948			}
949
950			sleep(1);
951
952			r = ioctl(fd, TIOCMBIS, &opins);
953			if ( r < 0 ) {
954				term_errno = TERM_EDTRUP;
955				rval = -1;
956				break;
957			}
958		}
959#else
960		{
961			struct termios tio, tioold;
962
963			r = tcgetattr(fd, &tio);
964			if ( r < 0 ) {
965				term_errno = TERM_ESETATTR;
966				rval = -1;
967				break;
968			}
969
970			tioold = tio;
971
972			cfsetospeed(&tio, B0);
973			cfsetispeed(&tio, B0);
974			r = tcsetattr(fd, TCSANOW, &tio);
975			if ( r < 0 ) {
976				term_errno = TERM_ESETATTR;
977				rval = -1;
978				break;
979			}
980
981			sleep(1);
982
983			r = tcsetattr(fd, TCSANOW, &tioold);
984			if ( r < 0 ) {
985				term.currtermios[i] = tio;
986				term_errno = TERM_ESETATTR;
987				rval = -1;
988				break;
989			}
990		}
991#endif /* of __linux__ */
992
993	} while (0);
994
995	return rval;
996}
997
998/***************************************************************************/
999
1000int
1001term_raise_dtr(int fd)
1002{
1003	int rval, r, i;
1004
1005	rval = 0;
1006
1007	do { /* dummy */
1008
1009		i = term_find(fd);
1010		if ( i < 0 ) {
1011			rval = -1;
1012			break;
1013		}
1014
1015#ifdef __linux__
1016		{
1017			int opins = TIOCM_DTR;
1018
1019			r = ioctl(fd, TIOCMBIS, &opins);
1020			if ( r < 0 ) {
1021				term_errno = TERM_EDTRUP;
1022				rval = -1;
1023				break;
1024			}
1025		}
1026#else
1027		r = tcsetattr(fd, TCSANOW, &term.currtermios[i]);
1028		if ( r < 0 ) {
1029			/* FIXME: perhaps try to update currtermios */
1030			term_errno = TERM_ESETATTR;
1031			rval = -1;
1032			break;
1033		}
1034#endif /* of __linux__ */
1035	} while (0);
1036
1037	return rval;
1038}
1039
1040/***************************************************************************/
1041
1042
1043int
1044term_lower_dtr(int fd)
1045{
1046	int rval, r, i;
1047
1048	rval = 0;
1049
1050	do { /* dummy */
1051
1052		i = term_find(fd);
1053		if ( i < 0 ) {
1054			rval = -1;
1055			break;
1056		}
1057
1058#ifdef __linux__
1059		{
1060			int opins = TIOCM_DTR;
1061
1062			r = ioctl(fd, TIOCMBIC, &opins);
1063			if ( r < 0 ) {
1064				term_errno = TERM_EDTRDOWN;
1065				rval = -1;
1066				break;
1067			}
1068		}
1069#else
1070		{
1071			struct termios tio;
1072
1073			r = tcgetattr(fd, &tio);
1074			if ( r < 0 ) {
1075				term_errno = TERM_EGETATTR;
1076				rval = -1;
1077				break;
1078			}
1079			term.currtermios[i] = tio;
1080
1081			cfsetospeed(&tio, B0);
1082			cfsetispeed(&tio, B0);
1083
1084			r = tcsetattr(fd, TCSANOW, &tio);
1085			if ( r < 0 ) {
1086				term_errno = TERM_ESETATTR;
1087				rval = -1;
1088				break;
1089			}
1090		}
1091#endif /* of __linux__ */
1092	} while (0);
1093
1094	return rval;
1095}
1096
1097/***************************************************************************/
1098
1099int
1100term_drain(int fd)
1101{
1102	int rval, r;
1103
1104	rval = 0;
1105
1106	do { /* dummy */
1107
1108		r = term_find(fd);
1109		if ( r < 0 ) {
1110			rval = -1;
1111			break;
1112		}
1113
1114		do {
1115			r = tcdrain(fd);
1116		} while ( r < 0 && errno == EINTR);
1117		if ( r < 0 ) {
1118			term_errno = TERM_EDRAIN;
1119			rval = -1;
1120			break;
1121		}
1122
1123	} while (0);
1124
1125	return rval;
1126}
1127
1128/***************************************************************************/
1129
1130int
1131term_flush(int fd)
1132{
1133	int rval, r;
1134
1135	rval = 0;
1136
1137	do { /* dummy */
1138
1139		r = term_find(fd);
1140		if ( r < 0 ) {
1141			rval = -1;
1142			break;
1143		}
1144
1145		r = tcflush(fd, TCIOFLUSH);
1146		if ( r < 0 ) {
1147			rval = -1;
1148			break;
1149		}
1150
1151	} while (0);
1152
1153	return rval;
1154}
1155
1156/***************************************************************************/
1157
1158int
1159term_break(int fd)
1160{
1161	int rval, r;
1162
1163	rval = 0;
1164
1165	do { /* dummy */
1166
1167		r = term_find(fd);
1168		if ( r < 0 ) {
1169			rval = -1;
1170			break;
1171		}
1172
1173		r = tcsendbreak(fd, 0);
1174		if ( r < 0 ) {
1175			term_errno = TERM_EBREAK;
1176			rval = -1;
1177			break;
1178		}
1179
1180	} while (0);
1181
1182	return rval;
1183}
1184
1185/**************************************************************************/
1186
1187/*
1188 * Local Variables:
1189 * mode:c
1190 * tab-width: 4
1191 * c-basic-offset: 4
1192 * End:
1193 */
1194