#include #include #include #include #include #include #include #include #include #include #include "runes.h" #include "pty-unix.h" #include "config.h" #include "loop.h" #include "term.h" #include "window-xlib.h" extern char **environ; static int runes_pty_input_cb(void *t); RunesPty *runes_pty_new() { RunesPty *pty; pty = calloc(1, sizeof(RunesPty)); pty->master = posix_openpt(O_RDWR); grantpt(pty->master); unlockpt(pty->master); return pty; } void runes_pty_spawn_subprocess(RunesTerm *t, char *envp[], char *cwd) { RunesPty *pty = t->pty; pty->slave = open(ptsname(pty->master), O_RDWR); pty->child_pid = fork(); if (pty->child_pid) { close(pty->slave); pty->slave = -1; } else { char *cmd, window_id[32]; int old_stderr_fd; FILE *old_stderr; old_stderr_fd = dup(2); fcntl(old_stderr_fd, F_SETFD, FD_CLOEXEC); old_stderr = fdopen(old_stderr_fd, "w"); setsid(); ioctl(pty->slave, TIOCSCTTY, NULL); close(pty->master); dup2(pty->slave, 0); dup2(pty->slave, 1); dup2(pty->slave, 2); close(pty->slave); if (cwd) { // XXX if (chdir(cwd)) {} } if (envp) { environ = envp; } /* XXX should use a different TERM value eventually, but for right now * screen is compatible enough */ setenv("TERM", "screen-256color", 1); /* gnome-terminal sets this, so avoid confusing applications which * introspect it. not setting it to something else because as far as i * can tell, it's not actually useful these days, given that terminfo * databases are much more reliable than they were 10 years ago */ unsetenv("COLORTERM"); /* less sure about this one being useless, but leaving it unset for now * until someone complains */ unsetenv("COLORFGBG"); /* this is used by, for instance, w3m */ sprintf(window_id, "%lu", runes_window_get_window_id(t)); setenv("WINDOWID", window_id, 1); unsetenv("LINES"); unsetenv("COLUMNS"); cmd = t->config->cmd; if (!cmd) { cmd = getenv("SHELL"); } if (!cmd) { cmd = "/bin/sh"; } if (strpbrk(cmd, " $")) { execlp("/bin/sh", "/bin/sh", "-c", cmd, (char *)NULL); } else { execlp(cmd, cmd, (char *)NULL); } fprintf(old_stderr, "Couldn't run %s: %s\n", cmd, strerror(errno)); exit(1); } } void runes_pty_init_loop(RunesTerm *t, RunesLoop *loop) { RunesPty *pty = t->pty; runes_term_refcnt_inc(t); runes_loop_start_work(loop, pty->master, t, runes_pty_input_cb); } void runes_pty_set_window_size( RunesTerm *t, int row, int col, int xpixel, int ypixel) { struct winsize size; size.ws_row = row; size.ws_col = col; size.ws_xpixel = xpixel; size.ws_ypixel = ypixel; ioctl(t->pty->master, TIOCSWINSZ, &size); } void runes_pty_write(RunesTerm *t, char *buf, size_t len) { // XXX if (write(t->pty->master, buf, len)) {} } void runes_pty_request_close(RunesTerm *t) { RunesPty *pty = t->pty; kill(pty->child_pid, SIGHUP); } void runes_pty_delete(RunesPty *pty) { close(pty->master); free(pty); } static int runes_pty_input_cb(void *t) { RunesPty *pty = ((RunesTerm *)t)->pty; pty->readlen = read( pty->master, pty->readbuf + pty->remaininglen, RUNES_READ_BUFFER_LENGTH - pty->remaininglen); if (pty->readlen > 0) { int to_process = pty->readlen + pty->remaininglen; int processed = vt100_screen_process_string( ((RunesTerm *)t)->scr, pty->readbuf, to_process); pty->remaininglen = to_process - processed; memmove(pty->readbuf, pty->readbuf + processed, pty->remaininglen); runes_window_flush(t); return 1; } else { runes_window_request_close(t); runes_term_refcnt_dec(t); return 0; } }