Fix to make_file() to exit earlier if a file is excluded, because doing
[rsync/rsync.git] / socket.c
CommitLineData
7c1b4daa
MP
1/* -*- c-file-style: "linux" -*-
2
eecd22ff 3 Copyright (C) 1992-2001 by Andrew Tridgell <tridge@samba.org>
7d91d5a6 4 Copyright (C) 2001 by Martin Pool <mbp@samba.org>
bc2e93eb
AT
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19*/
20
21/*
22 socket functions used in rsync
23
24 */
25
f0fca04e
AT
26#include "rsync.h"
27
4c3b4b25 28
660c6fbd
MP
29/* Establish a proxy connection on an open socket to a web roxy by
30 * using the CONNECT method. */
4c3b4b25
AT
31static int establish_proxy_connection(int fd, char *host, int port)
32{
33 char buffer[1024];
34 char *cp;
35
8950ac03 36 snprintf(buffer, sizeof(buffer), "CONNECT %s:%d HTTP/1.0\r\n\r\n", host, port);
4c3b4b25 37 if (write(fd, buffer, strlen(buffer)) != strlen(buffer)) {
660c6fbd 38 rprintf(FERROR, "failed to write to proxy: %s\n",
4c3b4b25
AT
39 strerror(errno));
40 return -1;
41 }
42
43 for (cp = buffer; cp < &buffer[sizeof(buffer) - 1]; cp++) {
44 if (read(fd, cp, 1) != 1) {
660c6fbd
MP
45 rprintf(FERROR, "failed to read from proxy: %s\n",
46 strerror(errno));
4c3b4b25
AT
47 return -1;
48 }
49 if (*cp == '\n')
50 break;
51 }
52
53 if (*cp != '\n')
54 cp++;
55 *cp-- = '\0';
56 if (*cp == '\r')
57 *cp = '\0';
58 if (strncmp(buffer, "HTTP/", 5) != 0) {
59 rprintf(FERROR, "bad response from proxy - %s\n",
60 buffer);
61 return -1;
62 }
63 for (cp = &buffer[5]; isdigit(*cp) || (*cp == '.'); cp++)
64 ;
65 while (*cp == ' ')
66 cp++;
67 if (*cp != '2') {
68 rprintf(FERROR, "bad response from proxy - %s\n",
69 buffer);
70 return -1;
71 }
72 /* throw away the rest of the HTTP header */
73 while (1) {
74 for (cp = buffer; cp < &buffer[sizeof(buffer) - 1];
75 cp++) {
76 if (read(fd, cp, 1) != 1) {
660c6fbd
MP
77 rprintf(FERROR, "failed to read from proxy: %s\n",
78 strerror(errno));
4c3b4b25
AT
79 return -1;
80 }
81 if (*cp == '\n')
82 break;
83 }
84 if ((cp > buffer) && (*cp == '\n'))
85 cp--;
86 if ((cp == buffer) && ((*cp == '\n') || (*cp == '\r')))
87 break;
88 }
89 return 0;
90}
91
92
eecd22ff 93
f0fca04e 94/* open a socket to a tcp remote host with the specified port
4c3b4b25
AT
95 based on code from Warren
96 proxy support by Stephen Rothwell */
eecd22ff
MP
97static int open_socket_out (char *host,
98 int port,
99 struct in_addr *address)
bc2e93eb 100{
f0fca04e
AT
101 int type = SOCK_STREAM;
102 struct sockaddr_in sock_out;
e30f0657 103 struct sockaddr_in sock;
f0fca04e
AT
104 int res;
105 struct hostent *hp;
4c3b4b25
AT
106 char *h;
107 unsigned p;
108 int proxied = 0;
109 char buffer[1024];
110 char *cp;
111
660c6fbd
MP
112 /* if we have a RSYNC_PROXY env variable then redirect our
113 * connetcion via a web proxy at the given address. The format
114 * is hostname:port */
4c3b4b25
AT
115 h = getenv("RSYNC_PROXY");
116 proxied = (h != NULL) && (*h != '\0');
117
118 if (proxied) {
119 strlcpy(buffer, h, sizeof(buffer));
120 cp = strchr(buffer, ':');
121 if (cp == NULL) {
660c6fbd
MP
122 rprintf(FERROR,
123 "invalid proxy specification: should be HOST:PORT\n");
4c3b4b25
AT
124 return -1;
125 }
126 *cp++ = '\0';
127 p = atoi(cp);
128 h = buffer;
129 } else {
130 h = host;
131 p = port;
132 }
f0fca04e
AT
133
134 res = socket(PF_INET, type, 0);
135 if (res == -1) {
136 return -1;
137 }
138
4c3b4b25 139 hp = gethostbyname(h);
f0fca04e 140 if (!hp) {
7d91d5a6 141 rprintf(FERROR,"unknown host: \"%s\"\n", h);
4c3b4b25 142 close(res);
f0fca04e
AT
143 return -1;
144 }
145
146 memcpy(&sock_out.sin_addr, hp->h_addr, hp->h_length);
4c3b4b25 147 sock_out.sin_port = htons(p);
f0fca04e
AT
148 sock_out.sin_family = PF_INET;
149
e30f0657
AT
150 if (address) {
151 sock.sin_addr = *address;
152 sock.sin_port = 0;
153 sock.sin_family = hp->h_addrtype;
154 bind(res, (struct sockaddr * ) &sock,sizeof(sock));
155 }
156
f0fca04e 157 if (connect(res,(struct sockaddr *)&sock_out,sizeof(sock_out))) {
eecd22ff
MP
158 rprintf (FERROR, RSYNC_NAME ": failed to connect to host %s: %s\n",
159 h, strerror(errno));
4c3b4b25
AT
160 close(res);
161 return -1;
162 }
163
164 if (proxied && establish_proxy_connection(res, host, port) != 0) {
f0fca04e 165 close(res);
f0fca04e
AT
166 return -1;
167 }
168
169 return res;
170}
171
172
eecd22ff
MP
173/**
174 * Open an outgoing socket, but allow for it to be intercepted by
175 * $RSYNC_CONNECT_PROG, which will execute a program across a TCP
176 * socketpair rather than really opening a socket.
177 *
178 * We use this primarily in testing to detect TCP flow bugs, but not
179 * cause security problems by really opening remote connections.
180 *
181 * This is based on the Samba LIBSMB_PROG feature.
182 **/
183int open_socket_out_wrapped (char *host,
184 int port,
185 struct in_addr *address)
186{
187 char *prog;
188
189 if ((prog = getenv ("RSYNC_CONNECT_PROG")) != NULL)
190 return sock_exec (prog);
191 else
192 return open_socket_out (host, port, address);
193}
194
195
196
f0fca04e
AT
197/****************************************************************************
198open a socket of the specified type, port and address for incoming data
199****************************************************************************/
5c9730a4 200static int open_socket_in(int type, int port, struct in_addr *address)
f0fca04e 201{
f0fca04e 202 struct sockaddr_in sock;
f0fca04e
AT
203 int res;
204 int one=1;
205
f5780433 206 memset((char *)&sock,0,sizeof(sock));
f0fca04e 207 sock.sin_port = htons(port);
376acbfa 208 sock.sin_family = AF_INET;
5c9730a4
AT
209 if (address) {
210 sock.sin_addr = *address;
211 } else {
212 sock.sin_addr.s_addr = INADDR_ANY;
213 }
376acbfa 214 res = socket(AF_INET, type, 0);
f0fca04e 215 if (res == -1) {
eecd22ff 216 rprintf(FERROR, RSYNC_NAME ": socket failed: %s\n",
660c6fbd 217 strerror(errno));
f0fca04e
AT
218 return -1;
219 }
220
221 setsockopt(res,SOL_SOCKET,SO_REUSEADDR,(char *)&one,sizeof(one));
222
223 /* now we've got a socket - we need to bind it */
224 if (bind(res, (struct sockaddr * ) &sock,sizeof(sock)) == -1) {
660c6fbd
MP
225 rprintf(FERROR,"bind failed on port %d: %s\n", port,
226 strerror(errno));
4d66e00a
MP
227 if (errno == EACCES && port < 1024) {
228 rprintf(FERROR, "Note: you must be root to bind "
229 "to low-numbered ports");
230 }
f0fca04e
AT
231 close(res);
232 return -1;
233 }
234
235 return res;
236}
237
238
7c1b4daa
MP
239/*
240 * Determine if a file descriptor is in fact a socket
241 */
f0fca04e
AT
242int is_a_socket(int fd)
243{
ac2a1a44
MP
244 int v;
245 socklen_t l;
3eb38818 246 l = sizeof(int);
7c1b4daa
MP
247
248 /* Parameters to getsockopt, setsockopt etc are very
249 * unstandardized across platforms, so don't be surprised if
ac2a1a44
MP
250 * there are compiler warnings on e.g. SCO OpenSwerver or AIX.
251 * It seems they all eventually get the right idea.
7c1b4daa
MP
252 *
253 * Debian says: ``The fifth argument of getsockopt and
254 * setsockopt is in reality an int [*] (and this is what BSD
255 * 4.* and libc4 and libc5 have). Some POSIX confusion
256 * resulted in the present socklen_t. The draft standard has
257 * not been adopted yet, but glibc2 already follows it and
258 * also has socklen_t [*]. See also accept(2).''
259 *
260 * We now return to your regularly scheduled programming. */
3eb38818 261 return(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&v, &l) == 0);
f0fca04e
AT
262}
263
264
8ef4ffd6 265void start_accept_loop(int port, int (*fn)(int ))
f0fca04e
AT
266{
267 int s;
5c9730a4 268 extern struct in_addr socket_address;
f0fca04e 269
f0fca04e 270 /* open an incoming socket */
5c9730a4 271 s = open_socket_in(SOCK_STREAM, port, &socket_address);
f0fca04e 272 if (s == -1)
65417579 273 exit_cleanup(RERR_SOCKETIO);
f0fca04e
AT
274
275 /* ready to listen */
276 if (listen(s, 5) == -1) {
277 close(s);
65417579 278 exit_cleanup(RERR_SOCKETIO);
f0fca04e
AT
279 }
280
281
282 /* now accept incoming connections - forking a new process
283 for each incoming connection */
284 while (1) {
285 fd_set fds;
286 int fd;
287 struct sockaddr addr;
546434f8 288 socklen_t in_addrlen = sizeof(addr);
f0fca04e 289
15b84e14
DD
290 /* close log file before the potentially very long select so
291 file can be trimmed by another process instead of growing
292 forever */
293 log_close();
45a83540 294
f0fca04e
AT
295 FD_ZERO(&fds);
296 FD_SET(s, &fds);
297
298 if (select(s+1, &fds, NULL, NULL, NULL) != 1) {
299 continue;
300 }
301
302 if(!FD_ISSET(s, &fds)) continue;
303
7c1b4daa 304 /* See note above prototypes. */
546434f8 305 fd = accept(s,&addr, &in_addrlen);
f0fca04e
AT
306
307 if (fd == -1) continue;
308
31f440e6
AT
309 signal(SIGCHLD, SIG_IGN);
310
311 /* we shouldn't have any children left hanging around
312 but I have had reports that on Digital Unix zombies
313 are produced, so this ensures that they are reaped */
314#ifdef WNOHANG
0503f060 315 while (waitpid(-1, NULL, WNOHANG) > 0);
31f440e6
AT
316#endif
317
f0fca04e
AT
318 if (fork()==0) {
319 close(s);
320
15b84e14
DD
321 /* open log file in child before possibly giving
322 up privileges */
323 log_open();
324
f0fca04e
AT
325 _exit(fn(fd));
326 }
327
328 close(fd);
329 }
f0fca04e
AT
330}
331
332
333enum SOCK_OPT_TYPES {OPT_BOOL,OPT_INT,OPT_ON};
334
335struct
336{
337 char *name;
338 int level;
339 int option;
340 int value;
341 int opttype;
342} socket_options[] = {
343 {"SO_KEEPALIVE", SOL_SOCKET, SO_KEEPALIVE, 0, OPT_BOOL},
344 {"SO_REUSEADDR", SOL_SOCKET, SO_REUSEADDR, 0, OPT_BOOL},
345 {"SO_BROADCAST", SOL_SOCKET, SO_BROADCAST, 0, OPT_BOOL},
346#ifdef TCP_NODELAY
347 {"TCP_NODELAY", IPPROTO_TCP, TCP_NODELAY, 0, OPT_BOOL},
348#endif
349#ifdef IPTOS_LOWDELAY
350 {"IPTOS_LOWDELAY", IPPROTO_IP, IP_TOS, IPTOS_LOWDELAY, OPT_ON},
351#endif
352#ifdef IPTOS_THROUGHPUT
353 {"IPTOS_THROUGHPUT", IPPROTO_IP, IP_TOS, IPTOS_THROUGHPUT, OPT_ON},
354#endif
355#ifdef SO_SNDBUF
356 {"SO_SNDBUF", SOL_SOCKET, SO_SNDBUF, 0, OPT_INT},
357#endif
358#ifdef SO_RCVBUF
359 {"SO_RCVBUF", SOL_SOCKET, SO_RCVBUF, 0, OPT_INT},
360#endif
361#ifdef SO_SNDLOWAT
362 {"SO_SNDLOWAT", SOL_SOCKET, SO_SNDLOWAT, 0, OPT_INT},
363#endif
364#ifdef SO_RCVLOWAT
365 {"SO_RCVLOWAT", SOL_SOCKET, SO_RCVLOWAT, 0, OPT_INT},
366#endif
367#ifdef SO_SNDTIMEO
368 {"SO_SNDTIMEO", SOL_SOCKET, SO_SNDTIMEO, 0, OPT_INT},
369#endif
370#ifdef SO_RCVTIMEO
371 {"SO_RCVTIMEO", SOL_SOCKET, SO_RCVTIMEO, 0, OPT_INT},
372#endif
373 {NULL,0,0,0,0}};
374
375
376
377/****************************************************************************
378set user socket options
379****************************************************************************/
380void set_socket_options(int fd, char *options)
381{
382 char *tok;
a6801c39
AT
383 if (!options || !*options) return;
384
f0fca04e
AT
385 options = strdup(options);
386
387 if (!options) out_of_memory("set_socket_options");
388
389 for (tok=strtok(options, " \t,"); tok; tok=strtok(NULL," \t,")) {
390 int ret=0,i;
391 int value = 1;
392 char *p;
393 int got_value = 0;
394
395 if ((p = strchr(tok,'='))) {
396 *p = 0;
397 value = atoi(p+1);
398 got_value = 1;
399 }
400
401 for (i=0;socket_options[i].name;i++)
402 if (strcmp(socket_options[i].name,tok)==0)
403 break;
404
405 if (!socket_options[i].name) {
406 rprintf(FERROR,"Unknown socket option %s\n",tok);
407 continue;
408 }
409
410 switch (socket_options[i].opttype) {
411 case OPT_BOOL:
412 case OPT_INT:
413 ret = setsockopt(fd,socket_options[i].level,
414 socket_options[i].option,(char *)&value,sizeof(int));
415 break;
416
417 case OPT_ON:
418 if (got_value)
419 rprintf(FERROR,"syntax error - %s does not take a value\n",tok);
420
421 {
422 int on = socket_options[i].value;
423 ret = setsockopt(fd,socket_options[i].level,
424 socket_options[i].option,(char *)&on,sizeof(int));
425 }
426 break;
427 }
428
429 if (ret != 0)
660c6fbd
MP
430 rprintf(FERROR, "failed to set socket option %s: %s\n", tok,
431 strerror(errno));
f0fca04e
AT
432 }
433
434 free(options);
435}
436
437/****************************************************************************
438become a daemon, discarding the controlling terminal
439****************************************************************************/
440void become_daemon(void)
441{
b11ed3b1
AT
442 int i;
443
c46ded46 444 if (fork()) {
f0fca04e 445 _exit(0);
c46ded46 446 }
f0fca04e
AT
447
448 /* detach from the terminal */
449#ifdef HAVE_SETSID
450 setsid();
451#else
452#ifdef TIOCNOTTY
c46ded46
AT
453 i = open("/dev/tty", O_RDWR);
454 if (i >= 0) {
455 ioctl(i, (int) TIOCNOTTY, (char *)0);
456 close(i);
f0fca04e
AT
457 }
458#endif /* TIOCNOTTY */
459#endif
b11ed3b1
AT
460 /* make sure that stdin, stdout an stderr don't stuff things
461 up (library functions, for example) */
462 for (i=0;i<3;i++) {
463 close(i);
464 open("/dev/null", O_RDWR);
465 }
bc2e93eb 466}
ff8b29b8
AT
467
468/*******************************************************************
469 return the IP addr of the client as a string
470 ******************************************************************/
471char *client_addr(int fd)
472{
473 struct sockaddr sa;
474 struct sockaddr_in *sockin = (struct sockaddr_in *) (&sa);
c1f62a57 475 socklen_t length = sizeof(sa);
ff8b29b8 476 static char addr_buf[100];
11a5a3c7
AT
477 static int initialised;
478
479 if (initialised) return addr_buf;
480
481 initialised = 1;
ff8b29b8
AT
482
483 if (getpeername(fd, &sa, &length)) {
65417579 484 exit_cleanup(RERR_SOCKETIO);
ff8b29b8 485 }
11a5a3c7 486
37f9805d 487 strlcpy(addr_buf,(char *)inet_ntoa(sockin->sin_addr), sizeof(addr_buf));
ff8b29b8
AT
488 return addr_buf;
489}
490
491
492/*******************************************************************
493 return the DNS name of the client
494 ******************************************************************/
495char *client_name(int fd)
496{
497 struct sockaddr sa;
498 struct sockaddr_in *sockin = (struct sockaddr_in *) (&sa);
546434f8 499 socklen_t length = sizeof(sa);
ff8b29b8
AT
500 static char name_buf[100];
501 struct hostent *hp;
de5fb374
AT
502 char **p;
503 char *def = "UNKNOWN";
11a5a3c7
AT
504 static int initialised;
505
506 if (initialised) return name_buf;
507
508 initialised = 1;
ff8b29b8 509
de5fb374 510 strcpy(name_buf,def);
ff8b29b8
AT
511
512 if (getpeername(fd, &sa, &length)) {
65417579 513 exit_cleanup(RERR_SOCKETIO);
ff8b29b8
AT
514 }
515
516 /* Look up the remote host name. */
517 if ((hp = gethostbyaddr((char *) &sockin->sin_addr,
518 sizeof(sockin->sin_addr),
519 AF_INET))) {
37f9805d 520 strlcpy(name_buf,(char *)hp->h_name,sizeof(name_buf));
ff8b29b8
AT
521 }
522
de5fb374
AT
523
524 /* do a forward lookup as well to prevent spoofing */
525 hp = gethostbyname(name_buf);
526 if (!hp) {
d58911fb 527 strcpy (name_buf,def);
f8014b86 528 rprintf (FERROR, "reverse name lookup for \"%s\" failed\n",
d58911fb 529 name_buf);
de5fb374
AT
530 } else {
531 for (p=hp->h_addr_list;*p;p++) {
532 if (memcmp(*p, &sockin->sin_addr, hp->h_length) == 0) {
533 break;
534 }
535 }
536 if (!*p) {
537 strcpy(name_buf,def);
538 rprintf(FERROR,"reverse name lookup mismatch - spoofed address?\n");
539 }
540 }
541
ff8b29b8
AT
542 return name_buf;
543}
5c9730a4 544
d58911fb
MP
545/**
546 Convert a string to an IP address. The string can be a name or
547 dotted decimal number.
548
549 Returns a pointer to a static in_addr struct -- if you call this
550 more than once then you should copy it.
551*/
5c9730a4
AT
552struct in_addr *ip_address(const char *str)
553{
554 static struct in_addr ret;
555 struct hostent *hp;
556
f8014b86
MP
557 if (!str) {
558 rprintf (FERROR, "ip_address received NULL name\n");
559 return NULL;
560 }
d58911fb 561
5c9730a4
AT
562 /* try as an IP address */
563 if (inet_aton(str, &ret) != 0) {
564 return &ret;
565 }
566
567 /* otherwise assume it's a network name of some sort and use
568 gethostbyname */
7d91d5a6 569 if ((hp = gethostbyname (str)) == 0) {
d58911fb 570 rprintf(FERROR, "gethostbyname failed for \"%s\": unknown host?\n",str);
5c9730a4
AT
571 return NULL;
572 }
573
574 if (hp->h_addr == NULL) {
d58911fb 575 rprintf(FERROR, "gethostbyname: host address is invalid for host \"%s\"\n",str);
5c9730a4
AT
576 return NULL;
577 }
578
7d91d5a6 579 if (hp->h_length > sizeof ret) {
d58911fb
MP
580 rprintf(FERROR, "gethostbyname: host address for \"%s\" is too large\n",
581 str);
5c9730a4
AT
582 return NULL;
583 }
584
7d91d5a6
MP
585 if (hp->h_addrtype != AF_INET) {
586 rprintf (FERROR, "gethostname: host address for \"%s\" is not IPv4\n",
587 str);
588 return NULL;
589 }
590
591 /* This is kind of difficult. The only field in ret is
592 s_addr, which is the IP address as a 32-bit int. On
593 UNICOS, s_addr is in fact a *bitfield* for reasons best
594 know to Cray. This means we can't memcpy in to it. On the
595 other hand, h_addr is a char*, so we can't just assign.
596
597 Since there's meant to be only one field inside the in_addr
598 structure we will try just copying over the top and see how
599 that goes. */
600 memcpy (&ret, hp->h_addr, hp->h_length);
5c9730a4 601
7d91d5a6 602 return &ret;
5c9730a4 603}
eecd22ff
MP
604
605
606
607/*******************************************************************
608this is like socketpair but uses tcp. It is used by the Samba
609regression test code
610The function guarantees that nobody else can attach to the socket,
611or if they do that this function fails and the socket gets closed
612returns 0 on success, -1 on failure
613the resulting file descriptors are symmetrical
614 ******************************************************************/
615static int socketpair_tcp(int fd[2])
616{
617 int listener;
618 struct sockaddr_in sock;
619 struct sockaddr_in sock2;
620 socklen_t socklen = sizeof(sock);
621 int connect_done = 0;
622
623 fd[0] = fd[1] = listener = -1;
624
625 memset(&sock, 0, sizeof(sock));
626
627 if ((listener = socket(PF_INET, SOCK_STREAM, 0)) == -1) goto failed;
628
629 memset(&sock2, 0, sizeof(sock2));
630#ifdef HAVE_SOCK_SIN_LEN
631 sock2.sin_len = sizeof(sock2);
632#endif
633 sock2.sin_family = PF_INET;
634
635 bind(listener, (struct sockaddr *)&sock2, sizeof(sock2));
636
637 if (listen(listener, 1) != 0) goto failed;
638
639 if (getsockname(listener, (struct sockaddr *)&sock, &socklen) != 0) goto failed;
640
641 if ((fd[1] = socket(PF_INET, SOCK_STREAM, 0)) == -1) goto failed;
642
643 set_nonblocking(fd[1]);
644
645 sock.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
646
647 if (connect(fd[1],(struct sockaddr *)&sock,sizeof(sock)) == -1) {
648 if (errno != EINPROGRESS) goto failed;
649 } else {
650 connect_done = 1;
651 }
652
653 if ((fd[0] = accept(listener, (struct sockaddr *)&sock, &socklen)) == -1) goto failed;
654
655 close(listener);
656 if (connect_done == 0) {
657 if (connect(fd[1],(struct sockaddr *)&sock,sizeof(sock)) != 0
658 && errno != EISCONN) goto failed;
659 }
660
661 set_blocking (fd[1]);
662
663 /* all OK! */
664 return 0;
665
666 failed:
667 if (fd[0] != -1) close(fd[0]);
668 if (fd[1] != -1) close(fd[1]);
669 if (listener != -1) close(listener);
670 return -1;
671}
672
673
674/*******************************************************************
675run a program on a local tcp socket, this is used to launch smbd
676when regression testing
677the return value is a socket which is attached to a subprocess
678running "prog". stdin and stdout are attached. stderr is left
679attached to the original stderr
680 ******************************************************************/
681int sock_exec(const char *prog)
682{
683 int fd[2];
684 if (socketpair_tcp(fd) != 0) {
685 rprintf (FERROR, RSYNC_NAME
686 ": socketpair_tcp failed (%s)\n",
687 strerror(errno));
688 return -1;
689 }
690 if (fork() == 0) {
691 close(fd[0]);
692 close(0);
693 close(1);
694 dup(fd[1]);
695 dup(fd[1]);
696 if (verbose > 3)
697 fprintf (stderr,
698 RSYNC_NAME ": execute socket program \"%s\"\n",
699 prog);
700 exit (system (prog));
701 }
702 close (fd[1]);
703 return fd[0];
704}
705
706
707