#ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #include #include #include #include #include #include #include #include #include #include #include #include static sig_atomic_t died; static void sigchld(int sig __attribute__((__unused__))) { const int old_errno = errno; int status; pid_t pid; while ((pid = waitpid(-1, &status, WNOHANG|WUNTRACED)) != 0) { if (errno == ECHILD) break; if (pid < 0) continue; died = 1; } errno = old_errno; } static pid_t pid = -1; static void sigother(int sig) { printf("%s\n", strsignal(sig)); if (sig == SIGINT) sig = SIGTERM; if (pid > 0) kill(pid, sig); } int main(int argc, char* argv[]) { int ptm, pts; ssize_t len; static struct termios o; static struct winsize w; char ptsname[NAME_MAX+1]; char buffer[65536]; sigset_t set; struct sigaction sa; if (ioctl(0, TIOCGWINSZ, &w) < 0) { w.ws_row = 24; w.ws_col = 160; errno = 0; } if (tcgetattr(0, &o) < 0) { cfmakeraw(&o); cfsetispeed(&o, B38400); cfsetospeed(&o, B38400); } o.c_lflag &= ~ECHO; o.c_lflag |= ISIG; o.c_cc[VTIME] = 0; o.c_cc[VMIN] = CMIN; if (openpty(&ptm, &pts, ptsname, &o, &w) < 0) perror("pty: can not open pty/tty pair"); (void)sigemptyset(&set); (void)sigaddset(&set, SIGCHLD); sigprocmask(SIG_UNBLOCK, &set, (sigset_t*)0); sa.sa_flags = SA_RESTART; sa.sa_handler = sigchld; sigemptyset (&sa.sa_mask); sigaction(SIGCHLD, &sa, (struct sigaction*)0); (void)sigemptyset(&set); (void)sigaddset(&set, SIGTERM); sigprocmask(SIG_UNBLOCK, &set, (sigset_t*)0); sa.sa_flags = SA_RESTART; sa.sa_handler = sigother; sigemptyset (&sa.sa_mask); sigaction(SIGTERM, &sa, (struct sigaction*)0); (void)sigemptyset(&set); (void)sigaddset(&set, SIGHUP); sigprocmask(SIG_UNBLOCK, &set, (sigset_t*)0); sa.sa_flags = SA_RESTART; sa.sa_handler = sigother; sigemptyset (&sa.sa_mask); sigaction(SIGHUP, &sa, (struct sigaction*)0); switch ((pid = fork())) { case 0: ioctl(1, TIOCNOTTY); if (setsid() < 0) perror("pty: can not get controlling tty"); dup2(pts, 1); dup2(pts, 2); close(pts); close(ptm); if (ioctl (1, TIOCSCTTY, 1) < 0) perror("pty: can not get controlling tty"); break; case -1: close(pts); close(ptm); perror("pty: can not fork"); exit(1); default: dup2(ptm, 0); close(pts); close(ptm); while ((len = read(0, buffer, sizeof(buffer)))) { ssize_t p = 0; const char* ptr = buffer; while (len > 0) { p = write(1, ptr, len); if (p < 0) { if (errno == EPIPE) exit (0); if (errno == EINTR || errno == EAGAIN) continue; return 1; } ptr += p; len -= p; } if (died) break; } return 0; } (void)sigfillset(&set); sigprocmask(SIG_UNBLOCK, &set, (sigset_t*)0); (void)sigemptyset(&set); (void)sigaddset(&set, SIGCHLD); sigprocmask(SIG_BLOCK, &set, (sigset_t*)0); sa.sa_flags = SA_RESTART; sa.sa_handler = SIG_DFL; sigemptyset (&sa.sa_mask); sigaction(SIGHUP, &sa, (struct sigaction*)0); sigaction(SIGPIPE, &sa, (struct sigaction*)0); sigaction(SIGTERM, &sa, (struct sigaction*)0); sigaction(SIGURG, &sa, (struct sigaction*)0); sigaction(SIGXFSZ, &sa, (struct sigaction*)0); sigaction(SIGQUIT, &sa, (struct sigaction*)0); sa.sa_handler = SIG_IGN; sigaction(SIGINT, &sa, (struct sigaction*)0); sigaction(SIGQUIT, &sa, (struct sigaction*)0); return execv(argv[0], &argv[1]); }