1 /* -*- c-file-style: "linux" -*-
3 Copyright (C) 1996-2000 by Andrew Tridgell
4 Copyright (C) Paul Mackerras 1996
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
30 /****************************************************************************
31 wait for a process to exit, calling io_flush while waiting
32 ****************************************************************************/
33 void wait_process(pid_t pid, int *status)
35 while (waitpid(pid, status, WNOHANG) == 0) {
39 *status = WEXITSTATUS(*status);
42 static void report(int f)
44 time_t t = time(NULL);
49 extern int remote_version;
53 log_exit(0, __FILE__, __LINE__);
54 if (f == -1 || !am_sender) return;
57 send_stats = verbose || (remote_version >= 20);
59 if (am_sender && send_stats) {
61 /* store total_written in a temporary
62 because write_longint changes it */
63 w = stats.total_written;
64 write_longint(f,stats.total_read);
66 write_longint(f,stats.total_size);
71 /* this is the client */
73 if (!am_sender && send_stats) {
75 stats.total_written = read_longint(f);
76 /* store total_read in a temporary, read_longint changes it */
78 stats.total_size = read_longint(f);
83 if (!am_sender && !send_stats) {
84 /* missing the bytes written by the generator */
85 rprintf(FINFO, "\nCannot show stats as receiver because remote protocol version is less than 20\n");
86 rprintf(FINFO, "Use --stats -v to show stats\n");
89 rprintf(FINFO,"\nNumber of files: %d\n", stats.num_files);
90 rprintf(FINFO,"Number of files transferred: %d\n",
91 stats.num_transferred_files);
92 rprintf(FINFO,"Total file size: %.0f bytes\n",
93 (double)stats.total_size);
94 rprintf(FINFO,"Total transferred file size: %.0f bytes\n",
95 (double)stats.total_transferred_size);
96 rprintf(FINFO,"Literal data: %.0f bytes\n",
97 (double)stats.literal_data);
98 rprintf(FINFO,"Matched data: %.0f bytes\n",
99 (double)stats.matched_data);
100 rprintf(FINFO,"File list size: %d\n", stats.flist_size);
101 rprintf(FINFO,"Total bytes written: %.0f\n",
102 (double)stats.total_written);
103 rprintf(FINFO,"Total bytes read: %.0f\n\n",
104 (double)stats.total_read);
107 if (verbose || do_stats) {
108 rprintf(FINFO,"wrote %.0f bytes read %.0f bytes %.2f bytes/sec\n",
109 (double)stats.total_written,
110 (double)stats.total_read,
111 (stats.total_written+stats.total_read)/(0.5 + (t-starttime)));
112 rprintf(FINFO,"total size is %.0f speedup is %.2f\n",
113 (double)stats.total_size,
114 (1.0*stats.total_size)/(stats.total_written+stats.total_read));
122 static int do_cmd(char *cmd,char *machine,char *user,char *path,int *f_in,int *f_out)
127 extern int local_server;
128 extern char *rsync_path;
129 extern int blocking_io;
133 cmd = getenv(RSYNC_RSH_ENV);
140 for (tok=strtok(cmd," ");tok;tok=strtok(NULL," ")) {
145 /* remsh (on HPUX) takes the arguments the other way around */
146 args[argc++] = machine;
156 args[argc++] = machine;
159 args[argc++] = rsync_path;
161 server_options(args,&argc);
164 if (strcmp(cmd, RSYNC_RSH) == 0) blocking_io = 1;
175 rprintf(FINFO,"cmd=");
177 rprintf(FINFO,"%s ",args[i]);
182 ret = local_child(argc, args, f_in, f_out);
184 ret = piped_child(args,f_in,f_out);
192 out_of_memory("do_cmd");
193 return 0; /* not reached */
199 static char *get_local_name(struct file_list *flist,char *name)
202 extern int orig_umask;
205 rprintf(FINFO,"get_local_name count=%d %s\n",
206 flist->count, NS(name));
211 if (do_stat(name,&st) == 0) {
212 if (S_ISDIR(st.st_mode)) {
213 if (!push_dir(name, 0)) {
214 rprintf(FERROR,"push_dir %s : %s (1)\n",
215 name,strerror(errno));
216 exit_cleanup(RERR_FILESELECT);
220 if (flist->count > 1) {
221 rprintf(FERROR,"ERROR: destination must be a directory when copying more than 1 file\n");
222 exit_cleanup(RERR_FILESELECT);
227 if (flist->count <= 1)
230 if (do_mkdir(name,0777 & ~orig_umask) != 0) {
231 rprintf(FERROR,"mkdir %s : %s (1)\n",name,strerror(errno));
232 exit_cleanup(RERR_FILEIO);
235 rprintf(FINFO,"created directory %s\n",name);
238 if (!push_dir(name, 0)) {
239 rprintf(FERROR,"push_dir %s : %s (2)\n",
240 name,strerror(errno));
241 exit_cleanup(RERR_FILESELECT);
250 static void do_server_sender(int f_in, int f_out, int argc,char *argv[])
253 struct file_list *flist;
255 extern int relative_paths;
257 extern int remote_version;
260 rprintf(FINFO,"server_sender starting pid=%d\n",(int)getpid());
262 if (!relative_paths && !push_dir(dir, 0)) {
263 rprintf(FERROR,"push_dir %s: %s (3)\n",dir,strerror(errno));
264 exit_cleanup(RERR_FILESELECT);
269 if (strcmp(dir,".")) {
271 if (strcmp(dir,"/") == 0)
277 if (argc == 0 && recurse) {
283 flist = send_file_list(f_out,argc,argv);
284 if (!flist || flist->count == 0) {
288 send_files(flist,f_out,f_in);
291 if (remote_version >= 24) {
292 /* final goodbye message */
300 static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
306 extern int preserve_hard_links;
307 extern int delete_after;
309 extern int delete_mode;
310 extern int remote_version;
312 if (preserve_hard_links)
313 init_hard_links(flist);
316 /* I moved this here from recv_files() to prevent a race condition */
317 if (recurse && delete_mode && !local_name && flist->count>0) {
322 if (fd_pair(recv_pipe) < 0) {
323 rprintf(FERROR,"pipe failed in do_recv\n");
324 exit_cleanup(RERR_SOCKETIO);
327 if (fd_pair(error_pipe) < 0) {
328 rprintf(FERROR,"error pipe failed in do_recv\n");
329 exit_cleanup(RERR_SOCKETIO);
334 if ((pid=do_fork()) == 0) {
336 close(error_pipe[0]);
337 if (f_in != f_out) close(f_out);
339 /* we can't let two processes write to the socket at one time */
340 io_multiplexing_close();
342 /* set place to send errors */
343 set_error_fd(error_pipe[1]);
345 recv_files(f_in,flist,local_name,recv_pipe[1]);
349 write_int(recv_pipe[1],1);
352 /* finally we go to sleep until our parent kills us
353 with a USR2 signal. We sleep for a short time as on
354 some OSes a signal won't interrupt a sleep! */
355 while (1) msleep(20);
359 close(error_pipe[1]);
360 if (f_in != f_out) close(f_in);
362 io_start_buffering(f_out);
364 io_set_error_fd(error_pipe[0]);
366 generate_files(f_out,flist,local_name,recv_pipe[0]);
368 read_int(recv_pipe[0]);
370 if (remote_version >= 24) {
371 /* send a final goodbye message */
372 write_int(f_out, -1);
377 wait_process(pid, &status);
382 static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
385 struct file_list *flist;
386 char *local_name=NULL;
388 extern int delete_mode;
389 extern int delete_excluded;
390 extern int am_daemon;
391 extern int module_id;
392 extern int am_sender;
395 rprintf(FINFO,"server_recv(%d) starting pid=%d\n",argc,(int)getpid());
397 if (am_daemon && lp_read_only(module_id) && !am_sender) {
398 rprintf(FERROR,"ERROR: module is read only\n");
399 exit_cleanup(RERR_SYNTAX);
408 if (!am_daemon && !push_dir(dir, 0)) {
409 rprintf(FERROR,"push_dir %s : %s (4)\n",
410 dir,strerror(errno));
411 exit_cleanup(RERR_FILESELECT);
415 if (delete_mode && !delete_excluded)
416 recv_exclude_list(f_in);
418 flist = recv_file_list(f_in);
420 rprintf(FERROR,"server_recv: recv_file_list error\n");
421 exit_cleanup(RERR_FILESELECT);
425 if (strcmp(dir,".")) {
426 argv[0] += strlen(dir);
427 if (argv[0][0] == '/') argv[0]++;
429 local_name = get_local_name(flist,argv[0]);
432 status = do_recv(f_in,f_out,flist,local_name);
433 exit_cleanup(status);
437 void start_server(int f_in, int f_out, int argc, char *argv[])
439 extern int cvs_exclude;
440 extern int am_sender;
441 extern int remote_version;
442 extern int want_privacy;
447 setup_protocol(f_out, f_in);
449 set_nonblocking(f_in);
450 set_nonblocking(f_out);
452 if (remote_version >= 23)
453 io_start_multiplex_out(f_out);
456 recv_exclude_list(f_in);
459 do_server_sender(f_in, f_out, argc, argv);
461 do_server_recv(f_in, f_out, argc, argv);
466 int client_run(int f_in, int f_out, int pid, int argc, char *argv[])
468 struct file_list *flist;
469 int status = 0, status2 = 0;
470 char *local_name = NULL;
471 extern int am_sender;
472 extern int remote_version;
473 extern int want_privacy;
475 set_nonblocking(f_in);
476 set_nonblocking(f_out);
481 setup_protocol(f_out,f_in);
483 if (remote_version >= 23)
484 io_start_multiplex_in(f_in);
487 extern int cvs_exclude;
488 extern int delete_mode;
489 extern int delete_excluded;
492 if (delete_mode && !delete_excluded)
493 send_exclude_list(f_out);
494 flist = send_file_list(f_out,argc,argv);
496 rprintf(FINFO,"file list sent\n");
498 send_files(flist,f_out,f_in);
501 rprintf(FINFO,"client_run waiting on %d\n",pid);
503 wait_process(pid, &status);
505 if (remote_version >= 24) {
506 /* final goodbye message */
510 exit_cleanup(status);
514 extern int list_only;
518 send_exclude_list(f_out);
520 flist = recv_file_list(f_in);
521 if (!flist || flist->count == 0) {
522 rprintf(FINFO, "client: nothing to do: "
523 "perhaps you need to specify some filenames or "
524 "the --recursive option?\n");
528 local_name = get_local_name(flist,argv[0]);
530 status2 = do_recv(f_in,f_out,flist,local_name);
534 rprintf(FINFO,"client_run2 waiting on %d\n",pid);
536 wait_process(pid, &status);
539 return status | status2;
542 static char *find_colon(char *s)
549 /* now check to see if there is a / in the string before the : - if there is then
550 discard the colon on the assumption that the : is part of a filename */
552 if (p2 && p2 < p) return NULL;
557 static int start_client(int argc, char *argv[])
560 char *shell_machine = NULL;
561 char *shell_path = NULL;
562 char *shell_user = NULL;
565 extern int local_server;
566 extern int am_sender;
567 extern char *shell_cmd;
568 extern int rsync_port;
569 char *argv0 = strdup(argv[0]);
571 if (strncasecmp(URL_PREFIX, argv0, strlen(URL_PREFIX)) == 0) {
574 host = argv0 + strlen(URL_PREFIX);
575 p = strchr(host,'/');
582 p = strchr(host,':');
584 rsync_port = atoi(p+1);
587 return start_socket_client(host, path, argc-1, argv+1);
590 p = find_colon(argv0);
595 return start_socket_client(argv0, p+2, argc-1, argv+1);
600 exit_cleanup(RERR_SYNTAX);
605 shell_machine = argv0;
612 p = find_colon(argv[argc-1]);
615 } else if (p[1] == ':') {
617 return start_socket_client(argv[argc-1], p+2, argc-1, argv);
622 exit_cleanup(RERR_SYNTAX);
626 shell_machine = NULL;
627 shell_path = argv[argc-1];
630 shell_machine = argv[argc-1];
637 p = strchr(shell_machine,'@');
640 shell_user = shell_machine;
646 rprintf(FINFO,"cmd=%s machine=%s user=%s path=%s\n",
647 shell_cmd?shell_cmd:"",
648 shell_machine?shell_machine:"",
649 shell_user?shell_user:"",
650 shell_path?shell_path:"");
653 if (!am_sender && argc > 1) {
655 exit_cleanup(RERR_SYNTAX);
658 if (argc == 0 && !am_sender) {
659 extern int list_only;
663 pid = do_cmd(shell_cmd,shell_machine,shell_user,shell_path,&f_in,&f_out);
665 ret = client_run(f_in, f_out, pid, argc, argv);
674 static RETSIGTYPE sigusr1_handler(int val) {
675 exit_cleanup(RERR_SIGNAL);
678 static RETSIGTYPE sigusr2_handler(int val) {
682 int main(int argc,char *argv[])
685 extern int orig_umask;
687 extern int am_daemon;
688 extern int am_server;
690 signal(SIGUSR1, sigusr1_handler);
691 signal(SIGUSR2, sigusr2_handler);
693 starttime = time(NULL);
694 am_root = (getuid() == 0);
696 memset(&stats, 0, sizeof(stats));
700 exit_cleanup(RERR_SYNTAX);
703 /* we set a 0 umask so that correct file permissions can be
705 orig_umask = (int)umask(0);
707 if (!parse_arguments(argc, argv, 1)) {
708 exit_cleanup(RERR_SYNTAX);
715 signal(SIGCHLD,SIG_IGN);
716 signal(SIGINT,SIGNAL_CAST sig_int);
717 signal(SIGPIPE,SIGNAL_CAST sig_int);
718 signal(SIGHUP,SIGNAL_CAST sig_int);
719 signal(SIGTERM,SIGNAL_CAST sig_int);
721 /* Initialize push_dir here because on some old systems getcwd
722 (implemented by forking "pwd" and reading its output) doesn't
723 work when there are other child processes. Also, on all systems
724 that implement getcwd that way "pwd" can't be found after chroot. */
728 return daemon_main();
733 exit_cleanup(RERR_SYNTAX);
737 verbose = MAX(verbose,1);
739 #ifndef SUPPORT_LINKS
740 if (!am_server && preserve_links) {
741 rprintf(FERROR,"ERROR: symbolic links not supported\n");
742 exit_cleanup(RERR_UNSUPPORTED);
747 set_nonblocking(STDIN_FILENO);
748 set_nonblocking(STDOUT_FILENO);
749 start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
752 return start_client(argc, argv);