aboutsummaryrefslogtreecommitdiffstats
path: root/pty-unix.c
blob: c02b31fcf95792b1cd6ba6bc11e5f94bf05f6f95 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#define _XOPEN_SOURCE 600
#include <fcntl.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <unistd.h>

#include "runes.h"

void runes_pty_backend_init(RunesTerm *t)
{
    RunesPtyBackend *pty;

    pty = &t->pty;
    pty->master = posix_openpt(O_RDWR);
    grantpt(pty->master);
    unlockpt(pty->master);
    pty->slave = open(ptsname(pty->master), O_RDWR);

    pty->child_pid = fork();
    if (pty->child_pid) {
        close(pty->slave);
        pty->slave = -1;
    }
    else {
        char *shell;

        setsid();
        ioctl(pty->slave, TIOCSCTTY, NULL);

        close(pty->master);

        dup2(pty->slave, 0);
        dup2(pty->slave, 1);
        dup2(pty->slave, 2);

        close(pty->slave);

        shell = getenv("SHELL");
        if (!shell) {
            shell = "/bin/sh";
        }

        execl(shell, shell, (char *)NULL);
    }
}

void runes_pty_backend_set_window_size(RunesTerm *t)
{
    struct winsize size;
    int row, col, xpixel, ypixel;

    runes_display_get_term_size(t, &row, &col, &xpixel, &ypixel);
    size.ws_row = row;
    size.ws_col = col;
    size.ws_xpixel = xpixel;
    size.ws_ypixel = ypixel;
    ioctl(t->pty.master, TIOCSWINSZ, &size);
}

static void runes_read_pty(uv_work_t *req)
{
    RunesPtyLoopData *data;

    data = (RunesPtyLoopData *)req->data;
    data->len = read(data->data.t->pty.master, data->buf, RUNES_PTY_BUFFER_LENGTH);
}

static void runes_got_pty_data(uv_work_t *req, int status)
{
    RunesTerm *t;
    RunesPtyLoopData *data;

    UNUSED(status);
    data = (RunesPtyLoopData *)req->data;
    t = data->data.t;

    if (data->len > 0) {
        runes_handle_pty_read(t, data->buf, data->len);
        uv_queue_work(t->loop, req, runes_read_pty, runes_got_pty_data);
    }
    else {
        runes_handle_pty_close(t);
        free(req);
    }
}

void runes_pty_backend_loop_init(RunesTerm *t)
{
    void *data;

    data = malloc(sizeof(RunesPtyLoopData));
    ((RunesLoopData *)data)->req.data = data;
    ((RunesLoopData *)data)->t = t;

    uv_queue_work(t->loop, data, runes_read_pty, runes_got_pty_data);
}

void runes_pty_backend_write(RunesTerm *t, char *buf, size_t len)
{
    write(t->pty.master, buf, len);
}

void runes_pty_backend_request_close(RunesTerm *t)
{
    RunesPtyBackend *pty;

    pty = &t->pty;
    kill(pty->child_pid, SIGHUP);
}

void runes_pty_backend_cleanup(RunesTerm *t)
{
    RunesPtyBackend *pty;

    pty = &t->pty;
    close(pty->master);
}