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


#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);
}

Reply via email to