+ /* make sure that stdin, stdout an stderr don't stuff things
+ up (library functions, for example) */
+ for (i=0;i<3;i++) {
+ close(i);
+ open("/dev/null", O_RDWR);
+ }
+}
+
+
+/**
+ * This is like socketpair but uses tcp. It is used by the Samba
+ * regression test code.
+ *
+ * The function guarantees that nobody else can attach to the socket,
+ * or if they do that this function fails and the socket gets closed
+ * returns 0 on success, -1 on failure the resulting file descriptors
+ * are symmetrical.
+ **/
+static int socketpair_tcp(int fd[2])
+{
+ int listener;
+ struct sockaddr_in sock;
+ struct sockaddr_in sock2;
+ socklen_t socklen = sizeof(sock);
+ int connect_done = 0;
+
+ fd[0] = fd[1] = listener = -1;
+
+ memset(&sock, 0, sizeof(sock));
+
+ if ((listener = socket(PF_INET, SOCK_STREAM, 0)) == -1) goto failed;
+
+ memset(&sock2, 0, sizeof(sock2));
+#ifdef HAVE_SOCKADDR_LEN
+ sock2.sin_len = sizeof(sock2);
+#endif
+ sock2.sin_family = PF_INET;
+
+ bind(listener, (struct sockaddr *)&sock2, sizeof(sock2));
+
+ if (listen(listener, 1) != 0) goto failed;
+
+ if (getsockname(listener, (struct sockaddr *)&sock, &socklen) != 0) goto failed;
+
+ if ((fd[1] = socket(PF_INET, SOCK_STREAM, 0)) == -1) goto failed;
+
+ set_nonblocking(fd[1]);
+
+ sock.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+ if (connect(fd[1],(struct sockaddr *)&sock,sizeof(sock)) == -1) {
+ if (errno != EINPROGRESS) goto failed;
+ } else {
+ connect_done = 1;
+ }
+
+ if ((fd[0] = accept(listener, (struct sockaddr *)&sock, &socklen)) == -1) goto failed;
+
+ close(listener);
+ if (connect_done == 0) {
+ if (connect(fd[1],(struct sockaddr *)&sock,sizeof(sock)) != 0
+ && errno != EISCONN) goto failed;
+ }
+
+ set_blocking (fd[1]);
+
+ /* all OK! */
+ return 0;
+
+ failed:
+ if (fd[0] != -1) close(fd[0]);
+ if (fd[1] != -1) close(fd[1]);
+ if (listener != -1) close(listener);
+ return -1;
+}
+
+
+
+/**
+ * Run a program on a local tcp socket, so that we can talk to it's
+ * stdin and stdout. This is used to fake a connection to a daemon
+ * for testing -- not for the normal case of running SSH.
+ *
+ * @return a socket which is attached to a subprocess running
+ * "prog". stdin and stdout are attached. stderr is left attached to
+ * the original stderr
+ **/
+int sock_exec(const char *prog)
+{
+ int fd[2];
+
+ if (socketpair_tcp(fd) != 0) {
+ rprintf (FERROR, RSYNC_NAME
+ ": socketpair_tcp failed (%s)\n",
+ strerror(errno));
+ return -1;
+ }
+ if (fork() == 0) {
+ close(fd[0]);
+ close(0);
+ close(1);
+ dup(fd[1]);
+ dup(fd[1]);
+ if (verbose > 3) {
+ /* Can't use rprintf because we've forked. */
+ fprintf (stderr,
+ RSYNC_NAME ": execute socket program \"%s\"\n",
+ prog);
+ }
+ exit (system (prog));
+ }
+ close (fd[1]);
+ return fd[0];