1 /* -*- c-file-style: "linux" -*-
3 Copyright (C) 1996-2001 by Andrew Tridgell <tridge@samba.org>
4 Copyright (C) Paul Mackerras 1996
5 Copyright (C) 2001, 2002 by Martin Pool <mbp@samba.org>
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
30 static void show_malloc_stats(void);
32 /****************************************************************************
33 wait for a process to exit, calling io_flush while waiting
34 ****************************************************************************/
35 void wait_process(pid_t pid, int *status)
37 while (waitpid(pid, status, WNOHANG) == 0) {
42 /* TODO: If the child exited on a signal, then log an
43 * appropriate error message. Perhaps we should also accept a
44 * message describing the purpose of the child. Also indicate
45 * this to the caller so that thhey know something went
47 *status = WEXITSTATUS(*status);
50 static void report(int f)
52 time_t t = time(NULL);
57 extern int remote_version;
61 /* These come out from every process */
67 log_exit(0, __FILE__, __LINE__);
68 if (f == -1 || !am_sender) return;
71 send_stats = verbose || (remote_version >= 20);
73 if (am_sender && send_stats) {
75 /* store total_written in a temporary
76 because write_longint changes it */
77 w = stats.total_written;
78 write_longint(f,stats.total_read);
80 write_longint(f,stats.total_size);
85 /* this is the client */
87 if (!am_sender && send_stats) {
89 stats.total_written = read_longint(f);
90 /* store total_read in a temporary, read_longint changes it */
92 stats.total_size = read_longint(f);
97 if (!am_sender && !send_stats) {
98 /* missing the bytes written by the generator */
99 rprintf(FINFO, "\nCannot show stats as receiver because remote protocol version is less than 20\n");
100 rprintf(FINFO, "Use --stats -v to show stats\n");
103 rprintf(FINFO,"\nNumber of files: %d\n", stats.num_files);
104 rprintf(FINFO,"Number of files transferred: %d\n",
105 stats.num_transferred_files);
106 rprintf(FINFO,"Total file size: %.0f bytes\n",
107 (double)stats.total_size);
108 rprintf(FINFO,"Total transferred file size: %.0f bytes\n",
109 (double)stats.total_transferred_size);
110 rprintf(FINFO,"Literal data: %.0f bytes\n",
111 (double)stats.literal_data);
112 rprintf(FINFO,"Matched data: %.0f bytes\n",
113 (double)stats.matched_data);
114 rprintf(FINFO,"File list size: %d\n", stats.flist_size);
115 rprintf(FINFO,"Total bytes written: %.0f\n",
116 (double)stats.total_written);
117 rprintf(FINFO,"Total bytes read: %.0f\n\n",
118 (double)stats.total_read);
121 if (verbose || do_stats) {
122 rprintf(FINFO,"wrote %.0f bytes read %.0f bytes %.2f bytes/sec\n",
123 (double)stats.total_written,
124 (double)stats.total_read,
125 (stats.total_written+stats.total_read)/(0.5 + (t-starttime)));
126 rprintf(FINFO,"total size is %.0f speedup is %.2f\n",
127 (double)stats.total_size,
128 (1.0*stats.total_size)/(stats.total_written+stats.total_read));
137 * If our C library can get malloc statistics, then show them to FINFO
139 static void show_malloc_stats(void)
143 extern int am_server;
144 extern int am_sender;
145 extern int am_daemon;
149 rprintf(FINFO, RSYNC_NAME "[%d] (%s%s%s) heap statistics:\n",
151 am_server ? "server " : "",
152 am_daemon ? "daemon " : "",
153 am_sender ? "sender" : "receiver");
154 rprintf(FINFO, " arena: %10d (bytes from sbrk)\n", mi.arena);
155 rprintf(FINFO, " ordblks: %10d (chunks not in use)\n", mi.ordblks);
156 rprintf(FINFO, " smblks: %10d\n", mi.smblks);
157 rprintf(FINFO, " hblks: %10d (chunks from mmap)\n", mi.hblks);
158 rprintf(FINFO, " hblkhd: %10d (bytes from mmap)\n", mi.hblkhd);
159 rprintf(FINFO, " usmblks: %10d\n", mi.usmblks);
160 rprintf(FINFO, " fsmblks: %10d\n", mi.fsmblks);
161 rprintf(FINFO, " uordblks: %10d (bytes used)\n", mi.uordblks);
162 rprintf(FINFO, " fordblks: %10d (bytes free)\n", mi.fordblks);
163 rprintf(FINFO, " keepcost: %10d (bytes in releasable chunk)\n", mi.keepcost);
164 #endif /* HAVE_MALLINFO */
168 /* Start the remote shell. cmd may be NULL to use the default. */
169 static pid_t do_cmd(char *cmd,char *machine,char *user,char *path,int *f_in,int *f_out)
175 extern int local_server;
176 extern char *rsync_path;
177 extern int blocking_io;
178 extern int read_batch;
180 if (!read_batch && !local_server) { /* dw -- added read_batch */
182 cmd = getenv(RSYNC_RSH_ENV);
189 for (tok=strtok(cmd," ");tok;tok=strtok(NULL," ")) {
194 /* remsh (on HPUX) takes the arguments the other way around */
195 args[argc++] = machine;
205 args[argc++] = machine;
208 args[argc++] = rsync_path;
210 server_options(args,&argc);
213 if (strcmp(cmd, RSYNC_RSH) == 0) blocking_io = 1;
224 rprintf(FINFO,"cmd=");
226 rprintf(FINFO,"%s ",args[i]);
232 create_flist_from_batch();
233 ret = local_child(argc, args, f_in, f_out);
235 ret = piped_child(args,f_in,f_out);
243 out_of_memory("do_cmd");
244 return 0; /* not reached */
250 static char *get_local_name(struct file_list *flist,char *name)
253 extern int orig_umask;
256 rprintf(FINFO,"get_local_name count=%d %s\n",
257 flist->count, NS(name));
262 if (do_stat(name,&st) == 0) {
263 if (S_ISDIR(st.st_mode)) {
264 if (!push_dir(name, 0)) {
265 rprintf(FERROR,"push_dir %s : %s (1)\n",
266 name,strerror(errno));
267 exit_cleanup(RERR_FILESELECT);
271 if (flist->count > 1) {
272 rprintf(FERROR,"ERROR: destination must be a directory when copying more than 1 file\n");
273 exit_cleanup(RERR_FILESELECT);
278 if (flist->count <= 1)
281 if (do_mkdir(name,0777 & ~orig_umask) != 0) {
282 rprintf(FERROR,"mkdir %s : %s (1)\n",name,strerror(errno));
283 exit_cleanup(RERR_FILEIO);
286 rprintf(FINFO,"created directory %s\n",name);
289 if (!push_dir(name, 0)) {
290 rprintf(FERROR,"push_dir %s : %s (2)\n",
291 name,strerror(errno));
292 exit_cleanup(RERR_FILESELECT);
301 static void do_server_sender(int f_in, int f_out, int argc,char *argv[])
304 struct file_list *flist;
306 extern int relative_paths;
308 extern int remote_version;
311 rprintf(FINFO,"server_sender starting pid=%d\n",(int)getpid());
313 if (!relative_paths && !push_dir(dir, 0)) {
314 rprintf(FERROR,"push_dir %s: %s (3)\n",dir,strerror(errno));
315 exit_cleanup(RERR_FILESELECT);
320 if (strcmp(dir,".")) {
322 if (strcmp(dir,"/") == 0)
328 if (argc == 0 && recurse) {
334 flist = send_file_list(f_out,argc,argv);
335 if (!flist || flist->count == 0) {
339 send_files(flist,f_out,f_in);
342 if (remote_version >= 24) {
343 /* final goodbye message */
351 static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
357 extern int preserve_hard_links;
358 extern int delete_after;
360 extern int delete_mode;
361 extern int remote_version;
363 if (preserve_hard_links)
364 init_hard_links(flist);
367 /* I moved this here from recv_files() to prevent a race condition */
368 if (recurse && delete_mode && !local_name && flist->count>0) {
373 if (fd_pair(recv_pipe) < 0) {
374 rprintf(FERROR,"pipe failed in do_recv\n");
375 exit_cleanup(RERR_SOCKETIO);
378 if (fd_pair(error_pipe) < 0) {
379 rprintf(FERROR,"error pipe failed in do_recv\n");
380 exit_cleanup(RERR_SOCKETIO);
385 if ((pid=do_fork()) == 0) {
387 close(error_pipe[0]);
388 if (f_in != f_out) close(f_out);
390 /* we can't let two processes write to the socket at one time */
391 io_multiplexing_close();
393 /* set place to send errors */
394 set_error_fd(error_pipe[1]);
396 recv_files(f_in,flist,local_name,recv_pipe[1]);
400 write_int(recv_pipe[1],1);
403 /* finally we go to sleep until our parent kills us
404 with a USR2 signal. We sleep for a short time as on
405 some OSes a signal won't interrupt a sleep! */
411 close(error_pipe[1]);
412 if (f_in != f_out) close(f_in);
414 io_start_buffering(f_out);
416 io_set_error_fd(error_pipe[0]);
418 generate_files(f_out,flist,local_name,recv_pipe[0]);
420 read_int(recv_pipe[0]);
422 if (remote_version >= 24) {
423 /* send a final goodbye message */
424 write_int(f_out, -1);
429 wait_process(pid, &status);
434 static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
437 struct file_list *flist;
438 char *local_name=NULL;
440 extern int delete_mode;
441 extern int delete_excluded;
442 extern int am_daemon;
443 extern int module_id;
444 extern int am_sender;
445 extern int read_batch; /* dw */
446 extern struct file_list *batch_flist; /* dw */
449 rprintf(FINFO,"server_recv(%d) starting pid=%d\n",argc,(int)getpid());
451 if (am_daemon && lp_read_only(module_id) && !am_sender) {
452 rprintf(FERROR,"ERROR: module is read only\n");
453 exit_cleanup(RERR_SYNTAX);
462 if (!am_daemon && !push_dir(dir, 0)) {
463 rprintf(FERROR,"push_dir %s : %s (4)\n",
464 dir,strerror(errno));
465 exit_cleanup(RERR_FILESELECT);
469 if (delete_mode && !delete_excluded)
470 recv_exclude_list(f_in);
472 if (read_batch) /* dw */
475 flist = recv_file_list(f_in);
477 rprintf(FERROR,"server_recv: recv_file_list error\n");
478 exit_cleanup(RERR_FILESELECT);
482 if (strcmp(dir,".")) {
483 argv[0] += strlen(dir);
484 if (argv[0][0] == '/') argv[0]++;
486 local_name = get_local_name(flist,argv[0]);
489 status = do_recv(f_in,f_out,flist,local_name);
490 exit_cleanup(status);
494 void start_server(int f_in, int f_out, int argc, char *argv[])
496 extern int cvs_exclude;
497 extern int am_sender;
498 extern int remote_version;
499 extern int read_batch; /* dw */
501 setup_protocol(f_out, f_in);
503 set_nonblocking(f_in);
504 set_nonblocking(f_out);
506 if (remote_version >= 23)
507 io_start_multiplex_out(f_out);
510 if (!read_batch) { /* dw */
511 recv_exclude_list(f_in);
515 do_server_sender(f_in, f_out, argc, argv);
517 do_server_recv(f_in, f_out, argc, argv);
524 * This is called once the connection has been negotiated. It is used
525 * for rsyncd, remote-shell, and local connections.
527 int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[])
529 struct file_list *flist;
530 int status = 0, status2 = 0;
531 char *local_name = NULL;
532 extern int am_sender;
533 extern int remote_version;
534 extern pid_t cleanup_child_pid;
535 extern int write_batch; /* dw */
536 extern int read_batch; /* dw */
537 extern struct file_list *batch_flist; /* dw */
539 cleanup_child_pid = pid;
541 flist = batch_flist; /* dw */
543 set_nonblocking(f_in);
544 set_nonblocking(f_out);
546 setup_protocol(f_out,f_in);
548 if (remote_version >= 23)
549 io_start_multiplex_in(f_in);
552 extern int cvs_exclude;
553 extern int delete_mode;
554 extern int delete_excluded;
557 if (delete_mode && !delete_excluded)
558 send_exclude_list(f_out);
559 if (!read_batch) /* dw -- don't write to pipe */
560 flist = send_file_list(f_out,argc,argv);
562 rprintf(FINFO,"file list sent\n");
564 send_files(flist,f_out,f_in);
565 if (remote_version >= 24) {
566 /* final goodbye message */
571 rprintf(FINFO,"client_run waiting on %d\n", (int) pid);
573 wait_process(pid, &status);
576 exit_cleanup(status);
580 extern int list_only;
584 if (!write_batch) /* dw */
585 send_exclude_list(f_out);
587 flist = recv_file_list(f_in);
588 if (!flist || flist->count == 0) {
589 rprintf(FINFO, "client: nothing to do: "
590 "perhaps you need to specify some filenames or "
591 "the --recursive option?\n");
595 local_name = get_local_name(flist,argv[0]);
597 status2 = do_recv(f_in,f_out,flist,local_name);
601 rprintf(FINFO,"client_run2 waiting on %d\n", (int) pid);
603 wait_process(pid, &status);
606 return MAX(status, status2);
609 static char *find_colon(char *s)
616 /* now check to see if there is a / in the string before the : - if there is then
617 discard the colon on the assumption that the : is part of a filename */
619 if (p2 && p2 < p) return NULL;
625 static int copy_argv (char *argv[])
629 for (i = 0; argv[i]; i++) {
630 if (!(argv[i] = strdup(argv[i]))) {
631 rprintf (FERROR, "out of memory at %s(%d)\n",
642 * Start a client for either type of remote connection. Work out
643 * whether the arguments request a remote shell or rsyncd connection,
644 * and call the appropriate connection function, then run_client.
646 static int start_client(int argc, char *argv[])
649 char *shell_machine = NULL;
650 char *shell_path = NULL;
651 char *shell_user = NULL;
655 extern int local_server;
656 extern int am_sender;
657 extern char *shell_cmd;
658 extern int rsync_port;
659 extern int whole_file;
660 extern int read_batch;
663 /* Don't clobber argv[] so that ps(1) can still show the right
665 if ((rc = copy_argv (argv)))
668 if (strncasecmp(URL_PREFIX, argv[0], strlen(URL_PREFIX)) == 0) {
671 host = argv[0] + strlen(URL_PREFIX);
672 p = strchr(host,'/');
679 p = strchr(host,':');
681 rsync_port = atoi(p+1);
684 return start_socket_client(host, path, argc-1, argv+1);
687 if (!read_batch) { /* dw */
688 p = find_colon(argv[0]);
693 return start_socket_client(argv[0], p+2, argc-1, argv+1);
698 exit_cleanup(RERR_SYNTAX);
703 shell_machine = argv[0];
710 p = find_colon(argv[argc-1]);
713 /* disable "rsync algorithm" when both sides local */
715 } else if (p[1] == ':') {
717 return start_socket_client(argv[argc-1], p+2, argc-1, argv);
722 exit_cleanup(RERR_SYNTAX);
726 shell_machine = NULL;
727 shell_path = argv[argc-1];
730 shell_machine = argv[argc-1];
736 am_sender = 1; /* dw */
737 local_server = 1; /* dw */
738 shell_path = argv[argc-1]; /* dw */
742 p = strchr(shell_machine,'@');
745 shell_user = shell_machine;
751 rprintf(FINFO,"cmd=%s machine=%s user=%s path=%s\n",
752 shell_cmd?shell_cmd:"",
753 shell_machine?shell_machine:"",
754 shell_user?shell_user:"",
755 shell_path?shell_path:"");
758 if (!am_sender && argc > 1) {
760 exit_cleanup(RERR_SYNTAX);
763 if (argc == 0 && !am_sender) {
764 extern int list_only;
768 pid = do_cmd(shell_cmd,shell_machine,shell_user,shell_path,&f_in,&f_out);
770 ret = client_run(f_in, f_out, pid, argc, argv);
779 static RETSIGTYPE sigusr1_handler(int val) {
780 exit_cleanup(RERR_SIGNAL);
783 static RETSIGTYPE sigusr2_handler(int val) {
784 extern int log_got_error;
785 if (log_got_error) _exit(RERR_PARTIAL);
789 static RETSIGTYPE sigchld_handler(int val) {
791 while (waitpid(-1, NULL, WNOHANG) > 0) ;
795 int main(int argc,char *argv[])
798 extern int orig_umask;
800 extern int am_daemon;
801 extern int am_server;
803 extern int read_batch; /* dw */
804 extern int write_batch; /* dw */
805 extern char *batch_ext; /* dw */
806 int orig_argc; /* dw */
809 orig_argc = argc; /* dw */
812 signal(SIGUSR1, sigusr1_handler);
813 signal(SIGUSR2, sigusr2_handler);
814 signal(SIGCHLD, sigchld_handler);
816 starttime = time(NULL);
817 am_root = (getuid() == 0);
819 memset(&stats, 0, sizeof(stats));
823 exit_cleanup(RERR_SYNTAX);
826 /* we set a 0 umask so that correct file permissions can be
828 orig_umask = (int)umask(0);
830 if (!parse_arguments(&argc, (const char ***) &argv, 1)) {
831 /* FIXME: We ought to call the same error-handling
832 * code here, rather than relying on getopt. */
834 exit_cleanup(RERR_SYNTAX);
837 signal(SIGINT,SIGNAL_CAST sig_int);
838 signal(SIGPIPE,SIGNAL_CAST sig_int);
839 signal(SIGHUP,SIGNAL_CAST sig_int);
840 signal(SIGTERM,SIGNAL_CAST sig_int);
842 /* Initialize push_dir here because on some old systems getcwd
843 (implemented by forking "pwd" and reading its output) doesn't
844 work when there are other child processes. Also, on all systems
845 that implement getcwd that way "pwd" can't be found after chroot. */
848 if (write_batch) { /* dw */
849 create_batch_file_ext();
850 write_batch_argvs_file(orig_argc, orig_argv);
853 if (read_batch) { /* dw */
854 set_batch_file_ext(batch_ext);
858 return daemon_main();
863 exit_cleanup(RERR_SYNTAX);
867 verbose = MAX(verbose,1);
869 #ifndef SUPPORT_LINKS
870 if (!am_server && preserve_links) {
871 rprintf(FERROR,"ERROR: symbolic links not supported\n");
872 exit_cleanup(RERR_UNSUPPORTED);
877 set_nonblocking(STDIN_FILENO);
878 set_nonblocking(STDOUT_FILENO);
879 start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
882 ret = start_client(argc, argv);