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 am_daemon;
341 rprintf(FINFO,"server_recv(%d) starting pid=%d\n",argc,(int)getpid());
347 if (!am_daemon && !push_dir(dir, 0)) {
348 rprintf(FERROR,"push_dir %s : %s (4)\n",
349 dir,strerror(errno));
350 exit_cleanup(RERR_FILESELECT);
355 recv_exclude_list(f_in);
357 flist = recv_file_list(f_in);
358 if (!flist || flist->count == 0) {
359 rprintf(FERROR,"server_recv: nothing to do\n");
360 exit_cleanup(RERR_FILESELECT);
364 if (strcmp(dir,".")) {
365 argv[0] += strlen(dir);
366 if (argv[0][0] == '/') argv[0]++;
368 local_name = get_local_name(flist,argv[0]);
371 status = do_recv(f_in,f_out,flist,local_name);
372 exit_cleanup(status);
376 void start_server(int f_in, int f_out, int argc, char *argv[])
378 extern int cvs_exclude;
379 extern int am_sender;
381 set_nonblocking(f_out);
383 set_nonblocking(f_in);
385 setup_protocol(f_out, f_in);
388 recv_exclude_list(f_in);
391 do_server_sender(f_in, f_out, argc, argv);
393 do_server_recv(f_in, f_out, argc, argv);
398 int client_run(int f_in, int f_out, int pid, int argc, char *argv[])
400 struct file_list *flist;
401 int status = 0, status2 = 0;
402 char *local_name = NULL;
403 extern int am_sender;
404 extern int list_only;
406 setup_protocol(f_out,f_in);
409 extern int cvs_exclude;
410 extern int delete_mode;
414 send_exclude_list(f_out);
415 flist = send_file_list(f_out,argc,argv);
417 rprintf(FINFO,"file list sent\n");
419 set_nonblocking(f_out);
421 set_nonblocking(f_in);
423 send_files(flist,f_out,f_in);
426 rprintf(FINFO,"client_run waiting on %d\n",pid);
428 waitpid(pid, &status, 0);
431 exit_cleanup(status);
434 if (argc == 0) list_only = 1;
436 send_exclude_list(f_out);
438 flist = recv_file_list(f_in);
439 if (!flist || flist->count == 0) {
440 rprintf(FINFO,"client: nothing to do\n");
444 local_name = get_local_name(flist,argv[0]);
446 status2 = do_recv(f_in,f_out,flist,local_name);
450 rprintf(FINFO,"client_run2 waiting on %d\n",pid);
452 waitpid(pid, &status, 0);
455 return status | status2;
458 static char *find_colon(char *s)
465 /* now check to see if there is a / in the string before the : - if there is then
466 discard the colon on the assumption that the : is part of a filename */
468 if (p2 && p2 < p) return NULL;
473 static int start_client(int argc, char *argv[])
476 char *shell_machine = NULL;
477 char *shell_path = NULL;
478 char *shell_user = NULL;
481 extern int local_server;
482 extern int am_sender;
483 extern char *shell_cmd;
484 extern int rsync_port;
486 if (strncasecmp(URL_PREFIX, argv[0], strlen(URL_PREFIX)) == 0) {
489 host = argv[0] + strlen(URL_PREFIX);
490 p = strchr(host,'/');
497 p = strchr(host,':');
499 rsync_port = atoi(p+1);
502 return start_socket_client(host, path, argc-1, argv+1);
505 p = find_colon(argv[0]);
510 return start_socket_client(argv[0], p+2, argc-1, argv+1);
515 exit_cleanup(RERR_SYNTAX);
520 shell_machine = argv[0];
527 p = find_colon(argv[argc-1]);
530 } else if (p[1] == ':') {
532 return start_socket_client(argv[argc-1], p+2, argc-1, argv);
537 exit_cleanup(RERR_SYNTAX);
541 shell_machine = NULL;
542 shell_path = argv[argc-1];
545 shell_machine = argv[argc-1];
552 p = strchr(shell_machine,'@');
555 shell_user = shell_machine;
561 rprintf(FINFO,"cmd=%s machine=%s user=%s path=%s\n",
562 shell_cmd?shell_cmd:"",
563 shell_machine?shell_machine:"",
564 shell_user?shell_user:"",
565 shell_path?shell_path:"");
568 if (!am_sender && argc > 1) {
570 exit_cleanup(RERR_SYNTAX);
573 pid = do_cmd(shell_cmd,shell_machine,shell_user,shell_path,&f_in,&f_out);
575 ret = client_run(f_in, f_out, pid, argc, argv);
584 static RETSIGTYPE sigusr1_handler(int val) {
585 exit_cleanup(RERR_SIGNAL);
588 int main(int argc,char *argv[])
591 extern int orig_umask;
593 extern int am_daemon;
594 extern int am_server;
596 signal(SIGUSR1, sigusr1_handler);
598 starttime = time(NULL);
599 am_root = (getuid() == 0);
601 memset(&stats, 0, sizeof(stats));
605 exit_cleanup(RERR_SYNTAX);
608 /* we set a 0 umask so that correct file permissions can be
610 orig_umask = (int)umask(0);
612 if (!parse_arguments(argc, argv, 1)) {
613 exit_cleanup(RERR_SYNTAX);
620 signal(SIGCHLD,SIG_IGN);
621 signal(SIGINT,SIGNAL_CAST sig_int);
622 signal(SIGPIPE,SIGNAL_CAST sig_int);
623 signal(SIGHUP,SIGNAL_CAST sig_int);
624 signal(SIGTERM,SIGNAL_CAST sig_int);
626 /* Initialize push_dir here because on some old systems getcwd
627 (implemented by forking "pwd" and reading its output) doesn't
628 work when there are other child processes. Also, on all systems
629 that implement getcwd that way "pwd" can't be found after chroot. */
633 return daemon_main();
638 exit_cleanup(RERR_SYNTAX);
642 verbose = MAX(verbose,1);
644 #ifndef SUPPORT_LINKS
645 if (!am_server && preserve_links) {
646 rprintf(FERROR,"ERROR: symbolic links not supported\n");
647 exit_cleanup(RERR_UNSUPPORTED);
652 start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
655 return start_client(argc, argv);