1 /* -*- c-file-style: "linux" -*-
3 Copyright (C) 1996-2001 by Andrew Tridgell <tridge@samba.org>
4 Copyright (C) Paul Mackerras 1996
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.
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.
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.
30 /****************************************************************************
31 wait for a process to exit, calling io_flush while waiting
32 ****************************************************************************/
33 void wait_process(pid_t pid
, int *status
)
35 while (waitpid(pid
, status
, WNOHANG
) == 0) {
40 /* TODO: If the child exited on a signal, then log an
41 * appropriate error message. Perhaps we should also accept a
42 * message describing the purpose of the child. Also indicate
43 * this to the caller so that thhey know something went
45 *status
= WEXITSTATUS(*status
);
48 static void report(int f
)
50 time_t t
= time(NULL
);
55 extern int remote_version
;
59 log_exit(0, __FILE__
, __LINE__
);
60 if (f
== -1 || !am_sender
) return;
63 send_stats
= verbose
|| (remote_version
>= 20);
65 if (am_sender
&& send_stats
) {
67 /* store total_written in a temporary
68 because write_longint changes it */
69 w
= stats
.total_written
;
70 write_longint(f
,stats
.total_read
);
72 write_longint(f
,stats
.total_size
);
77 /* this is the client */
79 if (!am_sender
&& send_stats
) {
81 stats
.total_written
= read_longint(f
);
82 /* store total_read in a temporary, read_longint changes it */
84 stats
.total_size
= read_longint(f
);
89 if (!am_sender
&& !send_stats
) {
90 /* missing the bytes written by the generator */
91 rprintf(FINFO
, "\nCannot show stats as receiver because remote protocol version is less than 20\n");
92 rprintf(FINFO
, "Use --stats -v to show stats\n");
95 rprintf(FINFO
,"\nNumber of files: %d\n", stats
.num_files
);
96 rprintf(FINFO
,"Number of files transferred: %d\n",
97 stats
.num_transferred_files
);
98 rprintf(FINFO
,"Total file size: %.0f bytes\n",
99 (double)stats
.total_size
);
100 rprintf(FINFO
,"Total transferred file size: %.0f bytes\n",
101 (double)stats
.total_transferred_size
);
102 rprintf(FINFO
,"Literal data: %.0f bytes\n",
103 (double)stats
.literal_data
);
104 rprintf(FINFO
,"Matched data: %.0f bytes\n",
105 (double)stats
.matched_data
);
106 rprintf(FINFO
,"File list size: %d\n", stats
.flist_size
);
107 rprintf(FINFO
,"Total bytes written: %.0f\n",
108 (double)stats
.total_written
);
109 rprintf(FINFO
,"Total bytes read: %.0f\n\n",
110 (double)stats
.total_read
);
113 if (verbose
|| do_stats
) {
114 rprintf(FINFO
,"wrote %.0f bytes read %.0f bytes %.2f bytes/sec\n",
115 (double)stats
.total_written
,
116 (double)stats
.total_read
,
117 (stats
.total_written
+stats
.total_read
)/(0.5 + (t
-starttime
)));
118 rprintf(FINFO
,"total size is %.0f speedup is %.2f\n",
119 (double)stats
.total_size
,
120 (1.0*stats
.total_size
)/(stats
.total_written
+stats
.total_read
));
128 /* Start the remote shell. cmd may be NULL to use the default. */
129 static pid_t
do_cmd(char *cmd
,char *machine
,char *user
,char *path
,int *f_in
,int *f_out
)
135 extern int local_server
;
136 extern char *rsync_path
;
137 extern int blocking_io
;
141 cmd
= getenv(RSYNC_RSH_ENV
);
148 for (tok
=strtok(cmd
," ");tok
;tok
=strtok(NULL
," ")) {
153 /* remsh (on HPUX) takes the arguments the other way around */
154 args
[argc
++] = machine
;
164 args
[argc
++] = machine
;
167 args
[argc
++] = rsync_path
;
169 server_options(args
,&argc
);
172 if (strcmp(cmd
, RSYNC_RSH
) == 0) blocking_io
= 1;
183 rprintf(FINFO
,"cmd=");
185 rprintf(FINFO
,"%s ",args
[i
]);
190 ret
= local_child(argc
, args
, f_in
, f_out
);
192 ret
= piped_child(args
,f_in
,f_out
);
200 out_of_memory("do_cmd");
201 return 0; /* not reached */
207 static char *get_local_name(struct file_list
*flist
,char *name
)
210 extern int orig_umask
;
213 rprintf(FINFO
,"get_local_name count=%d %s\n",
214 flist
->count
, NS(name
));
219 if (do_stat(name
,&st
) == 0) {
220 if (S_ISDIR(st
.st_mode
)) {
221 if (!push_dir(name
, 0)) {
222 rprintf(FERROR
,"push_dir %s : %s (1)\n",
223 name
,strerror(errno
));
224 exit_cleanup(RERR_FILESELECT
);
228 if (flist
->count
> 1) {
229 rprintf(FERROR
,"ERROR: destination must be a directory when copying more than 1 file\n");
230 exit_cleanup(RERR_FILESELECT
);
235 if (flist
->count
<= 1)
238 if (do_mkdir(name
,0777 & ~orig_umask
) != 0) {
239 rprintf(FERROR
,"mkdir %s : %s (1)\n",name
,strerror(errno
));
240 exit_cleanup(RERR_FILEIO
);
243 rprintf(FINFO
,"created directory %s\n",name
);
246 if (!push_dir(name
, 0)) {
247 rprintf(FERROR
,"push_dir %s : %s (2)\n",
248 name
,strerror(errno
));
249 exit_cleanup(RERR_FILESELECT
);
258 static void do_server_sender(int f_in
, int f_out
, int argc
,char *argv
[])
261 struct file_list
*flist
;
263 extern int relative_paths
;
265 extern int remote_version
;
268 rprintf(FINFO
,"server_sender starting pid=%d\n",(int)getpid());
270 if (!relative_paths
&& !push_dir(dir
, 0)) {
271 rprintf(FERROR
,"push_dir %s: %s (3)\n",dir
,strerror(errno
));
272 exit_cleanup(RERR_FILESELECT
);
277 if (strcmp(dir
,".")) {
279 if (strcmp(dir
,"/") == 0)
285 if (argc
== 0 && recurse
) {
291 flist
= send_file_list(f_out
,argc
,argv
);
292 if (!flist
|| flist
->count
== 0) {
296 send_files(flist
,f_out
,f_in
);
299 if (remote_version
>= 24) {
300 /* final goodbye message */
308 static int do_recv(int f_in
,int f_out
,struct file_list
*flist
,char *local_name
)
314 extern int preserve_hard_links
;
315 extern int delete_after
;
317 extern int delete_mode
;
318 extern int remote_version
;
320 if (preserve_hard_links
)
321 init_hard_links(flist
);
324 /* I moved this here from recv_files() to prevent a race condition */
325 if (recurse
&& delete_mode
&& !local_name
&& flist
->count
>0) {
330 if (fd_pair(recv_pipe
) < 0) {
331 rprintf(FERROR
,"pipe failed in do_recv\n");
332 exit_cleanup(RERR_SOCKETIO
);
335 if (fd_pair(error_pipe
) < 0) {
336 rprintf(FERROR
,"error pipe failed in do_recv\n");
337 exit_cleanup(RERR_SOCKETIO
);
342 if ((pid
=do_fork()) == 0) {
344 close(error_pipe
[0]);
345 if (f_in
!= f_out
) close(f_out
);
347 /* we can't let two processes write to the socket at one time */
348 io_multiplexing_close();
350 /* set place to send errors */
351 set_error_fd(error_pipe
[1]);
353 recv_files(f_in
,flist
,local_name
,recv_pipe
[1]);
357 write_int(recv_pipe
[1],1);
360 /* finally we go to sleep until our parent kills us
361 with a USR2 signal. We sleep for a short time as on
362 some OSes a signal won't interrupt a sleep! */
368 close(error_pipe
[1]);
369 if (f_in
!= f_out
) close(f_in
);
371 io_start_buffering(f_out
);
373 io_set_error_fd(error_pipe
[0]);
375 generate_files(f_out
,flist
,local_name
,recv_pipe
[0]);
377 read_int(recv_pipe
[0]);
379 if (remote_version
>= 24) {
380 /* send a final goodbye message */
381 write_int(f_out
, -1);
386 wait_process(pid
, &status
);
391 static void do_server_recv(int f_in
, int f_out
, int argc
,char *argv
[])
394 struct file_list
*flist
;
395 char *local_name
=NULL
;
397 extern int delete_mode
;
398 extern int delete_excluded
;
399 extern int am_daemon
;
400 extern int module_id
;
401 extern int am_sender
;
404 rprintf(FINFO
,"server_recv(%d) starting pid=%d\n",argc
,(int)getpid());
406 if (am_daemon
&& lp_read_only(module_id
) && !am_sender
) {
407 rprintf(FERROR
,"ERROR: module is read only\n");
408 exit_cleanup(RERR_SYNTAX
);
417 if (!am_daemon
&& !push_dir(dir
, 0)) {
418 rprintf(FERROR
,"push_dir %s : %s (4)\n",
419 dir
,strerror(errno
));
420 exit_cleanup(RERR_FILESELECT
);
424 if (delete_mode
&& !delete_excluded
)
425 recv_exclude_list(f_in
);
427 flist
= recv_file_list(f_in
);
429 rprintf(FERROR
,"server_recv: recv_file_list error\n");
430 exit_cleanup(RERR_FILESELECT
);
434 if (strcmp(dir
,".")) {
435 argv
[0] += strlen(dir
);
436 if (argv
[0][0] == '/') argv
[0]++;
438 local_name
= get_local_name(flist
,argv
[0]);
441 status
= do_recv(f_in
,f_out
,flist
,local_name
);
442 exit_cleanup(status
);
446 void start_server(int f_in
, int f_out
, int argc
, char *argv
[])
448 extern int cvs_exclude
;
449 extern int am_sender
;
450 extern int remote_version
;
452 setup_protocol(f_out
, f_in
);
454 set_nonblocking(f_in
);
455 set_nonblocking(f_out
);
457 if (remote_version
>= 23)
458 io_start_multiplex_out(f_out
);
461 recv_exclude_list(f_in
);
464 do_server_sender(f_in
, f_out
, argc
, argv
);
466 do_server_recv(f_in
, f_out
, argc
, argv
);
473 * This is called once the connection has been negotiated. It is used
474 * for rsyncd, remote-shell, and local connections.
476 int client_run(int f_in
, int f_out
, pid_t pid
, int argc
, char *argv
[])
478 struct file_list
*flist
;
479 int status
= 0, status2
= 0;
480 char *local_name
= NULL
;
481 extern int am_sender
;
482 extern int remote_version
;
483 extern pid_t cleanup_child_pid
;
485 cleanup_child_pid
= pid
;
487 set_nonblocking(f_in
);
488 set_nonblocking(f_out
);
490 setup_protocol(f_out
,f_in
);
492 if (remote_version
>= 23)
493 io_start_multiplex_in(f_in
);
496 extern int cvs_exclude
;
497 extern int delete_mode
;
498 extern int delete_excluded
;
501 if (delete_mode
&& !delete_excluded
)
502 send_exclude_list(f_out
);
503 flist
= send_file_list(f_out
,argc
,argv
);
505 rprintf(FINFO
,"file list sent\n");
507 send_files(flist
,f_out
,f_in
);
508 if (remote_version
>= 24) {
509 /* final goodbye message */
514 rprintf(FINFO
,"client_run waiting on %d\n",pid
);
516 wait_process(pid
, &status
);
519 exit_cleanup(status
);
523 extern int list_only
;
527 send_exclude_list(f_out
);
529 flist
= recv_file_list(f_in
);
530 if (!flist
|| flist
->count
== 0) {
531 rprintf(FINFO
, "client: nothing to do: "
532 "perhaps you need to specify some filenames or "
533 "the --recursive option?\n");
537 local_name
= get_local_name(flist
,argv
[0]);
539 status2
= do_recv(f_in
,f_out
,flist
,local_name
);
543 rprintf(FINFO
,"client_run2 waiting on %d\n",pid
);
545 wait_process(pid
, &status
);
548 return MAX(status
, status2
);
551 static char *find_colon(char *s
)
558 /* now check to see if there is a / in the string before the : - if there is then
559 discard the colon on the assumption that the : is part of a filename */
561 if (p2
&& p2
< p
) return NULL
;
568 * Start a client for either type of remote connection. Work out
569 * whether the arguments request a remote shell or rsyncd connection,
570 * and call the appropriate connection function, then run_client.
572 static int start_client(int argc
, char *argv
[])
575 char *shell_machine
= NULL
;
576 char *shell_path
= NULL
;
577 char *shell_user
= NULL
;
581 extern int local_server
;
582 extern int am_sender
;
583 extern char *shell_cmd
;
584 extern int rsync_port
;
585 extern int whole_file
;
586 char *argv0
= strdup(argv
[0]);
588 if (strncasecmp(URL_PREFIX
, argv0
, strlen(URL_PREFIX
)) == 0) {
591 host
= argv0
+ strlen(URL_PREFIX
);
592 p
= strchr(host
,'/');
599 p
= strchr(host
,':');
601 rsync_port
= atoi(p
+1);
604 return start_socket_client(host
, path
, argc
-1, argv
+1);
607 p
= find_colon(argv0
);
612 return start_socket_client(argv0
, p
+2, argc
-1, argv
+1);
617 exit_cleanup(RERR_SYNTAX
);
622 shell_machine
= argv0
;
629 p
= find_colon(argv
[argc
-1]);
632 /* disable "rsync algorithm" when both sides local */
634 } else if (p
[1] == ':') {
636 return start_socket_client(argv
[argc
-1], p
+2, argc
-1, argv
);
641 exit_cleanup(RERR_SYNTAX
);
645 shell_machine
= NULL
;
646 shell_path
= argv
[argc
-1];
649 shell_machine
= argv
[argc
-1];
656 p
= strchr(shell_machine
,'@');
659 shell_user
= shell_machine
;
665 rprintf(FINFO
,"cmd=%s machine=%s user=%s path=%s\n",
666 shell_cmd
?shell_cmd
:"",
667 shell_machine
?shell_machine
:"",
668 shell_user
?shell_user
:"",
669 shell_path
?shell_path
:"");
672 if (!am_sender
&& argc
> 1) {
674 exit_cleanup(RERR_SYNTAX
);
677 if (argc
== 0 && !am_sender
) {
678 extern int list_only
;
682 pid
= do_cmd(shell_cmd
,shell_machine
,shell_user
,shell_path
,&f_in
,&f_out
);
684 ret
= client_run(f_in
, f_out
, pid
, argc
, argv
);
693 static RETSIGTYPE
sigusr1_handler(int val
) {
694 exit_cleanup(RERR_SIGNAL
);
697 static RETSIGTYPE
sigusr2_handler(int val
) {
698 extern int log_got_error
;
699 if (log_got_error
) _exit(RERR_PARTIAL
);
703 static RETSIGTYPE
sigchld_handler(int val
) {
705 while (waitpid(-1, NULL
, WNOHANG
) > 0) ;
709 int main(int argc
,char *argv
[])
712 extern int orig_umask
;
714 extern int am_daemon
;
715 extern int am_server
;
718 signal(SIGUSR1
, sigusr1_handler
);
719 signal(SIGUSR2
, sigusr2_handler
);
720 signal(SIGCHLD
, sigchld_handler
);
722 starttime
= time(NULL
);
723 am_root
= (getuid() == 0);
725 memset(&stats
, 0, sizeof(stats
));
729 exit_cleanup(RERR_SYNTAX
);
732 /* we set a 0 umask so that correct file permissions can be
734 orig_umask
= (int)umask(0);
736 if (!parse_arguments(&argc
, (const char ***) &argv
, 1)) {
737 /* FIXME: We ought to call the same error-handling
738 * code here, rather than relying on getopt. */
740 exit_cleanup(RERR_SYNTAX
);
743 signal(SIGINT
,SIGNAL_CAST sig_int
);
744 signal(SIGPIPE
,SIGNAL_CAST sig_int
);
745 signal(SIGHUP
,SIGNAL_CAST sig_int
);
746 signal(SIGTERM
,SIGNAL_CAST sig_int
);
748 /* Initialize push_dir here because on some old systems getcwd
749 (implemented by forking "pwd" and reading its output) doesn't
750 work when there are other child processes. Also, on all systems
751 that implement getcwd that way "pwd" can't be found after chroot. */
755 return daemon_main();
760 exit_cleanup(RERR_SYNTAX
);
764 verbose
= MAX(verbose
,1);
766 #ifndef SUPPORT_LINKS
767 if (!am_server
&& preserve_links
) {
768 rprintf(FERROR
,"ERROR: symbolic links not supported\n");
769 exit_cleanup(RERR_UNSUPPORTED
);
774 set_nonblocking(STDIN_FILENO
);
775 set_nonblocking(STDOUT_FILENO
);
776 start_server(STDIN_FILENO
, STDOUT_FILENO
, argc
, argv
);
779 ret
= start_client(argc
, argv
);