]>
Commit | Line | Data |
---|---|---|
1fd5e000 CF |
1 | /* tty.cc |
2 | ||
1fd5e000 CF |
3 | This file is part of Cygwin. |
4 | ||
5 | This software is a copyrighted work licensed under the terms of the | |
6 | Cygwin license. Please consult the file "CYGWIN_LICENSE" for | |
7 | details. */ | |
8 | ||
4c8d72de | 9 | #include "winsup.h" |
ade47a34 | 10 | #include "miscfuncs.h" |
1fd5e000 CF |
11 | #include <unistd.h> |
12 | #include <utmp.h> | |
f0338f54 | 13 | #include <sys/cygwin.h> |
bccd5e0d | 14 | #include "cygerrno.h" |
6b91b8d5 | 15 | #include "security.h" |
47063f00 | 16 | #include "path.h" |
7ac61736 | 17 | #include "fhandler.h" |
e2ebe117 | 18 | #include "dtable.h" |
0381fec6 | 19 | #include "cygheap.h" |
e2ebe117 | 20 | #include "pinfo.h" |
29ac7f89 | 21 | #include "shared_info.h" |
1fd5e000 | 22 | |
c75b5b2d | 23 | HANDLE NO_COPY tty_list::mutex = NULL; |
1fd5e000 | 24 | |
d5f3e0ba YS |
25 | extern "C" int |
26 | getpt (void) | |
27 | { | |
28 | return open ("/dev/ptmx", O_RDWR | O_NOCTTY); | |
29 | } | |
30 | ||
70e476d2 CV |
31 | extern "C" int |
32 | posix_openpt (int oflags) | |
33 | { | |
34 | return open ("/dev/ptmx", oflags); | |
35 | } | |
36 | ||
c367dfd0 | 37 | extern "C" int |
8db71e01 | 38 | grantpt (int fd) |
1fd5e000 | 39 | { |
36b63207 CF |
40 | cygheap_fdget cfd (fd); |
41 | return cfd < 0 ? -1 : 0; | |
1fd5e000 CF |
42 | } |
43 | ||
c367dfd0 | 44 | extern "C" int |
8db71e01 | 45 | unlockpt (int fd) |
1fd5e000 | 46 | { |
36b63207 CF |
47 | cygheap_fdget cfd (fd); |
48 | return cfd < 0 ? -1 : 0; | |
1fd5e000 CF |
49 | } |
50 | ||
34a1d63d CV |
51 | extern "C" int |
52 | revoke (char *ttyname) | |
53 | { | |
54 | set_errno (ENOSYS); | |
55 | return -1; | |
56 | } | |
57 | ||
c367dfd0 | 58 | extern "C" int |
1fd5e000 CF |
59 | ttyslot (void) |
60 | { | |
13a84ac7 | 61 | if (!CTTY_IS_VALID (myself->ctty) || iscons_dev (myself->ctty)) |
1fd5e000 | 62 | return -1; |
44d2fc0a | 63 | return device::minor (myself->ctty); |
1fd5e000 CF |
64 | } |
65 | ||
30c5411d | 66 | void |
71d59a92 CF |
67 | tty_list::init_session () |
68 | { | |
495571e5 | 69 | char mutex_name[MAX_PATH]; |
71d59a92 | 70 | char *name = shared_name (mutex_name, "tty_list::mutex", 0); |
c75b5b2d CF |
71 | |
72 | /* tty_list::mutex is used while searching for a tty slot */ | |
71d59a92 CF |
73 | if (!(mutex = CreateMutex (&sec_all_nih, FALSE, name))) |
74 | api_fatal ("can't create tty_list::mutex '%s', %E", name); | |
75 | ProtectHandle (mutex); | |
76 | } | |
77 | ||
30c5411d | 78 | void |
71d59a92 | 79 | tty::init_session () |
1fd5e000 | 80 | { |
8cb359d9 | 81 | if (!myself->cygstarted && NOTSTATE (myself, PID_CYGPARENT)) |
083abe54 | 82 | cygheap->fdtab.get_debugger_info (); |
1fd5e000 CF |
83 | } |
84 | ||
2126f966 | 85 | int |
44d2fc0a | 86 | tty_list::attach (int n) |
1fd5e000 | 87 | { |
44d2fc0a CF |
88 | int res; |
89 | if (iscons_dev (n)) | |
90 | res = -1; | |
91 | else if (n != -1) | |
92 | res = connect (device::minor (n)); | |
44d2fc0a CF |
93 | else |
94 | res = -1; | |
95 | return res; | |
1fd5e000 CF |
96 | } |
97 | ||
1fd5e000 | 98 | int |
71d59a92 | 99 | tty_list::connect (int ttynum) |
1fd5e000 CF |
100 | { |
101 | if (ttynum < 0 || ttynum >= NTTYS) | |
102 | { | |
103 | termios_printf ("ttynum (%d) out of range", ttynum); | |
104 | return -1; | |
105 | } | |
106 | if (!ttys[ttynum].exists ()) | |
107 | { | |
23771fa1 | 108 | termios_printf ("pty %d was not allocated", ttynum); |
be96a30c | 109 | set_errno (ENXIO); |
1fd5e000 CF |
110 | return -1; |
111 | } | |
112 | ||
113 | return ttynum; | |
114 | } | |
115 | ||
116 | void | |
2f9ae2ed | 117 | tty_list::init () |
1fd5e000 CF |
118 | { |
119 | for (int i = 0; i < NTTYS; i++) | |
120 | { | |
121 | ttys[i].init (); | |
38d732a1 | 122 | ttys[i].setntty (DEV_PTYS_MAJOR, i); |
1fd5e000 CF |
123 | } |
124 | } | |
125 | ||
c75b5b2d | 126 | /* Search for a free tty and allocate it. |
1fd5e000 | 127 | Return tty number or -1 if error. |
1fd5e000 CF |
128 | */ |
129 | int | |
23771fa1 | 130 | tty_list::allocate (HANDLE& r, HANDLE& w) |
1fd5e000 | 131 | { |
71d59a92 | 132 | lock_ttys here; |
c75b5b2d | 133 | int freetty = -1; |
641654f7 | 134 | |
c75b5b2d | 135 | tty *t = NULL; |
1fd5e000 | 136 | for (int i = 0; i < NTTYS; i++) |
23771fa1 | 137 | if (ttys[i].not_allocated (r, w)) |
c75b5b2d CF |
138 | { |
139 | t = ttys + i; | |
140 | t->init (); | |
71ba0d76 | 141 | t->setsid (0); |
c75b5b2d CF |
142 | freetty = i; |
143 | break; | |
144 | } | |
1fd5e000 | 145 | |
23771fa1 CF |
146 | if (freetty >= 0) |
147 | termios_printf ("pty%d allocated", freetty); | |
c75b5b2d | 148 | else |
bfa76897 | 149 | { |
23771fa1 CF |
150 | system_printf ("No pty allocated"); |
151 | r = w = NULL; | |
bfa76897 | 152 | } |
23771fa1 | 153 | |
1fd5e000 CF |
154 | return freetty; |
155 | } | |
156 | ||
3c4f2024 | 157 | bool |
23771fa1 | 158 | tty::not_allocated (HANDLE& r, HANDLE& w) |
3c4f2024 CF |
159 | { |
160 | /* Attempt to open the from-master side of the tty. If it is accessible | |
23771fa1 CF |
161 | then it exists although we may not have privileges to actually use it. */ |
162 | char pipename[sizeof("ptyNNNN-from-master")]; | |
61522196 | 163 | __small_sprintf (pipename, "pty%d-from-master", get_minor ()); |
9f65451e CF |
164 | /* fhandler_pipe::create returns 0 when creation succeeds */ |
165 | return fhandler_pipe::create (&sec_none, &r, &w, | |
166 | fhandler_pty_common::pipesize, pipename, | |
167 | 0) == 0; | |
23771fa1 | 168 | } |
3c4f2024 | 169 | |
23771fa1 CF |
170 | bool |
171 | tty::exists () | |
172 | { | |
173 | HANDLE r, w; | |
174 | bool res; | |
175 | if (!not_allocated (r, w)) | |
176 | res = true; | |
3c4f2024 | 177 | |
23771fa1 | 178 | else |
3c4f2024 | 179 | { |
23771fa1 CF |
180 | /* Handles are left open when not_allocated finds a non-open "tty" */ |
181 | CloseHandle (r); | |
182 | CloseHandle (w); | |
183 | res = false; | |
3c4f2024 | 184 | } |
23771fa1 CF |
185 | debug_printf ("exists %d", res); |
186 | return res; | |
3c4f2024 CF |
187 | } |
188 | ||
2e008fb9 | 189 | bool |
cc01c77f | 190 | tty::slave_alive () |
1fd5e000 CF |
191 | { |
192 | HANDLE ev; | |
cc01c77f | 193 | if ((ev = open_inuse (READ_CONTROL))) |
1fd5e000 CF |
194 | CloseHandle (ev); |
195 | return ev != NULL; | |
196 | } | |
197 | ||
e3778517 | 198 | HANDLE |
cc01c77f | 199 | tty::open_mutex (const char *mutex, ACCESS_MASK access) |
8bdfa78a | 200 | { |
cc01c77f | 201 | char buf[MAX_PATH]; |
61522196 | 202 | shared_name (buf, mutex, get_minor ()); |
cc01c77f | 203 | return OpenMutex (access, TRUE, buf); |
e3778517 | 204 | } |
8bdfa78a | 205 | |
e3778517 | 206 | HANDLE |
cc01c77f | 207 | tty::open_inuse (ACCESS_MASK access) |
8bdfa78a | 208 | { |
495571e5 | 209 | char buf[MAX_PATH]; |
61522196 | 210 | shared_name (buf, TTY_SLAVE_ALIVE, get_minor ()); |
cc01c77f | 211 | return OpenEvent (access, FALSE, buf); |
8bdfa78a PH |
212 | } |
213 | ||
1fd5e000 | 214 | HANDLE |
cc01c77f | 215 | tty::create_inuse (PSECURITY_ATTRIBUTES sa) |
1fd5e000 CF |
216 | { |
217 | HANDLE h; | |
495571e5 | 218 | char buf[MAX_PATH]; |
1fd5e000 | 219 | |
61522196 | 220 | shared_name (buf, TTY_SLAVE_ALIVE, get_minor ()); |
cc01c77f | 221 | h = CreateEvent (sa, TRUE, FALSE, buf); |
0cd9f74f | 222 | termios_printf ("%s %p", buf, h); |
1fd5e000 | 223 | if (!h) |
61522196 | 224 | termios_printf ("couldn't open inuse event %s, %E", buf); |
1fd5e000 CF |
225 | return h; |
226 | } | |
227 | ||
228 | void | |
2f9ae2ed | 229 | tty::init () |
1fd5e000 | 230 | { |
b98ebf54 | 231 | output_stopped = 0; |
1fd5e000 CF |
232 | setsid (0); |
233 | pgid = 0; | |
c75b5b2d | 234 | was_opened = false; |
dad3ae73 | 235 | master_pid = 0; |
c75b5b2d | 236 | is_console = false; |
8c1a778e | 237 | column = 0; |
253352e7 | 238 | pcon_activated = false; |
aec053c6 TY |
239 | switch_to_nat_pipe = false; |
240 | nat_pipe_owner_pid = 0; | |
d83c45b4 | 241 | term_code_page = 0; |
aec053c6 TY |
242 | fwd_last_time = 0; |
243 | fwd_not_empty = false; | |
bb428520 | 244 | pcon_start = false; |
f2064178 | 245 | pcon_start_pid = 0; |
4e08fe42 TYC |
246 | pcon_cap_checked = false; |
247 | has_csi6n = false; | |
72770148 TYC |
248 | need_invisible_console = false; |
249 | invisible_console_pid = 0; | |
44209321 TYC |
250 | previous_code_page = 0; |
251 | previous_output_code_page = 0; | |
8aeb3f3e | 252 | master_is_running_as_service = false; |
f2064178 | 253 | req_xfer_input = false; |
aec053c6 | 254 | pty_input_state = to_cyg; |
ad287750 | 255 | last_sig = 0; |
9677efcf | 256 | mask_flusho = false; |
4e16e575 | 257 | discard_input = false; |
4f490c4c | 258 | stop_fwd_thread = false; |
1fd5e000 CF |
259 | } |
260 | ||
261 | HANDLE | |
cc01c77f | 262 | tty::get_event (const char *fmt, PSECURITY_ATTRIBUTES sa, BOOL manual_reset) |
1fd5e000 CF |
263 | { |
264 | HANDLE hev; | |
495571e5 | 265 | char buf[MAX_PATH]; |
1fd5e000 | 266 | |
61522196 | 267 | shared_name (buf, fmt, get_minor ()); |
cc01c77f CV |
268 | if (!sa) |
269 | sa = &sec_all; | |
270 | if (!(hev = CreateEvent (sa, manual_reset, FALSE, buf))) | |
1fd5e000 CF |
271 | { |
272 | termios_printf ("couldn't create %s", buf); | |
273 | set_errno (ENOENT); /* FIXME this can't be the right errno */ | |
274 | return NULL; | |
275 | } | |
276 | ||
277 | termios_printf ("created event %s", buf); | |
278 | return hev; | |
279 | } | |
71d59a92 CF |
280 | |
281 | lock_ttys::lock_ttys (DWORD howlong): release_me (true) | |
282 | { | |
283 | if (WaitForSingleObject (tty_list::mutex, howlong) == WAIT_FAILED) | |
284 | { | |
285 | termios_printf ("WFSO for mutex %p failed, %E", tty_list::mutex); | |
286 | release_me = false; | |
287 | } | |
288 | } | |
289 | ||
290 | void | |
291 | lock_ttys::release () | |
292 | { | |
293 | ReleaseMutex (tty_list::mutex); | |
294 | } | |
44d2fc0a CF |
295 | |
296 | const char * | |
297 | tty_min::ttyname () | |
298 | { | |
299 | device d; | |
300 | d.parse (ntty); | |
b2867a68 | 301 | return d.name (); |
44d2fc0a | 302 | } |
c26e0809 | 303 | |
aa499852 TY |
304 | extern DWORD mutex_timeout; /* defined in fhandler_termios.cc */ |
305 | ||
f2064178 TYC |
306 | void |
307 | tty_min::setpgid (int pid) | |
308 | { | |
054b00d9 TY |
309 | if (::cygheap->ctty) |
310 | ::cygheap->ctty->setpgid_aux (pid); | |
311 | ||
f2064178 TYC |
312 | pgid = pid; |
313 | } | |
314 | ||
c26e0809 | 315 | void |
aec053c6 | 316 | tty::wait_fwd () |
c26e0809 | 317 | { |
8014dc70 TYC |
318 | /* The forwarding in pseudo console sometimes stops for |
319 | 16-32 msec even if it already has data to transfer. | |
320 | If the time without transfer exceeds 32 msec, the | |
aec053c6 | 321 | forwarding is supposed to be finished. fwd_last_time |
faac7978 | 322 | is reset to GetTickCount64() in pty master forwarding |
8014dc70 | 323 | thread when the last data is transfered. */ |
faac7978 TY |
324 | const ULONGLONG sleep_in_nat_pipe = 16; |
325 | const ULONGLONG time_to_wait = sleep_in_nat_pipe * 2 + 1/* margine */; | |
2a2a6486 | 326 | ULONGLONG elapsed = 0; |
aec053c6 | 327 | while (fwd_not_empty |
faac7978 | 328 | || (elapsed = GetTickCount64 () - fwd_last_time) < time_to_wait) |
c26e0809 | 329 | { |
aec053c6 | 330 | int tw = fwd_not_empty ? 10 : (time_to_wait - elapsed); |
c26e0809 TYC |
331 | cygwait (tw); |
332 | } | |
333 | } | |
f2064178 TYC |
334 | |
335 | bool | |
aec053c6 | 336 | tty::nat_fg (pid_t pgid) |
f2064178 TYC |
337 | { |
338 | /* Check if the terminal pgid matches with the pgid of the | |
339 | non-cygwin process. */ | |
340 | winpids pids ((DWORD) 0); | |
341 | for (unsigned i = 0; i < pids.npids; i++) | |
342 | { | |
343 | _pinfo *p = pids[i]; | |
80f4b7d5 | 344 | if (p->ctty == ntty && p->pgid == pgid |
261acf73 TY |
345 | && ((p->process_state & PID_NOTCYGWIN) |
346 | /* Below is true for GDB with non-cygwin inferior */ | |
347 | || p->exec_dwProcessId == p->dwProcessId)) | |
f2064178 TYC |
348 | return true; |
349 | } | |
8bb5161f TY |
350 | if (pgid > MAX_PID) |
351 | return true; | |
f2064178 TYC |
352 | return false; |
353 | } |