2 Copyright (C) Andrew Tridgell 1996
3 Copyright (C) Paul Mackerras 1996
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 extern int csum_length;
30 static void report(int f)
32 time_t t = time(NULL);
37 extern int remote_version;
41 log_exit(0, __FILE__, __LINE__);
42 if (f == -1 || !am_sender) return;
45 send_stats = verbose ||
46 ((remote_version >= 20) && (PROTOCOL_VERSION >= 20));
48 if (am_sender && send_stats) {
50 /* store total_written in a temporary
51 because write_longint changes it */
52 w = stats.total_written;
53 write_longint(f,stats.total_read);
55 write_longint(f,stats.total_size);
60 /* this is the client */
62 if (!am_sender && send_stats) {
64 stats.total_written = read_longint(f);
65 /* store total_read in a temporary, read_longint changes it */
67 stats.total_size = read_longint(f);
72 if (!am_sender && !send_stats) {
73 /* missing the bytes written by the generator */
74 rprintf(FINFO, "\nCannot show stats as receiver because protocol version is less than 20\n");
75 rprintf(FINFO, "Use --stats -v to show stats\n");
78 rprintf(FINFO,"\nNumber of files: %d\n", stats.num_files);
79 rprintf(FINFO,"Number of files transferred: %d\n",
80 stats.num_transferred_files);
81 rprintf(FINFO,"Total file size: %.0f bytes\n",
82 (double)stats.total_size);
83 rprintf(FINFO,"Total transferred file size: %.0f bytes\n",
84 (double)stats.total_transferred_size);
85 rprintf(FINFO,"Literal data: %.0f bytes\n",
86 (double)stats.literal_data);
87 rprintf(FINFO,"Matched data: %.0f bytes\n",
88 (double)stats.matched_data);
89 rprintf(FINFO,"File list size: %d\n", stats.flist_size);
90 rprintf(FINFO,"Total bytes written: %.0f\n",
91 (double)stats.total_written);
92 rprintf(FINFO,"Total bytes read: %.0f\n\n",
93 (double)stats.total_read);
96 if (verbose || do_stats) {
97 rprintf(FINFO,"wrote %.0f bytes read %.0f bytes %.2f bytes/sec\n",
98 (double)stats.total_written,
99 (double)stats.total_read,
100 (stats.total_written+stats.total_read)/(0.5 + (t-starttime)));
101 rprintf(FINFO,"total size is %.0f speedup is %.2f\n",
102 (double)stats.total_size,
103 (1.0*stats.total_size)/(stats.total_written+stats.total_read));
111 static int do_cmd(char *cmd,char *machine,char *user,char *path,int *f_in,int *f_out)
116 extern int local_server;
117 extern char *rsync_path;
121 cmd = getenv(RSYNC_RSH_ENV);
128 for (tok=strtok(cmd," ");tok;tok=strtok(NULL," ")) {
133 /* remsh (on HPUX) takes the arguments the other way around */
134 args[argc++] = machine;
144 args[argc++] = machine;
147 args[argc++] = rsync_path;
149 server_options(args,&argc);
160 rprintf(FINFO,"cmd=");
162 rprintf(FINFO,"%s ",args[i]);
167 ret = local_child(argc, args, f_in, f_out);
169 ret = piped_child(args,f_in,f_out);
177 out_of_memory("do_cmd");
178 return 0; /* not reached */
184 static char *get_local_name(struct file_list *flist,char *name)
187 extern int orig_umask;
190 rprintf(FINFO,"get_local_name count=%d %s\n",
191 flist->count, NS(name));
196 if (do_stat(name,&st) == 0) {
197 if (S_ISDIR(st.st_mode)) {
198 if (!push_dir(name, 0)) {
199 rprintf(FERROR,"push_dir %s : %s (1)\n",
200 name,strerror(errno));
201 exit_cleanup(RERR_FILESELECT);
205 if (flist->count > 1) {
206 rprintf(FERROR,"ERROR: destination must be a directory when copying more than 1 file\n");
207 exit_cleanup(RERR_FILESELECT);
212 if (flist->count == 1)
215 if (do_mkdir(name,0777 & ~orig_umask) != 0) {
216 rprintf(FERROR,"mkdir %s : %s (1)\n",name,strerror(errno));
217 exit_cleanup(RERR_FILEIO);
220 rprintf(FINFO,"created directory %s\n",name);
223 if (!push_dir(name, 0)) {
224 rprintf(FERROR,"push_dir %s : %s (2)\n",
225 name,strerror(errno));
226 exit_cleanup(RERR_FILESELECT);
235 static void do_server_sender(int f_in, int f_out, int argc,char *argv[])
238 struct file_list *flist;
240 extern int relative_paths;
244 rprintf(FINFO,"server_sender starting pid=%d\n",(int)getpid());
246 if (!relative_paths && !push_dir(dir, 0)) {
247 rprintf(FERROR,"push_dir %s: %s (3)\n",dir,strerror(errno));
248 exit_cleanup(RERR_FILESELECT);
253 if (strcmp(dir,".")) {
255 if (strcmp(dir,"/") == 0)
261 if (argc == 0 && recurse) {
267 set_nonblocking(f_out);
269 set_nonblocking(f_in);
271 flist = send_file_list(f_out,argc,argv);
272 if (!flist || flist->count == 0) {
276 send_files(flist,f_out,f_in);
283 static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
288 extern int preserve_hard_links;
290 if (preserve_hard_links)
291 init_hard_links(flist);
293 if (pipe(recv_pipe) < 0) {
294 rprintf(FERROR,"pipe failed in do_recv\n");
295 exit_cleanup(RERR_SOCKETIO);
300 if ((pid=do_fork()) == 0) {
302 if (f_in != f_out) close(f_out);
304 set_nonblocking(f_in);
305 set_nonblocking(recv_pipe[1]);
307 recv_files(f_in,flist,local_name,recv_pipe[1]);
315 io_close_input(f_in);
316 if (f_in != f_out) close(f_in);
318 set_nonblocking(f_out);
319 set_nonblocking(recv_pipe[0]);
321 io_start_buffering(f_out);
323 generate_files(f_out,flist,local_name,recv_pipe[0]);
326 waitpid(pid, &status, 0);
331 static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
334 struct file_list *flist;
335 char *local_name=NULL;
337 extern int delete_mode;
338 extern int delete_excluded;
339 extern int am_daemon;
342 rprintf(FINFO,"server_recv(%d) starting pid=%d\n",argc,(int)getpid());
348 if (!am_daemon && !push_dir(dir, 0)) {
349 rprintf(FERROR,"push_dir %s : %s (4)\n",
350 dir,strerror(errno));
351 exit_cleanup(RERR_FILESELECT);
355 if (delete_mode && !delete_excluded)
356 recv_exclude_list(f_in);
358 flist = recv_file_list(f_in);
359 if (!flist || flist->count == 0) {
360 rprintf(FERROR,"server_recv: nothing to do\n");
361 exit_cleanup(RERR_FILESELECT);
365 if (strcmp(dir,".")) {
366 argv[0] += strlen(dir);
367 if (argv[0][0] == '/') argv[0]++;
369 local_name = get_local_name(flist,argv[0]);
372 status = do_recv(f_in,f_out,flist,local_name);
373 exit_cleanup(status);
377 void start_server(int f_in, int f_out, int argc, char *argv[])
379 extern int cvs_exclude;
380 extern int am_sender;
382 set_nonblocking(f_out);
384 set_nonblocking(f_in);
386 setup_protocol(f_out, f_in);
389 recv_exclude_list(f_in);
392 do_server_sender(f_in, f_out, argc, argv);
394 do_server_recv(f_in, f_out, argc, argv);
399 int client_run(int f_in, int f_out, int pid, int argc, char *argv[])
401 struct file_list *flist;
402 int status = 0, status2 = 0;
403 char *local_name = NULL;
404 extern int am_sender;
405 extern int list_only;
407 setup_protocol(f_out,f_in);
410 extern int cvs_exclude;
411 extern int delete_mode;
412 extern int delete_excluded;
415 if (delete_mode && !delete_excluded)
416 send_exclude_list(f_out);
417 flist = send_file_list(f_out,argc,argv);
419 rprintf(FINFO,"file list sent\n");
421 set_nonblocking(f_out);
423 set_nonblocking(f_in);
425 send_files(flist,f_out,f_in);
428 rprintf(FINFO,"client_run waiting on %d\n",pid);
430 waitpid(pid, &status, 0);
433 exit_cleanup(status);
436 if (argc == 0) list_only = 1;
438 send_exclude_list(f_out);
440 flist = recv_file_list(f_in);
441 if (!flist || flist->count == 0) {
442 rprintf(FINFO,"client: nothing to do\n");
446 local_name = get_local_name(flist,argv[0]);
448 status2 = do_recv(f_in,f_out,flist,local_name);
452 rprintf(FINFO,"client_run2 waiting on %d\n",pid);
454 waitpid(pid, &status, 0);
457 return status | status2;
460 static char *find_colon(char *s)
467 /* now check to see if there is a / in the string before the : - if there is then
468 discard the colon on the assumption that the : is part of a filename */
470 if (p2 && p2 < p) return NULL;
475 static int start_client(int argc, char *argv[])
478 char *shell_machine = NULL;
479 char *shell_path = NULL;
480 char *shell_user = NULL;
483 extern int local_server;
484 extern int am_sender;
485 extern char *shell_cmd;
486 extern int rsync_port;
488 if (strncasecmp(URL_PREFIX, argv[0], strlen(URL_PREFIX)) == 0) {
491 host = argv[0] + strlen(URL_PREFIX);
492 p = strchr(host,'/');
499 p = strchr(host,':');
501 rsync_port = atoi(p+1);
504 return start_socket_client(host, path, argc-1, argv+1);
507 p = find_colon(argv[0]);
512 return start_socket_client(argv[0], p+2, argc-1, argv+1);
517 exit_cleanup(RERR_SYNTAX);
522 shell_machine = argv[0];
529 p = find_colon(argv[argc-1]);
532 } else if (p[1] == ':') {
534 return start_socket_client(argv[argc-1], p+2, argc-1, argv);
539 exit_cleanup(RERR_SYNTAX);
543 shell_machine = NULL;
544 shell_path = argv[argc-1];
547 shell_machine = argv[argc-1];
554 p = strchr(shell_machine,'@');
557 shell_user = shell_machine;
563 rprintf(FINFO,"cmd=%s machine=%s user=%s path=%s\n",
564 shell_cmd?shell_cmd:"",
565 shell_machine?shell_machine:"",
566 shell_user?shell_user:"",
567 shell_path?shell_path:"");
570 if (!am_sender && argc > 1) {
572 exit_cleanup(RERR_SYNTAX);
575 pid = do_cmd(shell_cmd,shell_machine,shell_user,shell_path,&f_in,&f_out);
577 ret = client_run(f_in, f_out, pid, argc, argv);
586 static RETSIGTYPE sigusr1_handler(int val) {
587 exit_cleanup(RERR_SIGNAL);
590 int main(int argc,char *argv[])
593 extern int orig_umask;
595 extern int am_daemon;
596 extern int am_server;
598 signal(SIGUSR1, sigusr1_handler);
600 starttime = time(NULL);
601 am_root = (getuid() == 0);
603 memset(&stats, 0, sizeof(stats));
607 exit_cleanup(RERR_SYNTAX);
610 /* we set a 0 umask so that correct file permissions can be
612 orig_umask = (int)umask(0);
614 if (!parse_arguments(argc, argv, 1)) {
615 exit_cleanup(RERR_SYNTAX);
622 signal(SIGCHLD,SIG_IGN);
623 signal(SIGINT,SIGNAL_CAST sig_int);
624 signal(SIGPIPE,SIGNAL_CAST sig_int);
625 signal(SIGHUP,SIGNAL_CAST sig_int);
626 signal(SIGTERM,SIGNAL_CAST sig_int);
628 /* Initialize push_dir here because on some old systems getcwd
629 (implemented by forking "pwd" and reading its output) doesn't
630 work when there are other child processes. Also, on all systems
631 that implement getcwd that way "pwd" can't be found after chroot. */
635 return daemon_main();
640 exit_cleanup(RERR_SYNTAX);
644 verbose = MAX(verbose,1);
646 #ifndef SUPPORT_LINKS
647 if (!am_server && preserve_links) {
648 rprintf(FERROR,"ERROR: symbolic links not supported\n");
649 exit_cleanup(RERR_UNSUPPORTED);
654 start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
657 return start_client(argc, argv);