TIOCPKT mode of PTY is broken if ONLCR bit is cleared.
* tty.h (class tty_min): Remove variable "write_error" to which any errors are not currently set at anywhere. (class tty): Add variable "column" for handling ONOCR. * tty.cc (tty::init): Add initialization code for variable "column". * fhandler.h (class fhandler_pty_master): Remove variable "need_nl" which is not necessary any more. "need_nl" was needed by OPOST process in fhandler_pty_master::process_slave_output(). (class fhandler_pty_common): Add function process_opost_output() for handling post processing for OPOST in write process. * fhandler_tty.cc (fhandler_pty_master::process_slave_output): Count TIOCPKT control byte into length to be read in TIOCPKT mode. Move post processing for OPOST to write process. Remove code related to variable "write_error". Return with EIO error if slave is already closed. (fhandler_pty_master::fhandler_pty_master): Remove initialization code for variable "need_nl". (fhandler_pty_common::process_opost_output): Add this function for handling of OPOST in write process. Add code to avoid blocking in non-blocking mode when output is suspended by ^S. (fhandler_pty_slave::write): Call fhandler_pty_common:: process_opost_output() instead of WriteFile(). Remove code related to variable "write_error". (fhandler_pty_master::doecho): Call fhandler_pty_common:: process_opost_output() instead of WriteFile(). * select.cc (peek_pipe): Remove code related to variable "need_nl". Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
This commit is contained in:
parent
d70f57112f
commit
c596f5b73c
|
@ -1,3 +1,31 @@
|
||||||
|
2015-03-25 Takashi Yano <takashi.yano@nifty.ne.jp>
|
||||||
|
|
||||||
|
* tty.h (class tty_min): Remove variable "write_error" to which any
|
||||||
|
errors are not currently set at anywhere.
|
||||||
|
(class tty): Add variable "column" for handling ONOCR.
|
||||||
|
* tty.cc (tty::init): Add initialization code for variable "column".
|
||||||
|
* fhandler.h (class fhandler_pty_master): Remove variable "need_nl"
|
||||||
|
which is not necessary any more. "need_nl" was needed by OPOST process
|
||||||
|
in fhandler_pty_master::process_slave_output().
|
||||||
|
(class fhandler_pty_common): Add function process_opost_output() for
|
||||||
|
handling post processing for OPOST in write process.
|
||||||
|
* fhandler_tty.cc (fhandler_pty_master::process_slave_output): Count
|
||||||
|
TIOCPKT control byte into length to be read in TIOCPKT mode. Move
|
||||||
|
post processing for OPOST to write process. Remove code related to
|
||||||
|
variable "write_error". Return with EIO error if slave is already
|
||||||
|
closed.
|
||||||
|
(fhandler_pty_master::fhandler_pty_master): Remove initialization
|
||||||
|
code for variable "need_nl".
|
||||||
|
(fhandler_pty_common::process_opost_output): Add this function for
|
||||||
|
handling of OPOST in write process. Add code to avoid blocking in
|
||||||
|
non-blocking mode when output is suspended by ^S.
|
||||||
|
(fhandler_pty_slave::write): Call fhandler_pty_common::
|
||||||
|
process_opost_output() instead of WriteFile(). Remove code related to
|
||||||
|
variable "write_error".
|
||||||
|
(fhandler_pty_master::doecho): Call fhandler_pty_common::
|
||||||
|
process_opost_output() instead of WriteFile().
|
||||||
|
* select.cc (peek_pipe): Remove code related to variable "need_nl".
|
||||||
|
|
||||||
2015-03-24 Corinna Vinschen <corinna@vinschen.de>
|
2015-03-24 Corinna Vinschen <corinna@vinschen.de>
|
||||||
|
|
||||||
Per glibc BZ #15366:
|
Per glibc BZ #15366:
|
||||||
|
|
|
@ -1508,6 +1508,9 @@ class fhandler_pty_common: public fhandler_termios
|
||||||
copyto (fh);
|
copyto (fh);
|
||||||
return fh;
|
return fh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
BOOL process_opost_output (HANDLE h, const void *ptr, ssize_t& len, bool is_echo);
|
||||||
};
|
};
|
||||||
|
|
||||||
class fhandler_pty_slave: public fhandler_pty_common
|
class fhandler_pty_slave: public fhandler_pty_common
|
||||||
|
@ -1574,8 +1577,6 @@ class fhandler_pty_master: public fhandler_pty_common
|
||||||
DWORD dwProcessId; // Owner of master handles
|
DWORD dwProcessId; // Owner of master handles
|
||||||
|
|
||||||
public:
|
public:
|
||||||
int need_nl; // Next read should start with \n
|
|
||||||
|
|
||||||
HANDLE get_echo_handle () const { return echo_r; }
|
HANDLE get_echo_handle () const { return echo_r; }
|
||||||
/* Constructor */
|
/* Constructor */
|
||||||
fhandler_pty_master (int);
|
fhandler_pty_master (int);
|
||||||
|
|
|
@ -145,7 +145,8 @@ fhandler_pty_common::__release_output_mutex (const char *fn, int ln)
|
||||||
void
|
void
|
||||||
fhandler_pty_master::doecho (const void *str, DWORD len)
|
fhandler_pty_master::doecho (const void *str, DWORD len)
|
||||||
{
|
{
|
||||||
if (!WriteFile (echo_w, str, len, &len, NULL))
|
ssize_t towrite = len;
|
||||||
|
if (!process_opost_output (echo_w, str, towrite, true))
|
||||||
termios_printf ("Write to echo pipe failed, %E");
|
termios_printf ("Write to echo pipe failed, %E");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,10 +218,9 @@ int
|
||||||
fhandler_pty_master::process_slave_output (char *buf, size_t len, int pktmode_on)
|
fhandler_pty_master::process_slave_output (char *buf, size_t len, int pktmode_on)
|
||||||
{
|
{
|
||||||
size_t rlen;
|
size_t rlen;
|
||||||
char outbuf[OUT_BUFFER_SIZE + 1];
|
char outbuf[OUT_BUFFER_SIZE];
|
||||||
DWORD n;
|
DWORD n;
|
||||||
DWORD echo_cnt;
|
DWORD echo_cnt;
|
||||||
int column = 0;
|
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
flush_to_slave ();
|
flush_to_slave ();
|
||||||
|
@ -228,34 +228,8 @@ fhandler_pty_master::process_slave_output (char *buf, size_t len, int pktmode_on
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
goto out;
|
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 (;;)
|
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 = echo_cnt = 0;
|
n = echo_cnt = 0;
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
|
@ -267,7 +241,11 @@ fhandler_pty_master::process_slave_output (char *buf, size_t len, int pktmode_on
|
||||||
if (n)
|
if (n)
|
||||||
break;
|
break;
|
||||||
if (hit_eof ())
|
if (hit_eof ())
|
||||||
|
{
|
||||||
|
set_errno (EIO);
|
||||||
|
rc = -1;
|
||||||
goto out;
|
goto out;
|
||||||
|
}
|
||||||
/* DISCARD (FLUSHO) and tcflush can finish here. */
|
/* DISCARD (FLUSHO) and tcflush can finish here. */
|
||||||
if ((get_ttyp ()->ti.c_lflag & FLUSHO || !buf))
|
if ((get_ttyp ()->ti.c_lflag & FLUSHO || !buf))
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -289,6 +267,26 @@ fhandler_pty_master::process_slave_output (char *buf, size_t len, int pktmode_on
|
||||||
flush_to_slave ();
|
flush_to_slave ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Set RLEN to the number of bytes to read from the pipe. */
|
||||||
|
rlen = len;
|
||||||
|
|
||||||
|
char *optr;
|
||||||
|
optr = buf;
|
||||||
|
if (pktmode_on && buf)
|
||||||
|
{
|
||||||
|
*optr++ = TIOCPKT_DATA;
|
||||||
|
rlen -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rlen == 0)
|
||||||
|
{
|
||||||
|
rc = optr - buf;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rlen > sizeof outbuf)
|
||||||
|
rlen = sizeof outbuf;
|
||||||
|
|
||||||
/* If echo pipe has data (something has been typed or pasted), prefer
|
/* If echo pipe has data (something has been typed or pasted), prefer
|
||||||
it over slave output. */
|
it over slave output. */
|
||||||
if (echo_cnt > 0)
|
if (echo_cnt > 0)
|
||||||
|
@ -306,68 +304,12 @@ fhandler_pty_master::process_slave_output (char *buf, size_t len, int pktmode_on
|
||||||
}
|
}
|
||||||
|
|
||||||
termios_printf ("bytes read %u", n);
|
termios_printf ("bytes read %u", n);
|
||||||
get_ttyp ()->write_error = 0;
|
|
||||||
|
|
||||||
if (get_ttyp ()->ti.c_lflag & FLUSHO || !buf)
|
if (get_ttyp ()->ti.c_lflag & FLUSHO || !buf)
|
||||||
continue;
|
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);
|
memcpy (optr, outbuf, n);
|
||||||
optr += 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: %u unexpected characters", n);
|
|
||||||
need_nl = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
*optr++ = *iptr++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rc = optr - buf;
|
rc = optr - buf;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -639,7 +581,6 @@ fhandler_pty_slave::init (HANDLE h, DWORD a, mode_t)
|
||||||
ssize_t __stdcall
|
ssize_t __stdcall
|
||||||
fhandler_pty_slave::write (const void *ptr, size_t len)
|
fhandler_pty_slave::write (const void *ptr, size_t len)
|
||||||
{
|
{
|
||||||
DWORD n;
|
|
||||||
ssize_t towrite = len;
|
ssize_t towrite = len;
|
||||||
|
|
||||||
bg_check_types bg = bg_check (SIGTTOU);
|
bg_check_types bg = bg_check (SIGTTOU);
|
||||||
|
@ -650,29 +591,7 @@ fhandler_pty_slave::write (const void *ptr, size_t len)
|
||||||
|
|
||||||
push_process_state process_state (PID_TTYOU);
|
push_process_state process_state (PID_TTYOU);
|
||||||
|
|
||||||
while (len)
|
if (!process_opost_output (get_output_handle (), ptr, towrite, false))
|
||||||
{
|
|
||||||
n = MIN (OUT_BUFFER_SIZE, len);
|
|
||||||
char *buf = (char *)ptr;
|
|
||||||
ptr = (char *) ptr + n;
|
|
||||||
len -= n;
|
|
||||||
|
|
||||||
while (tc ()->output_stopped)
|
|
||||||
cygwait (10);
|
|
||||||
|
|
||||||
/* 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 = -1;
|
|
||||||
get_ttyp ()->write_error = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOL res = WriteFile (get_output_handle (), buf, n, &n, NULL);
|
|
||||||
if (!res)
|
|
||||||
{
|
{
|
||||||
DWORD err = GetLastError ();
|
DWORD err = GetLastError ();
|
||||||
termios_printf ("WriteFile failed, %E");
|
termios_printf ("WriteFile failed, %E");
|
||||||
|
@ -685,8 +604,6 @@ fhandler_pty_slave::write (const void *ptr, size_t len)
|
||||||
}
|
}
|
||||||
raise (SIGHUP); /* FIXME: Should this be SIGTTOU? */
|
raise (SIGHUP); /* FIXME: Should this be SIGTTOU? */
|
||||||
towrite = -1;
|
towrite = -1;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return towrite;
|
return towrite;
|
||||||
}
|
}
|
||||||
|
@ -1225,7 +1142,7 @@ errout:
|
||||||
fhandler_pty_master::fhandler_pty_master (int unit)
|
fhandler_pty_master::fhandler_pty_master (int unit)
|
||||||
: fhandler_pty_common (), pktmode (0), master_ctl (NULL),
|
: fhandler_pty_common (), pktmode (0), master_ctl (NULL),
|
||||||
master_thread (NULL), from_master (NULL), to_master (NULL),
|
master_thread (NULL), from_master (NULL), to_master (NULL),
|
||||||
echo_r (NULL), echo_w (NULL), dwProcessId (0), need_nl (0)
|
echo_r (NULL), echo_w (NULL), dwProcessId (0)
|
||||||
{
|
{
|
||||||
if (unit >= 0)
|
if (unit >= 0)
|
||||||
dev ().parse (DEV_PTYM_MAJOR, unit);
|
dev ().parse (DEV_PTYM_MAJOR, unit);
|
||||||
|
@ -1783,3 +1700,93 @@ fhandler_pty_master::fixup_after_exec ()
|
||||||
else
|
else
|
||||||
from_master = to_master = NULL;
|
from_master = to_master = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr, ssize_t& len, bool is_echo)
|
||||||
|
{
|
||||||
|
ssize_t towrite = len;
|
||||||
|
BOOL res = TRUE;
|
||||||
|
while (towrite)
|
||||||
|
{
|
||||||
|
if (!is_echo)
|
||||||
|
{
|
||||||
|
if (tc ()->output_stopped && is_nonblocking ())
|
||||||
|
{
|
||||||
|
if (towrite < len)
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
set_errno(EAGAIN);
|
||||||
|
len = -1;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (tc ()->output_stopped)
|
||||||
|
cygwait (10);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(get_ttyp ()->ti.c_oflag & OPOST)) // raw output mode
|
||||||
|
{
|
||||||
|
DWORD n = MIN (OUT_BUFFER_SIZE, towrite);
|
||||||
|
res = WriteFile (h, ptr, n, &n, NULL);
|
||||||
|
if (!res)
|
||||||
|
break;
|
||||||
|
ptr = (char *) ptr + n;
|
||||||
|
towrite -= n;
|
||||||
|
}
|
||||||
|
else // post-process output
|
||||||
|
{
|
||||||
|
char outbuf[OUT_BUFFER_SIZE + 1];
|
||||||
|
char *buf = (char *)ptr;
|
||||||
|
DWORD n = 0;
|
||||||
|
ssize_t rc = 0;
|
||||||
|
acquire_output_mutex (INFINITE);
|
||||||
|
while (n < OUT_BUFFER_SIZE && rc < towrite)
|
||||||
|
{
|
||||||
|
switch (buf[rc])
|
||||||
|
{
|
||||||
|
case '\r':
|
||||||
|
if ((get_ttyp ()->ti.c_oflag & ONOCR)
|
||||||
|
&& get_ttyp ()->column == 0)
|
||||||
|
{
|
||||||
|
rc++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (get_ttyp ()->ti.c_oflag & OCRNL)
|
||||||
|
{
|
||||||
|
outbuf[n++] = '\n';
|
||||||
|
rc++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
outbuf[n++] = buf[rc++];
|
||||||
|
get_ttyp ()->column = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '\n':
|
||||||
|
if (get_ttyp ()->ti.c_oflag & ONLCR)
|
||||||
|
{
|
||||||
|
outbuf[n++] = '\r';
|
||||||
|
get_ttyp ()->column = 0;
|
||||||
|
}
|
||||||
|
if (get_ttyp ()->ti.c_oflag & ONLRET)
|
||||||
|
get_ttyp ()->column = 0;
|
||||||
|
outbuf[n++] = buf[rc++];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
outbuf[n++] = buf[rc++];
|
||||||
|
get_ttyp ()->column++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
release_output_mutex ();
|
||||||
|
res = WriteFile (h, outbuf, n, &n, NULL);
|
||||||
|
if (!res)
|
||||||
|
break;
|
||||||
|
ptr = (char *) ptr + rc;
|
||||||
|
towrite -= rc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
len -= towrite;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
|
@ -18,3 +18,7 @@ Bug Fixes
|
||||||
|
|
||||||
- Fix a name change from symlink to target name in calls to execvp, system, etc.
|
- Fix a name change from symlink to target name in calls to execvp, system, etc.
|
||||||
Addresses: https://cygwin.com/ml/cygwin/2015-03/msg00270.html
|
Addresses: https://cygwin.com/ml/cygwin/2015-03/msg00270.html
|
||||||
|
|
||||||
|
- Fix internal error in pty -ONLCR handling. Fix timing bug in pty OPOST
|
||||||
|
handling.
|
||||||
|
Addresses: https://cygwin.com/ml/cygwin/2015-02/msg00929.html
|
||||||
|
|
|
@ -604,11 +604,6 @@ peek_pipe (select_record *s, bool from_select)
|
||||||
{
|
{
|
||||||
fhandler_pty_master *fhm = (fhandler_pty_master *) fh;
|
fhandler_pty_master *fhm = (fhandler_pty_master *) fh;
|
||||||
fhm->flush_to_slave ();
|
fhm->flush_to_slave ();
|
||||||
if (fhm->need_nl)
|
|
||||||
{
|
|
||||||
gotone = s->read_ready = true;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -237,6 +237,7 @@ tty::init ()
|
||||||
was_opened = false;
|
was_opened = false;
|
||||||
master_pid = 0;
|
master_pid = 0;
|
||||||
is_console = false;
|
is_console = false;
|
||||||
|
column = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
HANDLE
|
HANDLE
|
||||||
|
|
|
@ -67,7 +67,6 @@ public:
|
||||||
* -ERRNO
|
* -ERRNO
|
||||||
*/
|
*/
|
||||||
int ioctl_retval;
|
int ioctl_retval;
|
||||||
int write_error;
|
|
||||||
|
|
||||||
void setntty (_major_t t, _minor_t n) {ntty = (fh_devices) FHDEV (t, n);}
|
void setntty (_major_t t, _minor_t n) {ntty = (fh_devices) FHDEV (t, n);}
|
||||||
dev_t getntty () const {return ntty;}
|
dev_t getntty () const {return ntty;}
|
||||||
|
@ -117,6 +116,7 @@ public:
|
||||||
|
|
||||||
int read_retval;
|
int read_retval;
|
||||||
bool was_opened; /* True if opened at least once. */
|
bool was_opened; /* True if opened at least once. */
|
||||||
|
int column; /* Current Column */
|
||||||
|
|
||||||
void init ();
|
void init ();
|
||||||
HANDLE open_inuse (ACCESS_MASK access);
|
HANDLE open_inuse (ACCESS_MASK access);
|
||||||
|
|
Loading…
Reference in New Issue