00001 #define _GNU_SOURCE 1
00002
00003 #include <errno.h>
00004 #include <fcntl.h>
00005 #include <signal.h>
00006 #include <stdarg.h>
00007 #include <stdbool.h>
00008 #include <stddef.h>
00009 #include <stdio.h>
00010 #include <stdlib.h>
00011 #include <string.h>
00012 #include <stropts.h>
00013 #include <sys/ioctl.h>
00014 #include <sys/stat.h>
00015 #include <sys/time.h>
00016 #include <sys/types.h>
00017 #include <sys/wait.h>
00018 #include <sys/socket.h>
00019 #include <sys/un.h>
00020 #include <termios.h>
00021 #include <unistd.h>
00022
00023 static void
00024 fail_io (const char *msg, ...)
00025 __attribute__ ((noreturn))
00026 __attribute__ ((format (printf, 1, 2)));
00027
00028
00029
00030
00031 static void
00032 fail_io (const char *msg, ...)
00033 {
00034 va_list args;
00035
00036 va_start (args, msg);
00037 vfprintf (stderr, msg, args);
00038 va_end (args);
00039
00040 if (errno != 0)
00041 fprintf (stderr, ": %s", strerror (errno));
00042 putc ('\n', stderr);
00043 exit (EXIT_FAILURE);
00044 }
00045
00046
00047
00048
00049 static void
00050 make_noncanon (int fd, int vmin, int vtime)
00051 {
00052 if (isatty (fd))
00053 {
00054 struct termios termios;
00055 if (tcgetattr (fd, &termios) < 0)
00056 fail_io ("tcgetattr");
00057 termios.c_lflag &= ~(ICANON | ECHO);
00058 termios.c_cc[VMIN] = vmin;
00059 termios.c_cc[VTIME] = vtime;
00060 if (tcsetattr (fd, TCSANOW, &termios) < 0)
00061 fail_io ("tcsetattr");
00062 }
00063 }
00064
00065
00066
00067 static void
00068 make_nonblocking (int fd, bool nonblocking)
00069 {
00070 int flags = fcntl (fd, F_GETFL);
00071 if (flags < 0)
00072 fail_io ("fcntl");
00073 if (nonblocking)
00074 flags |= O_NONBLOCK;
00075 else
00076 flags &= ~O_NONBLOCK;
00077 if (fcntl (fd, F_SETFL, flags) < 0)
00078 fail_io ("fcntl");
00079 }
00080
00081
00082
00083
00084
00085
00086 static bool
00087 handle_error (ssize_t retval, int *fd, bool fd_is_sock, const char *call)
00088 {
00089 if (retval == 0)
00090 {
00091 if (fd_is_sock)
00092 return false;
00093 else
00094 {
00095 *fd = -1;
00096 return true;
00097 }
00098 }
00099 else
00100 fail_io (call);
00101 }
00102
00103
00104
00105 static void
00106 relay (int sock)
00107 {
00108 struct pipe
00109 {
00110 int in, out;
00111 char buf[BUFSIZ];
00112 size_t size, ofs;
00113 bool active;
00114 };
00115 struct pipe pipes[2];
00116
00117
00118
00119 lseek (STDIN_FILENO, 0, SEEK_SET);
00120
00121
00122 make_nonblocking (sock, true);
00123 make_nonblocking (STDIN_FILENO, true);
00124 make_nonblocking (STDOUT_FILENO, true);
00125
00126
00127
00128 make_noncanon (STDIN_FILENO, 1, 0);
00129
00130 memset (pipes, 0, sizeof pipes);
00131 pipes[0].in = STDIN_FILENO;
00132 pipes[0].out = sock;
00133 pipes[1].in = sock;
00134 pipes[1].out = STDOUT_FILENO;
00135
00136 while (pipes[0].in != -1 || pipes[1].in != -1
00137 || (pipes[1].size && pipes[1].out != -1))
00138 {
00139 fd_set read_fds, write_fds;
00140 sigset_t empty_set;
00141 int retval;
00142 int i;
00143
00144 FD_ZERO (&read_fds);
00145 FD_ZERO (&write_fds);
00146 for (i = 0; i < 2; i++)
00147 {
00148 struct pipe *p = &pipes[i];
00149
00150
00151
00152
00153 if (i == 0 && !pipes[1].active)
00154 continue;
00155
00156 if (p->in != -1 && p->size + p->ofs < sizeof p->buf)
00157 FD_SET (p->in, &read_fds);
00158 if (p->out != -1 && p->size > 0)
00159 FD_SET (p->out, &write_fds);
00160 }
00161 sigemptyset (&empty_set);
00162 retval = pselect (FD_SETSIZE, &read_fds, &write_fds, NULL, NULL,
00163 &empty_set);
00164 if (retval < 0)
00165 {
00166 if (errno == EINTR)
00167 {
00168
00169 struct pipe *p = &pipes[1];
00170 if (p->out == -1)
00171 exit (0);
00172 make_nonblocking (STDOUT_FILENO, false);
00173 for (;;)
00174 {
00175 ssize_t n;
00176
00177
00178 while (p->size > 0)
00179 {
00180 n = write (p->out, p->buf + p->ofs, p->size);
00181 if (n < 0)
00182 fail_io ("write");
00183 else if (n == 0)
00184 fail_io ("zero-length write");
00185 p->ofs += n;
00186 p->size -= n;
00187 }
00188 p->ofs = 0;
00189
00190 p->size = n = read (p->in, p->buf, sizeof p->buf);
00191 if (n <= 0)
00192 exit (0);
00193 }
00194 }
00195 fail_io ("select");
00196 }
00197
00198 for (i = 0; i < 2; i++)
00199 {
00200 struct pipe *p = &pipes[i];
00201 if (p->in != -1 && FD_ISSET (p->in, &read_fds))
00202 {
00203 ssize_t n = read (p->in, p->buf + p->ofs + p->size,
00204 sizeof p->buf - p->ofs - p->size);
00205 if (n > 0)
00206 {
00207 p->active = true;
00208 p->size += n;
00209 if (p->size == BUFSIZ && p->ofs != 0)
00210 {
00211 memmove (p->buf, p->buf + p->ofs, p->size);
00212 p->ofs = 0;
00213 }
00214 }
00215 else if (!handle_error (n, &p->in, p->in == sock, "read"))
00216 return;
00217 }
00218 if (p->out != -1 && FD_ISSET (p->out, &write_fds))
00219 {
00220 ssize_t n = write (p->out, p->buf + p->ofs, p->size);
00221 if (n > 0)
00222 {
00223 p->ofs += n;
00224 p->size -= n;
00225 if (p->size == 0)
00226 p->ofs = 0;
00227 }
00228 else if (!handle_error (n, &p->out, p->out == sock, "write"))
00229 return;
00230 }
00231 }
00232 }
00233 }
00234
00235 static void
00236 sigchld_handler (int signo __attribute__ ((unused)))
00237 {
00238
00239 }
00240
00241 int
00242 main (int argc __attribute__ ((unused)), char *argv[])
00243 {
00244 pid_t pid;
00245 struct itimerval zero_itimerval;
00246 struct sockaddr_un sun;
00247 sigset_t sigchld_set;
00248 int sock;
00249
00250 if (argc < 3)
00251 {
00252 fprintf (stderr,
00253 "usage: squish-unix SOCKET COMMAND [ARG]...\n"
00254 "Squishes both stdin and stdout into a single Unix domain\n"
00255 "socket named SOCKET, and runs COMMAND as a subprocess.\n");
00256 return EXIT_FAILURE;
00257 }
00258
00259
00260 sock = socket (PF_LOCAL, SOCK_STREAM, 0);
00261 if (sock < 0)
00262 fail_io ("socket");
00263
00264
00265 sun.sun_family = AF_LOCAL;
00266 strncpy (sun.sun_path, argv[1], sizeof sun.sun_path);
00267 sun.sun_path[sizeof sun.sun_path - 1] = '\0';
00268 if (unlink (sun.sun_path) < 0 && errno != ENOENT)
00269 fail_io ("unlink");
00270 if (bind (sock, (struct sockaddr *) &sun,
00271 (offsetof (struct sockaddr_un, sun_path)
00272 + strlen (sun.sun_path) + 1)) < 0)
00273 fail_io ("bind");
00274
00275
00276 if (listen (sock, 1) < 0)
00277 fail_io ("listen");
00278
00279
00280 sigemptyset (&sigchld_set);
00281 sigaddset (&sigchld_set, SIGCHLD);
00282 if (sigprocmask (SIG_BLOCK, &sigchld_set, NULL) < 0)
00283 fail_io ("sigprocmask");
00284 if (signal (SIGCHLD, sigchld_handler) == SIG_ERR)
00285 fail_io ("signal");
00286
00287
00288
00289
00290 memset (&zero_itimerval, 0, sizeof zero_itimerval);
00291 if (setitimer (ITIMER_VIRTUAL, &zero_itimerval, NULL) < 0)
00292 fail_io ("setitimer");
00293
00294 pid = fork ();
00295 if (pid < 0)
00296 fail_io ("fork");
00297 else if (pid != 0)
00298 {
00299
00300 make_nonblocking (sock, true);
00301 for (;;)
00302 {
00303 fd_set read_fds;
00304 sigset_t empty_set;
00305 int retval;
00306 int conn;
00307
00308
00309 FD_ZERO (&read_fds);
00310 FD_SET (sock, &read_fds);
00311 sigemptyset (&empty_set);
00312 retval = pselect (sock + 1, &read_fds, NULL, NULL, NULL, &empty_set);
00313 if (retval < 0)
00314 {
00315 if (errno == EINTR)
00316 break;
00317 fail_io ("select");
00318 }
00319
00320
00321 conn = accept (sock, NULL, NULL);
00322 if (conn < 0)
00323 fail_io ("accept");
00324
00325
00326 relay (conn);
00327 close (conn);
00328 }
00329 return 0;
00330 }
00331 else
00332 {
00333
00334 if (close (sock) < 0)
00335 fail_io ("close");
00336 execvp (argv[2], argv + 2);
00337 fail_io ("exec");
00338 }
00339 }