33 vfprintf (stderr,
msg, args);
37 fprintf (stderr,
": %s", strerror (errno));
50 struct termios termios;
51 if (tcgetattr (fd, &termios) < 0)
53 termios.c_lflag &= ~(ICANON | ECHO);
54 termios.c_cc[VMIN] = vmin;
55 termios.c_cc[VTIME] = vtime;
56 if (tcsetattr (fd, TCSANOW, &termios) < 0)
66 int flags = fcntl (fd, F_GETFL);
73 if (fcntl (fd, F_SETFL, flags) < 0)
82handle_error (ssize_t retval,
int *fd,
bool fd_is_pty,
const char *call)
121 struct pipe pipes[2];
135 memset (pipes, 0,
sizeof pipes);
141 while (pipes[1].in != -1)
143 fd_set read_fds, write_fds;
148 FD_ZERO (&write_fds);
149 for (i = 0; i < 2; i++)
151 struct pipe *p = &pipes[i];
156 if (i == 0 && !pipes[1].active)
159 if (p->in != -1 && p->size + p->ofs <
sizeof p->buf)
160 FD_SET (p->in, &read_fds);
161 if (p->out != -1 && p->size > 0)
162 FD_SET (p->out, &write_fds);
168 retval = select (FD_SETSIZE, &read_fds, &write_fds,
NULL,
NULL);
170 while (retval < 0 && errno == EINTR);
177 for (i = 0; i < 2; i++)
179 struct pipe *p = &pipes[i];
180 if (p->in != -1 && FD_ISSET (p->in, &read_fds))
182 ssize_t n =
read (p->in, p->buf + p->ofs + p->size,
183 sizeof p->buf - p->ofs - p->size);
188 if (p->size == BUFSIZ && p->ofs != 0)
190 memmove (p->buf, p->buf + p->ofs, p->size);
197 if (p->out != -1 && FD_ISSET (p->out, &write_fds))
199 ssize_t n =
write (p->out, p->buf + p->ofs, p->size);
213 if (pipes[1].out == -1)
219 struct pipe *p = &pipes[1];
225 n =
write (p->out, p->buf + p->ofs, p->size);
235 p->size = n =
read (p->in, p->buf,
sizeof p->buf);
258 struct itimerval zero_itimerval, old_itimerval;
263 "usage: squish-pty COMMAND [ARG]...\n"
264 "Squishes both stdin and stdout into a single pseudoterminal,\n"
265 "which is passed as stdout to run the specified COMMAND.\n");
270 master =
open (
"/dev/ptmx", O_RDWR | O_NOCTTY);
272 fail_io (
"open \"/dev/ptmx\"");
273 if (grantpt (master) < 0)
275 if (unlockpt (master) < 0)
279 name = ptsname (master);
300 if (pipe (pipe_fds) < 0)
304 memset (&sa, 0,
sizeof sa);
306 sigemptyset (&sa.sa_mask);
307 sa.sa_flags = SA_RESTART;
308 if (sigaction (SIGCHLD, &sa,
NULL) < 0)
314 memset (&zero_itimerval, 0,
sizeof zero_itimerval);
315 if (setitimer (ITIMER_VIRTUAL, &zero_itimerval, &old_itimerval) < 0)
326 relay (master, pipe_fds[0]);
331 if (waitpid (pid, &status, WNOHANG) > 0)
333 if (WIFEXITED (status))
334 return WEXITSTATUS (status);
335 else if (WIFSIGNALED (status))
336 raise (WTERMSIG (status));
349 if (old_itimerval.it_value.tv_usec < 0 || old_itimerval.it_value.tv_usec > 999999) {
350 old_itimerval.it_value.tv_usec = 999999;
352 if (old_itimerval.it_interval.tv_usec < 0 || old_itimerval.it_interval.tv_usec > 999999) {
353 old_itimerval.it_interval.tv_usec = 999999;
356 if (setitimer (ITIMER_VIRTUAL, &old_itimerval,
NULL) < 0)
360 if (
close (pipe_fds[0]) < 0 ||
close (pipe_fds[1]) < 0
363 execvp (argv[1], argv + 1);
static char dst[8192] __attribute__((section(".testEndmem,\"aw\",@nobits#")))
Utility function for tests that try to break system calls by passing them data that crosses from one ...
static char buf[BUF_SIZE]
int printf(const char *format,...)
Writes formatted output to the console.
int open(const char *file)
int write(int fd, const void *buffer, unsigned size)
int read(int fd, void *buffer, unsigned size)
int pid_t
Process identifier.
#define EXIT_FAILURE
Unsuccessful execution.
void msg(const char *format,...)
static void sigchld_handler(int signo __attribute__((unused)))
static void relay(int pty, int dead_child_fd)
Copies data from stdin to PTY and from PTY to stdout until no more data can be read or written.
static void make_noncanon(int fd, int vmin, int vtime)
If FD is a terminal, configures it for noncanonical input mode with VMIN and VTIME set as indicated.
int main(int argc __attribute__((unused)), char *argv[])
static void handle_error(ssize_t retval, int *fd, bool fd_is_pty, const char *call)
Handle a read or write on *FD, which is the pty if FD_IS_PTY is true, that returned end-of-file or er...
static void fail_io(const char *msg,...) __attribute__((noreturn)) __attribute__((format(printf
Prints MSG, formatting as with printf(), plus an error message based on errno, and exits.
static void make_nonblocking(int fd, bool nonblocking)
Make FD non-blocking if NONBLOCKING is true, or blocking if NONBLOCKING is false.
#define va_start(LIST, ARG)
__builtin_va_list va_list
GCC has <stdarg.h> functionality as built-ins, so all we need is to use it.
#define STDIN_FILENO
Include lib/user/stdio.h or lib/kernel/stdio.h, as appropriate.
void * memset(void *dst_, int value, size_t size)
Sets the SIZE bytes in DST to VALUE.
void * memmove(void *dst_, const void *src_, size_t size)
Copies SIZE bytes from SRC to DST, which are allowed to overlap.