1 /*        $NetBSD: tty.c,v 1.10 2021/07/24 21:31:31 andvar Exp $      */
2 
3 #include <sys/cdefs.h>
4 
5 #ifndef lint
6 __RCSID("$NetBSD: tty.c,v 1.10 2021/07/24 21:31:31 andvar Exp $");
7 #endif
8 
9 #include <sys/stat.h>
10 
11 #include "sh.h"
12 #define EXTERN
13 #include "tty.h"
14 #undef EXTERN
15 
16 int
get_tty(fd,ts)17 get_tty(fd, ts)
18           int fd;
19           TTY_state *ts;
20 {
21           int ret;
22 
23 # ifdef HAVE_TERMIOS_H
24           ret = tcgetattr(fd, ts);
25 # else /* HAVE_TERIOS_H */
26 #  ifdef HAVE_TERMIO_H
27           ret = ioctl(fd, TCGETA, ts);
28 #  else /* HAVE_TERMIO_H */
29           ret = ioctl(fd, TIOCGETP, &ts->sgttyb);
30 #   ifdef TIOCGATC
31           if (ioctl(fd, TIOCGATC, &ts->lchars) < 0)
32                     ret = -1;
33 #   else
34           if (ioctl(fd, TIOCGETC, &ts->tchars) < 0)
35                     ret = -1;
36 #    ifdef TIOCGLTC
37           if (ioctl(fd, TIOCGLTC, &ts->ltchars) < 0)
38                     ret = -1;
39 #    endif /* TIOCGLTC */
40 #   endif /* TIOCGATC */
41 #  endif /* HAVE_TERMIO_H */
42 # endif /* HAVE_TERIOS_H */
43           return ret;
44 }
45 
46 int
set_tty(fd,ts,flags)47 set_tty(fd, ts, flags)
48           int fd;
49           TTY_state *ts;
50           int flags;
51 {
52           int ret = 0;
53 
54 # ifdef HAVE_TERMIOS_H
55           ret = tcsetattr(fd, TCSADRAIN, ts);
56 # else /* HAVE_TERIOS_H */
57 #  ifdef HAVE_TERMIO_H
58 #   ifndef TCSETAW                                /* e.g. Cray-2 */
59                     /* first wait for output to drain */
60 #    ifdef TCSBRK
61                     if (ioctl(tty_fd, TCSBRK, 1) < 0)
62                               ret = -1;
63 #    else /* the following kludge is minimally intrusive, but sometimes fails */
64                     if (flags & TF_WAIT)
65                               sleep((unsigned)1); /* fake it */
66 #    endif
67 #   endif /* !TCSETAW */
68 #   if defined(_BSD_SYSV) || !defined(TCSETAW)
69 /* _BSD_SYSV must force TIOCSETN instead of TIOCSETP (preserve type-ahead) */
70                     if (ioctl(tty_fd, TCSETA, ts) < 0)
71                               ret = -1;
72 #   else
73                     if (ioctl(tty_fd, TCSETAW, ts) < 0)
74                               ret = -1;
75 #   endif
76 #  else /* HAVE_TERMIO_H */
77               ret = ioctl(fd, TIOCSETN, &ts->sgttyb);
78 #   ifdef TIOCGATC
79           if (ioctl(fd, TIOCSATC, &ts->lchars) < 0)
80                     ret = -1;
81 #   else
82           if (ioctl(fd, TIOCSETC, &ts->tchars) < 0)
83                     ret = -1;
84 #    ifdef TIOCGLTC
85           if (ioctl(fd, TIOCSLTC, &ts->ltchars) < 0)
86                     ret = -1;
87 #    endif /* TIOCGLTC */
88 #   endif /* TIOCGATC */
89 #  endif /* HAVE_TERMIO_H */
90 # endif /* HAVE_TERIOS_H */
91           return ret;
92 }
93 
94 
95 /* Initialize tty_fd.  Used for saving/resetting tty modes upon
96  * foreground job completion and for setting up tty process group.
97  */
98 void
tty_init(init_ttystate)99 tty_init(init_ttystate)
100           int init_ttystate;
101 {
102           int       do_close = 1;
103           int       tfd;
104           const char          *devtty = _PATH_TTY;
105 
106           if (tty_fd >= 0) {
107                     close(tty_fd);
108                     tty_fd = -1;
109           }
110           tty_devtty = 1;
111 
112           if ((tfd = open(devtty, O_RDWR, 0)) < 0) {
113                     if (tfd < 0) {
114                               tty_devtty = 0;
115                               warningf(false,
116                                         "No controlling tty (open %s: %s)",
117                                         devtty, strerror(errno));
118                     }
119           }
120 
121           if (tfd < 0) {
122                     do_close = 0;
123                     if (isatty(0))
124                               tfd = 0;
125                     else if (isatty(2))
126                               tfd = 2;
127                     else {
128                               warningf(false, "Can't find tty file descriptor");
129                               return;
130                     }
131           }
132           if ((tty_fd = ksh_dupbase(tfd, FDBASE)) < 0) {
133                     warningf(false, "j_ttyinit: dup of tty fd failed: %s",
134                               strerror(errno));
135           } else if (fd_clexec(tty_fd) < 0) {
136                     warningf(false, "j_ttyinit: can't set close-on-exec flag: %s",
137                               strerror(errno));
138                     close(tty_fd);
139                     tty_fd = -1;
140           } else if (init_ttystate)
141                     get_tty(tty_fd, &tty_state);
142           if (do_close)
143                     close(tfd);
144 }
145 
146 void
tty_close()147 tty_close()
148 {
149           if (tty_fd >= 0) {
150                     close(tty_fd);
151                     tty_fd = -1;
152           }
153 }
154