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 if ((blocking_io == -1) && (strcmp(cmd, RSYNC_RSH) == 0))
213 server_options(args,&argc);
225 rprintf(FINFO,"cmd=");
227 rprintf(FINFO,"%s ",args[i]);
233 create_flist_from_batch();
234 ret = local_child(argc, args, f_in, f_out);
236 ret = piped_child(args,f_in,f_out);
244 out_of_memory("do_cmd");
245 return 0; /* not reached */
251 static char *get_local_name(struct file_list *flist,char *name)
254 extern int orig_umask;
257 rprintf(FINFO,"get_local_name count=%d %s\n",
258 flist->count, NS(name));
263 if (do_stat(name,&st) == 0) {
264 if (S_ISDIR(st.st_mode)) {
265 if (!push_dir(name, 0)) {
266 rprintf(FERROR,"push_dir %s : %s (1)\n",
267 name,strerror(errno));
268 exit_cleanup(RERR_FILESELECT);
272 if (flist->count > 1) {
273 rprintf(FERROR,"ERROR: destination must be a directory when copying more than 1 file\n");
274 exit_cleanup(RERR_FILESELECT);
279 if (flist->count <= 1)
282 if (do_mkdir(name,0777 & ~orig_umask) != 0) {
283 rprintf(FERROR,"mkdir %s : %s (1)\n",name,strerror(errno));
284 exit_cleanup(RERR_FILEIO);
287 rprintf(FINFO,"created directory %s\n",name);
290 if (!push_dir(name, 0)) {
291 rprintf(FERROR,"push_dir %s : %s (2)\n",
292 name,strerror(errno));
293 exit_cleanup(RERR_FILESELECT);
302 static void do_server_sender(int f_in, int f_out, int argc,char *argv[])
305 struct file_list *flist;
307 extern int relative_paths;
309 extern int remote_version;
312 rprintf(FINFO,"server_sender starting pid=%d\n",(int)getpid());
314 if (!relative_paths && !push_dir(dir, 0)) {
315 rprintf(FERROR,"push_dir %s: %s (3)\n",dir,strerror(errno));
316 exit_cleanup(RERR_FILESELECT);
321 if (strcmp(dir,".")) {
323 if (strcmp(dir,"/") == 0)
329 if (argc == 0 && recurse) {
335 flist = send_file_list(f_out,argc,argv);
336 if (!flist || flist->count == 0) {
340 send_files(flist,f_out,f_in);
343 if (remote_version >= 24) {
344 /* final goodbye message */
352 static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
358 extern int preserve_hard_links;
359 extern int delete_after;
361 extern int delete_mode;
362 extern int remote_version;
364 if (preserve_hard_links)
365 init_hard_links(flist);
368 /* I moved this here from recv_files() to prevent a race condition */
369 if (recurse && delete_mode && !local_name && flist->count>0) {
374 if (fd_pair(recv_pipe) < 0) {
375 rprintf(FERROR,"pipe failed in do_recv\n");
376 exit_cleanup(RERR_SOCKETIO);
379 if (fd_pair(error_pipe) < 0) {
380 rprintf(FERROR,"error pipe failed in do_recv\n");
381 exit_cleanup(RERR_SOCKETIO);
386 if ((pid=do_fork()) == 0) {
388 close(error_pipe[0]);
389 if (f_in != f_out) close(f_out);
391 /* we can't let two processes write to the socket at one time */
392 io_multiplexing_close();
394 /* set place to send errors */
395 set_error_fd(error_pipe[1]);
397 recv_files(f_in,flist,local_name,recv_pipe[1]);
401 write_int(recv_pipe[1],1);
404 /* finally we go to sleep until our parent kills us
405 with a USR2 signal. We sleep for a short time as on
406 some OSes a signal won't interrupt a sleep! */
412 close(error_pipe[1]);
413 if (f_in != f_out) close(f_in);
415 io_start_buffering(f_out);
417 io_set_error_fd(error_pipe[0]);
419 generate_files(f_out,flist,local_name,recv_pipe[0]);
421 read_int(recv_pipe[0]);
423 if (remote_version >= 24) {
424 /* send a final goodbye message */
425 write_int(f_out, -1);
430 wait_process(pid, &status);
435 static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
438 struct file_list *flist;
439 char *local_name=NULL;
441 extern int delete_mode;
442 extern int delete_excluded;
443 extern int am_daemon;
444 extern int module_id;
445 extern int am_sender;
446 extern int read_batch; /* dw */
447 extern struct file_list *batch_flist; /* dw */
450 rprintf(FINFO,"server_recv(%d) starting pid=%d\n",argc,(int)getpid());
452 if (am_daemon && lp_read_only(module_id) && !am_sender) {
453 rprintf(FERROR,"ERROR: module is read only\n");
454 exit_cleanup(RERR_SYNTAX);
463 if (!am_daemon && !push_dir(dir, 0)) {
464 rprintf(FERROR,"push_dir %s : %s (4)\n",
465 dir,strerror(errno));
466 exit_cleanup(RERR_FILESELECT);
470 if (delete_mode && !delete_excluded)
471 recv_exclude_list(f_in);
473 if (read_batch) /* dw */
476 flist = recv_file_list(f_in);
478 rprintf(FERROR,"server_recv: recv_file_list error\n");
479 exit_cleanup(RERR_FILESELECT);
483 if (strcmp(dir,".")) {
484 argv[0] += strlen(dir);
485 if (argv[0][0] == '/') argv[0]++;
487 local_name = get_local_name(flist,argv[0]);
490 status = do_recv(f_in,f_out,flist,local_name);
491 exit_cleanup(status);
495 void start_server(int f_in, int f_out, int argc, char *argv[])
497 extern int cvs_exclude;
498 extern int am_sender;
499 extern int remote_version;
500 extern int read_batch; /* dw */
502 setup_protocol(f_out, f_in);
504 set_nonblocking(f_in);
505 set_nonblocking(f_out);
507 if (remote_version >= 23)
508 io_start_multiplex_out(f_out);
511 if (!read_batch) { /* dw */
512 recv_exclude_list(f_in);
516 do_server_sender(f_in, f_out, argc, argv);
518 do_server_recv(f_in, f_out, argc, argv);
525 * This is called once the connection has been negotiated. It is used
526 * for rsyncd, remote-shell, and local connections.
528 int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[])
530 struct file_list *flist;
531 int status = 0, status2 = 0;
532 char *local_name = NULL;
533 extern int am_sender;
534 extern int remote_version;
535 extern pid_t cleanup_child_pid;
536 extern int write_batch; /* dw */
537 extern int read_batch; /* dw */
538 extern struct file_list *batch_flist; /* dw */
540 cleanup_child_pid = pid;
542 flist = batch_flist; /* dw */
544 set_nonblocking(f_in);
545 set_nonblocking(f_out);
547 setup_protocol(f_out,f_in);
549 if (remote_version >= 23)
550 io_start_multiplex_in(f_in);
553 extern int cvs_exclude;
554 extern int delete_mode;
555 extern int delete_excluded;
558 if (delete_mode && !delete_excluded)
559 send_exclude_list(f_out);
560 if (!read_batch) /* dw -- don't write to pipe */
561 flist = send_file_list(f_out,argc,argv);
563 rprintf(FINFO,"file list sent\n");
565 send_files(flist,f_out,f_in);
566 if (remote_version >= 24) {
567 /* final goodbye message */
572 rprintf(FINFO,"client_run waiting on %d\n", (int) pid);
574 wait_process(pid, &status);
577 exit_cleanup(status);
581 extern int list_only;
585 if (!write_batch) /* dw */
586 send_exclude_list(f_out);
588 flist = recv_file_list(f_in);
589 if (!flist || flist->count == 0) {
590 rprintf(FINFO, "client: nothing to do: "
591 "perhaps you need to specify some filenames or "
592 "the --recursive option?\n");
596 local_name = get_local_name(flist,argv[0]);
598 status2 = do_recv(f_in,f_out,flist,local_name);
602 rprintf(FINFO,"client_run2 waiting on %d\n", (int) pid);
604 wait_process(pid, &status);
607 return MAX(status, status2);
610 static char *find_colon(char *s)
617 /* now check to see if there is a / in the string before the : - if there is then
618 discard the colon on the assumption that the : is part of a filename */
620 if (p2 && p2 < p) return NULL;
626 static int copy_argv (char *argv[])
630 for (i = 0; argv[i]; i++) {
631 if (!(argv[i] = strdup(argv[i]))) {
632 rprintf (FERROR, "out of memory at %s(%d)\n",
643 * Start a client for either type of remote connection. Work out
644 * whether the arguments request a remote shell or rsyncd connection,
645 * and call the appropriate connection function, then run_client.
647 static int start_client(int argc, char *argv[])
650 char *shell_machine = NULL;
651 char *shell_path = NULL;
652 char *shell_user = NULL;
656 extern int local_server;
657 extern int am_sender;
658 extern char *shell_cmd;
659 extern int rsync_port;
660 extern int whole_file;
661 extern int read_batch;
664 /* Don't clobber argv[] so that ps(1) can still show the right
666 if ((rc = copy_argv (argv)))
669 if (strncasecmp(URL_PREFIX, argv[0], strlen(URL_PREFIX)) == 0) {
672 host = argv[0] + strlen(URL_PREFIX);
673 p = strchr(host,'/');
680 p = strchr(host,':');
682 rsync_port = atoi(p+1);
685 return start_socket_client(host, path, argc-1, argv+1);
688 if (!read_batch) { /* dw */
689 p = find_colon(argv[0]);
694 return start_socket_client(argv[0], p+2, argc-1, argv+1);
699 exit_cleanup(RERR_SYNTAX);
704 shell_machine = argv[0];
711 p = find_colon(argv[argc-1]);
714 /* disable "rsync algorithm" when both sides local */
715 if (whole_file == -1)
717 } else if (p[1] == ':') {
719 return start_socket_client(argv[argc-1], p+2, argc-1, argv);
724 exit_cleanup(RERR_SYNTAX);
728 shell_machine = NULL;
729 shell_path = argv[argc-1];
732 shell_machine = argv[argc-1];
738 am_sender = 1; /* dw */
739 local_server = 1; /* dw */
740 shell_path = argv[argc-1]; /* dw */
744 p = strchr(shell_machine,'@');
747 shell_user = shell_machine;
753 rprintf(FINFO,"cmd=%s machine=%s user=%s path=%s\n",
754 shell_cmd?shell_cmd:"",
755 shell_machine?shell_machine:"",
756 shell_user?shell_user:"",
757 shell_path?shell_path:"");
760 if (!am_sender && argc > 1) {
762 exit_cleanup(RERR_SYNTAX);
765 if (argc == 0 && !am_sender) {
766 extern int list_only;
770 pid = do_cmd(shell_cmd,shell_machine,shell_user,shell_path,&f_in,&f_out);
772 ret = client_run(f_in, f_out, pid, argc, argv);
781 static RETSIGTYPE sigusr1_handler(int val) {
782 exit_cleanup(RERR_SIGNAL);
785 static RETSIGTYPE sigusr2_handler(int val) {
786 extern int log_got_error;
787 if (log_got_error) _exit(RERR_PARTIAL);
791 static RETSIGTYPE sigchld_handler(int val) {
793 while (waitpid(-1, NULL, WNOHANG) > 0) ;
797 int main(int argc,char *argv[])
800 extern int orig_umask;
802 extern int am_daemon;
803 extern int am_server;
805 extern int read_batch; /* dw */
806 extern int write_batch; /* dw */
807 extern char *batch_ext; /* dw */
808 int orig_argc; /* dw */
811 orig_argc = argc; /* dw */
814 signal(SIGUSR1, sigusr1_handler);
815 signal(SIGUSR2, sigusr2_handler);
816 signal(SIGCHLD, sigchld_handler);
818 starttime = time(NULL);
819 am_root = (getuid() == 0);
821 memset(&stats, 0, sizeof(stats));
825 exit_cleanup(RERR_SYNTAX);
828 /* we set a 0 umask so that correct file permissions can be
830 orig_umask = (int)umask(0);
832 if (!parse_arguments(&argc, (const char ***) &argv, 1)) {
833 /* FIXME: We ought to call the same error-handling
834 * code here, rather than relying on getopt. */
836 exit_cleanup(RERR_SYNTAX);
839 signal(SIGINT,SIGNAL_CAST sig_int);
840 signal(SIGPIPE,SIGNAL_CAST sig_int);
841 signal(SIGHUP,SIGNAL_CAST sig_int);
842 signal(SIGTERM,SIGNAL_CAST sig_int);
844 /* Initialize push_dir here because on some old systems getcwd
845 (implemented by forking "pwd" and reading its output) doesn't
846 work when there are other child processes. Also, on all systems
847 that implement getcwd that way "pwd" can't be found after chroot. */
850 if (write_batch) { /* dw */
851 create_batch_file_ext();
852 write_batch_argvs_file(orig_argc, orig_argv);
855 if (read_batch) { /* dw */
856 set_batch_file_ext(batch_ext);
860 return daemon_main();
865 exit_cleanup(RERR_SYNTAX);
869 verbose = MAX(verbose,1);
871 #ifndef SUPPORT_LINKS
872 if (!am_server && preserve_links) {
873 rprintf(FERROR,"ERROR: symbolic links not supported\n");
874 exit_cleanup(RERR_UNSUPPORTED);
879 set_nonblocking(STDIN_FILENO);
880 set_nonblocking(STDOUT_FILENO);
881 start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
884 ret = start_client(argc, argv);