mixing O_NONBLOCK and raw tty causes portability problems
Matthias Drochner
M.Drochner@fz-juelich.de
Wed, 15 Oct 2003 12:45:09 +0200
This is a multipart MIME message.
--==_Exmh_10149248080450
Content-Type: text/plain; charset=us-ascii
Hi -
I thought I'd give lsh a try, just to see how it compares to openssh...
The client didn't work well on NetBSD, got a message like "unexpected
EWOULDBLOCK" on each keystroke.
Looked a bit deeper and found that stdin is set to O_NONBLOCK and
a raw tty mode with c_cc[VMIN] > 1 and c_cc[VTIME] > 0.
I'll append a little test program which does the same. I've tried
it on 3 operating systems (Linux, NetBSD, Digital UNIX), and it
behaves differently on each:
-on Linux, if a key is pressed, the read returns immediately with
that one character
-on NetBSD, the read returns with no data but EWOULDBLOCK
-on D'UNIX, the poll() doesn't teturn before 4 keypresses are done;
the read() returns these 4 characters
Indeed, in SUSv2's termios page is a sentence which says that if
both O_NONBLOCK and VTIME>0 are set, the behaviour is more or less
undefined.
I've solved my immediate problems by setting VMIN to 1 instead of 4
in unix_interact.c:do_make_raw(), but VTIME is still pointless,
so I wouldn't call this a clean solution.
(Don't know what liboop uses under the hood, but in case it does
poll(), anything with VMIN>1 wouldn't work with D'Unix...)
best regards
Matthias
--==_Exmh_10149248080450
Content-Type: text/plain ; name="ttytest.c"; charset=us-ascii
Content-Description: ttytest.c
Content-Disposition: attachment; filename="ttytest.c"
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#include <poll.h>
#include <string.h>
#include <errno.h>
struct termios tsav;
void
dump(fd, save)
int fd;
{
struct termios t;
int res;
res = tcgetattr(fd, &t);
if (res < 0)
exit(errno);
if (save)
tsav = t;
fprintf(stderr, "fd %d: %x/%d/%d\n", fd, t.c_iflag,
t.c_cc[VMIN], t.c_cc[VTIME]);
}
void
setraw(fd)
int fd;
{
struct termios t;
int res;
res = tcgetattr(fd, &t);
if (res < 0)
exit(errno);
cfmakeraw(&t);
t.c_cc[VMIN] = 4;
t.c_cc[VTIME] = 1;
res = tcsetattr(fd, TCSAFLUSH, &t);
if (res < 0)
exit(errno);
}
void
restore(fd)
int fd;
{
tcsetattr(fd, TCSAFLUSH, &tsav);
}
int
main()
{
int in;
int flags, res;
struct pollfd inp;
char buf[100];
in = STDIN_FILENO;
flags = fcntl(in, F_GETFL);
if (flags == -1)
exit(errno);
flags |= O_NONBLOCK;
res = fcntl(in, F_SETFL, flags);
if (res < 0)
exit(errno);
dump(in, 1);
setraw(in);
dump(in, 0);
inp.fd = in;
inp.events = POLLIN;
res = poll(&inp, 1, -1);
fprintf(stderr, "poll: %d (%s)\n", res, strerror(errno));
res = read(in, buf, sizeof(buf));
fprintf(stderr, "read: %d (%s)\n", res, strerror(errno));
restore(in);
exit(0);
}
--==_Exmh_10149248080450--