Fixed a bunch of "warn_unused_result" compiler warnings.
[rsync/rsync.git] / socket.c
index dd7428e..0ad766d 100644 (file)
--- a/socket.c
+++ b/socket.c
@@ -3,11 +3,11 @@
  *
  * Copyright (C) 1992-2001 Andrew Tridgell <tridge@samba.org>
  * Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
- * Copyright (C) 2003, 2004, 2005, 2006 Wayne Davison
+ * Copyright (C) 2003-2008 Wayne Davison
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation; either version 3 of the License, or
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
@@ -16,8 +16,7 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
+ * with this program; if not, visit the http://fsf.org website.
  */
 
 /* This file is now converted to use the new-style getaddrinfo()
  * emulate it using the KAME implementation. */
 
 #include "rsync.h"
+#include "itypes.h"
 #include <netinet/in_systm.h>
 #include <netinet/ip.h>
 #include <netinet/tcp.h>
 
 extern char *bind_address;
+extern char *sockopts;
 extern int default_af_hint;
+extern int connect_timeout;
 
 #ifdef HAVE_SIGACTION
 static struct sigaction sigact;
@@ -95,7 +97,7 @@ static int establish_proxy_connection(int fd, char *host, int port,
                        buffer);
                return -1;
        }
-       for (cp = &buffer[5]; isdigit(*(uchar*)cp) || *cp == '.'; cp++) {}
+       for (cp = &buffer[5]; isDigit(cp) || *cp == '.'; cp++) {}
        while (*cp == ' ')
                cp++;
        if (*cp != '2') {
@@ -157,6 +159,11 @@ int try_bind_local(int s, int ai_family, int ai_socktype,
        return -1;
 }
 
+/* connect() timeout handler based on alarm() */
+static RETSIGTYPE contimeout_handler(UNUSED(int val))
+{
+       connect_timeout = -1;
+}
 
 /**
  * Open a socket to a tcp remote host with the specified port .
@@ -225,7 +232,7 @@ int open_socket_out(char *host, int port, const char *bind_addr,
                }
                *cp++ = '\0';
                strlcpy(portbuf, cp, sizeof portbuf);
-               if (verbose >= 2) {
+               if (DEBUG_GTE(CONNECT, 1)) {
                        rprintf(FINFO, "connection via http proxy %s port %s\n",
                                h, portbuf);
                }
@@ -261,11 +268,28 @@ int open_socket_out(char *host, int port, const char *bind_addr,
                        s = -1;
                        continue;
                }
-               if (connect(s, res->ai_addr, res->ai_addrlen) < 0) {
+               if (connect_timeout > 0) {
+                       SIGACTION(SIGALRM, contimeout_handler);
+                       alarm(connect_timeout);
+               }
+
+               set_socket_options(s, sockopts);
+               while (connect(s, res->ai_addr, res->ai_addrlen) < 0) {
+                       if (connect_timeout < 0)
+                               exit_cleanup(RERR_CONTIMEOUT);
+                       if (errno == EINTR)
+                               continue;
                        close(s);
                        s = -1;
-                       continue;
+                       break;
                }
+
+               if (connect_timeout > 0)
+                       alarm(0);
+
+               if (s < 0)
+                       continue;
+
                if (proxied
                 && establish_proxy_connection(s, host, port,
                                               proxy_user, proxy_pass) != 0) {
@@ -301,7 +325,43 @@ int open_socket_out_wrapped(char *host, int port, const char *bind_addr,
 {
        char *prog = getenv("RSYNC_CONNECT_PROG");
 
-       if (verbose >= 2) {
+       if (prog && strchr(prog, '%')) {
+               int hlen = strlen(host);
+               int len = strlen(prog) + 1;
+               char *f, *t;
+               for (f = prog; *f; f++) {
+                       if (*f != '%')
+                               continue;
+                       /* Compute more than enough room. */
+                       if (f[1] == '%')
+                               f++;
+                       else
+                               len += hlen;
+               }
+               f = prog;
+               if (!(prog = new_array(char, len)))
+                       out_of_memory("open_socket_out_wrapped");
+               for (t = prog; *f; f++) {
+                       if (*f == '%') {
+                               switch (*++f) {
+                               case '%':
+                                       /* Just skips the extra '%'. */
+                                       break;
+                               case 'H':
+                                       memcpy(t, host, hlen);
+                                       t += hlen;
+                                       continue;
+                               default:
+                                       f--; /* pass % through */
+                                       break;
+                               }
+                       }
+                       *t++ = *f;
+               }
+               *t = '\0';
+       }
+
+       if (DEBUG_GTE(CONNECT, 1)) {
                rprintf(FINFO, "%sopening tcp connection to %s port %d\n",
                        prog ? "Using RSYNC_CONNECT_PROG instead of " : "",
                        host, port);
@@ -375,6 +435,10 @@ static int *open_socket_in(int type, int port, const char *bind_addr,
 
                setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
                           (char *)&one, sizeof one);
+               if (sockopts)
+                       set_socket_options(s, sockopts);
+               else
+                       set_socket_options(s, lp_socket_options());
 
 #ifdef IPV6_V6ONLY
                if (resp->ai_family == AF_INET6) {
@@ -409,8 +473,8 @@ static int *open_socket_in(int type, int port, const char *bind_addr,
        /* Only output the socket()/bind() messages if we were totally
         * unsuccessful, or if the daemon is being run with -vv. */
        for (s = 0; s < ecnt; s++) {
-               if (!i || verbose > 1)
-                       rwrite(FLOG, errmsgs[s], strlen(errmsgs[s]));
+               if (!i || DEBUG_GTE(BIND, 1))
+                       rwrite(FLOG, errmsgs[s], strlen(errmsgs[s]), 0);
                free(errmsgs[s]);
        }
        free(errmsgs);
@@ -667,35 +731,6 @@ void set_socket_options(int fd, char *options)
        free(options);
 }
 
-/**
- * Become a daemon, discarding the controlling terminal
- **/
-void become_daemon(void)
-{
-       int i;
-
-       if (fork()) {
-               _exit(0);
-       }
-
-       /* detach from the terminal */
-#ifdef HAVE_SETSID
-       setsid();
-#elif defined TIOCNOTTY
-       i = open("/dev/tty", O_RDWR);
-       if (i >= 0) {
-               ioctl(i, (int)TIOCNOTTY, (char *)0);
-               close(i);
-       }
-#endif
-       /* 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
@@ -788,22 +823,32 @@ static int socketpair_tcp(int fd[2])
  **/
 int sock_exec(const char *prog)
 {
+       pid_t pid;
        int fd[2];
 
        if (socketpair_tcp(fd) != 0) {
                rsyserr(FERROR, errno, "socketpair_tcp failed");
                return -1;
        }
-       if (verbose >= 2)
+       if (DEBUG_GTE(CMD, 1))
                rprintf(FINFO, "Running socket program: \"%s\"\n", prog);
-       if (fork() == 0) {
+
+       pid = fork();
+       if (pid < 0) {
+               rsyserr(FERROR, errno, "fork");
+               exit_cleanup(RERR_IPC);
+       }
+
+       if (pid == 0) {
                close(fd[0]);
-               close(0);
-               close(1);
-               dup(fd[1]);
-               dup(fd[1]);
+               if (dup2(fd[1], STDIN_FILENO) < 0
+                || dup2(fd[1], STDOUT_FILENO) < 0) {
+                       fprintf(stderr, "Failed to run \"%s\"\n", prog);
+                       exit(1);
+               }
                exit(system(prog));
        }
+
        close(fd[1]);
        return fd[0];
 }