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 */
66 log_exit(0, __FILE__, __LINE__);
67 if (f == -1 || !am_sender) return;
70 send_stats = verbose || (remote_version >= 20);
72 if (am_sender && send_stats) {
74 /* store total_written in a temporary
75 because write_longint changes it */
76 w = stats.total_written;
77 write_longint(f,stats.total_read);
79 write_longint(f,stats.total_size);
84 /* this is the client */
86 if (!am_sender && send_stats) {
88 stats.total_written = read_longint(f);
89 /* store total_read in a temporary, read_longint changes it */
91 stats.total_size = read_longint(f);
96 if (!am_sender && !send_stats) {
97 /* missing the bytes written by the generator */
98 rprintf(FINFO, "\nCannot show stats as receiver because remote protocol version is less than 20\n");
99 rprintf(FINFO, "Use --stats -v to show stats\n");
102 rprintf(FINFO,"\nNumber of files: %d\n", stats.num_files);
103 rprintf(FINFO,"Number of files transferred: %d\n",
104 stats.num_transferred_files);
105 rprintf(FINFO,"Total file size: %.0f bytes\n",
106 (double)stats.total_size);
107 rprintf(FINFO,"Total transferred file size: %.0f bytes\n",
108 (double)stats.total_transferred_size);
109 rprintf(FINFO,"Literal data: %.0f bytes\n",
110 (double)stats.literal_data);
111 rprintf(FINFO,"Matched data: %.0f bytes\n",
112 (double)stats.matched_data);
113 rprintf(FINFO,"File list size: %d\n", stats.flist_size);
114 rprintf(FINFO,"Total bytes written: %.0f\n",
115 (double)stats.total_written);
116 rprintf(FINFO,"Total bytes read: %.0f\n\n",
117 (double)stats.total_read);
120 if (verbose || do_stats) {
121 rprintf(FINFO,"wrote %.0f bytes read %.0f bytes %.2f bytes/sec\n",
122 (double)stats.total_written,
123 (double)stats.total_read,
124 (stats.total_written+stats.total_read)/(0.5 + (t-starttime)));
125 rprintf(FINFO,"total size is %.0f speedup is %.2f\n",
126 (double)stats.total_size,
127 (1.0*stats.total_size)/(stats.total_written+stats.total_read));
136 * If our C library can get malloc statistics, then show them to FINFO
138 static void show_malloc_stats(void)
142 extern int am_server;
143 extern int am_sender;
144 extern int am_daemon;
148 rprintf(FINFO, RSYNC_NAME "[%d] (%s%s%s) heap statistics:\n",
150 am_server ? "server " : "",
151 am_daemon ? "daemon " : "",
152 am_sender ? "sender" : "receiver");
153 rprintf(FINFO, " arena: %10d (bytes from sbrk)\n", mi.arena);
154 rprintf(FINFO, " ordblks: %10d (chunks not in use)\n", mi.ordblks);
155 rprintf(FINFO, " smblks: %10d\n", mi.smblks);
156 rprintf(FINFO, " hblks: %10d (chunks from mmap)\n", mi.hblks);
157 rprintf(FINFO, " hblkhd: %10d (bytes from mmap)\n", mi.hblkhd);
158 rprintf(FINFO, " usmblks: %10d\n", mi.usmblks);
159 rprintf(FINFO, " fsmblks: %10d\n", mi.fsmblks);
160 rprintf(FINFO, " uordblks: %10d (bytes used)\n", mi.uordblks);
161 rprintf(FINFO, " fordblks: %10d (bytes free)\n", mi.fordblks);
162 rprintf(FINFO, " keepcost: %10d (bytes in releasable chunk)\n", mi.keepcost);
163 #endif /* HAVE_MALLINFO */
167 /* Start the remote shell. cmd may be NULL to use the default. */
168 static pid_t do_cmd(char *cmd,char *machine,char *user,char *path,int *f_in,int *f_out)
174 extern int local_server;
175 extern char *rsync_path;
176 extern int blocking_io;
177 extern int read_batch;
179 if (!read_batch && !local_server) { /* dw -- added read_batch */
181 cmd = getenv(RSYNC_RSH_ENV);
188 for (tok=strtok(cmd," ");tok;tok=strtok(NULL," ")) {
193 /* remsh (on HPUX) takes the arguments the other way around */
194 args[argc++] = machine;
204 args[argc++] = machine;
207 args[argc++] = rsync_path;
209 server_options(args,&argc);
212 if (strcmp(cmd, RSYNC_RSH) == 0) blocking_io = 1;
223 rprintf(FINFO,"cmd=");
225 rprintf(FINFO,"%s ",args[i]);
231 create_flist_from_batch();
232 ret = local_child(argc, args, f_in, f_out);
234 ret = piped_child(args,f_in,f_out);
242 out_of_memory("do_cmd");
243 return 0; /* not reached */
249 static char *get_local_name(struct file_list *flist,char *name)
252 extern int orig_umask;
255 rprintf(FINFO,"get_local_name count=%d %s\n",
256 flist->count, NS(name));
261 if (do_stat(name,&st) == 0) {
262 if (S_ISDIR(st.st_mode)) {
263 if (!push_dir(name, 0)) {
264 rprintf(FERROR,"push_dir %s : %s (1)\n",
265 name,strerror(errno));
266 exit_cleanup(RERR_FILESELECT);
270 if (flist->count > 1) {
271 rprintf(FERROR,"ERROR: destination must be a directory when copying more than 1 file\n");
272 exit_cleanup(RERR_FILESELECT);
277 if (flist->count <= 1)
280 if (do_mkdir(name,0777 & ~orig_umask) != 0) {
281 rprintf(FERROR,"mkdir %s : %s (1)\n",name,strerror(errno));
282 exit_cleanup(RERR_FILEIO);
285 rprintf(FINFO,"created directory %s\n",name);
288 if (!push_dir(name, 0)) {
289 rprintf(FERROR,"push_dir %s : %s (2)\n",
290 name,strerror(errno));
291 exit_cleanup(RERR_FILESELECT);
300 static void do_server_sender(int f_in, int f_out, int argc,char *argv[])
303 struct file_list *flist;
305 extern int relative_paths;
307 extern int remote_version;
310 rprintf(FINFO,"server_sender starting pid=%d\n",(int)getpid());
312 if (!relative_paths && !push_dir(dir, 0)) {
313 rprintf(FERROR,"push_dir %s: %s (3)\n",dir,strerror(errno));
314 exit_cleanup(RERR_FILESELECT);
319 if (strcmp(dir,".")) {
321 if (strcmp(dir,"/") == 0)
327 if (argc == 0 && recurse) {
333 flist = send_file_list(f_out,argc,argv);
334 if (!flist || flist->count == 0) {
338 send_files(flist,f_out,f_in);
341 if (remote_version >= 24) {
342 /* final goodbye message */
350 static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
356 extern int preserve_hard_links;
357 extern int delete_after;
359 extern int delete_mode;
360 extern int remote_version;
362 if (preserve_hard_links)
363 init_hard_links(flist);
366 /* I moved this here from recv_files() to prevent a race condition */
367 if (recurse && delete_mode && !local_name && flist->count>0) {
372 if (fd_pair(recv_pipe) < 0) {
373 rprintf(FERROR,"pipe failed in do_recv\n");
374 exit_cleanup(RERR_SOCKETIO);
377 if (fd_pair(error_pipe) < 0) {
378 rprintf(FERROR,"error pipe failed in do_recv\n");
379 exit_cleanup(RERR_SOCKETIO);
384 if ((pid=do_fork()) == 0) {
386 close(error_pipe[0]);
387 if (f_in != f_out) close(f_out);
389 /* we can't let two processes write to the socket at one time */
390 io_multiplexing_close();
392 /* set place to send errors */
393 set_error_fd(error_pipe[1]);
395 recv_files(f_in,flist,local_name,recv_pipe[1]);
399 write_int(recv_pipe[1],1);
402 /* finally we go to sleep until our parent kills us
403 with a USR2 signal. We sleep for a short time as on
404 some OSes a signal won't interrupt a sleep! */
410 close(error_pipe[1]);
411 if (f_in != f_out) close(f_in);
413 io_start_buffering(f_out);
415 io_set_error_fd(error_pipe[0]);
417 generate_files(f_out,flist,local_name,recv_pipe[0]);
419 read_int(recv_pipe[0]);
421 if (remote_version >= 24) {
422 /* send a final goodbye message */
423 write_int(f_out, -1);
428 wait_process(pid, &status);
433 static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
436 struct file_list *flist;
437 char *local_name=NULL;
439 extern int delete_mode;
440 extern int delete_excluded;
441 extern int am_daemon;
442 extern int module_id;
443 extern int am_sender;
444 extern int read_batch; /* dw */
445 extern struct file_list *batch_flist; /* dw */
448 rprintf(FINFO,"server_recv(%d) starting pid=%d\n",argc,(int)getpid());
450 if (am_daemon && lp_read_only(module_id) && !am_sender) {
451 rprintf(FERROR,"ERROR: module is read only\n");
452 exit_cleanup(RERR_SYNTAX);
461 if (!am_daemon && !push_dir(dir, 0)) {
462 rprintf(FERROR,"push_dir %s : %s (4)\n",
463 dir,strerror(errno));
464 exit_cleanup(RERR_FILESELECT);
468 if (delete_mode && !delete_excluded)
469 recv_exclude_list(f_in);
471 if (read_batch) /* dw */
474 flist = recv_file_list(f_in);
476 rprintf(FERROR,"server_recv: recv_file_list error\n");
477 exit_cleanup(RERR_FILESELECT);
481 if (strcmp(dir,".")) {
482 argv[0] += strlen(dir);
483 if (argv[0][0] == '/') argv[0]++;
485 local_name = get_local_name(flist,argv[0]);
488 status = do_recv(f_in,f_out,flist,local_name);
489 exit_cleanup(status);
493 void start_server(int f_in, int f_out, int argc, char *argv[])
495 extern int cvs_exclude;
496 extern int am_sender;
497 extern int remote_version;
498 extern int read_batch; /* dw */
500 setup_protocol(f_out, f_in);
502 set_nonblocking(f_in);
503 set_nonblocking(f_out);
505 if (remote_version >= 23)
506 io_start_multiplex_out(f_out);
509 if (!read_batch) { /* dw */
510 recv_exclude_list(f_in);
514 do_server_sender(f_in, f_out, argc, argv);
516 do_server_recv(f_in, f_out, argc, argv);
523 * This is called once the connection has been negotiated. It is used
524 * for rsyncd, remote-shell, and local connections.
526 int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[])
528 struct file_list *flist;
529 int status = 0, status2 = 0;
530 char *local_name = NULL;
531 extern int am_sender;
532 extern int remote_version;
533 extern pid_t cleanup_child_pid;
534 extern int write_batch; /* dw */
535 extern int read_batch; /* dw */
536 extern struct file_list *batch_flist; /* dw */
538 cleanup_child_pid = pid;
540 flist = batch_flist; /* dw */
542 set_nonblocking(f_in);
543 set_nonblocking(f_out);
545 setup_protocol(f_out,f_in);
547 if (remote_version >= 23)
548 io_start_multiplex_in(f_in);
551 extern int cvs_exclude;
552 extern int delete_mode;
553 extern int delete_excluded;
556 if (delete_mode && !delete_excluded)
557 send_exclude_list(f_out);
558 if (!read_batch) /* dw -- don't write to pipe */
559 flist = send_file_list(f_out,argc,argv);
561 rprintf(FINFO,"file list sent\n");
563 send_files(flist,f_out,f_in);
564 if (remote_version >= 24) {
565 /* final goodbye message */
570 rprintf(FINFO,"client_run waiting on %d\n", (int) pid);
572 wait_process(pid, &status);
575 exit_cleanup(status);
579 extern int list_only;
583 if (!write_batch) /* dw */
584 send_exclude_list(f_out);
586 flist = recv_file_list(f_in);
587 if (!flist || flist->count == 0) {
588 rprintf(FINFO, "client: nothing to do: "
589 "perhaps you need to specify some filenames or "
590 "the --recursive option?\n");
594 local_name = get_local_name(flist,argv[0]);
596 status2 = do_recv(f_in,f_out,flist,local_name);
600 rprintf(FINFO,"client_run2 waiting on %d\n", (int) pid);
602 wait_process(pid, &status);
605 return MAX(status, status2);
608 static char *find_colon(char *s)
615 /* now check to see if there is a / in the string before the : - if there is then
616 discard the colon on the assumption that the : is part of a filename */
618 if (p2 && p2 < p) return NULL;
624 static int copy_argv (char *argv[])
628 for (i = 0; argv[i]; i++) {
629 if (!(argv[i] = strdup(argv[i]))) {
630 rprintf (FERROR, "out of memory at %s(%d)\n",
641 * Start a client for either type of remote connection. Work out
642 * whether the arguments request a remote shell or rsyncd connection,
643 * and call the appropriate connection function, then run_client.
645 static int start_client(int argc, char *argv[])
648 char *shell_machine = NULL;
649 char *shell_path = NULL;
650 char *shell_user = NULL;
654 extern int local_server;
655 extern int am_sender;
656 extern char *shell_cmd;
657 extern int rsync_port;
658 extern int whole_file;
659 extern int read_batch;
662 /* Don't clobber argv[] so that ps(1) can still show the right
664 if ((rc = copy_argv (argv)))
667 if (strncasecmp(URL_PREFIX, argv[0], strlen(URL_PREFIX)) == 0) {
670 host = argv[0] + strlen(URL_PREFIX);
671 p = strchr(host,'/');
678 p = strchr(host,':');
680 rsync_port = atoi(p+1);
683 return start_socket_client(host, path, argc-1, argv+1);
686 if (!read_batch) { /* dw */
687 p = find_colon(argv[0]);
692 return start_socket_client(argv[0], p+2, argc-1, argv+1);
697 exit_cleanup(RERR_SYNTAX);
702 shell_machine = argv[0];
709 p = find_colon(argv[argc-1]);
712 /* disable "rsync algorithm" when both sides local */
714 } else if (p[1] == ':') {
716 return start_socket_client(argv[argc-1], p+2, argc-1, argv);
721 exit_cleanup(RERR_SYNTAX);
725 shell_machine = NULL;
726 shell_path = argv[argc-1];
729 shell_machine = argv[argc-1];
735 am_sender = 1; /* dw */
736 local_server = 1; /* dw */
737 shell_path = argv[argc-1]; /* dw */
741 p = strchr(shell_machine,'@');
744 shell_user = shell_machine;
750 rprintf(FINFO,"cmd=%s machine=%s user=%s path=%s\n",
751 shell_cmd?shell_cmd:"",
752 shell_machine?shell_machine:"",
753 shell_user?shell_user:"",
754 shell_path?shell_path:"");
757 if (!am_sender && argc > 1) {
759 exit_cleanup(RERR_SYNTAX);
762 if (argc == 0 && !am_sender) {
763 extern int list_only;
767 pid = do_cmd(shell_cmd,shell_machine,shell_user,shell_path,&f_in,&f_out);
769 ret = client_run(f_in, f_out, pid, argc, argv);
778 static RETSIGTYPE sigusr1_handler(int val) {
779 exit_cleanup(RERR_SIGNAL);
782 static RETSIGTYPE sigusr2_handler(int val) {
783 extern int log_got_error;
784 if (log_got_error) _exit(RERR_PARTIAL);
788 static RETSIGTYPE sigchld_handler(int val) {
790 while (waitpid(-1, NULL, WNOHANG) > 0) ;
794 int main(int argc,char *argv[])
797 extern int orig_umask;
799 extern int am_daemon;
800 extern int am_server;
802 extern int read_batch; /* dw */
803 extern int write_batch; /* dw */
804 extern char *batch_ext; /* dw */
805 int orig_argc; /* dw */
807 orig_argc = argc; /* dw */
809 signal(SIGUSR1, sigusr1_handler);
810 signal(SIGUSR2, sigusr2_handler);
811 signal(SIGCHLD, sigchld_handler);
813 starttime = time(NULL);
814 am_root = (getuid() == 0);
816 memset(&stats, 0, sizeof(stats));
820 exit_cleanup(RERR_SYNTAX);
823 /* we set a 0 umask so that correct file permissions can be
825 orig_umask = (int)umask(0);
827 if (!parse_arguments(&argc, (const char ***) &argv, 1)) {
828 /* FIXME: We ought to call the same error-handling
829 * code here, rather than relying on getopt. */
831 exit_cleanup(RERR_SYNTAX);
834 signal(SIGINT,SIGNAL_CAST sig_int);
835 signal(SIGPIPE,SIGNAL_CAST sig_int);
836 signal(SIGHUP,SIGNAL_CAST sig_int);
837 signal(SIGTERM,SIGNAL_CAST sig_int);
839 /* Initialize push_dir here because on some old systems getcwd
840 (implemented by forking "pwd" and reading its output) doesn't
841 work when there are other child processes. Also, on all systems
842 that implement getcwd that way "pwd" can't be found after chroot. */
845 if (write_batch) { /* dw */
846 create_batch_file_ext();
847 write_batch_argvs_file(orig_argc, argc, argv);
850 if (read_batch) { /* dw */
851 set_batch_file_ext(batch_ext);
855 return daemon_main();
860 exit_cleanup(RERR_SYNTAX);
864 verbose = MAX(verbose,1);
866 #ifndef SUPPORT_LINKS
867 if (!am_server && preserve_links) {
868 rprintf(FERROR,"ERROR: symbolic links not supported\n");
869 exit_cleanup(RERR_UNSUPPORTED);
874 set_nonblocking(STDIN_FILENO);
875 set_nonblocking(STDOUT_FILENO);
876 start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
879 ret = start_client(argc, argv);