#define _XOPEN_SOURCE #include #include #include #include #include #include #include #include "vt100_headless.h" #include "vt100.h" struct vt100_headless *vt100_headless_init(void) { return malloc(sizeof(struct vt100_headless)); } static void set_non_canonical(struct vt100_headless *this, int fd) { struct termios termios; ioctl(fd, TCGETS, &this->backup); ioctl(fd, TCGETS, &termios); termios.c_iflag |= ICANON; termios.c_cc[VMIN] = 1; termios.c_cc[VTIME] = 0; ioctl(fd, TCSETS, &termios); } static void restore_termios(struct vt100_headless *this, int fd) { ioctl(fd, TCSETS, &this->backup); } /* static void debug(struct vt100_headless *this, char *title) */ /* { */ /* unsigned int argc; */ /* fprintf(stderr, "%s ", title); */ /* for (argc = 0; argc < this->term->argc; ++argc) */ /* { */ /* fprintf(stderr, "%d", this->term->argv[argc]); */ /* if (argc != this->term->argc - 1) */ /* fprintf(stderr, ", "); */ /* } */ /* fprintf(stderr, "\n"); */ /* } */ #ifndef NDEBUG static void strdump(char *str) { while (*str != '\0') { if (*str >= ' ' && *str <= '~') fprintf(stderr, "%c", *str); else fprintf(stderr, "\\0%o", *str); str += 1; } fprintf(stderr, "\n"); } #endif static int main_loop(struct vt100_headless *this) { char buffer[4096]; fd_set rfds; int retval; ssize_t read_size; while (42) { FD_ZERO(&rfds); FD_SET(this->master, &rfds); FD_SET(0, &rfds); retval = select(this->master + 1, &rfds, NULL, NULL, NULL); if (retval == -1) { perror("select()"); } if (FD_ISSET(0, &rfds)) { read_size = read(0, &buffer, 4096); if (read_size == -1) { perror("read"); return EXIT_FAILURE; } buffer[read_size] = '\0'; write(this->master, buffer, read_size); } if (FD_ISSET(this->master, &rfds)) { read_size = read(this->master, &buffer, 4096); if (read_size == -1) { perror("read"); return EXIT_FAILURE; } buffer[read_size] = '\0'; #ifndef NDEBUG strdump(buffer); #endif terminal_read_str(this->term->terminal, buffer); this->changed(this); } } } void vt100_headless_fork(struct vt100_headless *this, const char *progname, char *const argv[]) { int child; struct winsize winsize; set_non_canonical(this, 0); winsize.ws_row = 24; winsize.ws_col = 24; child = forkpty(&this->master, NULL, NULL, NULL); if (child == CHILD) { setsid(); putenv("TERM=vt100"); execvp(progname, argv); return ; } else { this->term = vt100_init(terminal_default_unimplemented); ioctl(this->master, TIOCSWINSZ, &winsize); this->term->terminal->fd = this->master; main_loop(this); } restore_termios(this, 0); }