Beispiel #1
0
int pty_forward_set_ignore_vhangup(PTYForward *f, bool b) {
        int r;

        assert(f);

        if (!!(f->flags & PTY_FORWARD_IGNORE_VHANGUP) == b)
                return 0;

        if (b)
                f->flags |= PTY_FORWARD_IGNORE_VHANGUP;
        else
                f->flags &= ~PTY_FORWARD_IGNORE_VHANGUP;

        if (!ignore_vhangup(f)) {

                /* We shall now react to vhangup()s? Let's check
                 * immediately if we might be in one */

                f->master_readable = true;
                r = shovel(f);
                if (r < 0)
                        return r;
        }

        return 0;
}
Beispiel #2
0
static int shovel(PTYForward *f) {
    ssize_t k;

    assert(f);

    while ((f->stdin_readable && f->in_buffer_full <= 0) ||
            (f->master_writable && f->in_buffer_full > 0) ||
            (f->master_readable && f->out_buffer_full <= 0) ||
            (f->stdout_writable && f->out_buffer_full > 0)) {

        if (f->stdin_readable && f->in_buffer_full < LINE_MAX) {

            k = read(STDIN_FILENO, f->in_buffer + f->in_buffer_full, LINE_MAX - f->in_buffer_full);
            if (k < 0) {

                if (errno == EAGAIN)
                    f->stdin_readable = false;
                else if (errno == EIO || errno == EPIPE || errno == ECONNRESET) {
                    f->stdin_readable = false;
                    f->stdin_hangup = true;

                    f->stdin_event_source = sd_event_source_unref(f->stdin_event_source);
                } else {
                    log_error_errno(errno, "read(): %m");
                    return pty_forward_done(f, -errno);
                }
            } else if (k == 0) {
                /* EOF on stdin */
                f->stdin_readable = false;
                f->stdin_hangup = true;

                f->stdin_event_source = sd_event_source_unref(f->stdin_event_source);
            } else  {
                /* Check if ^] has been pressed three times within one second. If we get this we quite
                 * immediately. */
                if (look_for_escape(f, f->in_buffer + f->in_buffer_full, k))
                    return pty_forward_done(f, -ECANCELED);

                f->in_buffer_full += (size_t) k;
            }
        }

        if (f->master_writable && f->in_buffer_full > 0) {

            k = write(f->master, f->in_buffer, f->in_buffer_full);
            if (k < 0) {

                if (errno == EAGAIN || errno == EIO)
                    f->master_writable = false;
                else if (errno == EPIPE || errno == ECONNRESET) {
                    f->master_writable = f->master_readable = false;
                    f->master_hangup = true;

                    f->master_event_source = sd_event_source_unref(f->master_event_source);
                } else {
                    log_error_errno(errno, "write(): %m");
                    return pty_forward_done(f, -errno);
                }
            } else {
                assert(f->in_buffer_full >= (size_t) k);
                memmove(f->in_buffer, f->in_buffer + k, f->in_buffer_full - k);
                f->in_buffer_full -= k;
            }
        }

        if (f->master_readable && f->out_buffer_full < LINE_MAX) {

            k = read(f->master, f->out_buffer + f->out_buffer_full, LINE_MAX - f->out_buffer_full);
            if (k < 0) {

                /* Note that EIO on the master device
                 * might be caused by vhangup() or
                 * temporary closing of everything on
                 * the other side, we treat it like
                 * EAGAIN here and try again, unless
                 * ignore_vhangup is off. */

                if (errno == EAGAIN || (errno == EIO && ignore_vhangup(f)))
                    f->master_readable = false;
                else if (errno == EPIPE || errno == ECONNRESET || errno == EIO) {
                    f->master_readable = f->master_writable = false;
                    f->master_hangup = true;

                    f->master_event_source = sd_event_source_unref(f->master_event_source);
                } else {
                    log_error_errno(errno, "read(): %m");
                    return pty_forward_done(f, -errno);
                }
            }  else {
                f->read_from_master = true;
                f->out_buffer_full += (size_t) k;
            }
        }

        if (f->stdout_writable && f->out_buffer_full > 0) {

            k = write(STDOUT_FILENO, f->out_buffer, f->out_buffer_full);
            if (k < 0) {

                if (errno == EAGAIN)
                    f->stdout_writable = false;
                else if (errno == EIO || errno == EPIPE || errno == ECONNRESET) {
                    f->stdout_writable = false;
                    f->stdout_hangup = true;
                    f->stdout_event_source = sd_event_source_unref(f->stdout_event_source);
                } else {
                    log_error_errno(errno, "write(): %m");
                    return pty_forward_done(f, -errno);
                }

            } else {

                if (k > 0) {
                    f->last_char = f->out_buffer[k-1];
                    f->last_char_set = true;
                }

                assert(f->out_buffer_full >= (size_t) k);
                memmove(f->out_buffer, f->out_buffer + k, f->out_buffer_full - k);
                f->out_buffer_full -= k;
            }
        }
    }

    if (f->stdin_hangup || f->stdout_hangup || f->master_hangup) {
        /* Exit the loop if any side hung up and if there's
         * nothing more to write or nothing we could write. */

        if ((f->out_buffer_full <= 0 || f->stdout_hangup) &&
                (f->in_buffer_full <= 0 || f->master_hangup))
            return pty_forward_done(f, 0);
    }

    return 0;
}