]> sourceware.org Git - newlib-cygwin.git/blob - winsup/cygwin/fhandler_tty.cc
* exceptions.cc (try_to_debug): Improve comment.
[newlib-cygwin.git] / winsup / cygwin / fhandler_tty.cc
1 /* fhandler_tty.cc
2
3 Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
4 2006, 2007, 2008, 2009, 2010 Red Hat, Inc.
5
6 This file is part of Cygwin.
7
8 This software is a copyrighted work licensed under the terms of the
9 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
10 details. */
11
12 #include "winsup.h"
13 #include <stdlib.h>
14 #include <cygwin/kd.h>
15 #include "cygerrno.h"
16 #include "security.h"
17 #include "path.h"
18 #include "fhandler.h"
19 #include "dtable.h"
20 #include "sigproc.h"
21 #include "pinfo.h"
22 #include "ntdll.h"
23 #include "cygheap.h"
24 #include "shared_info.h"
25 #include "cygthread.h"
26 #include "child_info.h"
27
28 #define close_maybe(h) \
29 do { \
30 if (h && h != INVALID_HANDLE_VALUE) \
31 CloseHandle (h); \
32 } while (0)
33
34 /* pty master control pipe messages */
35 struct pipe_request {
36 DWORD pid;
37 };
38
39 struct pipe_reply {
40 HANDLE from_master;
41 HANDLE to_master;
42 DWORD error;
43 };
44
45 /* tty master stuff */
46
47 fhandler_tty_master NO_COPY *tty_master;
48
49 static void WINAPI process_input (void *) __attribute__((noreturn)); // Input queue thread
50 static void WINAPI process_output (void *) __attribute__((noreturn)); // Output queue thread
51 static void WINAPI process_ioctl (void *) __attribute__((noreturn)); // Ioctl requests thread
52
53 fhandler_tty_master::fhandler_tty_master ()
54 : fhandler_pty_master (), console (NULL)
55 {
56 }
57
58 int
59 fhandler_tty_slave::get_unit ()
60 {
61 return dev () == FH_TTY ? myself->ctty : dev ().minor;
62 }
63
64 void
65 fhandler_tty_master::set_winsize (bool sendSIGWINCH)
66 {
67 winsize w;
68 console->ioctl (TIOCGWINSZ, &w);
69 get_ttyp ()->winsize = w;
70 if (sendSIGWINCH)
71 tc->kill_pgrp (SIGWINCH);
72 }
73
74 int
75 fhandler_tty_master::init ()
76 {
77 termios_printf ("Creating master for tty%d", get_unit ());
78
79 if (init_console ())
80 {
81 termios_printf ("can't create fhandler");
82 return -1;
83 }
84
85 if (!setup (false))
86 return 1;
87
88 set_winsize (false);
89
90 set_close_on_exec (true);
91
92 new cygthread (process_input, cygself, "ttyin");
93 new cygthread (process_ioctl, cygself, "ttyioctl");
94 new cygthread (process_output, cygself, "ttyout");
95
96 return 0;
97 }
98
99 #ifdef DEBUGGING
100 static class mutex_stack
101 {
102 public:
103 const char *fn;
104 int ln;
105 const char *tname;
106 } ostack[100];
107
108 static int osi;
109 #endif /*DEBUGGING*/
110
111 DWORD
112 fhandler_tty_common::__acquire_output_mutex (const char *fn, int ln,
113 DWORD ms)
114 {
115 if (strace.active ())
116 strace.prntf (_STRACE_TERMIOS, fn, "(%d): tty output_mutex: waiting %d ms", ln, ms);
117 DWORD res = WaitForSingleObject (output_mutex, ms);
118 if (res == WAIT_OBJECT_0)
119 {
120 #ifndef DEBUGGING
121 if (strace.active ())
122 strace.prntf (_STRACE_TERMIOS, fn, "(%d): tty output_mutex: acquired", ln, res);
123 #else
124 ostack[osi].fn = fn;
125 ostack[osi].ln = ln;
126 ostack[osi].tname = cygthread::name ();
127 termios_printf ("acquired for %s:%d, osi %d", fn, ln, osi);
128 osi++;
129 #endif
130 }
131 return res;
132 }
133
134 void
135 fhandler_tty_common::__release_output_mutex (const char *fn, int ln)
136 {
137 if (ReleaseMutex (output_mutex))
138 {
139 #ifndef DEBUGGING
140 if (strace.active ())
141 strace.prntf (_STRACE_TERMIOS, fn, "(%d): tty output_mutex released", ln);
142 #else
143 if (osi > 0)
144 osi--;
145 termios_printf ("released at %s:%d, osi %d", fn, ln, osi);
146 termios_printf (" for %s:%d (%s)", ostack[osi].fn, ostack[osi].ln, ostack[osi].tname);
147 ostack[osi].ln = -ln;
148 #endif
149 }
150 #ifdef DEBUGGING
151 else if (osi > 0)
152 {
153 system_printf ("couldn't release output mutex but we seem to own it, %E");
154 try_to_debug ();
155 }
156 #endif
157 }
158
159 /* Process tty input. */
160
161 void
162 fhandler_pty_master::doecho (const void *str, DWORD len)
163 {
164 acquire_output_mutex (INFINITE);
165 if (!WriteFile (to_master, str, len, &len, NULL))
166 termios_printf ("Write to %p failed, %E", to_master);
167 // WaitForSingleObject (output_done_event, INFINITE);
168 release_output_mutex ();
169 }
170
171 int
172 fhandler_pty_master::accept_input ()
173 {
174 DWORD bytes_left;
175 int ret = 1;
176
177 WaitForSingleObject (input_mutex, INFINITE);
178
179 bytes_left = eat_readahead (-1);
180
181 if (!bytes_left)
182 {
183 termios_printf ("sending EOF to slave");
184 get_ttyp ()->read_retval = 0;
185 }
186 else
187 {
188 char *p = rabuf;
189 DWORD rc;
190 DWORD written = 0;
191
192 termios_printf ("about to write %d chars to slave", bytes_left);
193 rc = WriteFile (get_output_handle (), p, bytes_left, &written, NULL);
194 if (!rc)
195 {
196 debug_printf ("error writing to pipe %E");
197 get_ttyp ()->read_retval = -1;
198 ret = -1;
199 }
200 else
201 {
202 get_ttyp ()->read_retval = 1;
203 p += written;
204 bytes_left -= written;
205 if (bytes_left > 0)
206 {
207 debug_printf ("to_slave pipe is full");
208 puts_readahead (p, bytes_left);
209 ret = 0;
210 }
211 }
212 }
213
214 SetEvent (input_available_event);
215 ReleaseMutex (input_mutex);
216 return ret;
217 }
218
219 static void WINAPI
220 process_input (void *)
221 {
222 char rawbuf[INP_BUFFER_SIZE];
223
224 while (1)
225 {
226 size_t nraw = INP_BUFFER_SIZE;
227 tty_master->console->read ((void *) rawbuf, nraw);
228 if (tty_master->line_edit (rawbuf, nraw, tty_master->get_ttyp ()->ti)
229 == line_edit_signalled)
230 tty_master->console->eat_readahead (-1);
231 }
232 }
233
234 bool
235 fhandler_pty_master::hit_eof ()
236 {
237 if (get_ttyp ()->was_opened && !get_ttyp ()->slave_alive ())
238 {
239 /* We have the only remaining open handle to this pty, and
240 the slave pty has been opened at least once. We treat
241 this as EOF. */
242 termios_printf ("all other handles closed");
243 return 1;
244 }
245 return 0;
246 }
247
248 /* Process tty output requests */
249
250 int
251 fhandler_pty_master::process_slave_output (char *buf, size_t len, int pktmode_on)
252 {
253 size_t rlen;
254 char outbuf[OUT_BUFFER_SIZE + 1];
255 DWORD n;
256 int column = 0;
257 int rc = 0;
258
259 if (len == 0)
260 goto out;
261
262 if (need_nl)
263 {
264 /* We need to return a left over \n character, resulting from
265 \r\n conversion. Note that we already checked for FLUSHO and
266 output_stopped at the time that we read the character, so we
267 don't check again here. */
268 if (buf)
269 buf[0] = '\n';
270 need_nl = 0;
271 rc = 1;
272 goto out;
273 }
274
275
276 for (;;)
277 {
278 /* Set RLEN to the number of bytes to read from the pipe. */
279 rlen = len;
280 if (get_ttyp ()->ti.c_oflag & OPOST && get_ttyp ()->ti.c_oflag & ONLCR)
281 {
282 /* We are going to expand \n to \r\n, so don't read more than
283 half of the number of bytes requested. */
284 rlen /= 2;
285 if (rlen == 0)
286 rlen = 1;
287 }
288 if (rlen > sizeof outbuf)
289 rlen = sizeof outbuf;
290
291 HANDLE handle = get_io_handle ();
292
293 n = 0; // get_readahead_into_buffer (outbuf, len);
294 if (!n)
295 {
296 /* Doing a busy wait like this is quite inefficient, but nothing
297 else seems to work completely. Windows should provide some sort
298 of overlapped I/O for pipes, or something, but it doesn't. */
299 while (1)
300 {
301 if (!PeekNamedPipe (handle, NULL, 0, NULL, &n, NULL))
302 goto err;
303 if (n > 0)
304 break;
305 if (hit_eof ())
306 goto out;
307 /* DISCARD (FLUSHO) and tcflush can finish here. */
308 if (n == 0 && (get_ttyp ()->ti.c_lflag & FLUSHO || !buf))
309 goto out;
310 if (n == 0 && is_nonblocking ())
311 {
312 set_errno (EAGAIN);
313 rc = -1;
314 break;
315 }
316
317 Sleep (10);
318 }
319
320 if (ReadFile (handle, outbuf, rlen, &n, NULL) == FALSE)
321 goto err;
322 }
323
324 termios_printf ("bytes read %u", n);
325 get_ttyp ()->write_error = 0;
326 if (output_done_event != NULL)
327 SetEvent (output_done_event);
328
329 if (get_ttyp ()->ti.c_lflag & FLUSHO || !buf)
330 continue;
331
332 char *optr;
333 optr = buf;
334 if (pktmode_on)
335 *optr++ = TIOCPKT_DATA;
336
337 if (!(get_ttyp ()->ti.c_oflag & OPOST)) // post-process output
338 {
339 memcpy (optr, outbuf, n);
340 optr += n;
341 }
342 else // raw output mode
343 {
344 char *iptr = outbuf;
345
346 while (n--)
347 {
348 switch (*iptr)
349 {
350 case '\r':
351 if ((get_ttyp ()->ti.c_oflag & ONOCR) && column == 0)
352 {
353 iptr++;
354 continue;
355 }
356 if (get_ttyp ()->ti.c_oflag & OCRNL)
357 *iptr = '\n';
358 else
359 column = 0;
360 break;
361 case '\n':
362 if (get_ttyp ()->ti.c_oflag & ONLCR)
363 {
364 *optr++ = '\r';
365 column = 0;
366 }
367 if (get_ttyp ()->ti.c_oflag & ONLRET)
368 column = 0;
369 break;
370 default:
371 column++;
372 break;
373 }
374
375 /* Don't store data past the end of the user's buffer. This
376 can happen if the user requests a read of 1 byte when
377 doing \r\n expansion. */
378 if (optr - buf >= (int) len)
379 {
380 if (*iptr != '\n' || n != 0)
381 system_printf ("internal error: %d unexpected characters", n);
382 need_nl = 1;
383 break;
384 }
385
386 *optr++ = *iptr++;
387 }
388 }
389 rc = optr - buf;
390 break;
391
392 err:
393 if (GetLastError () == ERROR_BROKEN_PIPE)
394 rc = 0;
395 else
396 {
397 __seterrno ();
398 rc = -1;
399 }
400 break;
401 }
402
403 out:
404 termios_printf ("returning %d", rc);
405 return rc;
406 }
407
408 static void WINAPI
409 process_output (void *)
410 {
411 char buf[OUT_BUFFER_SIZE * 2];
412
413 for (;;)
414 {
415 int n = tty_master->process_slave_output (buf, OUT_BUFFER_SIZE, 0);
416 if (n <= 0)
417 {
418 if (n < 0)
419 termios_printf ("ReadFile %E");
420 ExitThread (0);
421 }
422 n = tty_master->console->write ((void *) buf, (size_t) n);
423 tty_master->get_ttyp ()->write_error = n == -1 ? get_errno () : 0;
424 }
425 }
426
427
428 /* Process tty ioctl requests */
429
430 static void WINAPI
431 process_ioctl (void *)
432 {
433 while (1)
434 {
435 WaitForSingleObject (tty_master->ioctl_request_event, INFINITE);
436 termios_printf ("ioctl() request");
437 tty *ttyp = tty_master->get_ttyp ();
438 ttyp->ioctl_retval =
439 tty_master->console->ioctl (ttyp->cmd,
440 (ttyp->cmd == KDSKBMETA)
441 ? (void *) ttyp->arg.value
442 : (void *) &ttyp->arg);
443 SetEvent (tty_master->ioctl_done_event);
444 }
445 }
446
447 /**********************************************************************/
448 /* Tty slave stuff */
449
450 fhandler_tty_slave::fhandler_tty_slave ()
451 : fhandler_tty_common (), inuse (NULL)
452 {
453 uninterruptible_io (true);
454 }
455
456 /* FIXME: This function needs to close handles when it has
457 a failing condition. */
458 int
459 fhandler_tty_slave::open (int flags, mode_t)
460 {
461 HANDLE tty_owner, from_master_local, to_master_local;
462 HANDLE *handles[] =
463 {
464 &from_master_local, &input_available_event, &input_mutex, &inuse,
465 &ioctl_done_event, &ioctl_request_event, &output_done_event,
466 &output_mutex, &to_master_local, &tty_owner,
467 NULL
468 };
469
470 const char *errmsg = NULL;
471
472 for (HANDLE **h = handles; *h; h++)
473 **h = NULL;
474
475 if (get_device () == FH_TTY)
476 dev().tty_to_real_device ();
477 fhandler_tty_slave *arch = (fhandler_tty_slave *) cygheap->fdtab.find_archetype (pc.dev);
478 if (arch)
479 {
480 *this = *(fhandler_tty_slave *) arch;
481 termios_printf ("copied fhandler_tty_slave archetype");
482 set_flags ((flags & ~O_TEXT) | O_BINARY);
483 cygheap->manage_console_count ("fhandler_tty_slave::open<arch>", 1);
484 goto out;
485 }
486
487 tcinit (cygwin_shared->tty[get_unit ()], false);
488
489 cygwin_shared->tty.attach (get_unit ());
490
491 set_flags ((flags & ~O_TEXT) | O_BINARY);
492 /* Create synchronisation events */
493 char buf[MAX_PATH];
494
495 /* output_done_event may or may not exist. It will exist if the tty
496 was opened by fhandler_tty_master::init, normally called at
497 startup if use_tty is non-zero. It will not exist if this is a
498 pty opened by fhandler_pty_master::open. In the former case, tty
499 output is handled by a separate thread which controls output. */
500 shared_name (buf, OUTPUT_DONE_EVENT, get_unit ());
501 output_done_event = OpenEvent (MAXIMUM_ALLOWED, TRUE, buf);
502
503 if (!(output_mutex = get_ttyp ()->open_output_mutex (MAXIMUM_ALLOWED)))
504 {
505 errmsg = "open output mutex failed, %E";
506 goto err;
507 }
508 if (!(input_mutex = get_ttyp ()->open_input_mutex (MAXIMUM_ALLOWED)))
509 {
510 errmsg = "open input mutex failed, %E";
511 goto err;
512 }
513 shared_name (buf, INPUT_AVAILABLE_EVENT, get_unit ());
514 if (!(input_available_event = OpenEvent (MAXIMUM_ALLOWED, TRUE, buf)))
515 {
516 errmsg = "open input event failed, %E";
517 goto err;
518 }
519
520 /* The ioctl events may or may not exist. See output_done_event,
521 above. */
522 shared_name (buf, IOCTL_REQUEST_EVENT, get_unit ());
523 ioctl_request_event = OpenEvent (MAXIMUM_ALLOWED, TRUE, buf);
524 shared_name (buf, IOCTL_DONE_EVENT, get_unit ());
525 ioctl_done_event = OpenEvent (MAXIMUM_ALLOWED, TRUE, buf);
526
527 /* FIXME: Needs a method to eliminate tty races */
528 {
529 /* Create security attribute. Default permissions are 0620. */
530 security_descriptor sd;
531 sd.malloc (sizeof (SECURITY_DESCRIPTOR));
532 InitializeSecurityDescriptor (sd, SECURITY_DESCRIPTOR_REVISION);
533 SECURITY_ATTRIBUTES sa = { sizeof (SECURITY_ATTRIBUTES), NULL, TRUE };
534 if (!create_object_sd_from_attribute (NULL, myself->uid, myself->gid,
535 S_IFCHR | S_IRUSR | S_IWUSR | S_IWGRP,
536 sd))
537 sa.lpSecurityDescriptor = (PSECURITY_DESCRIPTOR) sd;
538 acquire_output_mutex (500);
539 inuse = get_ttyp ()->create_inuse (&sa);
540 get_ttyp ()->was_opened = true;
541 release_output_mutex ();
542 }
543
544 if (!get_ttyp ()->from_master || !get_ttyp ()->to_master)
545 {
546 errmsg = "tty handles have been closed";
547 set_errno (EACCES);
548 goto err_no_errno;
549 }
550
551 if (get_ttyp ()->master_pid < 0)
552 {
553 errmsg = "*** master is closed";
554 set_errno (EAGAIN);
555 goto err_no_errno;
556 }
557 /* Three case for duplicating the pipe handles:
558 - Either we're the master. In this case, just duplicate the handles.
559 - Or, we have the right to open the master process for handle duplication.
560 In this case, just duplicate the handles.
561 - Or, we have to ask the master process itself. In this case, send our
562 pid to the master process and check the reply. The reply contains
563 either the handles, or an error code which tells us why we didn't
564 get the handles. */
565 if (myself->pid == get_ttyp ()->master_pid)
566 {
567 /* This is the most common case, just calling openpty. */
568 termios_printf ("dup handles within myself.");
569 tty_owner = GetCurrentProcess ();
570 }
571 else
572 {
573 pinfo p (get_ttyp ()->master_pid);
574 if (!p)
575 termios_printf ("*** couldn't find tty master");
576 else
577 {
578 tty_owner = OpenProcess (PROCESS_DUP_HANDLE, FALSE, p->dwProcessId);
579 if (tty_owner)
580 termios_printf ("dup handles directly since I'm allmighty.");
581 }
582 }
583 if (tty_owner)
584 {
585 if (!DuplicateHandle (tty_owner, get_ttyp ()->from_master,
586 GetCurrentProcess (), &from_master_local, 0, TRUE,
587 DUPLICATE_SAME_ACCESS))
588 {
589 termios_printf ("can't duplicate input from %u/%p, %E",
590 get_ttyp ()->master_pid, get_ttyp ()->from_master);
591 __seterrno ();
592 goto err_no_msg;
593 }
594 if (!DuplicateHandle (tty_owner, get_ttyp ()->to_master,
595 GetCurrentProcess (), &to_master_local, 0, TRUE,
596 DUPLICATE_SAME_ACCESS))
597 {
598 errmsg = "can't duplicate output, %E";
599 goto err;
600 }
601 if (tty_owner != GetCurrentProcess ())
602 CloseHandle (tty_owner);
603 }
604 else
605 {
606 pipe_request req = { GetCurrentProcessId () };
607 pipe_reply repl;
608 DWORD len;
609
610 __small_sprintf (buf, "\\\\.\\pipe\\cygwin-%S-tty%d-master-ctl",
611 &installation_key, get_unit ());
612 termios_printf ("dup handles via master control pipe %s", buf);
613 if (!CallNamedPipe (buf, &req, sizeof req, &repl, sizeof repl,
614 &len, 500))
615 {
616 errmsg = "can't call master, %E";
617 goto err;
618 }
619 from_master_local = repl.from_master;
620 to_master_local = repl.to_master;
621 if (!from_master_local || !to_master_local)
622 {
623 SetLastError (repl.error);
624 errmsg = "error duplicating pipes, %E";
625 goto err;
626 }
627 }
628 VerifyHandle (from_master_local);
629 VerifyHandle (to_master_local);
630
631 termios_printf ("duplicated from_master %p->%p from tty_owner",
632 get_ttyp ()->from_master, from_master_local);
633 termios_printf ("duplicated to_master %p->%p from tty_owner",
634 get_ttyp ()->to_master, to_master_local);
635
636 set_io_handle (from_master_local);
637 set_output_handle (to_master_local);
638 set_close_on_exec (!!(flags & O_CLOEXEC));
639
640 set_open_status ();
641 if (cygheap->manage_console_count ("fhandler_tty_slave::open", 1) == 1
642 && !output_done_event)
643 fhandler_console::need_invisible ();
644
645 // FIXME: Do this better someday
646 arch = (fhandler_tty_slave *) cmalloc_abort (HEAP_ARCHETYPES, sizeof (*this));
647 *((fhandler_tty_slave **) cygheap->fdtab.add_archetype ()) = arch;
648 archetype = arch;
649 *arch = *this;
650
651 out:
652 usecount = 0;
653 arch->usecount++;
654 report_tty_counts (this, "opened", "");
655 myself->set_ctty (get_ttyp (), flags, arch);
656
657 return 1;
658
659 err:
660 __seterrno ();
661 err_no_errno:
662 termios_printf (errmsg);
663 err_no_msg:
664 for (HANDLE **h = handles; *h; h++)
665 if (**h && **h != INVALID_HANDLE_VALUE)
666 CloseHandle (**h);
667 return 0;
668 }
669
670 int
671 fhandler_tty_slave::close ()
672 {
673 /* This used to always call fhandler_tty_common::close when hExeced but that
674 caused multiple closes of the handles associated with this tty. Since
675 close_all_files is not called until after the cygwin process has synced
676 or before a non-cygwin process has exited, it should be safe to just
677 close this normally. cgf 2006-05-20 */
678 cygheap->manage_console_count ("fhandler_tty_slave::close", -1);
679
680 archetype->usecount--;
681 report_tty_counts (this, "closed", "");
682
683 if (archetype->usecount)
684 {
685 #ifdef DEBUGGING
686 if (archetype->usecount < 0)
687 system_printf ("error: usecount %d", archetype->usecount);
688 #endif
689 termios_printf ("just returning because archetype usecount is != 0");
690 return 0;
691 }
692
693 termios_printf ("closing last open %s handle", ttyname ());
694 if (inuse && !CloseHandle (inuse))
695 termios_printf ("CloseHandle (inuse), %E");
696 return fhandler_tty_common::close ();
697 }
698
699 int
700 fhandler_tty_slave::init (HANDLE f, DWORD a, mode_t)
701 {
702 int flags = 0;
703
704 a &= GENERIC_READ | GENERIC_WRITE;
705 if (a == GENERIC_READ)
706 flags = O_RDONLY;
707 if (a == GENERIC_WRITE)
708 flags = O_WRONLY;
709 if (a == (GENERIC_READ | GENERIC_WRITE))
710 flags = O_RDWR;
711
712 int ret = open (flags);
713
714 if (ret && !cygwin_finished_initializing && !being_debugged ())
715 {
716 /* This only occurs when called from dtable::init_std_file_from_handle
717 We have been started from a non-Cygwin process. So we should become
718 tty process group leader.
719 TODO: Investigate how SIGTTIN should be handled with pure-windows
720 programs. */
721 pinfo p (tc->getpgid ());
722 /* We should only grab this when the process group owner for this
723 tty is a non-cygwin process or we've been started directly
724 from a non-Cygwin process with no Cygwin ancestry. */
725 if (!p || ISSTATE (p, PID_NOTCYGWIN))
726 {
727 termios_printf ("Setting process group leader to %d since %W(%d) is not a cygwin process",
728 myself->pgid, p->progname, p->pid);
729 tc->setpgid (myself->pgid);
730 }
731 }
732
733 if (f != INVALID_HANDLE_VALUE)
734 CloseHandle (f); /* Reopened by open */
735
736 return ret;
737 }
738
739 ssize_t __stdcall
740 fhandler_tty_slave::write (const void *ptr, size_t len)
741 {
742 DWORD n, towrite = len;
743
744 termios_printf ("tty%d, write(%x, %d)", get_unit (), ptr, len);
745
746 acquire_output_mutex (INFINITE);
747
748 while (len)
749 {
750 n = min (OUT_BUFFER_SIZE, len);
751 char *buf = (char *)ptr;
752 ptr = (char *) ptr + n;
753 len -= n;
754
755 /* Previous write may have set write_error to != 0. Check it here.
756 This is less than optimal, but the alternative slows down tty
757 writes enormously. */
758 if (get_ttyp ()->write_error)
759 {
760 set_errno (get_ttyp ()->write_error);
761 towrite = (DWORD) -1;
762 break;
763 }
764
765 if (WriteFile (get_output_handle (), buf, n, &n, NULL) == FALSE)
766 {
767 DWORD err = GetLastError ();
768 termios_printf ("WriteFile failed, %E");
769 switch (err)
770 {
771 case ERROR_NO_DATA:
772 err = ERROR_IO_DEVICE;
773 default:
774 __seterrno_from_win_error (err);
775 }
776 raise (SIGHUP); /* FIXME: Should this be SIGTTOU? */
777 towrite = (DWORD) -1;
778 break;
779 }
780
781 if (output_done_event != NULL)
782 {
783 DWORD rc;
784 DWORD x = n * 1000;
785 rc = WaitForSingleObject (output_done_event, x);
786 termios_printf ("waited %d ms for output_done_event, WFSO %d", x, rc);
787 }
788 }
789 release_output_mutex ();
790 return towrite;
791 }
792
793 void __stdcall
794 fhandler_tty_slave::read (void *ptr, size_t& len)
795 {
796 int totalread = 0;
797 int vmin = 0;
798 int vtime = 0; /* Initialized to prevent -Wuninitialized warning */
799 size_t readlen;
800 DWORD bytes_in_pipe;
801 char buf[INP_BUFFER_SIZE];
802 char peek_buf[INP_BUFFER_SIZE];
803 DWORD time_to_wait;
804 DWORD rc;
805 HANDLE w4[2];
806
807 termios_printf ("read(%x, %d) handle %p", ptr, len, get_handle ());
808
809 if (!ptr) /* Indicating tcflush(). */
810 time_to_wait = 0;
811 else if ((get_ttyp ()->ti.c_lflag & ICANON))
812 time_to_wait = INFINITE;
813 else
814 {
815 vmin = get_ttyp ()->ti.c_cc[VMIN];
816 if (vmin > INP_BUFFER_SIZE)
817 vmin = INP_BUFFER_SIZE;
818 vtime = get_ttyp ()->ti.c_cc[VTIME];
819 if (vmin < 0)
820 vmin = 0;
821 if (vtime < 0)
822 vtime = 0;
823 if (!vmin && !vtime)
824 time_to_wait = 0;
825 else
826 time_to_wait = !vtime ? INFINITE : 100 * vtime;
827 }
828
829 w4[0] = signal_arrived;
830 w4[1] = input_available_event;
831
832 DWORD waiter = time_to_wait;
833 while (len)
834 {
835 rc = WaitForMultipleObjects (2, w4, FALSE, waiter);
836
837 if (rc == WAIT_TIMEOUT)
838 {
839 termios_printf ("wait timed out, waiter %u", waiter);
840 break;
841 }
842
843 if (rc == WAIT_FAILED)
844 {
845 termios_printf ("wait for input event failed, %E");
846 break;
847 }
848
849 if (rc == WAIT_OBJECT_0)
850 {
851 /* if we've received signal after successfully reading some data,
852 just return all data successfully read */
853 if (totalread > 0)
854 break;
855 set_sig_errno (EINTR);
856 len = (size_t) -1;
857 return;
858 }
859
860 rc = WaitForSingleObject (input_mutex, 1000);
861 if (rc == WAIT_FAILED)
862 {
863 termios_printf ("wait for input mutex failed, %E");
864 break;
865 }
866 else if (rc == WAIT_TIMEOUT)
867 {
868 termios_printf ("failed to acquire input mutex after input event arrived");
869 break;
870 }
871 if (!PeekNamedPipe (get_handle (), peek_buf, sizeof (peek_buf), &bytes_in_pipe, NULL, NULL))
872 {
873 termios_printf ("PeekNamedPipe failed, %E");
874 raise (SIGHUP);
875 bytes_in_pipe = 0;
876 }
877
878 /* On first peek determine no. of bytes to flush. */
879 if (!ptr && len == UINT_MAX)
880 len = (size_t) bytes_in_pipe;
881
882 if (ptr && !bytes_in_pipe && !vmin && !time_to_wait)
883 {
884 ReleaseMutex (input_mutex);
885 len = (size_t) bytes_in_pipe;
886 return;
887 }
888
889 readlen = min (bytes_in_pipe, min (len, sizeof (buf)));
890
891 if (ptr && vmin && readlen > (unsigned) vmin)
892 readlen = vmin;
893
894 DWORD n = 0;
895 if (readlen)
896 {
897 termios_printf ("reading %d bytes (vtime %d)", readlen, vtime);
898 if (ReadFile (get_handle (), buf, readlen, &n, NULL) == FALSE)
899 {
900 termios_printf ("read failed, %E");
901 raise (SIGHUP);
902 }
903 /* MSDN states that 5th prameter can be used to determine total
904 number of bytes in pipe, but for some reason this number doesn't
905 change after successful read. So we have to peek into the pipe
906 again to see if input is still available */
907 if (!PeekNamedPipe (get_handle (), peek_buf, 1, &bytes_in_pipe, NULL, NULL))
908 {
909 termios_printf ("PeekNamedPipe failed, %E");
910 raise (SIGHUP);
911 bytes_in_pipe = 0;
912 }
913 if (n)
914 {
915 len -= n;
916 totalread += n;
917 if (ptr)
918 {
919 memcpy (ptr, buf, n);
920 ptr = (char *) ptr + n;
921 }
922 }
923 }
924
925 if (!bytes_in_pipe)
926 ResetEvent (input_available_event);
927
928 ReleaseMutex (input_mutex);
929
930 if (!ptr)
931 {
932 if (!bytes_in_pipe)
933 break;
934 continue;
935 }
936
937 if (get_ttyp ()->read_retval < 0) // read error
938 {
939 set_errno (-get_ttyp ()->read_retval);
940 totalread = -1;
941 break;
942 }
943 if (get_ttyp ()->read_retval == 0) //EOF
944 {
945 termios_printf ("saw EOF");
946 break;
947 }
948 if (get_ttyp ()->ti.c_lflag & ICANON || is_nonblocking ())
949 break;
950 if (vmin && totalread >= vmin)
951 break;
952
953 /* vmin == 0 && vtime == 0:
954 * we've already read all input, if any, so return immediately
955 * vmin == 0 && vtime > 0:
956 * we've waited for input 10*vtime ms in WFSO(input_available_event),
957 * no matter whether any input arrived, we shouldn't wait any longer,
958 * so return immediately
959 * vmin > 0 && vtime == 0:
960 * here, totalread < vmin, so continue waiting until more data
961 * arrive
962 * vmin > 0 && vtime > 0:
963 * similar to the previous here, totalread < vmin, and timer
964 * hadn't expired -- WFSO(input_available_event) != WAIT_TIMEOUT,
965 * so "restart timer" and wait until more data arrive
966 */
967
968 if (vmin == 0)
969 break;
970
971 if (n)
972 waiter = time_to_wait;
973 }
974 termios_printf ("%d=read(%x, %d)", totalread, ptr, len);
975 len = (size_t) totalread;
976 }
977
978 int
979 fhandler_tty_slave::dup (fhandler_base *child)
980 {
981 fhandler_tty_slave *arch = (fhandler_tty_slave *) archetype;
982 *(fhandler_tty_slave *) child = *arch;
983 child->set_flags (get_flags ());
984 child->usecount = 0;
985 arch->usecount++;
986 cygheap->manage_console_count ("fhandler_tty_slave::dup", 1);
987 report_tty_counts (child, "duped", "");
988 return 0;
989 }
990
991 int
992 fhandler_pty_master::dup (fhandler_base *child)
993 {
994 fhandler_tty_master *arch = (fhandler_tty_master *) archetype;
995 *(fhandler_tty_master *) child = *arch;
996 child->set_flags (get_flags ());
997 child->usecount = 0;
998 arch->usecount++;
999 report_tty_counts (child, "duped master", "");
1000 return 0;
1001 }
1002
1003 int
1004 fhandler_tty_slave::tcgetattr (struct termios *t)
1005 {
1006 *t = get_ttyp ()->ti;
1007 return 0;
1008 }
1009
1010 int
1011 fhandler_tty_slave::tcsetattr (int, const struct termios *t)
1012 {
1013 acquire_output_mutex (INFINITE);
1014 get_ttyp ()->ti = *t;
1015 release_output_mutex ();
1016 return 0;
1017 }
1018
1019 int
1020 fhandler_tty_slave::tcflush (int queue)
1021 {
1022 int ret = 0;
1023
1024 termios_printf ("tcflush(%d) handle %p", queue, get_handle ());
1025
1026 if (queue == TCIFLUSH || queue == TCIOFLUSH)
1027 {
1028 size_t len = UINT_MAX;
1029 read (NULL, len);
1030 ret = ((int) len) >= 0 ? 0 : -1;
1031 }
1032 if (queue == TCOFLUSH || queue == TCIOFLUSH)
1033 {
1034 /* do nothing for now. */
1035 }
1036
1037 termios_printf ("%d=tcflush(%d)", ret, queue);
1038 return ret;
1039 }
1040
1041 int
1042 fhandler_tty_slave::ioctl (unsigned int cmd, void *arg)
1043 {
1044 termios_printf ("ioctl (%x)", cmd);
1045
1046 if (myself->pgid && get_ttyp ()->getpgid () != myself->pgid
1047 && myself->ctty == get_unit () && (get_ttyp ()->ti.c_lflag & TOSTOP))
1048 {
1049 /* background process */
1050 termios_printf ("bg ioctl pgid %d, tpgid %d, %s", myself->pgid,
1051 get_ttyp ()->getpgid (), myctty ());
1052 raise (SIGTTOU);
1053 }
1054
1055 int retval;
1056 switch (cmd)
1057 {
1058 case TIOCGWINSZ:
1059 case TIOCSWINSZ:
1060 case TIOCLINUX:
1061 case KDGKBMETA:
1062 case KDSKBMETA:
1063 break;
1064 case FIONBIO:
1065 set_nonblocking (*(int *) arg);
1066 retval = 0;
1067 goto out;
1068 case TIOCGPGRP:
1069 {
1070 pid_t pid = this->tcgetpgrp ();
1071 if (pid < 0)
1072 retval = -1;
1073 else
1074 {
1075 *((pid_t *) arg) = pid;
1076 retval = 0;
1077 }
1078 }
1079 goto out;
1080 case TIOCSPGRP:
1081 retval = this->tcsetpgrp ((pid_t) arg);
1082 goto out;
1083 default:
1084 set_errno (EINVAL);
1085 return -1;
1086 }
1087
1088 acquire_output_mutex (INFINITE);
1089
1090 get_ttyp ()->cmd = cmd;
1091 get_ttyp ()->ioctl_retval = 0;
1092 int val;
1093 switch (cmd)
1094 {
1095 case TIOCGWINSZ:
1096 get_ttyp ()->arg.winsize = get_ttyp ()->winsize;
1097 if (ioctl_request_event)
1098 SetEvent (ioctl_request_event);
1099 *(struct winsize *) arg = get_ttyp ()->arg.winsize;
1100 if (ioctl_done_event)
1101 WaitForSingleObject (ioctl_done_event, INFINITE);
1102 get_ttyp ()->winsize = get_ttyp ()->arg.winsize;
1103 break;
1104 case TIOCSWINSZ:
1105 if (get_ttyp ()->winsize.ws_row != ((struct winsize *) arg)->ws_row
1106 || get_ttyp ()->winsize.ws_col != ((struct winsize *) arg)->ws_col)
1107 {
1108 get_ttyp ()->arg.winsize = *(struct winsize *) arg;
1109 if (ioctl_request_event)
1110 {
1111 get_ttyp ()->ioctl_retval = -EINVAL;
1112 SetEvent (ioctl_request_event);
1113 }
1114 else
1115 {
1116 get_ttyp ()->winsize = *(struct winsize *) arg;
1117 killsys (-get_ttyp ()->getpgid (), SIGWINCH);
1118 }
1119 if (ioctl_done_event)
1120 WaitForSingleObject (ioctl_done_event, INFINITE);
1121 }
1122 break;
1123 case TIOCLINUX:
1124 val = *(unsigned char *) arg;
1125 if (val != 6 || !ioctl_request_event || !ioctl_done_event)
1126 get_ttyp ()->ioctl_retval = -EINVAL;
1127 else
1128 {
1129 get_ttyp ()->arg.value = val;
1130 SetEvent (ioctl_request_event);
1131 WaitForSingleObject (ioctl_done_event, INFINITE);
1132 *(unsigned char *) arg = (unsigned char) (get_ttyp ()->arg.value);
1133 }
1134 break;
1135 case KDGKBMETA:
1136 if (ioctl_request_event)
1137 {
1138 SetEvent (ioctl_request_event);
1139 if (ioctl_done_event)
1140 WaitForSingleObject (ioctl_done_event, INFINITE);
1141 *(int *) arg = get_ttyp ()->arg.value;
1142 }
1143 else
1144 get_ttyp ()->ioctl_retval = -EINVAL;
1145 break;
1146 case KDSKBMETA:
1147 if (ioctl_request_event)
1148 {
1149 get_ttyp ()->arg.value = (int) arg;
1150 SetEvent (ioctl_request_event);
1151 if (ioctl_done_event)
1152 WaitForSingleObject (ioctl_done_event, INFINITE);
1153 }
1154 else
1155 get_ttyp ()->ioctl_retval = -EINVAL;
1156 break;
1157 }
1158
1159 release_output_mutex ();
1160 retval = get_ttyp ()->ioctl_retval;
1161 if (retval < 0)
1162 {
1163 set_errno (-retval);
1164 retval = -1;
1165 }
1166
1167 out:
1168 termios_printf ("%d = ioctl (%x)", retval, cmd);
1169 return retval;
1170 }
1171
1172 int __stdcall
1173 fhandler_tty_slave::fstat (struct __stat64 *st)
1174 {
1175 fhandler_base::fstat (st);
1176
1177 bool to_close = false;
1178 if (!input_available_event)
1179 {
1180 char buf[MAX_PATH];
1181 shared_name (buf, INPUT_AVAILABLE_EVENT, get_unit ());
1182 input_available_event = OpenEvent (READ_CONTROL, TRUE, buf);
1183 if (input_available_event)
1184 to_close = true;
1185 }
1186 if (!input_available_event
1187 || get_object_attribute (input_available_event, &st->st_uid, &st->st_gid,
1188 &st->st_mode))
1189 {
1190 /* If we can't access the ACL, or if the tty doesn't actually exist,
1191 then fake uid and gid to strict, system-like values. */
1192 st->st_mode = S_IFCHR | S_IRUSR | S_IWUSR;
1193 st->st_uid = 18;
1194 st->st_gid = 544;
1195 }
1196 if (to_close)
1197 CloseHandle (input_available_event);
1198 return 0;
1199 }
1200
1201 /* Helper function for fchmod and fchown, which just opens all handles
1202 and signals success via bool return. */
1203 bool
1204 fhandler_tty_slave::fch_open_handles ()
1205 {
1206 char buf[MAX_PATH];
1207
1208 tc = cygwin_shared->tty[get_unit ()];
1209 shared_name (buf, INPUT_AVAILABLE_EVENT, get_unit ());
1210 input_available_event = OpenEvent (READ_CONTROL | WRITE_DAC | WRITE_OWNER,
1211 TRUE, buf);
1212 output_mutex = get_ttyp ()->open_output_mutex (WRITE_DAC | WRITE_OWNER);
1213 input_mutex = get_ttyp ()->open_input_mutex (WRITE_DAC | WRITE_OWNER);
1214 inuse = get_ttyp ()->open_inuse (WRITE_DAC | WRITE_OWNER);
1215 if (!input_available_event || !output_mutex || !input_mutex || !inuse)
1216 {
1217 __seterrno ();
1218 return false;
1219 }
1220 /* These members are optional, no error checking */
1221 shared_name (buf, OUTPUT_DONE_EVENT, get_unit ());
1222 output_done_event = OpenEvent (WRITE_DAC | WRITE_OWNER, TRUE, buf);
1223 shared_name (buf, IOCTL_REQUEST_EVENT, get_unit ());
1224 ioctl_request_event = OpenEvent (WRITE_DAC | WRITE_OWNER, TRUE, buf);
1225 shared_name (buf, IOCTL_DONE_EVENT, get_unit ());
1226 ioctl_done_event = OpenEvent (WRITE_DAC | WRITE_OWNER, TRUE, buf);
1227 return true;
1228 }
1229
1230 /* Helper function for fchmod and fchown, which sets the new security
1231 descriptor on all objects representing the tty. */
1232 int
1233 fhandler_tty_slave::fch_set_sd (security_descriptor &sd, bool chown)
1234 {
1235 security_descriptor sd_old;
1236
1237 get_object_sd (input_available_event, sd_old);
1238 if (!set_object_sd (input_available_event, sd, chown)
1239 && !set_object_sd (output_mutex, sd, chown)
1240 && !set_object_sd (input_mutex, sd, chown)
1241 && !set_object_sd (inuse, sd, chown)
1242 && (!output_done_event
1243 || !set_object_sd (output_done_event, sd, chown))
1244 && (!ioctl_request_event
1245 || !set_object_sd (ioctl_request_event, sd, chown))
1246 && (!ioctl_done_event
1247 || !set_object_sd (ioctl_done_event, sd, chown)))
1248 return 0;
1249 set_object_sd (input_available_event, sd_old, chown);
1250 set_object_sd (output_mutex, sd_old, chown);
1251 set_object_sd (input_mutex, sd_old, chown);
1252 set_object_sd (inuse, sd_old, chown);
1253 if (!output_done_event)
1254 set_object_sd (output_done_event, sd_old, chown);
1255 if (!ioctl_request_event)
1256 set_object_sd (ioctl_request_event, sd_old, chown);
1257 if (!ioctl_done_event)
1258 set_object_sd (ioctl_done_event, sd_old, chown);
1259 return -1;
1260 }
1261
1262 /* Helper function for fchmod and fchown, which closes all object handles in
1263 the tty. */
1264 void
1265 fhandler_tty_slave::fch_close_handles ()
1266 {
1267 close_maybe (get_io_handle ());
1268 close_maybe (get_output_handle ());
1269 close_maybe (output_done_event);
1270 close_maybe (ioctl_done_event);
1271 close_maybe (ioctl_request_event);
1272 close_maybe (input_available_event);
1273 close_maybe (output_mutex);
1274 close_maybe (input_mutex);
1275 close_maybe (inuse);
1276 }
1277
1278 int __stdcall
1279 fhandler_tty_slave::fchmod (mode_t mode)
1280 {
1281 int ret = -1;
1282 bool to_close = false;
1283 security_descriptor sd;
1284 __uid32_t uid;
1285 __gid32_t gid;
1286
1287 if (!input_available_event)
1288 {
1289 to_close = true;
1290 if (!fch_open_handles ())
1291 goto errout;
1292 }
1293 sd.malloc (sizeof (SECURITY_DESCRIPTOR));
1294 InitializeSecurityDescriptor (sd, SECURITY_DESCRIPTOR_REVISION);
1295 if (!get_object_attribute (input_available_event, &uid, &gid, NULL)
1296 && !create_object_sd_from_attribute (NULL, uid, gid, S_IFCHR | mode, sd))
1297 ret = fch_set_sd (sd, false);
1298 errout:
1299 if (to_close)
1300 fch_close_handles ();
1301 return ret;
1302 }
1303
1304 int __stdcall
1305 fhandler_tty_slave::fchown (__uid32_t uid, __gid32_t gid)
1306 {
1307 int ret = -1;
1308 bool to_close = false;
1309 mode_t mode;
1310 __uid32_t o_uid;
1311 __gid32_t o_gid;
1312 security_descriptor sd;
1313
1314 if (uid == ILLEGAL_UID && gid == ILLEGAL_GID)
1315 return 0;
1316 if (!input_available_event)
1317 {
1318 to_close = true;
1319 if (!fch_open_handles ())
1320 goto errout;
1321 }
1322 sd.malloc (sizeof (SECURITY_DESCRIPTOR));
1323 InitializeSecurityDescriptor (sd, SECURITY_DESCRIPTOR_REVISION);
1324 if (!get_object_attribute (input_available_event, &o_uid, &o_gid, &mode))
1325 {
1326 if ((uid == ILLEGAL_UID || uid == o_uid)
1327 && (gid == ILLEGAL_GID || gid == o_gid))
1328 ret = 0;
1329 else if (!create_object_sd_from_attribute (input_available_event,
1330 uid, gid, S_IFCHR | mode, sd))
1331 ret = fch_set_sd (sd, true);
1332 }
1333 errout:
1334 if (to_close)
1335 fch_close_handles ();
1336 return ret;
1337 }
1338
1339 /*******************************************************
1340 fhandler_pty_master
1341 */
1342 fhandler_pty_master::fhandler_pty_master ()
1343 : fhandler_tty_common (), pktmode (0), need_nl (0), dwProcessId (0)
1344 {
1345 }
1346
1347 int
1348 fhandler_pty_master::open (int flags, mode_t)
1349 {
1350 /* Note that allocate returns with the tty lock set if it was successful. */
1351 int ntty = cygwin_shared->tty.allocate (false);
1352 if (ntty < 0)
1353 return 0;
1354
1355 dev().devn = FHDEV (DEV_TTYM_MAJOR, ntty);
1356 if (!setup (true))
1357 {
1358 lock_ttys::release ();
1359 return 0;
1360 }
1361 lock_ttys::release ();
1362 set_flags ((flags & ~O_TEXT) | O_BINARY);
1363 set_open_status ();
1364
1365 /* FIXME: Do this better someday */
1366 fhandler_pty_master *arch = (fhandler_tty_master *) cmalloc_abort (HEAP_ARCHETYPES, sizeof (*this));
1367 *((fhandler_pty_master **) cygheap->fdtab.add_archetype ()) = arch;
1368 archetype = arch;
1369 *arch = *this;
1370 arch->dwProcessId = GetCurrentProcessId ();
1371
1372 usecount = 0;
1373 arch->usecount++;
1374 char buf[sizeof ("opened pty master for ttyNNNNNNNNNNN")];
1375 __small_sprintf (buf, "opened pty master for tty%d", get_unit ());
1376 report_tty_counts (this, buf, "");
1377 return 1;
1378 }
1379
1380 _off64_t
1381 fhandler_tty_common::lseek (_off64_t, int)
1382 {
1383 set_errno (ESPIPE);
1384 return -1;
1385 }
1386
1387 int
1388 fhandler_tty_common::close ()
1389 {
1390 termios_printf ("tty%d <%p,%p> closing", get_unit (), get_handle (), get_output_handle ());
1391 if (output_done_event && !CloseHandle (output_done_event))
1392 termios_printf ("CloseHandle (output_done_event), %E");
1393 if (ioctl_done_event && !CloseHandle (ioctl_done_event))
1394 termios_printf ("CloseHandle (ioctl_done_event), %E");
1395 if (ioctl_request_event && !CloseHandle (ioctl_request_event))
1396 termios_printf ("CloseHandle (ioctl_request_event), %E");
1397 if (!ForceCloseHandle (input_mutex))
1398 termios_printf ("CloseHandle (input_mutex<%p>), %E", input_mutex);
1399 if (!ForceCloseHandle (output_mutex))
1400 termios_printf ("CloseHandle (output_mutex<%p>), %E", output_mutex);
1401 if (!ForceCloseHandle1 (get_handle (), from_pty))
1402 termios_printf ("CloseHandle (get_handle ()<%p>), %E", get_handle ());
1403 if (!ForceCloseHandle1 (get_output_handle (), to_pty))
1404 termios_printf ("CloseHandle (get_output_handle ()<%p>), %E", get_output_handle ());
1405
1406 if (!ForceCloseHandle (input_available_event))
1407 termios_printf ("CloseHandle (input_available_event<%p>), %E", input_available_event);
1408
1409 return 0;
1410 }
1411
1412 int
1413 fhandler_pty_master::close ()
1414 {
1415 #if 0
1416 while (accept_input () > 0)
1417 continue;
1418 #endif
1419 archetype->usecount--;
1420 report_tty_counts (this, "closing master", "");
1421
1422 if (archetype->usecount)
1423 {
1424 #ifdef DEBUGGING
1425 if (archetype->usecount < 0)
1426 system_printf ("error: usecount %d", archetype->usecount);
1427 #endif
1428 termios_printf ("just returning because archetype usecount is != 0");
1429 return 0;
1430 }
1431
1432 fhandler_tty_master *arch = (fhandler_tty_master *) archetype;
1433 termios_printf ("closing from_master(%p)/to_master(%p) since we own them(%d)",
1434 arch->from_master, arch->to_master, arch->dwProcessId);
1435 if (cygwin_finished_initializing)
1436 {
1437 if (arch->master_ctl && get_ttyp ()->master_pid == myself->pid)
1438 {
1439 char buf[MAX_PATH];
1440 pipe_request req = { (DWORD) -1 };
1441 pipe_reply repl;
1442 DWORD len;
1443
1444 __small_sprintf (buf, "\\\\.\\pipe\\cygwin-%S-tty%d-master-ctl",
1445 &installation_key, get_unit ());
1446 CallNamedPipe (buf, &req, sizeof req, &repl, sizeof repl, &len, 500);
1447 CloseHandle (arch->master_ctl);
1448 arch->master_thread->detach ();
1449 }
1450 if (!ForceCloseHandle (arch->from_master))
1451 termios_printf ("error closing from_master %p, %E", arch->from_master);
1452 if (!ForceCloseHandle (arch->to_master))
1453 termios_printf ("error closing from_master %p, %E", arch->to_master);
1454 }
1455 fhandler_tty_common::close ();
1456
1457 if (hExeced || get_ttyp ()->master_pid != myself->pid)
1458 termios_printf ("not clearing: %d, master_pid %d", hExeced, get_ttyp ()->master_pid);
1459 else
1460 get_ttyp ()->set_master_closed ();
1461
1462 return 0;
1463 }
1464
1465 ssize_t __stdcall
1466 fhandler_pty_master::write (const void *ptr, size_t len)
1467 {
1468 int i;
1469 char *p = (char *) ptr;
1470 termios ti = tc->ti;
1471
1472 for (i = 0; i < (int) len; i++)
1473 {
1474 line_edit_status status = line_edit (p++, 1, ti);
1475 if (status > line_edit_signalled)
1476 {
1477 if (status != line_edit_pipe_full)
1478 i = -1;
1479 break;
1480 }
1481 }
1482 return i;
1483 }
1484
1485 void __stdcall
1486 fhandler_pty_master::read (void *ptr, size_t& len)
1487 {
1488 len = (size_t) process_slave_output ((char *) ptr, len, pktmode);
1489 }
1490
1491 int
1492 fhandler_pty_master::tcgetattr (struct termios *t)
1493 {
1494 *t = cygwin_shared->tty[get_unit ()]->ti;
1495 return 0;
1496 }
1497
1498 int
1499 fhandler_pty_master::tcsetattr (int, const struct termios *t)
1500 {
1501 cygwin_shared->tty[get_unit ()]->ti = *t;
1502 return 0;
1503 }
1504
1505 int
1506 fhandler_pty_master::tcflush (int queue)
1507 {
1508 int ret = 0;
1509
1510 termios_printf ("tcflush(%d) handle %p", queue, get_handle ());
1511
1512 if (queue == TCIFLUSH || queue == TCIOFLUSH)
1513 ret = process_slave_output (NULL, OUT_BUFFER_SIZE, 0);
1514 else if (queue == TCIFLUSH || queue == TCIOFLUSH)
1515 {
1516 /* do nothing for now. */
1517 }
1518
1519 termios_printf ("%d=tcflush(%d)", ret, queue);
1520 return ret;
1521 }
1522
1523 int
1524 fhandler_pty_master::ioctl (unsigned int cmd, void *arg)
1525 {
1526 switch (cmd)
1527 {
1528 case TIOCPKT:
1529 pktmode = *(int *) arg;
1530 break;
1531 case TIOCGWINSZ:
1532 *(struct winsize *) arg = get_ttyp ()->winsize;
1533 break;
1534 case TIOCSWINSZ:
1535 if (get_ttyp ()->winsize.ws_row != ((struct winsize *) arg)->ws_row
1536 || get_ttyp ()->winsize.ws_col != ((struct winsize *) arg)->ws_col)
1537 {
1538 get_ttyp ()->winsize = *(struct winsize *) arg;
1539 killsys (-get_ttyp ()->getpgid (), SIGWINCH);
1540 }
1541 break;
1542 case TIOCGPGRP:
1543 *((pid_t *) arg) = this->tcgetpgrp ();
1544 break;
1545 case TIOCSPGRP:
1546 return this->tcsetpgrp ((pid_t) arg);
1547 case FIONBIO:
1548 set_nonblocking (*(int *) arg);
1549 break;
1550 default:
1551 set_errno (EINVAL);
1552 return -1;
1553 }
1554 return 0;
1555 }
1556
1557 char *
1558 fhandler_pty_master::ptsname ()
1559 {
1560 static char buf[TTY_NAME_MAX];
1561
1562 __small_sprintf (buf, "/dev/tty%d", get_unit ());
1563 return buf;
1564 }
1565
1566 void
1567 fhandler_tty_common::set_close_on_exec (bool val)
1568 {
1569 // Cygwin processes will handle this specially on exec.
1570 close_on_exec (val);
1571 }
1572
1573 void
1574 fhandler_tty_slave::fixup_after_fork (HANDLE parent)
1575 {
1576 // fork_fixup (parent, inuse, "inuse");
1577 // fhandler_tty_common::fixup_after_fork (parent);
1578 report_tty_counts (this, "inherited", "");
1579 }
1580
1581 void
1582 fhandler_tty_slave::fixup_after_exec ()
1583 {
1584 if (!close_on_exec ())
1585 fixup_after_fork (NULL);
1586 }
1587
1588 int
1589 fhandler_tty_master::init_console ()
1590 {
1591 console = (fhandler_console *) build_fh_dev (*console_dev, "/dev/ttym");
1592 if (console == NULL)
1593 return -1;
1594
1595 console->init (INVALID_HANDLE_VALUE, GENERIC_READ | GENERIC_WRITE, O_BINARY);
1596 cygheap->manage_console_count ("fhandler_tty_master::init_console", -1, true);
1597 console->uninterruptible_io (true);
1598 return 0;
1599 }
1600
1601 extern "C" BOOL WINAPI GetNamedPipeClientProcessId (HANDLE, PULONG);
1602
1603 /* This thread function handles the master control pipe. It waits for a
1604 client to connect. Then it checks if the client process has permissions
1605 to access the tty handles. If so, it opens the client process and
1606 duplicates the handles into that process. If that fails, it sends a reply
1607 with at least one handle set to NULL and an error code. Last but not
1608 least, the client is disconnected and the thread waits for the next client.
1609
1610 A special case is when the master side of the tty is about to be closed.
1611 The client side is the fhandler_pty_master::close function and it sends
1612 a PID -1 in that case. On Vista and later a check is performed that the
1613 request to leave really comes from the master process itself. On earlier
1614 OSes there's no function to check for the PID of the client process so
1615 we have to trust the client side.
1616
1617 Since there's
1618 always only one pipe instance, there's a chance that clients have to
1619 wait to connect to the master control pipe. Therefore the client calls
1620 to CallNamedPipe should have a big enough timeout value. For now this
1621 is 500ms. Hope that's enough. */
1622
1623 DWORD
1624 fhandler_pty_master::pty_master_thread ()
1625 {
1626 bool exit = false;
1627 GENERIC_MAPPING map = { EVENT_QUERY_STATE, EVENT_MODIFY_STATE, 0,
1628 EVENT_QUERY_STATE | EVENT_MODIFY_STATE };
1629 pipe_request req;
1630 DWORD len;
1631 security_descriptor sd;
1632 HANDLE token;
1633 PRIVILEGE_SET ps;
1634 BOOL ret;
1635 DWORD pid;
1636
1637 termios_printf ("Entered");
1638 while (!exit && ConnectNamedPipe (master_ctl, NULL))
1639 {
1640 pipe_reply repl = { NULL, NULL, 0 };
1641 bool deimp = false;
1642 BOOL allow = FALSE;
1643 ACCESS_MASK access = EVENT_MODIFY_STATE;
1644 HANDLE client = NULL;
1645
1646 if (!ReadFile (master_ctl, &req, sizeof req, &len, NULL))
1647 {
1648 termios_printf ("ReadFile, %E");
1649 goto reply;
1650 }
1651 /* This function is only available since Vista, unfortunately.
1652 In earlier OSes we simply have to believe that the client
1653 has no malicious intent (== sends arbitrary PIDs). */
1654 if (!GetNamedPipeClientProcessId (master_ctl, &pid))
1655 pid = req.pid;
1656 if (get_object_sd (input_available_event, sd))
1657 {
1658 termios_printf ("get_object_sd, %E");
1659 goto reply;
1660 }
1661 cygheap->user.deimpersonate ();
1662 deimp = true;
1663 if (!ImpersonateNamedPipeClient (master_ctl))
1664 {
1665 termios_printf ("ImpersonateNamedPipeClient, %E");
1666 goto reply;
1667 }
1668 if (!OpenThreadToken (GetCurrentThread (), TOKEN_QUERY, TRUE, &token))
1669 {
1670 termios_printf ("OpenThreadToken, %E");
1671 goto reply;
1672 }
1673 len = sizeof ps;
1674 ret = AccessCheck (sd, token, access, &map, &ps, &len, &access, &allow);
1675 CloseHandle (token);
1676 if (!ret)
1677 {
1678 termios_printf ("AccessCheck, %E");
1679 goto reply;
1680 }
1681 if (!RevertToSelf ())
1682 {
1683 termios_printf ("RevertToSelf, %E");
1684 goto reply;
1685 }
1686 if (req.pid == (DWORD) -1) /* Request to finish thread. */
1687 {
1688 /* Pre-Vista: Just believe in the good of the client process.
1689 Post-Vista: Check if the requesting process is the master
1690 process itself. */
1691 if (pid == (DWORD) -1 || pid == GetCurrentProcessId ())
1692 exit = true;
1693 goto reply;
1694 }
1695 if (allow)
1696 {
1697 client = OpenProcess (PROCESS_DUP_HANDLE, FALSE, pid);
1698 if (!client)
1699 {
1700 termios_printf ("OpenProcess, %E");
1701 goto reply;
1702 }
1703 if (!DuplicateHandle (GetCurrentProcess (), from_master,
1704 client, &repl.from_master,
1705 0, TRUE, DUPLICATE_SAME_ACCESS))
1706 {
1707 termios_printf ("DuplicateHandle (from_master), %E");
1708 goto reply;
1709 }
1710 if (!DuplicateHandle (GetCurrentProcess (), to_master,
1711 client, &repl.to_master,
1712 0, TRUE, DUPLICATE_SAME_ACCESS))
1713 {
1714 termios_printf ("DuplicateHandle (to_master), %E");
1715 goto reply;
1716 }
1717 }
1718 reply:
1719 repl.error = GetLastError ();
1720 if (client)
1721 CloseHandle (client);
1722 if (deimp)
1723 cygheap->user.reimpersonate ();
1724 sd.free ();
1725 termios_printf ("Reply: from %p, to %p, error %lu",
1726 repl.from_master, repl.to_master, repl.error );
1727 if (!WriteFile (master_ctl, &repl, sizeof repl, &len, NULL))
1728 termios_printf ("WriteFile, %E");
1729 if (!DisconnectNamedPipe (master_ctl))
1730 termios_printf ("DisconnectNamedPipe, %E");
1731 }
1732 termios_printf ("Leaving");
1733 return 0;
1734 }
1735
1736 static DWORD WINAPI
1737 pty_master_thread (VOID *arg)
1738 {
1739 return ((fhandler_pty_master *) arg)->pty_master_thread ();
1740 }
1741
1742 bool
1743 fhandler_pty_master::setup (bool ispty)
1744 {
1745 int res;
1746 security_descriptor sd;
1747 SECURITY_ATTRIBUTES sa = { sizeof (SECURITY_ATTRIBUTES), NULL, TRUE };
1748
1749 tty& t = *cygwin_shared->tty[get_unit ()];
1750
1751 tcinit (&t, true); /* Set termios information. Force initialization. */
1752
1753 const char *errstr = NULL;
1754 DWORD pipe_mode = PIPE_NOWAIT;
1755
1756 /* Create communication pipes */
1757 char pipename[sizeof("ttyNNNN-from-master")];
1758 __small_sprintf (pipename, "tty%d-from-master", get_unit ());
1759 res = fhandler_pipe::create_selectable (ispty ? &sec_none : &sec_none_nih,
1760 from_master, get_output_handle (),
1761 128 * 1024, pipename);
1762 if (res)
1763 {
1764 errstr = "input pipe";
1765 goto err;
1766 }
1767
1768 if (!SetNamedPipeHandleState (get_output_handle (), &pipe_mode, NULL, NULL))
1769 termios_printf ("can't set output_handle(%p) to non-blocking mode",
1770 get_output_handle ());
1771
1772 __small_sprintf (pipename, "tty%d-to-master", get_unit ());
1773 res = fhandler_pipe::create_selectable (ispty ? &sec_none : &sec_none_nih,
1774 get_io_handle (), to_master,
1775 128 * 1024, pipename);
1776 if (res)
1777 {
1778 errstr = "output pipe";
1779 goto err;
1780 }
1781
1782 need_nl = 0;
1783
1784 /* Create security attribute. Default permissions are 0620. */
1785 sd.malloc (sizeof (SECURITY_DESCRIPTOR));
1786 InitializeSecurityDescriptor (sd, SECURITY_DESCRIPTOR_REVISION);
1787 if (!create_object_sd_from_attribute (NULL, myself->uid, myself->gid,
1788 S_IFCHR | S_IRUSR | S_IWUSR | S_IWGRP,
1789 sd))
1790 sa.lpSecurityDescriptor = (PSECURITY_DESCRIPTOR) sd;
1791
1792 /* Create synchronisation events */
1793
1794 if (!ispty)
1795 {
1796 if (!(output_done_event = t.get_event (errstr = OUTPUT_DONE_EVENT, &sa)))
1797 goto err;
1798 if (!(ioctl_done_event = t.get_event (errstr = IOCTL_DONE_EVENT, &sa)))
1799 goto err;
1800 if (!(ioctl_request_event = t.get_event (errstr = IOCTL_REQUEST_EVENT,
1801 &sa)))
1802 goto err;
1803 }
1804
1805 /* Carefully check that the input_available_event didn't already exist.
1806 This is a measure to make sure that the event security descriptor
1807 isn't occupied by a malicious process. We must make sure that the
1808 event's security descriptor is what we expect it to be. */
1809 if (!(input_available_event = t.get_event (errstr = INPUT_AVAILABLE_EVENT,
1810 &sa, TRUE))
1811 || GetLastError () == ERROR_ALREADY_EXISTS)
1812 goto err;
1813
1814 char buf[MAX_PATH];
1815 errstr = shared_name (buf, OUTPUT_MUTEX, t.ntty);
1816 if (!(output_mutex = CreateMutex (&sa, FALSE, buf)))
1817 goto err;
1818
1819 errstr = shared_name (buf, INPUT_MUTEX, t.ntty);
1820 if (!(input_mutex = CreateMutex (&sa, FALSE, buf)))
1821 goto err;
1822
1823 /* Create master control pipe which allows the master to duplicate
1824 the pty pipe handles to processes which deserve it. */
1825 __small_sprintf (buf, "\\\\.\\pipe\\cygwin-%S-tty%d-master-ctl",
1826 &installation_key, get_unit ());
1827 master_ctl = CreateNamedPipe (buf, PIPE_ACCESS_DUPLEX,
1828 PIPE_WAIT | PIPE_TYPE_MESSAGE
1829 | PIPE_READMODE_MESSAGE, 1, 4096, 4096,
1830 0, &sec_all_nih);
1831 if (master_ctl == INVALID_HANDLE_VALUE)
1832 {
1833 errstr = "pty master control pipe";
1834 goto err;
1835 }
1836 master_thread = new cygthread (::pty_master_thread, this, "pty_master");
1837 if (!master_thread)
1838 {
1839 errstr = "pty master control thread";
1840 goto err;
1841 }
1842
1843 t.from_master = from_master;
1844 t.to_master = to_master;
1845 // /* screws up tty master */ ProtectHandle1INH (output_mutex, output_mutex);
1846 // /* screws up tty master */ ProtectHandle1INH (input_mutex, input_mutex);
1847 t.winsize.ws_col = 80;
1848 t.winsize.ws_row = 25;
1849 t.master_pid = myself->pid;
1850
1851 termios_printf ("tty%d opened - from_slave %p, to_slave %p", t.ntty,
1852 get_io_handle (), get_output_handle ());
1853 return true;
1854
1855 err:
1856 __seterrno ();
1857 close_maybe (get_io_handle ());
1858 close_maybe (get_output_handle ());
1859 close_maybe (output_done_event);
1860 close_maybe (ioctl_done_event);
1861 close_maybe (ioctl_request_event);
1862 close_maybe (input_available_event);
1863 close_maybe (output_mutex);
1864 close_maybe (input_mutex);
1865 close_maybe (from_master);
1866 close_maybe (to_master);
1867 close_maybe (master_ctl);
1868 termios_printf ("tty%d open failed - failed to create %s", errstr);
1869 return false;
1870 }
1871
1872 void
1873 fhandler_pty_master::fixup_after_fork (HANDLE parent)
1874 {
1875 DWORD wpid = GetCurrentProcessId ();
1876 fhandler_tty_master *arch = (fhandler_tty_master *) archetype;
1877 if (arch->dwProcessId != wpid)
1878 {
1879 tty& t = *get_ttyp ();
1880 if (!DuplicateHandle (parent, arch->from_master, GetCurrentProcess (),
1881 &arch->from_master, 0, false, DUPLICATE_SAME_ACCESS))
1882 system_printf ("couldn't duplicate from_parent(%p), %E", arch->from_master);
1883 if (!DuplicateHandle (parent, arch->to_master, GetCurrentProcess (),
1884 &arch->to_master, 0, false, DUPLICATE_SAME_ACCESS))
1885 system_printf ("couldn't duplicate to_parent(%p), %E", arch->from_master);
1886 if (myself->pid == t.master_pid)
1887 {
1888 t.from_master = arch->from_master;
1889 t.to_master = arch->to_master;
1890 }
1891 arch->dwProcessId = wpid;
1892 }
1893 from_master = arch->from_master;
1894 to_master = arch->to_master;
1895 report_tty_counts (this, "inherited master", "");
1896 }
1897
1898 void
1899 fhandler_pty_master::fixup_after_exec ()
1900 {
1901 if (!close_on_exec ())
1902 fixup_after_fork (spawn_info->parent);
1903 else
1904 from_master = to_master = NULL;
1905 }
This page took 0.13773 seconds and 5 git commands to generate.