summaryrefslogtreecommitdiff
path: root/tty.c
blob: d106b3e0f9fbc994e1e8fdc4063bb2ca0808fa05 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/*	$NetBSD: tty.c,v 1.9 2017/06/30 04:41:19 kamil Exp $	*/

#include <sys/cdefs.h>

#ifndef lint
__RCSID("$NetBSD: tty.c,v 1.9 2017/06/30 04:41:19 kamil Exp $");
#endif

#include <sys/stat.h>

#include "sh.h"
#define EXTERN
#include "tty.h"
#undef EXTERN

int
get_tty(fd, ts)
	int fd;
	TTY_state *ts;
{
	int ret;

# ifdef HAVE_TERMIOS_H
	ret = tcgetattr(fd, ts);
# else /* HAVE_TERIOS_H */
#  ifdef HAVE_TERMIO_H
	ret = ioctl(fd, TCGETA, ts);
#  else /* HAVE_TERMIO_H */
	ret = ioctl(fd, TIOCGETP, &ts->sgttyb);
#   ifdef TIOCGATC
	if (ioctl(fd, TIOCGATC, &ts->lchars) < 0)
		ret = -1;
#   else
	if (ioctl(fd, TIOCGETC, &ts->tchars) < 0)
		ret = -1;
#    ifdef TIOCGLTC
	if (ioctl(fd, TIOCGLTC, &ts->ltchars) < 0)
		ret = -1;
#    endif /* TIOCGLTC */
#   endif /* TIOCGATC */
#  endif /* HAVE_TERMIO_H */
# endif /* HAVE_TERIOS_H */
	return ret;
}

int
set_tty(fd, ts, flags)
	int fd;
	TTY_state *ts;
	int flags;
{
	int ret = 0;

# ifdef HAVE_TERMIOS_H
	ret = tcsetattr(fd, TCSADRAIN, ts);
# else /* HAVE_TERIOS_H */
#  ifdef HAVE_TERMIO_H
#   ifndef TCSETAW				/* e.g. Cray-2 */
		/* first wait for output to drain */
#    ifdef TCSBRK
		if (ioctl(tty_fd, TCSBRK, 1) < 0)
			ret = -1;
#    else /* the following kludge is minimally intrusive, but sometimes fails */
		if (flags & TF_WAIT)
			sleep((unsigned)1);	/* fake it */
#    endif
#   endif /* !TCSETAW */
#   if defined(_BSD_SYSV) || !defined(TCSETAW)
/* _BSD_SYSV must force TIOCSETN instead of TIOCSETP (preserve type-ahead) */
		if (ioctl(tty_fd, TCSETA, ts) < 0)
			ret = -1;
#   else
		if (ioctl(tty_fd, TCSETAW, ts) < 0)
			ret = -1;
#   endif
#  else /* HAVE_TERMIO_H */
	    ret = ioctl(fd, TIOCSETN, &ts->sgttyb);
#   ifdef TIOCGATC
	if (ioctl(fd, TIOCSATC, &ts->lchars) < 0)
		ret = -1;
#   else
	if (ioctl(fd, TIOCSETC, &ts->tchars) < 0)
		ret = -1;
#    ifdef TIOCGLTC
	if (ioctl(fd, TIOCSLTC, &ts->ltchars) < 0)
		ret = -1;
#    endif /* TIOCGLTC */
#   endif /* TIOCGATC */
#  endif /* HAVE_TERMIO_H */
# endif /* HAVE_TERIOS_H */
	return ret;
}


/* Initialize tty_fd.  Used for saving/reseting tty modes upon
 * foreground job completion and for setting up tty process group.
 */
void
tty_init(init_ttystate)
	int init_ttystate;
{
	int	do_close = 1;
	int	tfd;
	const char	*devtty = _PATH_TTY;

	if (tty_fd >= 0) {
		close(tty_fd);
		tty_fd = -1;
	}
	tty_devtty = 1;

	if ((tfd = open(devtty, O_RDWR, 0)) < 0) {
		if (tfd < 0) {
			tty_devtty = 0;
			warningf(false,
				"No controlling tty (open %s: %s)",
				devtty, strerror(errno));
		}
	}

	if (tfd < 0) {
		do_close = 0;
		if (isatty(0))
			tfd = 0;
		else if (isatty(2))
			tfd = 2;
		else {
			warningf(false, "Can't find tty file descriptor");
			return;
		}
	}
	if ((tty_fd = ksh_dupbase(tfd, FDBASE)) < 0) {
		warningf(false, "j_ttyinit: dup of tty fd failed: %s",
			strerror(errno));
	} else if (fd_clexec(tty_fd) < 0) {
		warningf(false, "j_ttyinit: can't set close-on-exec flag: %s",
			strerror(errno));
		close(tty_fd);
		tty_fd = -1;
	} else if (init_ttystate)
		get_tty(tty_fd, &tty_state);
	if (do_close)
		close(tfd);
}

void
tty_close()
{
	if (tty_fd >= 0) {
		close(tty_fd);
		tty_fd = -1;
	}
}