#include #include #include #include #include #include #include #include #define BUFSIZE 128 int read_to_buffer(int fd, char *buf); int sh_unset_nodelay_mode (int fd); int give_terminal_to (pid_t pgrp, int shell_tty, int force); /* Function int main(int argc, char **argv) {{{ */ int main(int argc, char **argv) { register int ret, pid; int pipe0[2], pipe1[2], pipe2[2]; char buf[BUFSIZE]; fd_set fds; if (argc <= 1) { printf("Usage: %s \n", argv[0]); return 1; } if (pipe(pipe0) || pipe(pipe1) || pipe(pipe2)) { puts("pipe() failure"); return 1; } /* fcntl(pipe1[1], F_SETFL, O_NONBLOCK|O_NDELAY); fcntl(pipe2[1], F_SETFL, O_NONBLOCK|O_NDELAY); */ sh_unset_nodelay_mode(0); sh_unset_nodelay_mode(pipe1[1]); sh_unset_nodelay_mode(pipe1[2]); switch (pid = fork()) { case -1: puts("fork() failure"); return 1; break; case 0: /* Child */ if (dup2(pipe0[0], 0) == -1 || dup2(pipe1[1], 1) == -1 || dup2(pipe2[1], 2) == -1) { puts("dup2() failure"); return 1; } close(pipe0[0]); close(pipe0[1]); close(pipe1[0]); close(pipe1[1]); close(pipe2[0]); close(pipe2[1]); execvp(argv[1], argv + 1); break; default: /* Parent */ break; }; give_terminal_to(pid, 1, 0); while (1) { FD_ZERO(&fds); FD_SET(0, &fds); FD_SET(pipe1[0], &fds); FD_SET(pipe2[0], &fds); switch (select(FD_SETSIZE, &fds, NULL, NULL, NULL)) { case -1: puts("select() failure"); return 1; break; default: if (FD_ISSET(0, &fds)) { ret = read_to_buffer(0, buf); write(pipe0[1], buf, ret); } if (FD_ISSET(pipe1[0], &fds)) { ret = read_to_buffer(pipe1[0], buf); write(1, buf, ret); } if (FD_ISSET(pipe2[0], &fds)) { ret = read_to_buffer(pipe2[0], buf); write(2, buf, ret); } break; } } return 0; } /* }}} */ int read_to_buffer(int fd, char *buf) { register int ret; ret = read(fd, buf, BUFSIZE); if (ret < 0) { printf("read() error, returned %d\n", ret); exit(-1 * ret); } else if (ret == 0) { printf("read() == 0, terminating\n"); exit(0); } return ret; } /* Make sure no-delay mode is not set on file descriptor FD. */ int sh_unset_nodelay_mode (int fd) { int flags, bflags; if ((flags = fcntl (fd, F_GETFL, 0)) < 0) return -1; bflags = 0; /* This is defined to O_NDELAY in filecntl.h if O_NONBLOCK is not present and O_NDELAY is defined. */ #ifdef O_NONBLOCK bflags |= O_NONBLOCK; #endif #ifdef O_NDELAY bflags |= O_NDELAY; #endif if (flags & bflags) { flags &= ~bflags; return (fcntl (fd, F_SETFL, flags)); } return 0; } /* Give the terminal to PGRP. */ int give_terminal_to (pid_t pgrp, int shell_tty, int force) { sigset_t set, oset; int r; r = 0; if (/* job_control ||*/ force) { sigemptyset (&set); sigaddset (&set, SIGTTOU); sigaddset (&set, SIGTTIN); sigaddset (&set, SIGTSTP); sigaddset (&set, SIGCHLD); sigemptyset (&oset); sigprocmask (SIG_BLOCK, &set, &oset); if (tcsetpgrp (shell_tty, pgrp) < 0) { /* Maybe we should print an error message? */ #if 0 sys_error ("tcsetpgrp(%d) failed: pid %ld to pgrp %ld", shell_tty, (long)getpid(), (long)pgrp); #endif r = -1; } else { /* terminal_pgrp = pgrp; */ } sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL); } return r; } /* Modeline for ViM {{{1 * vim:set ts=4: * vim600:fdm=marker fdl=0 fdc=3: * }}}1 */