17#include <sys/socket.h>
36 vfprintf (stderr,
msg, args);
40 fprintf (stderr,
": %s", strerror (errno));
53 struct termios termios;
54 if (tcgetattr (fd, &termios) < 0)
56 termios.c_lflag &= ~(ICANON | ECHO);
57 termios.c_cc[VMIN] = vmin;
58 termios.c_cc[VTIME] = vtime;
59 if (tcsetattr (fd, TCSANOW, &termios) < 0)
69 int flags = fcntl (fd, F_GETFL);
76 if (fcntl (fd, F_SETFL, flags) < 0)
86handle_error (ssize_t retval,
int *fd,
bool fd_is_sock,
const char *call)
114 struct pipe pipes[2];
129 memset (pipes, 0,
sizeof pipes);
135 while (pipes[0].in != -1 || pipes[1].in != -1
136 || (pipes[1].size && pipes[1].out != -1))
138 fd_set read_fds, write_fds;
144 FD_ZERO (&write_fds);
145 for (i = 0; i < 2; i++)
147 struct pipe *p = &pipes[i];
152 if (i == 0 && !pipes[1].active)
155 if (p->in != -1 && p->size + p->ofs <
sizeof p->buf)
156 FD_SET (p->in, &read_fds);
157 if (p->out != -1 && p->size > 0)
158 FD_SET (p->out, &write_fds);
160 sigemptyset (&empty_set);
161 retval = pselect (FD_SETSIZE, &read_fds, &write_fds,
NULL,
NULL,
168 struct pipe *p = &pipes[1];
179 n =
write (p->out, p->buf + p->ofs, p->size);
189 p->size = n =
read (p->in, p->buf,
sizeof p->buf);
197 for (i = 0; i < 2; i++)
199 struct pipe *p = &pipes[i];
200 if (p->in != -1 && FD_ISSET (p->in, &read_fds))
202 ssize_t n =
read (p->in, p->buf + p->ofs + p->size,
203 sizeof p->buf - p->ofs - p->size);
208 if (p->size == BUFSIZ && p->ofs != 0)
210 memmove (p->buf, p->buf + p->ofs, p->size);
214 else if (!
handle_error (n, &p->in, p->in == sock,
"read"))
217 if (p->out != -1 && FD_ISSET (p->out, &write_fds))
219 ssize_t n =
write (p->out, p->buf + p->ofs, p->size);
227 else if (!
handle_error (n, &p->out, p->out == sock,
"write"))
244 struct itimerval zero_itimerval;
245 struct sockaddr_un sun;
246 sigset_t sigchld_set;
252 "usage: squish-unix SOCKET COMMAND [ARG]...\n"
253 "Squishes both stdin and stdout into a single Unix domain\n"
254 "socket named SOCKET, and runs COMMAND as a subprocess.\n");
259 sock = socket (PF_LOCAL, SOCK_STREAM, 0);
264 sun.sun_family = AF_LOCAL;
265 strncpy (sun.sun_path, argv[1],
sizeof sun.sun_path);
266 sun.sun_path[
sizeof sun.sun_path - 1] =
'\0';
267 if (unlink (sun.sun_path) < 0 && errno != ENOENT)
269 if (bind (sock, (
struct sockaddr *) &sun,
270 (
offsetof (
struct sockaddr_un, sun_path)
271 +
strlen (sun.sun_path) + 1)) < 0)
275 if (listen (sock, 1) < 0)
279 sigemptyset (&sigchld_set);
280 sigaddset (&sigchld_set, SIGCHLD);
281 if (sigprocmask (SIG_BLOCK, &sigchld_set,
NULL) < 0)
289 memset (&zero_itimerval, 0,
sizeof zero_itimerval);
290 if (setitimer (ITIMER_VIRTUAL, &zero_itimerval,
NULL) < 0)
309 FD_SET (sock, &read_fds);
310 sigemptyset (&empty_set);
311 retval = pselect (sock + 1, &read_fds,
NULL,
NULL,
NULL, &empty_set);
333 if (
close (sock) < 0)
335 execvp (argv[2], argv + 2);
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]
static void signal(struct intq *q, struct thread **waiter)
int printf(const char *format,...)
Writes formatted output to the console.
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 bool handle_error(ssize_t retval, int *fd, bool fd_is_sock, const char *call)
Handle a read or write on *FD, which is the socket if FD_IS_SOCK is true, that returned end-of-file o...
static void sigchld_handler(int signo __attribute__((unused)))
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 relay(int sock)
Copies data from stdin to SOCK and from SOCK to stdout until no more data can be read or written.
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 offsetof(TYPE, MEMBER)
#define STDIN_FILENO
Include lib/user/stdio.h or lib/kernel/stdio.h, as appropriate.
size_t strlen(const char *string)
Returns the length of STRING.
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.