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.
28 static void report(int f)
30 time_t t = time(NULL);
35 extern int remote_version;
39 log_exit(0, __FILE__, __LINE__);
40 if (f == -1 || !am_sender) return;
43 send_stats = verbose || (remote_version >= 20);
45 if (am_sender && send_stats) {
47 /* store total_written in a temporary
48 because write_longint changes it */
49 w = stats.total_written;
50 write_longint(f,stats.total_read);
52 write_longint(f,stats.total_size);
57 /* this is the client */
59 if (!am_sender && send_stats) {
61 stats.total_written = read_longint(f);
62 /* store total_read in a temporary, read_longint changes it */
64 stats.total_size = read_longint(f);
69 if (!am_sender && !send_stats) {
70 /* missing the bytes written by the generator */
71 rprintf(FINFO, "\nCannot show stats as receiver because remote protocol version is less than 20\n");
72 rprintf(FINFO, "Use --stats -v to show stats\n");
75 rprintf(FINFO,"\nNumber of files: %d\n", stats.num_files);
76 rprintf(FINFO,"Number of files transferred: %d\n",
77 stats.num_transferred_files);
78 rprintf(FINFO,"Total file size: %.0f bytes\n",
79 (double)stats.total_size);
80 rprintf(FINFO,"Total transferred file size: %.0f bytes\n",
81 (double)stats.total_transferred_size);
82 rprintf(FINFO,"Literal data: %.0f bytes\n",
83 (double)stats.literal_data);
84 rprintf(FINFO,"Matched data: %.0f bytes\n",
85 (double)stats.matched_data);
86 rprintf(FINFO,"File list size: %d\n", stats.flist_size);
87 rprintf(FINFO,"Total bytes written: %.0f\n",
88 (double)stats.total_written);
89 rprintf(FINFO,"Total bytes read: %.0f\n\n",
90 (double)stats.total_read);
93 if (verbose || do_stats) {
94 rprintf(FINFO,"wrote %.0f bytes read %.0f bytes %.2f bytes/sec\n",
95 (double)stats.total_written,
96 (double)stats.total_read,
97 (stats.total_written+stats.total_read)/(0.5 + (t-starttime)));
98 rprintf(FINFO,"total size is %.0f speedup is %.2f\n",
99 (double)stats.total_size,
100 (1.0*stats.total_size)/(stats.total_written+stats.total_read));
108 static int do_cmd(char *cmd,char *machine,char *user,char *path,int *f_in,int *f_out)
113 extern int local_server;
114 extern char *rsync_path;
115 extern int blocking_io;
119 cmd = getenv(RSYNC_RSH_ENV);
126 for (tok=strtok(cmd," ");tok;tok=strtok(NULL," ")) {
131 /* remsh (on HPUX) takes the arguments the other way around */
132 args[argc++] = machine;
142 args[argc++] = machine;
145 args[argc++] = rsync_path;
147 server_options(args,&argc);
150 if (strcmp(cmd, RSYNC_RSH) == 0) blocking_io = 1;
161 rprintf(FINFO,"cmd=");
163 rprintf(FINFO,"%s ",args[i]);
168 ret = local_child(argc, args, f_in, f_out);
170 ret = piped_child(args,f_in,f_out);
178 out_of_memory("do_cmd");
179 return 0; /* not reached */
185 static char *get_local_name(struct file_list *flist,char *name)
188 extern int orig_umask;
191 rprintf(FINFO,"get_local_name count=%d %s\n",
192 flist->count, NS(name));
197 if (do_stat(name,&st) == 0) {
198 if (S_ISDIR(st.st_mode)) {
199 if (!push_dir(name, 0)) {
200 rprintf(FERROR,"push_dir %s : %s (1)\n",
201 name,strerror(errno));
202 exit_cleanup(RERR_FILESELECT);
206 if (flist->count > 1) {
207 rprintf(FERROR,"ERROR: destination must be a directory when copying more than 1 file\n");
208 exit_cleanup(RERR_FILESELECT);
213 if (flist->count <= 1)
216 if (do_mkdir(name,0777 & ~orig_umask) != 0) {
217 rprintf(FERROR,"mkdir %s : %s (1)\n",name,strerror(errno));
218 exit_cleanup(RERR_FILEIO);
221 rprintf(FINFO,"created directory %s\n",name);
224 if (!push_dir(name, 0)) {
225 rprintf(FERROR,"push_dir %s : %s (2)\n",
226 name,strerror(errno));
227 exit_cleanup(RERR_FILESELECT);
236 static void do_server_sender(int f_in, int f_out, int argc,char *argv[])
239 struct file_list *flist;
241 extern int relative_paths;
243 extern int remote_version;
246 rprintf(FINFO,"server_sender starting pid=%d\n",(int)getpid());
248 if (!relative_paths && !push_dir(dir, 0)) {
249 rprintf(FERROR,"push_dir %s: %s (3)\n",dir,strerror(errno));
250 exit_cleanup(RERR_FILESELECT);
255 if (strcmp(dir,".")) {
257 if (strcmp(dir,"/") == 0)
263 if (argc == 0 && recurse) {
269 flist = send_file_list(f_out,argc,argv);
270 if (!flist || flist->count == 0) {
274 send_files(flist,f_out,f_in);
277 if (remote_version >= 24) {
278 /* final goodbye message */
286 static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
292 extern int preserve_hard_links;
293 extern int delete_after;
295 extern int delete_mode;
296 extern int remote_version;
298 if (preserve_hard_links)
299 init_hard_links(flist);
302 /* I moved this here from recv_files() to prevent a race condition */
303 if (recurse && delete_mode && !local_name && flist->count>0) {
308 if (fd_pair(recv_pipe) < 0) {
309 rprintf(FERROR,"pipe failed in do_recv\n");
310 exit_cleanup(RERR_SOCKETIO);
313 if (fd_pair(error_pipe) < 0) {
314 rprintf(FERROR,"error pipe failed in do_recv\n");
315 exit_cleanup(RERR_SOCKETIO);
320 if ((pid=do_fork()) == 0) {
322 close(error_pipe[0]);
323 if (f_in != f_out) close(f_out);
325 /* we can't let two processes write to the socket at one time */
326 io_multiplexing_close();
328 /* set place to send errors */
329 set_error_fd(error_pipe[1]);
331 recv_files(f_in,flist,local_name,recv_pipe[1]);
335 write_int(recv_pipe[1],1);
338 /* finally we go to sleep until our parent kills us
339 with a USR2 signal. We sleepp for a short time as on
340 some OSes a signal won't interrupt a sleep! */
345 close(error_pipe[1]);
346 io_close_input(f_in);
347 if (f_in != f_out) close(f_in);
349 io_start_buffering(f_out);
351 io_set_error_fd(error_pipe[0]);
353 generate_files(f_out,flist,local_name,recv_pipe[0]);
355 read_int(recv_pipe[0]);
357 if (remote_version >= 24) {
358 /* send a final goodbye message */
359 write_int(f_out, -1);
364 wait_process(pid, &status);
369 static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
372 struct file_list *flist;
373 char *local_name=NULL;
375 extern int delete_mode;
376 extern int delete_excluded;
377 extern int am_daemon;
378 extern int module_id;
379 extern int am_sender;
382 rprintf(FINFO,"server_recv(%d) starting pid=%d\n",argc,(int)getpid());
384 if (am_daemon && lp_read_only(module_id) && !am_sender) {
385 rprintf(FERROR,"ERROR: module is read only\n");
386 exit_cleanup(RERR_SYNTAX);
395 if (!am_daemon && !push_dir(dir, 0)) {
396 rprintf(FERROR,"push_dir %s : %s (4)\n",
397 dir,strerror(errno));
398 exit_cleanup(RERR_FILESELECT);
402 if (delete_mode && !delete_excluded)
403 recv_exclude_list(f_in);
405 flist = recv_file_list(f_in);
407 rprintf(FERROR,"server_recv: recv_file_list error\n");
408 exit_cleanup(RERR_FILESELECT);
412 if (strcmp(dir,".")) {
413 argv[0] += strlen(dir);
414 if (argv[0][0] == '/') argv[0]++;
416 local_name = get_local_name(flist,argv[0]);
419 status = do_recv(f_in,f_out,flist,local_name);
420 exit_cleanup(status);
424 void start_server(int f_in, int f_out, int argc, char *argv[])
426 extern int cvs_exclude;
427 extern int am_sender;
428 extern int remote_version;
430 setup_protocol(f_out, f_in);
432 set_nonblocking(f_in);
433 set_nonblocking(f_out);
435 if (remote_version >= 23)
436 io_start_multiplex_out(f_out);
439 recv_exclude_list(f_in);
442 do_server_sender(f_in, f_out, argc, argv);
444 do_server_recv(f_in, f_out, argc, argv);
449 int client_run(int f_in, int f_out, int pid, int argc, char *argv[])
451 struct file_list *flist;
452 int status = 0, status2 = 0;
453 char *local_name = NULL;
454 extern int am_sender;
455 extern int list_only;
456 extern int remote_version;
458 set_nonblocking(f_in);
459 set_nonblocking(f_out);
461 setup_protocol(f_out,f_in);
463 if (remote_version >= 23)
464 io_start_multiplex_in(f_in);
467 extern int cvs_exclude;
468 extern int delete_mode;
469 extern int delete_excluded;
472 if (delete_mode && !delete_excluded)
473 send_exclude_list(f_out);
474 flist = send_file_list(f_out,argc,argv);
476 rprintf(FINFO,"file list sent\n");
478 send_files(flist,f_out,f_in);
481 rprintf(FINFO,"client_run waiting on %d\n",pid);
483 wait_process(pid, &status);
485 if (remote_version >= 24) {
486 /* final goodbye message */
490 exit_cleanup(status);
493 if (argc == 0) list_only = 1;
495 send_exclude_list(f_out);
497 flist = recv_file_list(f_in);
498 if (!flist || flist->count == 0) {
499 rprintf(FINFO,"client: nothing to do\n");
503 local_name = get_local_name(flist,argv[0]);
505 status2 = do_recv(f_in,f_out,flist,local_name);
509 rprintf(FINFO,"client_run2 waiting on %d\n",pid);
511 wait_process(pid, &status);
514 return status | status2;
517 static char *find_colon(char *s)
524 /* now check to see if there is a / in the string before the : - if there is then
525 discard the colon on the assumption that the : is part of a filename */
527 if (p2 && p2 < p) return NULL;
532 static int start_client(int argc, char *argv[])
535 char *shell_machine = NULL;
536 char *shell_path = NULL;
537 char *shell_user = NULL;
540 extern int local_server;
541 extern int am_sender;
542 extern char *shell_cmd;
543 extern int rsync_port;
545 if (strncasecmp(URL_PREFIX, argv[0], strlen(URL_PREFIX)) == 0) {
548 host = argv[0] + strlen(URL_PREFIX);
549 p = strchr(host,'/');
556 p = strchr(host,':');
558 rsync_port = atoi(p+1);
561 return start_socket_client(host, path, argc-1, argv+1);
564 p = find_colon(argv[0]);
569 return start_socket_client(argv[0], p+2, argc-1, argv+1);
574 exit_cleanup(RERR_SYNTAX);
579 shell_machine = argv[0];
586 p = find_colon(argv[argc-1]);
589 } else if (p[1] == ':') {
591 return start_socket_client(argv[argc-1], p+2, argc-1, argv);
596 exit_cleanup(RERR_SYNTAX);
600 shell_machine = NULL;
601 shell_path = argv[argc-1];
604 shell_machine = argv[argc-1];
611 p = strchr(shell_machine,'@');
614 shell_user = shell_machine;
620 rprintf(FINFO,"cmd=%s machine=%s user=%s path=%s\n",
621 shell_cmd?shell_cmd:"",
622 shell_machine?shell_machine:"",
623 shell_user?shell_user:"",
624 shell_path?shell_path:"");
627 if (!am_sender && argc > 1) {
629 exit_cleanup(RERR_SYNTAX);
632 pid = do_cmd(shell_cmd,shell_machine,shell_user,shell_path,&f_in,&f_out);
634 ret = client_run(f_in, f_out, pid, argc, argv);
643 static RETSIGTYPE sigusr1_handler(int val) {
644 exit_cleanup(RERR_SIGNAL);
647 static RETSIGTYPE sigusr2_handler(int val) {
651 int main(int argc,char *argv[])
654 extern int orig_umask;
656 extern int am_daemon;
657 extern int am_server;
659 signal(SIGUSR1, sigusr1_handler);
660 signal(SIGUSR2, sigusr2_handler);
662 starttime = time(NULL);
663 am_root = (getuid() == 0);
665 memset(&stats, 0, sizeof(stats));
669 exit_cleanup(RERR_SYNTAX);
672 /* we set a 0 umask so that correct file permissions can be
674 orig_umask = (int)umask(0);
676 if (!parse_arguments(argc, argv, 1)) {
677 exit_cleanup(RERR_SYNTAX);
684 signal(SIGCHLD,SIG_IGN);
685 signal(SIGINT,SIGNAL_CAST sig_int);
686 signal(SIGPIPE,SIGNAL_CAST sig_int);
687 signal(SIGHUP,SIGNAL_CAST sig_int);
688 signal(SIGTERM,SIGNAL_CAST sig_int);
690 /* Initialize push_dir here because on some old systems getcwd
691 (implemented by forking "pwd" and reading its output) doesn't
692 work when there are other child processes. Also, on all systems
693 that implement getcwd that way "pwd" can't be found after chroot. */
697 return daemon_main();
702 exit_cleanup(RERR_SYNTAX);
706 verbose = MAX(verbose,1);
708 #ifndef SUPPORT_LINKS
709 if (!am_server && preserve_links) {
710 rprintf(FERROR,"ERROR: symbolic links not supported\n");
711 exit_cleanup(RERR_UNSUPPORTED);
716 set_nonblocking(STDIN_FILENO);
717 set_nonblocking(STDOUT_FILENO);
718 start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
721 return start_client(argc, argv);