From 4f670845ff9ab6c48bcb5f7bf4d4ef6dc3c3064b Mon Sep 17 00:00:00 2001 From: manuel Date: Tue, 27 Mar 2012 11:51:08 +0200 Subject: reorganize file structure to match the upstream requirements --- pintos-progos/utils/squish-pty.c | 355 --------------------------------------- 1 file changed, 355 deletions(-) delete mode 100644 pintos-progos/utils/squish-pty.c (limited to 'pintos-progos/utils/squish-pty.c') diff --git a/pintos-progos/utils/squish-pty.c b/pintos-progos/utils/squish-pty.c deleted file mode 100644 index c8375a5..0000000 --- a/pintos-progos/utils/squish-pty.c +++ /dev/null @@ -1,355 +0,0 @@ -#define _GNU_SOURCE 1 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static void -fail_io (const char *msg, ...) - __attribute__ ((noreturn)) - __attribute__ ((format (printf, 1, 2))); - -/* Prints MSG, formatting as with printf(), - plus an error message based on errno, - and exits. */ -static void -fail_io (const char *msg, ...) -{ - va_list args; - - va_start (args, msg); - vfprintf (stderr, msg, args); - va_end (args); - - if (errno != 0) - fprintf (stderr, ": %s", strerror (errno)); - putc ('\n', stderr); - exit (EXIT_FAILURE); -} - -/* If FD is a terminal, configures it for noncanonical input mode - with VMIN and VTIME set as indicated. - If FD is not a terminal, has no effect. */ -static void -make_noncanon (int fd, int vmin, int vtime) -{ - if (isatty (fd)) - { - struct termios termios; - if (tcgetattr (fd, &termios) < 0) - fail_io ("tcgetattr"); - termios.c_lflag &= ~(ICANON | ECHO); - termios.c_cc[VMIN] = vmin; - termios.c_cc[VTIME] = vtime; - if (tcsetattr (fd, TCSANOW, &termios) < 0) - fail_io ("tcsetattr"); - } -} - -/* Make FD non-blocking if NONBLOCKING is true, - or blocking if NONBLOCKING is false. */ -static void -make_nonblocking (int fd, bool nonblocking) -{ - int flags = fcntl (fd, F_GETFL); - if (flags < 0) - fail_io ("fcntl"); - if (nonblocking) - flags |= O_NONBLOCK; - else - flags &= ~O_NONBLOCK; - if (fcntl (fd, F_SETFL, flags) < 0) - fail_io ("fcntl"); -} - -/* Handle a read or write on *FD, which is the pty if FD_IS_PTY - is true, that returned end-of-file or error indication RETVAL. - The system call is named CALL, for use in error messages. - Returns true if processing may continue, false if we're all - done. */ -static bool -handle_error (ssize_t retval, int *fd, bool fd_is_pty, const char *call) -{ - if (fd_is_pty) - { - if (retval < 0) - { - if (errno == EIO) - { - /* Slave side of pty has been closed. */ - return false; - } - else - fail_io (call); - } - else - return true; - } - else - { - if (retval == 0) - { - close (*fd); - *fd = -1; - return true; - } - else - fail_io (call); - } -} - -/* Copies data from stdin to PTY and from PTY to stdout until no - more data can be read or written. */ -static void -relay (int pty, int dead_child_fd) -{ - struct pipe - { - int in, out; - char buf[BUFSIZ]; - size_t size, ofs; - bool active; - }; - struct pipe pipes[2]; - - /* Make PTY, stdin, and stdout non-blocking. */ - make_nonblocking (pty, true); - make_nonblocking (STDIN_FILENO, true); - make_nonblocking (STDOUT_FILENO, true); - - /* Configure noncanonical mode on PTY and stdin to avoid - waiting for end-of-line. We want to minimize context - switching on PTY (for efficiency) and minimize latency on - stdin to avoid a laggy user experience. */ - make_noncanon (pty, 16, 1); - make_noncanon (STDIN_FILENO, 1, 0); - - memset (pipes, 0, sizeof pipes); - pipes[0].in = STDIN_FILENO; - pipes[0].out = pty; - pipes[1].in = pty; - pipes[1].out = STDOUT_FILENO; - - while (pipes[0].in != -1 || pipes[1].in != -1) - { - fd_set read_fds, write_fds; - int retval; - int i; - - FD_ZERO (&read_fds); - FD_ZERO (&write_fds); - for (i = 0; i < 2; i++) - { - struct pipe *p = &pipes[i]; - - /* Don't do anything with the stdin->pty pipe until we - have some data for the pty->stdout pipe. If we get - too eager, Bochs will throw away our input. */ - if (i == 0 && !pipes[1].active) - continue; - - if (p->in != -1 && p->size + p->ofs < sizeof p->buf) - FD_SET (p->in, &read_fds); - if (p->out != -1 && p->size > 0) - FD_SET (p->out, &write_fds); - } - FD_SET (dead_child_fd, &read_fds); - - do - { - retval = select (FD_SETSIZE, &read_fds, &write_fds, NULL, NULL); - } - while (retval < 0 && errno == EINTR); - if (retval < 0) - fail_io ("select"); - - if (FD_ISSET (dead_child_fd, &read_fds)) - { - /* Child died. Do final relaying. */ - struct pipe *p = &pipes[1]; - if (p->out == -1) - return; - make_nonblocking (STDOUT_FILENO, false); - for (;;) - { - ssize_t n; - - /* Write buffer. */ - while (p->size > 0) - { - n = write (p->out, p->buf + p->ofs, p->size); - if (n < 0) - fail_io ("write"); - else if (n == 0) - fail_io ("zero-length write"); - p->ofs += n; - p->size -= n; - } - p->ofs = 0; - - p->size = n = read (p->in, p->buf, sizeof p->buf); - if (n <= 0) - return; - } - } - - for (i = 0; i < 2; i++) - { - struct pipe *p = &pipes[i]; - if (p->in != -1 && FD_ISSET (p->in, &read_fds)) - { - ssize_t n = read (p->in, p->buf + p->ofs + p->size, - sizeof p->buf - p->ofs - p->size); - if (n > 0) - { - p->active = true; - p->size += n; - if (p->size == BUFSIZ && p->ofs != 0) - { - memmove (p->buf, p->buf + p->ofs, p->size); - p->ofs = 0; - } - } - else if (!handle_error (n, &p->in, p->in == pty, "read")) - return; - } - if (p->out != -1 && FD_ISSET (p->out, &write_fds)) - { - ssize_t n = write (p->out, p->buf + p->ofs, p->size); - if (n > 0) - { - p->ofs += n; - p->size -= n; - if (p->size == 0) - p->ofs = 0; - } - else if (!handle_error (n, &p->out, p->out == pty, "write")) - return; - } - } - } -} - -static int dead_child_fd; - -static void -sigchld_handler (int signo __attribute__ ((unused))) -{ - if (write (dead_child_fd, "", 1) < 0) - _exit (1); -} - -int -main (int argc __attribute__ ((unused)), char *argv[]) -{ - int master, slave; - char *name; - pid_t pid; - struct sigaction sa; - int pipe_fds[2]; - struct itimerval zero_itimerval, old_itimerval; - - if (argc < 2) - { - fprintf (stderr, - "usage: squish-pty COMMAND [ARG]...\n" - "Squishes both stdin and stdout into a single pseudoterminal,\n" - "which is passed as stdout to run the specified COMMAND.\n"); - return EXIT_FAILURE; - } - - /* Open master side of pty and get ready to open slave. */ - master = open ("/dev/ptmx", O_RDWR | O_NOCTTY); - if (master < 0) - fail_io ("open \"/dev/ptmx\""); - if (grantpt (master) < 0) - fail_io ("grantpt"); - if (unlockpt (master) < 0) - fail_io ("unlockpt"); - - /* Open slave side of pty. */ - name = ptsname (master); - if (name == NULL) - fail_io ("ptsname"); - slave = open (name, O_RDWR); - if (slave < 0) - fail_io ("open \"%s\"", name); - - /* System V implementations need STREAMS configuration for the - slave. */ - if (isastream (slave)) - { - if (ioctl (slave, I_PUSH, "ptem") < 0 - || ioctl (slave, I_PUSH, "ldterm") < 0) - fail_io ("ioctl"); - } - - /* Arrange to get notified when a child dies, by writing a byte - to a pipe fd. We really want to use pselect() and - sigprocmask(), but Solaris 2.7 doesn't have it. */ - if (pipe (pipe_fds) < 0) - fail_io ("pipe"); - dead_child_fd = pipe_fds[1]; - - memset (&sa, 0, sizeof sa); - sa.sa_handler = sigchld_handler; - sigemptyset (&sa.sa_mask); - sa.sa_flags = SA_RESTART; - if (sigaction (SIGCHLD, &sa, NULL) < 0) - fail_io ("sigaction"); - - /* Save the virtual interval timer, which might have been set - by the process that ran us. It really should be applied to - our child process. */ - memset (&zero_itimerval, 0, sizeof zero_itimerval); - if (setitimer (ITIMER_VIRTUAL, &zero_itimerval, &old_itimerval) < 0) - fail_io ("setitimer"); - - pid = fork (); - if (pid < 0) - fail_io ("fork"); - else if (pid != 0) - { - /* Running in parent process. */ - int status; - close (slave); - relay (master, pipe_fds[0]); - - /* If the subprocess has died, die in the same fashion. - In particular, dying from SIGVTALRM tells the pintos - script that we ran out of CPU time. */ - if (waitpid (pid, &status, WNOHANG) > 0) - { - if (WIFEXITED (status)) - return WEXITSTATUS (status); - else if (WIFSIGNALED (status)) - raise (WTERMSIG (status)); - } - return 0; - } - else - { - /* Running in child process. */ - if (setitimer (ITIMER_VIRTUAL, &old_itimerval, NULL) < 0) - fail_io ("setitimer"); - if (dup2 (slave, STDOUT_FILENO) < 0) - fail_io ("dup2"); - if (close (pipe_fds[0]) < 0 || close (pipe_fds[1]) < 0 - || close (slave) < 0 || close (master) < 0) - fail_io ("close"); - execvp (argv[1], argv + 1); - fail_io ("exec"); - } -} -- cgit v1.2.3