#define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include "unix.h" #include "panic.h" #include "stty_print.h" /* arch-tag: d7ab6d47-0ea7-470e-acd3-b1eaf4023dac */ static char * gen_styname(char *tty, unsigned pid) { char *sty = NULL; struct utsname utsname; int ret = uname(&utsname); if (ret == -1) panicno("uname"); char *n = alloca(strlen(tty) + 3); strcpy(n, tty); if(!strncmp(n,"/", 1)) n += 1; if(!strncmp(n,"dev/", 4)) n += 4; ret = asprintf(&sty, "%u.%s.%s",(unsigned)pid, n, utsname.nodename); if(ret == -1) panicno("asprintf"); for(int i = 0; sty[i]; i++) if(!isalnum(sty[i]) && sty[i] != '.') sty[i] = '-'; return sty; } struct pty * spawn_p(char *argv[], int erase) { int child_fd; int child_pid; int signal_pipe[2]; if(pipe(signal_pipe) == -1) panicno("signal pipe"); char dummy = 'x'; struct pty *pty = malloc(sizeof(struct pty)); memset(pty, 0, sizeof(struct pty)); signal(SIGHUP,SIG_DFL); child_pid = forkpty(&child_fd,NULL,NULL,NULL); if(child_pid == -1) panicno("forkpty"); if(child_pid==0) { char *sty = gen_styname(ttyname(1), getppid()); setenv("STY",sty,1); // wait for teminal all set up properly to exec child. close(signal_pipe[1]); if(read(signal_pipe[0],&dummy,1) != 1) { perror("Could not wait on signal_pipe"); getchar(); _exit(2); } close(signal_pipe[0]); execvp(argv[0],argv); perror("execvp"); fprintf(stderr, "Could not exec: %s\n", argv[0]); getchar(); _exit(2); } pty->sty = gen_styname(ptsname(child_fd), getpid()); pty->name = strdup(ptsname(child_fd)); pty->fd = child_fd; pty->pid = child_pid; tcgetattr(pty->fd, &pty->termios); // ensure we have some sane settings pty->termios.c_iflag &= ~(IXON | IXOFF); // not needed for pty, allows us to use ^s and ^q pty->termios.c_cc[VERASE] = erase; // consistent with terminfo and xterm pty->termios.c_cc[VEOF] = 004; // ^d pty->termios.c_cc[VKILL] = 025; // ^u pty->termios.c_cc[VSUSP] = 032; // ^z pty->termios.c_cc[VINTR] = 003; // ^c pty->termios.c_cc[VQUIT] = 034; /* ^\ */ tcsetattr(pty->fd, TCSANOW, &pty->termios); ioctl(pty->fd, TIOCGWINSZ, &pty->winsize); close(signal_pipe[0]); if(write(signal_pipe[1],&dummy,1) != 1) { panicno("writing signal byte"); } close(signal_pipe[1]); return pty; } int writen(int fd, const void *vptr, size_t *n) { size_t nleft, nwritten; const char *ptr; ptr = vptr; /* can't do pointer arithmetic on void* */ nleft = *n; while (nleft > 0) { if ( (nwritten = write(fd, ptr, nleft)) <= 0) { switch(errno) { case EINTR: continue; case EAGAIN: *n = *n - nleft; return -1; default: panicno("writen"); return -1; } } nleft -= nwritten; ptr += nwritten; } //*n = *n - nleft; return(0); } void print_pty_state(FILE *f, struct pty *pty) { /* refresh info */ tcgetattr(pty->fd, &pty->termios); ioctl(pty->fd, TIOCGWINSZ, &pty->winsize); stty_print(&pty->termios, &pty->winsize); }