Get rid of global_opts struct as suggested by Dave -- too many
[rsync/rsync.git] / socket.c
... / ...
CommitLineData
1/* -*- c-file-style: "linux" -*-
2
3 Copyright (C) 1992-2001 by Andrew Tridgell <tridge@samba.org>
4 Copyright (C) 2001 by Martin Pool <mbp@samba.org>
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 * @file socket.c
23 *
24 * Socket functions used in rsync.
25 **/
26
27#include "rsync.h"
28
29/* Establish a proxy connection on an open socket to a web roxy by
30 * using the CONNECT method. */
31static int establish_proxy_connection(int fd, char *host, int port)
32{
33 char buffer[1024];
34 char *cp;
35
36 snprintf(buffer, sizeof(buffer), "CONNECT %s:%d HTTP/1.0\r\n\r\n", host, port);
37 if (write(fd, buffer, strlen(buffer)) != strlen(buffer)) {
38 rprintf(FERROR, "failed to write to proxy: %s\n",
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) {
45 rprintf(FERROR, "failed to read from proxy: %s\n",
46 strerror(errno));
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) {
77 rprintf(FERROR, "failed to read from proxy: %s\n",
78 strerror(errno));
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
93/**
94 * Try to set the local address for a newly-created socket. Return -1
95 * if this fails.
96 **/
97int try_bind_local(int s,
98 int ai_family, int ai_socktype,
99 const char *bind_address)
100{
101 int error;
102 struct addrinfo bhints, *bres_all, *r;
103
104 memset(&bhints, 0, sizeof(bhints));
105 bhints.ai_family = ai_family;
106 bhints.ai_socktype = ai_socktype;
107 bhints.ai_flags = AI_PASSIVE;
108 if (getaddrinfo(bind_address, NULL, &bhints, &bres_all) == -1) {
109 rprintf(FERROR, RSYNC_NAME ": getaddrinfo %s: %s\n",
110 bind_address, gai_strerror(error));
111 return -1;
112 }
113
114 for (r = bres_all; r; r = r->ai_next) {
115 if (bind(s, bres->ai_addr, bres->ai_addrlen) == -1)
116 continue;
117 return s;
118 }
119
120 /* no error message; there might be some problem that allows
121 * creation of the socket but not binding, perhaps if the
122 * machine has no ipv6 address of this name. */
123 return -1;
124}
125
126
127/**
128 * Open a socket to a tcp remote host with the specified port .
129 *
130 * Based on code from Warren. Proxy support by Stephen Rothwell.
131 * getaddrinfo() rewrite contributed by KAME.net.
132 *
133 * Now that we support IPv6 we need to look up the remote machine's
134 * address first, using @p af_hint to set a preference for the type
135 * of address. Then depending on whether it has v4 or v6 addresses we
136 * try to open a connection.
137 *
138 * The loop allows for machines with some addresses which may not be
139 * reachable, perhaps because we can't e.g. route ipv6 to that network
140 * but we can get ip4 packets through.
141 *
142 * @param bind_address Local address to use. Normally NULL to bind
143 * the wildcard address.
144 *
145 * @param af_hint Address family, e.g. AF_INET or AF_INET6.
146 **/
147int open_socket_out(char *host, int port, const char *bind_address,
148 int af_hint)
149{
150 int type = SOCK_STREAM;
151 int error;
152 int s;
153 int result;
154 struct addrinfo hints, *res0, *res;
155 char portbuf[10];
156 char *h;
157 int proxied = 0;
158 char buffer[1024];
159 char *cp;
160
161 /* if we have a RSYNC_PROXY env variable then redirect our
162 * connetcion via a web proxy at the given address. The format
163 * is hostname:port */
164 h = getenv("RSYNC_PROXY");
165 proxied = (h != NULL) && (*h != '\0');
166
167 if (proxied) {
168 strlcpy(buffer, h, sizeof(buffer));
169 cp = strchr(buffer, ':');
170 if (cp == NULL) {
171 rprintf(FERROR,
172 "invalid proxy specification: should be HOST:PORT\n");
173 return -1;
174 }
175 *cp++ = '\0';
176 strcpy(portbuf, cp);
177 h = buffer;
178 } else {
179 snprintf(portbuf, sizeof(portbuf), "%d", port);
180 h = host;
181 }
182
183 memset(&hints, 0, sizeof(hints));
184 hints.ai_family = af_hint;
185 hints.ai_socktype = type;
186 error = getaddrinfo(h, portbuf, &hints, &res0);
187 if (error) {
188 rprintf(FERROR, RSYNC_NAME ": getaddrinfo: %s %s: %s\n",
189 h, portbuf, gai_strerror(error));
190 return -1;
191 }
192
193 s = -1;
194 /* Try to connect to all addresses for this machine until we get
195 * through. It might e.g. be multi-homed, or have both IPv4 and IPv6
196 * addresses. We need to create a socket for each record, since the
197 * address record tells us what protocol to use to try to connect. */
198 for (res = res0; res; res = res->ai_next) {
199 s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
200 if (s < 0)
201 continue;
202
203 if (bind_address)
204 if (try_bind_local(s, res->ai_family, type,
205 bind_address) == -1) {
206 close(s);
207 s = -1;
208 continue;
209 }
210
211 if (connect(s, res->ai_addr, res->ai_addrlen) < 0) {
212 close(s);
213 s = -1;
214 continue;
215 }
216 if (proxied &&
217 establish_proxy_connection(s, host, port) != 0) {
218 close(s);
219 s = -1;
220 continue;
221 } else
222 break;
223 }
224 freeaddrinfo(res0);
225 if (s < 0) {
226 rprintf(FERROR, RSYNC_NAME ": failed to connect to %s: %s\n",
227 h, strerror(errno));
228 return -1;
229 }
230 return s;
231}
232
233
234/**
235 * Open an outgoing socket, but allow for it to be intercepted by
236 * $RSYNC_CONNECT_PROG, which will execute a program across a TCP
237 * socketpair rather than really opening a socket.
238 *
239 * We use this primarily in testing to detect TCP flow bugs, but not
240 * cause security problems by really opening remote connections.
241 *
242 * This is based on the Samba LIBSMB_PROG feature.
243 *
244 * @param bind_address Local address to use. Normally NULL to get the stack default.
245 **/
246int open_socket_out_wrapped (char *host,
247 int port,
248 const char *bind_address,
249 int af_hint)
250{
251 char *prog;
252
253 if ((prog = getenv ("RSYNC_CONNECT_PROG")) != NULL)
254 return sock_exec (prog);
255 else
256 return open_socket_out (host, port, bind_address,
257 af_hint);
258}
259
260
261
262/**
263 * Open a socket of the specified type, port and address for incoming data
264 *
265 * Try to be better about handling the results of getaddrinfo(): when
266 * opening an inbound socket, we might get several address results,
267 * e.g. for the machine's ipv4 and ipv6 name.
268 *
269 * If binding a wildcard, then any one of them should do. If an address
270 * was specified but it's insufficiently specific then that's not our
271 * fault.
272 *
273 * However, some of the advertized addresses may not work because e.g. we
274 * don't have IPv6 support in the kernel. In that case go on and try all
275 * addresses until one succeeds.
276 *
277 * @param bind_address Local address to bind, or NULL to allow it to
278 * default.
279 **/
280static int open_socket_in(int type, int port, const char *bind_address,
281 int af_hint)
282{
283 int one=1;
284 int s;
285 struct addrinfo hints, *all_ai, *resp;
286 char portbuf[10];
287 int error;
288
289 memset(&hints, 0, sizeof(hints));
290 hints.ai_family = af_hint;
291 hints.ai_socktype = type;
292 hints.ai_flags = AI_PASSIVE;
293 snprintf(portbuf, sizeof(portbuf), "%d", port);
294 error = getaddrinfo(bind_address, portbuf, &hints, &all_ai);
295 if (error) {
296 rprintf(FERROR, RSYNC_NAME ": getaddrinfo: bind address %s: %s\n",
297 bind_address, gai_strerror(error));
298 return -1;
299 }
300
301 /* We may not be able to create the socket, if for example the
302 * machine knows about IPv6 in the C library, but not in the
303 * kernel. */
304 for (resp = all_ai; resp; resp = resp->ai_next) {
305 s = socket(resp->ai_family, resp->ai_socktype,
306 resp->ai_protocol);
307
308 if (s == -1)
309 /* See if there's another address that will work... */
310 continue;
311
312 setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
313 (char *)&one, sizeof one);
314
315 /* now we've got a socket - we need to bind it */
316 if (bind(s, all_ai->ai_addr, all_ai->ai_addrlen) < 0) {
317 /* Nope, try another */
318 close(s);
319 continue;
320 }
321
322 return s;
323 }
324
325 rprintf(FERROR, RSYNC_NAME ": open inbound socket on port %d failed: "
326 "%s\n",
327 port,
328 strerror(errno));
329
330 freeaddrinfo(all_ai);
331 return -1;
332}
333
334
335/*
336 * Determine if a file descriptor is in fact a socket
337 */
338int is_a_socket(int fd)
339{
340 int v;
341 socklen_t l;
342 l = sizeof(int);
343
344 /* Parameters to getsockopt, setsockopt etc are very
345 * unstandardized across platforms, so don't be surprised if
346 * there are compiler warnings on e.g. SCO OpenSwerver or AIX.
347 * It seems they all eventually get the right idea.
348 *
349 * Debian says: ``The fifth argument of getsockopt and
350 * setsockopt is in reality an int [*] (and this is what BSD
351 * 4.* and libc4 and libc5 have). Some POSIX confusion
352 * resulted in the present socklen_t. The draft standard has
353 * not been adopted yet, but glibc2 already follows it and
354 * also has socklen_t [*]. See also accept(2).''
355 *
356 * We now return to your regularly scheduled programming. */
357 return(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&v, &l) == 0);
358}
359
360
361void start_accept_loop(int port, int (*fn)(int ))
362{
363 int s;
364 extern char *bind_address;
365 extern int default_af_hint;
366
367 /* open an incoming socket */
368 s = open_socket_in(SOCK_STREAM, port, bind_address, default_af_hint);
369 if (s == -1)
370 exit_cleanup(RERR_SOCKETIO);
371
372 /* ready to listen */
373 if (listen(s, 5) == -1) {
374 close(s);
375 exit_cleanup(RERR_SOCKETIO);
376 }
377
378
379 /* now accept incoming connections - forking a new process
380 for each incoming connection */
381 while (1) {
382 fd_set fds;
383 int fd;
384 struct sockaddr_storage addr;
385 int addrlen = sizeof(addr);
386
387 /* close log file before the potentially very long select so
388 file can be trimmed by another process instead of growing
389 forever */
390 log_close();
391
392 FD_ZERO(&fds);
393 FD_SET(s, &fds);
394
395 if (select(s+1, &fds, NULL, NULL, NULL) != 1) {
396 continue;
397 }
398
399 if(!FD_ISSET(s, &fds)) continue;
400
401 fd = accept(s,(struct sockaddr *)&addr,&addrlen);
402
403 if (fd == -1) continue;
404
405 signal(SIGCHLD, SIG_IGN);
406
407 /* we shouldn't have any children left hanging around
408 but I have had reports that on Digital Unix zombies
409 are produced, so this ensures that they are reaped */
410#ifdef WNOHANG
411 while (waitpid(-1, NULL, WNOHANG) > 0);
412#endif
413
414 if (fork()==0) {
415 close(s);
416 /* open log file in child before possibly giving
417 up privileges */
418 log_open();
419 _exit(fn(fd));
420 }
421
422 close(fd);
423 }
424}
425
426
427enum SOCK_OPT_TYPES {OPT_BOOL,OPT_INT,OPT_ON};
428
429struct
430{
431 char *name;
432 int level;
433 int option;
434 int value;
435 int opttype;
436} socket_options[] = {
437 {"SO_KEEPALIVE", SOL_SOCKET, SO_KEEPALIVE, 0, OPT_BOOL},
438 {"SO_REUSEADDR", SOL_SOCKET, SO_REUSEADDR, 0, OPT_BOOL},
439 {"SO_BROADCAST", SOL_SOCKET, SO_BROADCAST, 0, OPT_BOOL},
440#ifdef TCP_NODELAY
441 {"TCP_NODELAY", IPPROTO_TCP, TCP_NODELAY, 0, OPT_BOOL},
442#endif
443#ifdef IPTOS_LOWDELAY
444 {"IPTOS_LOWDELAY", IPPROTO_IP, IP_TOS, IPTOS_LOWDELAY, OPT_ON},
445#endif
446#ifdef IPTOS_THROUGHPUT
447 {"IPTOS_THROUGHPUT", IPPROTO_IP, IP_TOS, IPTOS_THROUGHPUT, OPT_ON},
448#endif
449#ifdef SO_SNDBUF
450 {"SO_SNDBUF", SOL_SOCKET, SO_SNDBUF, 0, OPT_INT},
451#endif
452#ifdef SO_RCVBUF
453 {"SO_RCVBUF", SOL_SOCKET, SO_RCVBUF, 0, OPT_INT},
454#endif
455#ifdef SO_SNDLOWAT
456 {"SO_SNDLOWAT", SOL_SOCKET, SO_SNDLOWAT, 0, OPT_INT},
457#endif
458#ifdef SO_RCVLOWAT
459 {"SO_RCVLOWAT", SOL_SOCKET, SO_RCVLOWAT, 0, OPT_INT},
460#endif
461#ifdef SO_SNDTIMEO
462 {"SO_SNDTIMEO", SOL_SOCKET, SO_SNDTIMEO, 0, OPT_INT},
463#endif
464#ifdef SO_RCVTIMEO
465 {"SO_RCVTIMEO", SOL_SOCKET, SO_RCVTIMEO, 0, OPT_INT},
466#endif
467 {NULL,0,0,0,0}};
468
469
470
471/****************************************************************************
472set user socket options
473****************************************************************************/
474void set_socket_options(int fd, char *options)
475{
476 char *tok;
477 if (!options || !*options) return;
478
479 options = strdup(options);
480
481 if (!options) out_of_memory("set_socket_options");
482
483 for (tok=strtok(options, " \t,"); tok; tok=strtok(NULL," \t,")) {
484 int ret=0,i;
485 int value = 1;
486 char *p;
487 int got_value = 0;
488
489 if ((p = strchr(tok,'='))) {
490 *p = 0;
491 value = atoi(p+1);
492 got_value = 1;
493 }
494
495 for (i=0;socket_options[i].name;i++)
496 if (strcmp(socket_options[i].name,tok)==0)
497 break;
498
499 if (!socket_options[i].name) {
500 rprintf(FERROR,"Unknown socket option %s\n",tok);
501 continue;
502 }
503
504 switch (socket_options[i].opttype) {
505 case OPT_BOOL:
506 case OPT_INT:
507 ret = setsockopt(fd,socket_options[i].level,
508 socket_options[i].option,(char *)&value,sizeof(int));
509 break;
510
511 case OPT_ON:
512 if (got_value)
513 rprintf(FERROR,"syntax error - %s does not take a value\n",tok);
514
515 {
516 int on = socket_options[i].value;
517 ret = setsockopt(fd,socket_options[i].level,
518 socket_options[i].option,(char *)&on,sizeof(int));
519 }
520 break;
521 }
522
523 if (ret != 0)
524 rprintf(FERROR, "failed to set socket option %s: %s\n", tok,
525 strerror(errno));
526 }
527
528 free(options);
529}
530
531/****************************************************************************
532become a daemon, discarding the controlling terminal
533****************************************************************************/
534void become_daemon(void)
535{
536 int i;
537
538 if (fork()) {
539 _exit(0);
540 }
541
542 /* detach from the terminal */
543#ifdef HAVE_SETSID
544 setsid();
545#else
546#ifdef TIOCNOTTY
547 i = open("/dev/tty", O_RDWR);
548 if (i >= 0) {
549 ioctl(i, (int) TIOCNOTTY, (char *)0);
550 close(i);
551 }
552#endif /* TIOCNOTTY */
553#endif
554 /* make sure that stdin, stdout an stderr don't stuff things
555 up (library functions, for example) */
556 for (i=0;i<3;i++) {
557 close(i);
558 open("/dev/null", O_RDWR);
559 }
560}
561
562/**
563 * Return the IP addr of the client as a string
564 **/
565char *client_addr(int fd)
566{
567 struct sockaddr_storage ss;
568 int length = sizeof(ss);
569 static char addr_buf[100];
570 static int initialised;
571
572 if (initialised) return addr_buf;
573
574 initialised = 1;
575
576 if (getpeername(fd, (struct sockaddr *)&ss, &length)) {
577 exit_cleanup(RERR_SOCKETIO);
578 }
579
580 getnameinfo((struct sockaddr *)&ss, length,
581 addr_buf, sizeof(addr_buf), NULL, 0, NI_NUMERICHOST);
582 return addr_buf;
583}
584
585
586static int get_sockaddr_family(const struct sockaddr_storage *ss)
587{
588 return ((struct sockaddr *) ss)->sa_family;
589}
590
591
592/**
593 * Return the DNS name of the client
594 **/
595char *client_name(int fd)
596{
597 struct sockaddr_storage ss;
598 int length = sizeof(ss);
599 static char name_buf[100];
600 static char port_buf[100];
601 char *def = "UNKNOWN";
602 static int initialised;
603 struct addrinfo hints, *res, *res0;
604 int error;
605
606 if (initialised) return name_buf;
607
608 initialised = 1;
609
610 strcpy(name_buf,def);
611
612 if (getpeername(fd, (struct sockaddr *)&ss, &length)) {
613 /* FIXME: Can we really not continue? */
614 rprintf(FERROR, RSYNC_NAME ": getpeername on fd%d failed: %s\n",
615 fd, strerror(errno));
616 exit_cleanup(RERR_SOCKETIO);
617 }
618
619#ifdef INET6
620 if (get_sockaddr_family(&ss) == AF_INET6 &&
621 IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)&ss)->sin6_addr)) {
622 struct sockaddr_in6 sin6;
623 struct sockaddr_in *sin;
624
625 memcpy(&sin6, &ss, sizeof(sin6));
626 sin = (struct sockaddr_in *)&ss;
627 memset(sin, 0, sizeof(*sin));
628 sin->sin_family = AF_INET;
629 length = sizeof(struct sockaddr_in);
630#ifdef HAVE_SOCKADDR_LEN
631 sin->sin_len = length;
632#endif
633 sin->sin_port = sin6.sin6_port;
634 memcpy(&sin->sin_addr, &sin6.sin6_addr.s6_addr[12],
635 sizeof(sin->sin_addr));
636 }
637#endif
638
639 /* reverse lookup */
640 if (getnameinfo((struct sockaddr *)&ss, length,
641 name_buf, sizeof(name_buf), port_buf, sizeof(port_buf),
642 NI_NAMEREQD | NI_NUMERICSERV) != 0) {
643 strcpy(name_buf, def);
644 rprintf(FERROR, "reverse name lookup failed\n");
645 }
646
647 /* forward lookup */
648 memset(&hints, 0, sizeof(hints));
649 hints.ai_family = PF_UNSPEC;
650 hints.ai_flags = AI_CANONNAME;
651 hints.ai_socktype = SOCK_STREAM;
652 error = getaddrinfo(name_buf, port_buf, &hints, &res0);
653 if (error) {
654 strcpy(name_buf, def);
655 rprintf(FERROR,
656 RSYNC_NAME ": forward name lookup for %s failed: %s\n",
657 port_buf,
658 gai_strerror(error));
659 return name_buf;
660 }
661
662 /* XXX sin6_flowinfo and other fields */
663 for (res = res0; res; res = res->ai_next) {
664 if (res->ai_family != get_sockaddr_family(&ss))
665 continue;
666 if (res->ai_addrlen != length)
667 continue;
668 if (memcmp(res->ai_addr, &ss, res->ai_addrlen) == 0)
669 break;
670 }
671
672 /* TODO: Do a forward lookup as well to prevent spoofing */
673
674 if (res == NULL) {
675 strcpy(name_buf, def);
676 rprintf(FERROR, RSYNC_NAME ": "
677 "reverse name lookup mismatch on fd%d - spoofed address?\n",
678 fd);
679 }
680
681 freeaddrinfo(res0);
682 return name_buf;
683}
684
685
686/*******************************************************************
687this is like socketpair but uses tcp. It is used by the Samba
688regression test code
689The function guarantees that nobody else can attach to the socket,
690or if they do that this function fails and the socket gets closed
691returns 0 on success, -1 on failure
692the resulting file descriptors are symmetrical
693 ******************************************************************/
694static int socketpair_tcp(int fd[2])
695{
696 int listener;
697 struct sockaddr_in sock;
698 struct sockaddr_in sock2;
699 socklen_t socklen = sizeof(sock);
700 int connect_done = 0;
701
702 fd[0] = fd[1] = listener = -1;
703
704 memset(&sock, 0, sizeof(sock));
705
706 if ((listener = socket(PF_INET, SOCK_STREAM, 0)) == -1) goto failed;
707
708 memset(&sock2, 0, sizeof(sock2));
709#ifdef HAVE_SOCK_SIN_LEN
710 sock2.sin_len = sizeof(sock2);
711#endif
712 sock2.sin_family = PF_INET;
713
714 bind(listener, (struct sockaddr *)&sock2, sizeof(sock2));
715
716 if (listen(listener, 1) != 0) goto failed;
717
718 if (getsockname(listener, (struct sockaddr *)&sock, &socklen) != 0) goto failed;
719
720 if ((fd[1] = socket(PF_INET, SOCK_STREAM, 0)) == -1) goto failed;
721
722 set_nonblocking(fd[1]);
723
724 sock.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
725
726 if (connect(fd[1],(struct sockaddr *)&sock,sizeof(sock)) == -1) {
727 if (errno != EINPROGRESS) goto failed;
728 } else {
729 connect_done = 1;
730 }
731
732 if ((fd[0] = accept(listener, (struct sockaddr *)&sock, &socklen)) == -1) goto failed;
733
734 close(listener);
735 if (connect_done == 0) {
736 if (connect(fd[1],(struct sockaddr *)&sock,sizeof(sock)) != 0
737 && errno != EISCONN) goto failed;
738 }
739
740 set_blocking (fd[1]);
741
742 /* all OK! */
743 return 0;
744
745 failed:
746 if (fd[0] != -1) close(fd[0]);
747 if (fd[1] != -1) close(fd[1]);
748 if (listener != -1) close(listener);
749 return -1;
750}
751
752
753/*******************************************************************
754run a program on a local tcp socket, this is used to launch smbd
755when regression testing
756the return value is a socket which is attached to a subprocess
757running "prog". stdin and stdout are attached. stderr is left
758attached to the original stderr
759 ******************************************************************/
760int sock_exec(const char *prog)
761{
762 int fd[2];
763 if (socketpair_tcp(fd) != 0) {
764 rprintf (FERROR, RSYNC_NAME
765 ": socketpair_tcp failed (%s)\n",
766 strerror(errno));
767 return -1;
768 }
769 if (fork() == 0) {
770 close(fd[0]);
771 close(0);
772 close(1);
773 dup(fd[1]);
774 dup(fd[1]);
775 if (verbose > 3)
776 fprintf (stderr,
777 RSYNC_NAME ": execute socket program \"%s\"\n",
778 prog);
779 exit (system (prog));
780 }
781 close (fd[1]);
782 return fd[0];
783}
784
785
786