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 || (remote_version >= 20);
47 if (am_sender && send_stats) {
49 /* store total_written in a temporary
50 because write_longint changes it */
51 w = stats.total_written;
52 write_longint(f,stats.total_read);
54 write_longint(f,stats.total_size);
59 /* this is the client */
61 if (!am_sender && send_stats) {
63 stats.total_written = read_longint(f);
64 /* store total_read in a temporary, read_longint changes it */
66 stats.total_size = read_longint(f);
71 if (!am_sender && !send_stats) {
72 /* missing the bytes written by the generator */
73 rprintf(FINFO, "\nCannot show stats as receiver because remote protocol version is less than 20\n");
74 rprintf(FINFO, "Use --stats -v to show stats\n");
77 rprintf(FINFO,"\nNumber of files: %d\n", stats.num_files);
78 rprintf(FINFO,"Number of files transferred: %d\n",
79 stats.num_transferred_files);
80 rprintf(FINFO,"Total file size: %.0f bytes\n",
81 (double)stats.total_size);
82 rprintf(FINFO,"Total transferred file size: %.0f bytes\n",
83 (double)stats.total_transferred_size);
84 rprintf(FINFO,"Literal data: %.0f bytes\n",
85 (double)stats.literal_data);
86 rprintf(FINFO,"Matched data: %.0f bytes\n",
87 (double)stats.matched_data);
88 rprintf(FINFO,"File list size: %d\n", stats.flist_size);
89 rprintf(FINFO,"Total bytes written: %.0f\n",
90 (double)stats.total_written);
91 rprintf(FINFO,"Total bytes read: %.0f\n\n",
92 (double)stats.total_read);
95 if (verbose || do_stats) {
96 rprintf(FINFO,"wrote %.0f bytes read %.0f bytes %.2f bytes/sec\n",
97 (double)stats.total_written,
98 (double)stats.total_read,
99 (stats.total_written+stats.total_read)/(0.5 + (t-starttime)));
100 rprintf(FINFO,"total size is %.0f speedup is %.2f\n",
101 (double)stats.total_size,
102 (1.0*stats.total_size)/(stats.total_written+stats.total_read));
110 static int do_cmd(char *cmd,char *machine,char *user,char *path,int *f_in,int *f_out)
115 extern int local_server;
116 extern char *rsync_path;
120 cmd = getenv(RSYNC_RSH_ENV);
127 for (tok=strtok(cmd," ");tok;tok=strtok(NULL," ")) {
132 /* remsh (on HPUX) takes the arguments the other way around */
133 args[argc++] = machine;
143 args[argc++] = machine;
146 args[argc++] = rsync_path;
148 server_options(args,&argc);
159 rprintf(FINFO,"cmd=");
161 rprintf(FINFO,"%s ",args[i]);
166 ret = local_child(argc, args, f_in, f_out);
168 ret = piped_child(args,f_in,f_out);
176 out_of_memory("do_cmd");
177 return 0; /* not reached */
183 static char *get_local_name(struct file_list *flist,char *name)
186 extern int orig_umask;
189 rprintf(FINFO,"get_local_name count=%d %s\n",
190 flist->count, NS(name));
195 if (do_stat(name,&st) == 0) {
196 if (S_ISDIR(st.st_mode)) {
197 if (!push_dir(name, 0)) {
198 rprintf(FERROR,"push_dir %s : %s (1)\n",
199 name,strerror(errno));
200 exit_cleanup(RERR_FILESELECT);
204 if (flist->count > 1) {
205 rprintf(FERROR,"ERROR: destination must be a directory when copying more than 1 file\n");
206 exit_cleanup(RERR_FILESELECT);
211 if (flist->count == 1)
214 if (do_mkdir(name,0777 & ~orig_umask) != 0) {
215 rprintf(FERROR,"mkdir %s : %s (1)\n",name,strerror(errno));
216 exit_cleanup(RERR_FILEIO);
219 rprintf(FINFO,"created directory %s\n",name);
222 if (!push_dir(name, 0)) {
223 rprintf(FERROR,"push_dir %s : %s (2)\n",
224 name,strerror(errno));
225 exit_cleanup(RERR_FILESELECT);
234 static void do_server_sender(int f_in, int f_out, int argc,char *argv[])
237 struct file_list *flist;
239 extern int relative_paths;
243 rprintf(FINFO,"server_sender starting pid=%d\n",(int)getpid());
245 if (!relative_paths && !push_dir(dir, 0)) {
246 rprintf(FERROR,"push_dir %s: %s (3)\n",dir,strerror(errno));
247 exit_cleanup(RERR_FILESELECT);
252 if (strcmp(dir,".")) {
254 if (strcmp(dir,"/") == 0)
260 if (argc == 0 && recurse) {
266 set_nonblocking(f_out);
268 set_nonblocking(f_in);
270 flist = send_file_list(f_out,argc,argv);
271 if (!flist || flist->count == 0) {
275 send_files(flist,f_out,f_in);
282 static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
287 extern int preserve_hard_links;
289 if (preserve_hard_links)
290 init_hard_links(flist);
292 if (pipe(recv_pipe) < 0) {
293 rprintf(FERROR,"pipe failed in do_recv\n");
294 exit_cleanup(RERR_SOCKETIO);
299 if ((pid=do_fork()) == 0) {
301 if (f_in != f_out) close(f_out);
303 set_nonblocking(f_in);
304 set_nonblocking(recv_pipe[1]);
306 recv_files(f_in,flist,local_name,recv_pipe[1]);
314 io_close_input(f_in);
315 if (f_in != f_out) close(f_in);
317 set_nonblocking(f_out);
318 set_nonblocking(recv_pipe[0]);
320 io_start_buffering(f_out);
322 generate_files(f_out,flist,local_name,recv_pipe[0]);
325 waitpid(pid, &status, 0);
330 static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
333 struct file_list *flist;
334 char *local_name=NULL;
336 extern int delete_mode;
337 extern int delete_excluded;
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);
354 if (delete_mode && !delete_excluded)
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;
411 extern int delete_excluded;
414 if (delete_mode && !delete_excluded)
415 send_exclude_list(f_out);
416 flist = send_file_list(f_out,argc,argv);
418 rprintf(FINFO,"file list sent\n");
420 set_nonblocking(f_out);
422 set_nonblocking(f_in);
424 send_files(flist,f_out,f_in);
427 rprintf(FINFO,"client_run waiting on %d\n",pid);
429 waitpid(pid, &status, 0);
432 exit_cleanup(status);
435 if (argc == 0) list_only = 1;
437 send_exclude_list(f_out);
439 flist = recv_file_list(f_in);
440 if (!flist || flist->count == 0) {
441 rprintf(FINFO,"client: nothing to do\n");
445 local_name = get_local_name(flist,argv[0]);
447 status2 = do_recv(f_in,f_out,flist,local_name);
451 rprintf(FINFO,"client_run2 waiting on %d\n",pid);
453 waitpid(pid, &status, 0);
456 return status | status2;
459 static char *find_colon(char *s)
466 /* now check to see if there is a / in the string before the : - if there is then
467 discard the colon on the assumption that the : is part of a filename */
469 if (p2 && p2 < p) return NULL;
474 static int start_client(int argc, char *argv[])
477 char *shell_machine = NULL;
478 char *shell_path = NULL;
479 char *shell_user = NULL;
482 extern int local_server;
483 extern int am_sender;
484 extern char *shell_cmd;
485 extern int rsync_port;
487 if (strncasecmp(URL_PREFIX, argv[0], strlen(URL_PREFIX)) == 0) {
490 host = argv[0] + strlen(URL_PREFIX);
491 p = strchr(host,'/');
498 p = strchr(host,':');
500 rsync_port = atoi(p+1);
503 return start_socket_client(host, path, argc-1, argv+1);
506 p = find_colon(argv[0]);
511 return start_socket_client(argv[0], p+2, argc-1, argv+1);
516 exit_cleanup(RERR_SYNTAX);
521 shell_machine = argv[0];
528 p = find_colon(argv[argc-1]);
531 } else if (p[1] == ':') {
533 return start_socket_client(argv[argc-1], p+2, argc-1, argv);
538 exit_cleanup(RERR_SYNTAX);
542 shell_machine = NULL;
543 shell_path = argv[argc-1];
546 shell_machine = argv[argc-1];
553 p = strchr(shell_machine,'@');
556 shell_user = shell_machine;
562 rprintf(FINFO,"cmd=%s machine=%s user=%s path=%s\n",
563 shell_cmd?shell_cmd:"",
564 shell_machine?shell_machine:"",
565 shell_user?shell_user:"",
566 shell_path?shell_path:"");
569 if (!am_sender && argc > 1) {
571 exit_cleanup(RERR_SYNTAX);
574 pid = do_cmd(shell_cmd,shell_machine,shell_user,shell_path,&f_in,&f_out);
576 ret = client_run(f_in, f_out, pid, argc, argv);
585 static RETSIGTYPE sigusr1_handler(int val) {
586 exit_cleanup(RERR_SIGNAL);
589 int main(int argc,char *argv[])
592 extern int orig_umask;
594 extern int am_daemon;
595 extern int am_server;
597 signal(SIGUSR1, sigusr1_handler);
599 starttime = time(NULL);
600 am_root = (getuid() == 0);
602 memset(&stats, 0, sizeof(stats));
606 exit_cleanup(RERR_SYNTAX);
609 /* we set a 0 umask so that correct file permissions can be
611 orig_umask = (int)umask(0);
613 if (!parse_arguments(argc, argv, 1)) {
614 exit_cleanup(RERR_SYNTAX);
621 signal(SIGCHLD,SIG_IGN);
622 signal(SIGINT,SIGNAL_CAST sig_int);
623 signal(SIGPIPE,SIGNAL_CAST sig_int);
624 signal(SIGHUP,SIGNAL_CAST sig_int);
625 signal(SIGTERM,SIGNAL_CAST sig_int);
627 /* Initialize push_dir here because on some old systems getcwd
628 (implemented by forking "pwd" and reading its output) doesn't
629 work when there are other child processes. Also, on all systems
630 that implement getcwd that way "pwd" can't be found after chroot. */
634 return daemon_main();
639 exit_cleanup(RERR_SYNTAX);
643 verbose = MAX(verbose,1);
645 #ifndef SUPPORT_LINKS
646 if (!am_server && preserve_links) {
647 rprintf(FERROR,"ERROR: symbolic links not supported\n");
648 exit_cleanup(RERR_UNSUPPORTED);
653 start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
656 return start_client(argc, argv);