diff options
Diffstat (limited to 'winsup/cygwin/fhandler_tty.cc')
-rw-r--r-- | winsup/cygwin/fhandler_tty.cc | 1771 |
1 files changed, 0 insertions, 1771 deletions
diff --git a/winsup/cygwin/fhandler_tty.cc b/winsup/cygwin/fhandler_tty.cc deleted file mode 100644 index 032231ade..000000000 --- a/winsup/cygwin/fhandler_tty.cc +++ /dev/null @@ -1,1771 +0,0 @@ -/* fhandler_tty.cc - - Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, - 2006, 2007, 2008, 2009, 2010, 2011, 2012 Red Hat, Inc. - -This file is part of Cygwin. - -This software is a copyrighted work licensed under the terms of the -Cygwin license. Please consult the file "CYGWIN_LICENSE" for -details. */ - -#include "winsup.h" -#include <stdlib.h> -#include <sys/param.h> -#include <cygwin/kd.h> -#include "cygerrno.h" -#include "security.h" -#include "path.h" -#include "fhandler.h" -#include "dtable.h" -#include "sigproc.h" -#include "pinfo.h" -#include "ntdll.h" -#include "cygheap.h" -#include "shared_info.h" -#include "cygthread.h" -#include "child_info.h" -#include <asm/socket.h> -#include "cygwait.h" - -#define close_maybe(h) \ - do { \ - if (h && h != INVALID_HANDLE_VALUE) \ - CloseHandle (h); \ - } while (0) - -/* pty master control pipe messages */ -struct pipe_request { - DWORD pid; -}; - -struct pipe_reply { - HANDLE from_master; - HANDLE to_master; - DWORD error; -}; - -int -fhandler_pty_slave::get_unit () -{ - return dev ().get_minor (); -} - -bool -bytes_available (DWORD& n, HANDLE h) -{ - DWORD navail, nleft; - navail = nleft = 0; - bool succeeded = PeekNamedPipe (h, NULL, 0, NULL, &navail, &nleft); - if (succeeded) - /* nleft should always be the right choice unless something has written 0 - bytes to the pipe. In that pathological case we return the actual number - of bytes available in the pipe. See cgf-000008 for more details. */ - n = nleft ?: navail; - else - { - termios_printf ("PeekNamedPipe(%p) failed, %E", h); - n = 0; - } - debug_only_printf ("n %u, nleft %u, navail %u", n, nleft, navail); - return succeeded; -} - -bool -fhandler_pty_common::bytes_available (DWORD &n) -{ - return ::bytes_available (n, get_handle ()); -} - -#ifdef DEBUGGING -static class mutex_stack -{ -public: - const char *fn; - int ln; - const char *tname; -} ostack[100]; - -static int osi; -#endif /*DEBUGGING*/ - -void -fhandler_pty_master::flush_to_slave () -{ - if (get_readahead_valid () && !(get_ttyp ()->ti.c_lflag & ICANON)) - accept_input (); -} - -DWORD -fhandler_pty_common::__acquire_output_mutex (const char *fn, int ln, - DWORD ms) -{ - if (strace.active ()) - strace.prntf (_STRACE_TERMIOS, fn, "(%d): pty output_mutex (%p): waiting %d ms", ln, output_mutex, ms); - DWORD res = WaitForSingleObject (output_mutex, ms); - if (res == WAIT_OBJECT_0) - { -#ifndef DEBUGGING - if (strace.active ()) - strace.prntf (_STRACE_TERMIOS, fn, "(%d): pty output_mutex: acquired", ln, res); -#else - ostack[osi].fn = fn; - ostack[osi].ln = ln; - ostack[osi].tname = cygthread::name (); - termios_printf ("acquired for %s:%d, osi %d", fn, ln, osi); - osi++; -#endif - } - return res; -} - -void -fhandler_pty_common::__release_output_mutex (const char *fn, int ln) -{ - if (ReleaseMutex (output_mutex)) - { -#ifndef DEBUGGING - if (strace.active ()) - strace.prntf (_STRACE_TERMIOS, fn, "(%d): pty output_mutex(%p) released", ln, output_mutex); -#else - if (osi > 0) - osi--; - termios_printf ("released(%p) at %s:%d, osi %d", output_mutex, fn, ln, osi); - termios_printf (" for %s:%d (%s)", ostack[osi].fn, ostack[osi].ln, ostack[osi].tname); - ostack[osi].ln = -ln; -#endif - } -#ifdef DEBUGGING - else if (osi > 0) - { - system_printf ("couldn't release output mutex but we seem to own it, %E"); - try_to_debug (); - } -#endif -} - -/* Process pty input. */ - -void -fhandler_pty_master::doecho (const void *str, DWORD len) -{ - acquire_output_mutex (INFINITE); - if (!WriteFile (to_master, str, len, &len, NULL)) - termios_printf ("Write to %p failed, %E", to_master); - release_output_mutex (); -} - -int -fhandler_pty_master::accept_input () -{ - DWORD bytes_left; - int ret = 1; - - WaitForSingleObject (input_mutex, INFINITE); - - bytes_left = eat_readahead (-1); - - if (!bytes_left) - { - termios_printf ("sending EOF to slave"); - get_ttyp ()->read_retval = 0; - } - else - { - char *p = rabuf; - DWORD rc; - DWORD written = 0; - - paranoid_printf ("about to write %d chars to slave", bytes_left); - rc = WriteFile (get_output_handle (), p, bytes_left, &written, NULL); - if (!rc) - { - debug_printf ("error writing to pipe %p %E", get_output_handle ()); - get_ttyp ()->read_retval = -1; - ret = -1; - } - else - { - get_ttyp ()->read_retval = 1; - p += written; - bytes_left -= written; - if (bytes_left > 0) - { - debug_printf ("to_slave pipe is full"); - puts_readahead (p, bytes_left); - ret = 0; - } - } - } - - SetEvent (input_available_event); - ReleaseMutex (input_mutex); - return ret; -} - -bool -fhandler_pty_master::hit_eof () -{ - if (get_ttyp ()->was_opened && !get_ttyp ()->slave_alive ()) - { - /* We have the only remaining open handle to this pty, and - the slave pty has been opened at least once. We treat - this as EOF. */ - termios_printf ("all other handles closed"); - return 1; - } - return 0; -} - -/* Process pty output requests */ - -int -fhandler_pty_master::process_slave_output (char *buf, size_t len, int pktmode_on) -{ - size_t rlen; - char outbuf[OUT_BUFFER_SIZE + 1]; - DWORD n; - int column = 0; - int rc = 0; - - flush_to_slave (); - - if (len == 0) - goto out; - - if (need_nl) - { - /* We need to return a left over \n character, resulting from - \r\n conversion. Note that we already checked for FLUSHO and - output_stopped at the time that we read the character, so we - don't check again here. */ - if (buf) - buf[0] = '\n'; - need_nl = 0; - rc = 1; - goto out; - } - - for (;;) - { - /* Set RLEN to the number of bytes to read from the pipe. */ - rlen = len; - if (get_ttyp ()->ti.c_oflag & OPOST && get_ttyp ()->ti.c_oflag & ONLCR) - { - /* We are going to expand \n to \r\n, so don't read more than - half of the number of bytes requested. */ - rlen /= 2; - if (rlen == 0) - rlen = 1; - } - if (rlen > sizeof outbuf) - rlen = sizeof outbuf; - - n = 0; - for (;;) - { - if (!bytes_available (n)) - goto err; - if (n) - break; - if (hit_eof ()) - goto out; - /* DISCARD (FLUSHO) and tcflush can finish here. */ - if ((get_ttyp ()->ti.c_lflag & FLUSHO || !buf)) - goto out; - - if (is_nonblocking ()) - { - set_errno (EAGAIN); - rc = -1; - goto out; - } - pthread_testcancel (); - if (cygwait (NULL, 10, cw_sig_eintr) == WAIT_SIGNALED - && !_my_tls.call_signal_handler ()) - { - set_errno (EINTR); - rc = -1; - goto out; - } - flush_to_slave (); - } - - if (!ReadFile (get_handle (), outbuf, rlen, &n, NULL)) - { - termios_printf ("ReadFile failed, %E"); - goto err; - } - - termios_printf ("bytes read %u", n); - get_ttyp ()->write_error = 0; - - if (get_ttyp ()->ti.c_lflag & FLUSHO || !buf) - continue; - - char *optr; - optr = buf; - if (pktmode_on) - *optr++ = TIOCPKT_DATA; - - if (!(get_ttyp ()->ti.c_oflag & OPOST)) // post-process output - { - memcpy (optr, outbuf, n); - optr += n; - } - else // raw output mode - { - char *iptr = outbuf; - - while (n--) - { - switch (*iptr) - { - case '\r': - if ((get_ttyp ()->ti.c_oflag & ONOCR) && column == 0) - { - iptr++; - continue; - } - if (get_ttyp ()->ti.c_oflag & OCRNL) - *iptr = '\n'; - else - column = 0; - break; - case '\n': - if (get_ttyp ()->ti.c_oflag & ONLCR) - { - *optr++ = '\r'; - column = 0; - } - if (get_ttyp ()->ti.c_oflag & ONLRET) - column = 0; - break; - default: - column++; - break; - } - - /* Don't store data past the end of the user's buffer. This - can happen if the user requests a read of 1 byte when - doing \r\n expansion. */ - if (optr - buf >= (int) len) - { - if (*iptr != '\n' || n != 0) - system_printf ("internal error: %d unexpected characters", n); - need_nl = 1; - break; - } - - *optr++ = *iptr++; - } - } - rc = optr - buf; - break; - - err: - if (GetLastError () == ERROR_BROKEN_PIPE) - rc = 0; - else - { - __seterrno (); - rc = -1; - } - break; - } - -out: - termios_printf ("returning %d", rc); - return rc; -} - -/* pty slave stuff */ - -fhandler_pty_slave::fhandler_pty_slave (int unit) - : fhandler_pty_common (), inuse (NULL) -{ - if (unit >= 0) - dev ().parse (DEV_PTYS_MAJOR, unit); -} - -int -fhandler_pty_slave::open (int flags, mode_t) -{ - HANDLE pty_owner, from_master_local, to_master_local; - HANDLE *handles[] = - { - &from_master_local, &input_available_event, &input_mutex, &inuse, - &output_mutex, &to_master_local, &pty_owner, - NULL - }; - - for (HANDLE **h = handles; *h; h++) - **h = NULL; - - _tc = cygwin_shared->tty[get_unit ()]; - - tcinit (false); - - cygwin_shared->tty.attach (get_unit ()); - - /* Create synchronisation events */ - char buf[MAX_PATH]; - - const char *errmsg = NULL; - - if (!(output_mutex = get_ttyp ()->open_output_mutex (MAXIMUM_ALLOWED))) - { - errmsg = "open output mutex failed, %E"; - goto err; - } - if (!(input_mutex = get_ttyp ()->open_input_mutex (MAXIMUM_ALLOWED))) - { - errmsg = "open input mutex failed, %E"; - goto err; - } - shared_name (buf, INPUT_AVAILABLE_EVENT, get_unit ()); - if (!(input_available_event = OpenEvent (MAXIMUM_ALLOWED, TRUE, buf))) - { - errmsg = "open input event failed, %E"; - goto err; - } - - /* FIXME: Needs a method to eliminate tty races */ - { - /* Create security attribute. Default permissions are 0620. */ - security_descriptor sd; - sd.malloc (sizeof (SECURITY_DESCRIPTOR)); - RtlCreateSecurityDescriptor (sd, SECURITY_DESCRIPTOR_REVISION); - SECURITY_ATTRIBUTES sa = { sizeof (SECURITY_ATTRIBUTES), NULL, TRUE }; - if (!create_object_sd_from_attribute (NULL, myself->uid, myself->gid, - S_IFCHR | S_IRUSR | S_IWUSR | S_IWGRP, - sd)) - sa.lpSecurityDescriptor = (PSECURITY_DESCRIPTOR) sd; - acquire_output_mutex (500); - inuse = get_ttyp ()->create_inuse (&sa); - get_ttyp ()->was_opened = true; - release_output_mutex (); - } - - if (!get_ttyp ()->from_master || !get_ttyp ()->to_master) - { - errmsg = "pty handles have been closed"; - set_errno (EACCES); - goto err_no_errno; - } - - if (get_ttyp ()->is_master_closed ()) - { - errmsg = "*** master is closed"; - set_errno (EAGAIN); - goto err_no_errno; - } - /* Three case for duplicating the pipe handles: - - Either we're the master. In this case, just duplicate the handles. - - Or, we have the right to open the master process for handle duplication. - In this case, just duplicate the handles. - - Or, we have to ask the master process itself. In this case, send our - pid to the master process and check the reply. The reply contains - either the handles, or an error code which tells us why we didn't - get the handles. */ - if (myself->pid == get_ttyp ()->master_pid) - { - /* This is the most common case, just calling openpty. */ - termios_printf ("dup handles within myself."); - pty_owner = GetCurrentProcess (); - } - else - { - pinfo p (get_ttyp ()->master_pid); - if (!p) - termios_printf ("*** couldn't find pty master"); - else - { - pty_owner = OpenProcess (PROCESS_DUP_HANDLE, FALSE, p->dwProcessId); - if (pty_owner) - termios_printf ("dup handles directly since I'm the owner"); - } - } - if (pty_owner) - { - if (!DuplicateHandle (pty_owner, get_ttyp ()->from_master, - GetCurrentProcess (), &from_master_local, 0, TRUE, - DUPLICATE_SAME_ACCESS)) - { - termios_printf ("can't duplicate input from %u/%p, %E", - get_ttyp ()->master_pid, get_ttyp ()->from_master); - __seterrno (); - goto err_no_msg; - } - if (!DuplicateHandle (pty_owner, get_ttyp ()->to_master, - GetCurrentProcess (), &to_master_local, 0, TRUE, - DUPLICATE_SAME_ACCESS)) - { - errmsg = "can't duplicate output, %E"; - goto err; - } - if (pty_owner != GetCurrentProcess ()) - CloseHandle (pty_owner); - } - else - { - pipe_request req = { GetCurrentProcessId () }; - pipe_reply repl; - DWORD len; - - __small_sprintf (buf, "\\\\.\\pipe\\cygwin-%S-pty%d-master-ctl", - &cygheap->installation_key, get_unit ()); - termios_printf ("dup handles via master control pipe %s", buf); - if (!CallNamedPipe (buf, &req, sizeof req, &repl, sizeof repl, - &len, 500)) - { - errmsg = "can't call master, %E"; - goto err; - } - from_master_local = repl.from_master; - to_master_local = repl.to_master; - if (!from_master_local || !to_master_local) - { - SetLastError (repl.error); - errmsg = "error duplicating pipes, %E"; - goto err; - } - } - VerifyHandle (from_master_local); - VerifyHandle (to_master_local); - - termios_printf ("duplicated from_master %p->%p from pty_owner", - get_ttyp ()->from_master, from_master_local); - termios_printf ("duplicated to_master %p->%p from pty_owner", - get_ttyp ()->to_master, to_master_local); - - set_io_handle (from_master_local); - set_output_handle (to_master_local); - - fhandler_console::need_invisible (); - set_open_status (); - return 1; - -err: - if (GetLastError () == ERROR_FILE_NOT_FOUND) - set_errno (ENXIO); - else - __seterrno (); -err_no_errno: - termios_printf (errmsg); -err_no_msg: - for (HANDLE **h = handles; *h; h++) - if (**h && **h != INVALID_HANDLE_VALUE) - CloseHandle (**h); - return 0; -} - -void -fhandler_pty_slave::open_setup (int flags) -{ - set_flags ((flags & ~O_TEXT) | O_BINARY); - myself->set_ctty (this, flags); - report_tty_counts (this, "opened", ""); -} - -void -fhandler_pty_slave::cleanup () -{ - /* This used to always call fhandler_pty_common::close when we were execing - but that caused multiple closes of the handles associated with this pty. - Since close_all_files is not called until after the cygwin process has - synced or before a non-cygwin process has exited, it should be safe to - just close this normally. cgf 2006-05-20 */ - report_tty_counts (this, "closed", ""); -} - -int -fhandler_pty_slave::close () -{ - termios_printf ("closing last open %s handle", ttyname ()); - if (inuse && !CloseHandle (inuse)) - termios_printf ("CloseHandle (inuse), %E"); - if (!ForceCloseHandle (input_available_event)) - termios_printf ("CloseHandle (input_available_event<%p>), %E", input_available_event); - if ((unsigned) myself->ctty == FHDEV (DEV_PTYS_MAJOR, get_unit ())) - fhandler_console::free_console (); /* assumes that we are the last pty closer */ - return fhandler_pty_common::close (); -} - -int -fhandler_pty_slave::init (HANDLE h, DWORD a, mode_t) -{ - int flags = 0; - - a &= GENERIC_READ | GENERIC_WRITE; - if (a == GENERIC_READ) - flags = O_RDONLY; - if (a == GENERIC_WRITE) - flags = O_WRONLY; - if (a == (GENERIC_READ | GENERIC_WRITE)) - flags = O_RDWR; - - int ret = open_with_arch (flags); - - if (ret && !cygwin_finished_initializing && !being_debugged ()) - { - /* This only occurs when called from dtable::init_std_file_from_handle - We have been started from a non-Cygwin process. So we should become - pty process group leader. - TODO: Investigate how SIGTTIN should be handled with pure-windows - programs. */ - pinfo p (tc ()->getpgid ()); - /* We should only grab this when the process group owner for this - pty is a non-cygwin process or we've been started directly - from a non-Cygwin process with no Cygwin ancestry. */ - if (!p || ISSTATE (p, PID_NOTCYGWIN)) - { - termios_printf ("Setting process group leader to %d since %W(%d) is not a cygwin process", - myself->pgid, p->progname, p->pid); - tc ()->setpgid (myself->pgid); - } - } - - if (h != INVALID_HANDLE_VALUE) - CloseHandle (h); /* Reopened by open */ - - return ret; -} - -ssize_t __stdcall -fhandler_pty_slave::write (const void *ptr, size_t len) -{ - DWORD n, towrite = len; - - bg_check_types bg = bg_check (SIGTTOU); - if (bg <= bg_eof) - return (ssize_t) bg; - - termios_printf ("pty%d, write(%x, %d)", get_unit (), ptr, len); - - push_process_state process_state (PID_TTYOU); - - while (len) - { - n = MIN (OUT_BUFFER_SIZE, len); - char *buf = (char *)ptr; - ptr = (char *) ptr + n; - len -= n; - - while (tc ()->output_stopped) - cygwait (10); - acquire_output_mutex (INFINITE); - - /* Previous write may have set write_error to != 0. Check it here. - This is less than optimal, but the alternative slows down pty - writes enormously. */ - if (get_ttyp ()->write_error) - { - set_errno (get_ttyp ()->write_error); - towrite = (DWORD) -1; - get_ttyp ()->write_error = 0; - release_output_mutex (); - break; - } - - BOOL res = WriteFile (get_output_handle (), buf, n, &n, NULL); - release_output_mutex (); - if (!res) - { - DWORD err = GetLastError (); - termios_printf ("WriteFile failed, %E"); - switch (err) - { - case ERROR_NO_DATA: - err = ERROR_IO_DEVICE; - default: - __seterrno_from_win_error (err); - } - raise (SIGHUP); /* FIXME: Should this be SIGTTOU? */ - towrite = (DWORD) -1; - break; - } - } - return towrite; -} - -void __stdcall -fhandler_pty_slave::read (void *ptr, size_t& len) -{ - int totalread = 0; - int vmin = 0; - int vtime = 0; /* Initialized to prevent -Wuninitialized warning */ - size_t readlen; - DWORD bytes_in_pipe; - char buf[INP_BUFFER_SIZE]; - DWORD time_to_wait; - - bg_check_types bg = bg_check (SIGTTIN); - if (bg <= bg_eof) - { - len = (size_t) bg; - return; - } - - termios_printf ("read(%x, %d) handle %p", ptr, len, get_handle ()); - - push_process_state process_state (PID_TTYIN); - - if (is_nonblocking () || !ptr) /* Indicating tcflush(). */ - time_to_wait = 0; - else if ((get_ttyp ()->ti.c_lflag & ICANON)) - time_to_wait = INFINITE; - else - { - vmin = get_ttyp ()->ti.c_cc[VMIN]; - if (vmin > INP_BUFFER_SIZE) - vmin = INP_BUFFER_SIZE; - vtime = get_ttyp ()->ti.c_cc[VTIME]; - if (vmin < 0) - vmin = 0; - if (vtime < 0) - vtime = 0; - if (!vmin && !vtime) - time_to_wait = 0; - else - time_to_wait = !vtime ? INFINITE : 100 * vtime; - } - - while (len) - { - switch (cygwait (input_available_event, time_to_wait)) - { - case WAIT_OBJECT_0: - if (get_ttyp ()->is_master_closed ()) - { - raise (SIGHUP); - totalread = 0; - goto out; - } - break; - case WAIT_SIGNALED: - if (totalread > 0) - goto out; - termios_printf ("wait catched signal"); - set_sig_errno (EINTR); - totalread = -1; - goto out; - case WAIT_CANCELED: - process_state.pop (); - pthread::static_cancel_self (); - /*NOTREACHED*/ - case WAIT_TIMEOUT: - termios_printf ("wait timed out, time_to_wait %u", time_to_wait); - if (!totalread) - { - set_sig_errno (EAGAIN); - totalread = -1; - } - goto out; - default: - termios_printf ("wait for input event failed, %E"); - if (!totalread) - { - __seterrno (); - totalread = -1; - } - goto out; - } - /* Now that we know that input is available we have to grab the - input mutex. */ - switch (cygwait (input_mutex, 1000)) - { - case WAIT_OBJECT_0: - case WAIT_ABANDONED_0: - break; - case WAIT_SIGNALED: - if (totalread > 0) - goto out; - termios_printf ("wait for mutex caught signal"); - set_sig_errno (EINTR); - totalread = -1; - goto out; - case WAIT_CANCELED: - process_state.pop (); - pthread::static_cancel_self (); - /*NOTREACHED*/ - case WAIT_TIMEOUT: - termios_printf ("failed to acquire input mutex after input event " - "arrived"); - /* If we have a timeout, we can simply handle this failure to - grab the mutex as an EAGAIN situation. Otherwise, if this - is an infinitely blocking read, restart the loop. */ - if (time_to_wait != INFINITE) - { - if (!totalread) - { - set_sig_errno (EAGAIN); - totalread = -1; - } - goto out; - } - continue; - default: - termios_printf ("wait for input mutex failed, %E"); - if (!totalread) - { - __seterrno (); - totalread = -1; - } - goto out; - } - if (!bytes_available (bytes_in_pipe)) - raise (SIGHUP); - - /* On first peek determine no. of bytes to flush. */ - if (!ptr && len == UINT_MAX) - len = (size_t) bytes_in_pipe; - - if (ptr && !bytes_in_pipe && !vmin && !time_to_wait) - { - ReleaseMutex (input_mutex); - len = (size_t) bytes_in_pipe; - return; - } - - readlen = MIN (bytes_in_pipe, MIN (len, sizeof (buf))); - - if (ptr && vmin && readlen > (unsigned) vmin) - readlen = vmin; - - DWORD n = 0; - if (readlen) - { - termios_printf ("reading %d bytes (vtime %d)", readlen, vtime); - if (!ReadFile (get_handle (), buf, readlen, &n, NULL)) - { - termios_printf ("read failed, %E"); - raise (SIGHUP); - bytes_in_pipe = 0; - ptr = NULL; - } - else - { - /* MSDN states that 5th prameter can be used to determine total - number of bytes in pipe, but for some reason this number doesn't - change after successful read. So we have to peek into the pipe - again to see if input is still available */ - if (!bytes_available (bytes_in_pipe)) - raise (SIGHUP); - if (n) - { - len -= n; - totalread += n; - if (ptr) - { - memcpy (ptr, buf, n); - ptr = (char *) ptr + n; - } - } - } - } - - if (!bytes_in_pipe) - ResetEvent (input_available_event); - - ReleaseMutex (input_mutex); - - if (!ptr) - { - if (!bytes_in_pipe) - break; - continue; - } - - if (get_ttyp ()->read_retval < 0) // read error - { - set_errno (-get_ttyp ()->read_retval); - totalread = -1; - break; - } - if (get_ttyp ()->read_retval == 0) //EOF - { - termios_printf ("saw EOF"); - break; - } - if (get_ttyp ()->ti.c_lflag & ICANON || is_nonblocking ()) - break; - if (vmin && totalread >= vmin) - break; - - /* vmin == 0 && vtime == 0: - * we've already read all input, if any, so return immediately - * vmin == 0 && vtime > 0: - * we've waited for input 10*vtime ms in WFSO(input_available_event), - * no matter whether any input arrived, we shouldn't wait any longer, - * so return immediately - * vmin > 0 && vtime == 0: - * here, totalread < vmin, so continue waiting until more data - * arrive - * vmin > 0 && vtime > 0: - * similar to the previous here, totalread < vmin, and timer - * hadn't expired -- WFSO(input_available_event) != WAIT_TIMEOUT, - * so "restart timer" and wait until more data arrive - */ - - if (vmin == 0) - break; - } -out: - termios_printf ("%d=read(%x, %d)", totalread, ptr, len); - len = (size_t) totalread; -} - -int -fhandler_pty_slave::dup (fhandler_base *child, int flags) -{ - /* This code was added in Oct 2001 for some undisclosed reason. - However, setting the controlling tty on a dup causes rxvt to - hang when the parent does a dup since the controlling pgid changes. - Specifically testing for -2 (ctty has been setsid'ed) works around - this problem. However, it's difficult to see scenarios in which you - have a dup'able fd, no controlling tty, and not having run setsid. - So, we might want to consider getting rid of the set_ctty in tty-like dup - methods entirely at some point */ - if (myself->ctty != -2) - myself->set_ctty (this, flags); - report_tty_counts (child, "duped slave", ""); - return 0; -} - -int -fhandler_pty_master::dup (fhandler_base *child, int) -{ - report_tty_counts (child, "duped master", ""); - return 0; -} - -int -fhandler_pty_slave::tcgetattr (struct termios *t) -{ - *t = get_ttyp ()->ti; - return 0; -} - -int -fhandler_pty_slave::tcsetattr (int, const struct termios *t) -{ - acquire_output_mutex (INFINITE); - get_ttyp ()->ti = *t; - release_output_mutex (); - return 0; -} - -int -fhandler_pty_slave::tcflush (int queue) -{ - int ret = 0; - - termios_printf ("tcflush(%d) handle %p", queue, get_handle ()); - - if (queue == TCIFLUSH || queue == TCIOFLUSH) - { - size_t len = UINT_MAX; - read (NULL, len); - ret = ((int) len) >= 0 ? 0 : -1; - } - if (queue == TCOFLUSH || queue == TCIOFLUSH) - { - /* do nothing for now. */ - } - - termios_printf ("%d=tcflush(%d)", ret, queue); - return ret; -} - -int -fhandler_pty_slave::ioctl (unsigned int cmd, void *arg) -{ - termios_printf ("ioctl (%x)", cmd); - int res = fhandler_termios::ioctl (cmd, arg); - if (res <= 0) - return res; - - if (myself->pgid && get_ttyp ()->getpgid () != myself->pgid - && (unsigned) myself->ctty == FHDEV (DEV_PTYS_MAJOR, get_unit ()) - && (get_ttyp ()->ti.c_lflag & TOSTOP)) - { - /* background process */ - termios_printf ("bg ioctl pgid %d, tpgid %d, %s", myself->pgid, - get_ttyp ()->getpgid (), myctty ()); - raise (SIGTTOU); - } - - int retval; - switch (cmd) - { - case TIOCGWINSZ: - case TIOCSWINSZ: - break; - case TIOCGPGRP: - { - pid_t pid = this->tcgetpgrp (); - if (pid < 0) - retval = -1; - else - { - *((pid_t *) arg) = pid; - retval = 0; - } - } - goto out; - case TIOCSPGRP: - retval = this->tcsetpgrp ((pid_t) arg); - goto out; - case FIONREAD: - { - DWORD n; - if (!bytes_available (n)) - { - set_errno (EINVAL); - retval = -1; - } - else - { - *(int *) arg = (int) n; - retval = 0; - } - } - goto out; - default: - return fhandler_base::ioctl (cmd, arg); - } - - acquire_output_mutex (INFINITE); - - get_ttyp ()->cmd = cmd; - get_ttyp ()->ioctl_retval = 0; - switch (cmd) - { - case TIOCGWINSZ: - get_ttyp ()->arg.winsize = get_ttyp ()->winsize; - *(struct winsize *) arg = get_ttyp ()->arg.winsize; - get_ttyp ()->winsize = get_ttyp ()->arg.winsize; - break; - case TIOCSWINSZ: - if (get_ttyp ()->winsize.ws_row != ((struct winsize *) arg)->ws_row - || get_ttyp ()->winsize.ws_col != ((struct winsize *) arg)->ws_col) - { - get_ttyp ()->arg.winsize = *(struct winsize *) arg; - get_ttyp ()->winsize = *(struct winsize *) arg; - killsys (-get_ttyp ()->getpgid (), SIGWINCH); - } - break; - } - - release_output_mutex (); - retval = get_ttyp ()->ioctl_retval; - if (retval < 0) - { - set_errno (-retval); - retval = -1; - } - -out: - termios_printf ("%d = ioctl(%x)", retval, cmd); - return retval; -} - -int __stdcall -fhandler_pty_slave::fstat (struct __stat64 *st) -{ - fhandler_base::fstat (st); - - bool to_close = false; - if (!input_available_event) - { - char buf[MAX_PATH]; - shared_name (buf, INPUT_AVAILABLE_EVENT, get_unit ()); - input_available_event = OpenEvent (READ_CONTROL, TRUE, buf); - if (input_available_event) - to_close = true; - } - if (!input_available_event - || get_object_attribute (input_available_event, &st->st_uid, &st->st_gid, - &st->st_mode)) - { - /* If we can't access the ACL, or if the tty doesn't actually exist, - then fake uid and gid to strict, system-like values. */ - st->st_mode = S_IFCHR | S_IRUSR | S_IWUSR; - st->st_uid = 18; - st->st_gid = 544; - } - if (to_close) - CloseHandle (input_available_event); - return 0; -} - -/* Helper function for fchmod and fchown, which just opens all handles - and signals success via bool return. */ -bool -fhandler_pty_slave::fch_open_handles () -{ - char buf[MAX_PATH]; - - _tc = cygwin_shared->tty[get_unit ()]; - shared_name (buf, INPUT_AVAILABLE_EVENT, get_unit ()); - input_available_event = OpenEvent (READ_CONTROL | WRITE_DAC | WRITE_OWNER, - TRUE, buf); - output_mutex = get_ttyp ()->open_output_mutex (WRITE_DAC | WRITE_OWNER); - input_mutex = get_ttyp ()->open_input_mutex (WRITE_DAC | WRITE_OWNER); - inuse = get_ttyp ()->open_inuse (WRITE_DAC | WRITE_OWNER); - if (!input_available_event || !output_mutex || !input_mutex || !inuse) - { - __seterrno (); - return false; - } - return true; -} - -/* Helper function for fchmod and fchown, which sets the new security - descriptor on all objects representing the pty. */ -int -fhandler_pty_slave::fch_set_sd (security_descriptor &sd, bool chown) -{ - security_descriptor sd_old; - - get_object_sd (input_available_event, sd_old); - if (!set_object_sd (input_available_event, sd, chown) - && !set_object_sd (output_mutex, sd, chown) - && !set_object_sd (input_mutex, sd, chown) - && !set_object_sd (inuse, sd, chown)) - return 0; - set_object_sd (input_available_event, sd_old, chown); - set_object_sd (output_mutex, sd_old, chown); - set_object_sd (input_mutex, sd_old, chown); - set_object_sd (inuse, sd_old, chown); - return -1; -} - -/* Helper function for fchmod and fchown, which closes all object handles in - the pty. */ -void -fhandler_pty_slave::fch_close_handles () -{ - close_maybe (get_io_handle ()); - close_maybe (get_output_handle ()); - close_maybe (input_available_event); - close_maybe (output_mutex); - close_maybe (input_mutex); - close_maybe (inuse); -} - -int __stdcall -fhandler_pty_slave::fchmod (mode_t mode) -{ - int ret = -1; - bool to_close = false; - security_descriptor sd; - __uid32_t uid; - __gid32_t gid; - - if (!input_available_event) - { - to_close = true; - if (!fch_open_handles ()) - goto errout; - } - sd.malloc (sizeof (SECURITY_DESCRIPTOR)); - RtlCreateSecurityDescriptor (sd, SECURITY_DESCRIPTOR_REVISION); - if (!get_object_attribute (input_available_event, &uid, &gid, NULL) - && !create_object_sd_from_attribute (NULL, uid, gid, S_IFCHR | mode, sd)) - ret = fch_set_sd (sd, false); -errout: - if (to_close) - fch_close_handles (); - return ret; -} - -int __stdcall -fhandler_pty_slave::fchown (__uid32_t uid, __gid32_t gid) -{ - int ret = -1; - bool to_close = false; - mode_t mode = 0; - __uid32_t o_uid; - __gid32_t o_gid; - security_descriptor sd; - - if (uid == ILLEGAL_UID && gid == ILLEGAL_GID) - return 0; - if (!input_available_event) - { - to_close = true; - if (!fch_open_handles ()) - goto errout; - } - sd.malloc (sizeof (SECURITY_DESCRIPTOR)); - RtlCreateSecurityDescriptor (sd, SECURITY_DESCRIPTOR_REVISION); - if (!get_object_attribute (input_available_event, &o_uid, &o_gid, &mode)) - { - if ((uid == ILLEGAL_UID || uid == o_uid) - && (gid == ILLEGAL_GID || gid == o_gid)) - ret = 0; - else if (!create_object_sd_from_attribute (input_available_event, - uid, gid, S_IFCHR | mode, sd)) - ret = fch_set_sd (sd, true); - } -errout: - if (to_close) - fch_close_handles (); - return ret; -} - -/******************************************************* - fhandler_pty_master -*/ -fhandler_pty_master::fhandler_pty_master (int unit) - : fhandler_pty_common (), pktmode (0), master_ctl (NULL), - master_thread (NULL), from_master (NULL), to_master (NULL), - dwProcessId (0), need_nl (0) -{ - if (unit >= 0) - dev ().parse (DEV_PTYM_MAJOR, unit); - else if (!setup ()) - { - dev ().parse (FH_ERROR); - return; - } - set_name ("/dev/ptmx"); -} - -int -fhandler_pty_master::open (int flags, mode_t) -{ - set_open_status (); - dwProcessId = GetCurrentProcessId (); - return 1; -} - -void -fhandler_pty_master::open_setup (int flags) -{ - set_flags ((flags & ~O_TEXT) | O_BINARY); - char buf[sizeof ("opened pty master for ptyNNNNNNNNNNN")]; - __small_sprintf (buf, "opened pty master for pty%d", get_unit ()); - report_tty_counts (this, buf, ""); -} - -_off64_t -fhandler_pty_common::lseek (_off64_t, int) -{ - set_errno (ESPIPE); - return -1; -} - -int -fhandler_pty_common::close () -{ - termios_printf ("pty%d <%p,%p> closing", get_unit (), get_handle (), get_output_handle ()); - if (!ForceCloseHandle (input_mutex)) - termios_printf ("CloseHandle (input_mutex<%p>), %E", input_mutex); - if (!ForceCloseHandle (output_mutex)) - termios_printf ("CloseHandle (output_mutex<%p>), %E", output_mutex); - if (!ForceCloseHandle1 (get_handle (), from_pty)) - termios_printf ("CloseHandle (get_handle ()<%p>), %E", get_handle ()); - if (!ForceCloseHandle1 (get_output_handle (), to_pty)) - termios_printf ("CloseHandle (get_output_handle ()<%p>), %E", get_output_handle ()); - - return 0; -} - -void -fhandler_pty_master::cleanup () -{ - report_tty_counts (this, "closing master", ""); - if (archetype) - from_master = to_master = NULL; -} - -int -fhandler_pty_master::close () -{ - termios_printf ("closing from_master(%p)/to_master(%p) since we own them(%d)", - from_master, to_master, dwProcessId); - if (cygwin_finished_initializing) - { - if (master_ctl && get_ttyp ()->master_pid == myself->pid) - { - char buf[MAX_PATH]; - pipe_request req = { (DWORD) -1 }; - pipe_reply repl; - DWORD len; - - __small_sprintf (buf, "\\\\.\\pipe\\cygwin-%S-pty%d-master-ctl", - &cygheap->installation_key, get_unit ()); - CallNamedPipe (buf, &req, sizeof req, &repl, sizeof repl, &len, 500); - CloseHandle (master_ctl); - master_thread->detach (); - } - } - - if (!ForceCloseHandle (from_master)) - termios_printf ("error closing from_master %p, %E", from_master); - if (!ForceCloseHandle (to_master)) - termios_printf ("error closing from_master %p, %E", to_master); - from_master = to_master = NULL; - - fhandler_pty_common::close (); - - if (have_execed || get_ttyp ()->master_pid != myself->pid) - termios_printf ("not clearing: %d, master_pid %d", have_execed, get_ttyp ()->master_pid); - else - { - get_ttyp ()->set_master_closed (); - SetEvent (input_available_event); - } - if (!ForceCloseHandle (input_available_event)) - termios_printf ("CloseHandle (input_available_event<%p>), %E", input_available_event); - - return 0; -} - -/* This is just to catch error conditions. Since the constructor - actually opens some handles, and stat() does not open an fd, they need - to be closed when the fhandler goes away. */ -fhandler_pty_master::~fhandler_pty_master () -{ - if (from_master && to_master) - close_with_arch (); -} - -ssize_t __stdcall -fhandler_pty_master::write (const void *ptr, size_t len) -{ - int i; - char *p = (char *) ptr; - termios ti = tc ()->ti; - - bg_check_types bg = bg_check (SIGTTOU); - if (bg <= bg_eof) - return (ssize_t) bg; - - push_process_state process_state (PID_TTYOU); - - for (i = 0; i < (int) len; i++) - { - line_edit_status status = line_edit (p++, 1, ti); - if (status > line_edit_signalled) - { - if (status != line_edit_pipe_full) - i = -1; - break; - } - } - return i; -} - -void __stdcall -fhandler_pty_master::read (void *ptr, size_t& len) -{ - bg_check_types bg = bg_check (SIGTTIN); - if (bg <= bg_eof) - { - len = (size_t) bg; - return; - } - push_process_state process_state (PID_TTYIN); - len = (size_t) process_slave_output ((char *) ptr, len, pktmode); -} - -int -fhandler_pty_master::tcgetattr (struct termios *t) -{ - *t = cygwin_shared->tty[get_unit ()]->ti; - return 0; -} - -int -fhandler_pty_master::tcsetattr (int, const struct termios *t) -{ - cygwin_shared->tty[get_unit ()]->ti = *t; - return 0; -} - -int -fhandler_pty_master::tcflush (int queue) -{ - int ret = 0; - - termios_printf ("tcflush(%d) handle %p", queue, get_handle ()); - - if (queue == TCIFLUSH || queue == TCIOFLUSH) - ret = process_slave_output (NULL, OUT_BUFFER_SIZE, 0); - else if (queue == TCIFLUSH || queue == TCIOFLUSH) - { - /* do nothing for now. */ - } - - termios_printf ("%d=tcflush(%d)", ret, queue); - return ret; -} - -int -fhandler_pty_master::ioctl (unsigned int cmd, void *arg) -{ - int res = fhandler_termios::ioctl (cmd, arg); - if (res <= 0) - return res; - - switch (cmd) - { - case TIOCPKT: - pktmode = *(int *) arg; - break; - case TIOCGWINSZ: - *(struct winsize *) arg = get_ttyp ()->winsize; - break; - case TIOCSWINSZ: - if (get_ttyp ()->winsize.ws_row != ((struct winsize *) arg)->ws_row - || get_ttyp ()->winsize.ws_col != ((struct winsize *) arg)->ws_col) - { - get_ttyp ()->winsize = *(struct winsize *) arg; - killsys (-get_ttyp ()->getpgid (), SIGWINCH); - } - break; - case TIOCGPGRP: - *((pid_t *) arg) = this->tcgetpgrp (); - break; - case TIOCSPGRP: - return this->tcsetpgrp ((pid_t) arg); - case FIONREAD: - { - DWORD n; - if (!::bytes_available (n, to_master)) - { - set_errno (EINVAL); - return -1; - } - *(int *) arg = (int) n; - } - break; - default: - return fhandler_base::ioctl (cmd, arg); - } - return 0; -} - -int -fhandler_pty_master::ptsname_r (char *buf, size_t buflen) -{ - char tmpbuf[TTY_NAME_MAX]; - - __ptsname (tmpbuf, get_unit ()); - if (buflen <= strlen (tmpbuf)) - { - set_errno (ERANGE); - return ERANGE; - } - strcpy (buf, tmpbuf); - return 0; -} - -void -fhandler_pty_common::set_close_on_exec (bool val) -{ - // Cygwin processes will handle this specially on exec. - close_on_exec (val); -} - -void -fhandler_pty_slave::fixup_after_fork (HANDLE parent) -{ - // fork_fixup (parent, inuse, "inuse"); - // fhandler_pty_common::fixup_after_fork (parent); - report_tty_counts (this, "inherited", ""); -} - -void -fhandler_pty_slave::fixup_after_exec () -{ - if (!close_on_exec ()) - fixup_after_fork (NULL); -} - -/* This thread function handles the master control pipe. It waits for a - client to connect. Then it checks if the client process has permissions - to access the tty handles. If so, it opens the client process and - duplicates the handles into that process. If that fails, it sends a reply - with at least one handle set to NULL and an error code. Last but not - least, the client is disconnected and the thread waits for the next client. - - A special case is when the master side of the tty is about to be closed. - The client side is the fhandler_pty_master::close function and it sends - a PID -1 in that case. On Vista and later a check is performed that the - request to leave really comes from the master process itself. On earlier - OSes there's no function to check for the PID of the client process so - we have to trust the client side. - - Since there's always only one pipe instance, there's a chance that clients - have to wait to connect to the master control pipe. Therefore the client - calls to CallNamedPipe should have a big enough timeout value. For now this - is 500ms. Hope that's enough. */ - -DWORD -fhandler_pty_master::pty_master_thread () -{ - bool exit = false; - GENERIC_MAPPING map = { EVENT_QUERY_STATE, EVENT_MODIFY_STATE, 0, - EVENT_QUERY_STATE | EVENT_MODIFY_STATE }; - pipe_request req; - DWORD len; - security_descriptor sd; - HANDLE token; - PRIVILEGE_SET ps; - DWORD pid; - NTSTATUS status; - - termios_printf ("Entered"); - while (!exit && (ConnectNamedPipe (master_ctl, NULL) - || GetLastError () == ERROR_PIPE_CONNECTED)) - { - pipe_reply repl = { NULL, NULL, 0 }; - bool deimp = false; - NTSTATUS allow = STATUS_ACCESS_DENIED; - ACCESS_MASK access = EVENT_MODIFY_STATE; - HANDLE client = NULL; - - if (!ReadFile (master_ctl, &req, sizeof req, &len, NULL)) - { - termios_printf ("ReadFile, %E"); - goto reply; - } - /* This function is only available since Vista, unfortunately. - In earlier OSes we simply have to believe that the client - has no malicious intent (== sends arbitrary PIDs). */ - if (!GetNamedPipeClientProcessId (master_ctl, &pid)) - pid = req.pid; - if (get_object_sd (input_available_event, sd)) - { - termios_printf ("get_object_sd, %E"); - goto reply; - } - cygheap->user.deimpersonate (); - deimp = true; - if (!ImpersonateNamedPipeClient (master_ctl)) - { - termios_printf ("ImpersonateNamedPipeClient, %E"); - goto reply; - } - status = NtOpenThreadToken (GetCurrentThread (), TOKEN_QUERY, TRUE, - &token); - if (!NT_SUCCESS (status)) - { - termios_printf ("NtOpenThreadToken, %p", status); - SetLastError (RtlNtStatusToDosError (status)); - goto reply; - } - len = sizeof ps; - status = NtAccessCheck (sd, token, access, &map, &ps, &len, &access, - &allow); - NtClose (token); - if (!NT_SUCCESS (status)) - { - termios_printf ("NtAccessCheck, %p", status); - SetLastError (RtlNtStatusToDosError (status)); - goto reply; - } - if (!RevertToSelf ()) - { - termios_printf ("RevertToSelf, %E"); - goto reply; - } - if (req.pid == (DWORD) -1) /* Request to finish thread. */ - { - /* Pre-Vista: Just believe in the good of the client process. - Post-Vista: Check if the requesting process is the master - process itself. */ - if (pid == (DWORD) -1 || pid == GetCurrentProcessId ()) - exit = true; - goto reply; - } - if (NT_SUCCESS (allow)) - { - client = OpenProcess (PROCESS_DUP_HANDLE, FALSE, pid); - if (!client) - { - termios_printf ("OpenProcess, %E"); - goto reply; - } - if (!DuplicateHandle (GetCurrentProcess (), from_master, - client, &repl.from_master, - 0, TRUE, DUPLICATE_SAME_ACCESS)) - { - termios_printf ("DuplicateHandle (from_master), %E"); - goto reply; - } - if (!DuplicateHandle (GetCurrentProcess (), to_master, - client, &repl.to_master, - 0, TRUE, DUPLICATE_SAME_ACCESS)) - { - termios_printf ("DuplicateHandle (to_master), %E"); - goto reply; - } - } -reply: - repl.error = GetLastError (); - if (client) - CloseHandle (client); - if (deimp) - cygheap->user.reimpersonate (); - sd.free (); - termios_printf ("Reply: from %p, to %p, error %lu", - repl.from_master, repl.to_master, repl.error ); - if (!WriteFile (master_ctl, &repl, sizeof repl, &len, NULL)) - termios_printf ("WriteFile, %E"); - if (!DisconnectNamedPipe (master_ctl)) - termios_printf ("DisconnectNamedPipe, %E"); - } - termios_printf ("Leaving"); - return 0; -} - -static DWORD WINAPI -pty_master_thread (VOID *arg) -{ - return ((fhandler_pty_master *) arg)->pty_master_thread (); -} - -bool -fhandler_pty_master::setup () -{ - int res; - security_descriptor sd; - SECURITY_ATTRIBUTES sa = { sizeof (SECURITY_ATTRIBUTES), NULL, TRUE }; - - /* Find an unallocated pty to use. */ - int unit = cygwin_shared->tty.allocate (from_master, get_output_handle ()); - if (unit < 0) - return false; - - ProtectHandle1 (get_output_handle (), to_pty); - - tty& t = *cygwin_shared->tty[unit]; - _tc = (tty_min *) &t; - - tcinit (true); /* Set termios information. Force initialization. */ - - const char *errstr = NULL; - DWORD pipe_mode = PIPE_NOWAIT; - - if (!SetNamedPipeHandleState (get_output_handle (), &pipe_mode, NULL, NULL)) - termios_printf ("can't set output_handle(%p) to non-blocking mode", - get_output_handle ()); - - char pipename[sizeof("ptyNNNN-from-master")]; - __small_sprintf (pipename, "pty%d-to-master", unit); - res = fhandler_pipe::create (&sec_none, &get_io_handle (), &to_master, - fhandler_pty_common::pipesize, pipename, 0); - if (res) - { - errstr = "output pipe"; - goto err; - } - - ProtectHandle1 (get_io_handle (), from_pty); - - /* Create security attribute. Default permissions are 0620. */ - sd.malloc (sizeof (SECURITY_DESCRIPTOR)); - RtlCreateSecurityDescriptor (sd, SECURITY_DESCRIPTOR_REVISION); - if (!create_object_sd_from_attribute (NULL, myself->uid, myself->gid, - S_IFCHR | S_IRUSR | S_IWUSR | S_IWGRP, - sd)) - sa.lpSecurityDescriptor = (PSECURITY_DESCRIPTOR) sd; - - /* Carefully check that the input_available_event didn't already exist. - This is a measure to make sure that the event security descriptor - isn't occupied by a malicious process. We must make sure that the - event's security descriptor is what we expect it to be. */ - if (!(input_available_event = t.get_event (errstr = INPUT_AVAILABLE_EVENT, - &sa, TRUE)) - || GetLastError () == ERROR_ALREADY_EXISTS) - goto err; - - char buf[MAX_PATH]; - errstr = shared_name (buf, OUTPUT_MUTEX, unit); - if (!(output_mutex = CreateMutex (&sa, FALSE, buf))) - goto err; - - errstr = shared_name (buf, INPUT_MUTEX, unit); - if (!(input_mutex = CreateMutex (&sa, FALSE, buf))) - goto err; - - /* Create master control pipe which allows the master to duplicate - the pty pipe handles to processes which deserve it. */ - __small_sprintf (buf, "\\\\.\\pipe\\cygwin-%S-pty%d-master-ctl", - &cygheap->installation_key, unit); - master_ctl = CreateNamedPipe (buf, PIPE_ACCESS_DUPLEX, - PIPE_WAIT | PIPE_TYPE_MESSAGE - | PIPE_READMODE_MESSAGE, 1, 4096, 4096, - 0, &sec_all_nih); - if (master_ctl == INVALID_HANDLE_VALUE) - { - errstr = "pty master control pipe"; - goto err; - } - master_thread = new cygthread (::pty_master_thread, this, "ptym"); - if (!master_thread) - { - errstr = "pty master control thread"; - goto err; - } - - t.from_master = from_master; - t.to_master = to_master; - t.winsize.ws_col = 80; - t.winsize.ws_row = 25; - t.master_pid = myself->pid; - - dev ().parse (DEV_PTYM_MAJOR, unit); - - termios_printf ("this %p, pty%d opened - from_pty %p, to_pty %p", this, unit, - get_io_handle (), get_output_handle ()); - return true; - -err: - __seterrno (); - close_maybe (get_io_handle ()); - close_maybe (get_output_handle ()); - close_maybe (input_available_event); - close_maybe (output_mutex); - close_maybe (input_mutex); - close_maybe (from_master); - close_maybe (to_master); - close_maybe (master_ctl); - termios_printf ("pty%d open failed - failed to create %s", unit, errstr); - return false; -} - -void -fhandler_pty_master::fixup_after_fork (HANDLE parent) -{ - DWORD wpid = GetCurrentProcessId (); - fhandler_pty_master *arch = (fhandler_pty_master *) archetype; - if (arch->dwProcessId != wpid) - { - tty& t = *get_ttyp (); - if (myself->pid == t.master_pid) - { - t.from_master = arch->from_master; - t.to_master = arch->to_master; - } - arch->dwProcessId = wpid; - } - from_master = arch->from_master; - to_master = arch->to_master; - report_tty_counts (this, "inherited master", ""); -} - -void -fhandler_pty_master::fixup_after_exec () -{ - if (!close_on_exec ()) - fixup_after_fork (spawn_info->parent); - else - from_master = to_master = NULL; -} |