1 /* -*- c-file-style: "linux" -*-
3 Copyright (C) 1996-2001 by Andrew Tridgell <tridge@samba.org>
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) {
40 /* TODO: If the child exited on a signal, then log an
41 * appropriate error message. Perhaps we should also accept a
42 * message describing the purpose of the child. Also indicate
43 * this to the caller so that thhey know something went
45 *status = WEXITSTATUS(*status);
48 static void report(int f)
50 time_t t = time(NULL);
55 extern int remote_version;
59 log_exit(0, __FILE__, __LINE__);
60 if (f == -1 || !am_sender) return;
63 send_stats = verbose || (remote_version >= 20);
65 if (am_sender && send_stats) {
67 /* store total_written in a temporary
68 because write_longint changes it */
69 w = stats.total_written;
70 write_longint(f,stats.total_read);
72 write_longint(f,stats.total_size);
77 /* this is the client */
79 if (!am_sender && send_stats) {
81 stats.total_written = read_longint(f);
82 /* store total_read in a temporary, read_longint changes it */
84 stats.total_size = read_longint(f);
89 if (!am_sender && !send_stats) {
90 /* missing the bytes written by the generator */
91 rprintf(FINFO, "\nCannot show stats as receiver because remote protocol version is less than 20\n");
92 rprintf(FINFO, "Use --stats -v to show stats\n");
95 rprintf(FINFO,"\nNumber of files: %d\n", stats.num_files);
96 rprintf(FINFO,"Number of files transferred: %d\n",
97 stats.num_transferred_files);
98 rprintf(FINFO,"Total file size: %.0f bytes\n",
99 (double)stats.total_size);
100 rprintf(FINFO,"Total transferred file size: %.0f bytes\n",
101 (double)stats.total_transferred_size);
102 rprintf(FINFO,"Literal data: %.0f bytes\n",
103 (double)stats.literal_data);
104 rprintf(FINFO,"Matched data: %.0f bytes\n",
105 (double)stats.matched_data);
106 rprintf(FINFO,"File list size: %d\n", stats.flist_size);
107 rprintf(FINFO,"Total bytes written: %.0f\n",
108 (double)stats.total_written);
109 rprintf(FINFO,"Total bytes read: %.0f\n\n",
110 (double)stats.total_read);
113 if (verbose || do_stats) {
114 rprintf(FINFO,"wrote %.0f bytes read %.0f bytes %.2f bytes/sec\n",
115 (double)stats.total_written,
116 (double)stats.total_read,
117 (stats.total_written+stats.total_read)/(0.5 + (t-starttime)));
118 rprintf(FINFO,"total size is %.0f speedup is %.2f\n",
119 (double)stats.total_size,
120 (1.0*stats.total_size)/(stats.total_written+stats.total_read));
128 /* Start the remote shell. */
129 /* TODO: When the shell exits, look at its return value, as this may
130 * well tell us if something went wrong in trying to connect to the
131 * remote machine. Although it doesn't seem to be specified anywhere,
132 * ssh and the shell seem to return these values:
134 * 124 if the command exited with status 255
135 * 125 if the command is killed by a signal
136 * 126 if the command cannot be run
137 * 127 if the command is not found
139 * and we could use this to give a better explanation if the remote
140 * command is not found.
142 static int do_cmd(char *cmd,char *machine,char *user,char *path,int *f_in,int *f_out)
147 extern int local_server;
148 extern char *rsync_path;
149 extern int blocking_io;
153 cmd = getenv(RSYNC_RSH_ENV);
160 for (tok=strtok(cmd," ");tok;tok=strtok(NULL," ")) {
165 /* remsh (on HPUX) takes the arguments the other way around */
166 args[argc++] = machine;
176 args[argc++] = machine;
179 args[argc++] = rsync_path;
181 server_options(args,&argc);
184 if (strcmp(cmd, RSYNC_RSH) == 0) blocking_io = 1;
195 rprintf(FINFO,"cmd=");
197 rprintf(FINFO,"%s ",args[i]);
202 ret = local_child(argc, args, f_in, f_out);
204 ret = piped_child(args,f_in,f_out);
212 out_of_memory("do_cmd");
213 return 0; /* not reached */
219 static char *get_local_name(struct file_list *flist,char *name)
222 extern int orig_umask;
225 rprintf(FINFO,"get_local_name count=%d %s\n",
226 flist->count, NS(name));
231 if (do_stat(name,&st) == 0) {
232 if (S_ISDIR(st.st_mode)) {
233 if (!push_dir(name, 0)) {
234 rprintf(FERROR,"push_dir %s : %s (1)\n",
235 name,strerror(errno));
236 exit_cleanup(RERR_FILESELECT);
240 if (flist->count > 1) {
241 rprintf(FERROR,"ERROR: destination must be a directory when copying more than 1 file\n");
242 exit_cleanup(RERR_FILESELECT);
247 if (flist->count <= 1)
250 if (do_mkdir(name,0777 & ~orig_umask) != 0) {
251 rprintf(FERROR,"mkdir %s : %s (1)\n",name,strerror(errno));
252 exit_cleanup(RERR_FILEIO);
255 rprintf(FINFO,"created directory %s\n",name);
258 if (!push_dir(name, 0)) {
259 rprintf(FERROR,"push_dir %s : %s (2)\n",
260 name,strerror(errno));
261 exit_cleanup(RERR_FILESELECT);
270 static void do_server_sender(int f_in, int f_out, int argc,char *argv[])
273 struct file_list *flist;
275 extern int relative_paths;
277 extern int remote_version;
280 rprintf(FINFO,"server_sender starting pid=%d\n",(int)getpid());
282 if (!relative_paths && !push_dir(dir, 0)) {
283 rprintf(FERROR,"push_dir %s: %s (3)\n",dir,strerror(errno));
284 exit_cleanup(RERR_FILESELECT);
289 if (strcmp(dir,".")) {
291 if (strcmp(dir,"/") == 0)
297 if (argc == 0 && recurse) {
303 flist = send_file_list(f_out,argc,argv);
304 if (!flist || flist->count == 0) {
308 send_files(flist,f_out,f_in);
311 if (remote_version >= 24) {
312 /* final goodbye message */
320 static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
326 extern int preserve_hard_links;
327 extern int delete_after;
329 extern int delete_mode;
330 extern int remote_version;
332 if (preserve_hard_links)
333 init_hard_links(flist);
336 /* I moved this here from recv_files() to prevent a race condition */
337 if (recurse && delete_mode && !local_name && flist->count>0) {
342 if (fd_pair(recv_pipe) < 0) {
343 rprintf(FERROR,"pipe failed in do_recv\n");
344 exit_cleanup(RERR_SOCKETIO);
347 if (fd_pair(error_pipe) < 0) {
348 rprintf(FERROR,"error pipe failed in do_recv\n");
349 exit_cleanup(RERR_SOCKETIO);
354 if ((pid=do_fork()) == 0) {
356 close(error_pipe[0]);
357 if (f_in != f_out) close(f_out);
359 /* we can't let two processes write to the socket at one time */
360 io_multiplexing_close();
362 /* set place to send errors */
363 set_error_fd(error_pipe[1]);
365 recv_files(f_in,flist,local_name,recv_pipe[1]);
369 write_int(recv_pipe[1],1);
372 /* finally we go to sleep until our parent kills us
373 with a USR2 signal. We sleep for a short time as on
374 some OSes a signal won't interrupt a sleep! */
375 while (1) msleep(20);
379 close(error_pipe[1]);
380 if (f_in != f_out) close(f_in);
382 io_start_buffering(f_out);
384 io_set_error_fd(error_pipe[0]);
386 generate_files(f_out,flist,local_name,recv_pipe[0]);
388 read_int(recv_pipe[0]);
390 if (remote_version >= 24) {
391 /* send a final goodbye message */
392 write_int(f_out, -1);
397 wait_process(pid, &status);
402 static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
405 struct file_list *flist;
406 char *local_name=NULL;
408 extern int delete_mode;
409 extern int delete_excluded;
410 extern int am_daemon;
411 extern int module_id;
412 extern int am_sender;
415 rprintf(FINFO,"server_recv(%d) starting pid=%d\n",argc,(int)getpid());
417 if (am_daemon && lp_read_only(module_id) && !am_sender) {
418 rprintf(FERROR,"ERROR: module is read only\n");
419 exit_cleanup(RERR_SYNTAX);
428 if (!am_daemon && !push_dir(dir, 0)) {
429 rprintf(FERROR,"push_dir %s : %s (4)\n",
430 dir,strerror(errno));
431 exit_cleanup(RERR_FILESELECT);
435 if (delete_mode && !delete_excluded)
436 recv_exclude_list(f_in);
438 flist = recv_file_list(f_in);
440 rprintf(FERROR,"server_recv: recv_file_list error\n");
441 exit_cleanup(RERR_FILESELECT);
445 if (strcmp(dir,".")) {
446 argv[0] += strlen(dir);
447 if (argv[0][0] == '/') argv[0]++;
449 local_name = get_local_name(flist,argv[0]);
452 status = do_recv(f_in,f_out,flist,local_name);
453 exit_cleanup(status);
457 void start_server(int f_in, int f_out, int argc, char *argv[])
459 extern int cvs_exclude;
460 extern int am_sender;
461 extern int remote_version;
463 setup_protocol(f_out, f_in);
465 set_nonblocking(f_in);
466 set_nonblocking(f_out);
468 if (remote_version >= 23)
469 io_start_multiplex_out(f_out);
472 recv_exclude_list(f_in);
475 do_server_sender(f_in, f_out, argc, argv);
477 do_server_recv(f_in, f_out, argc, argv);
484 * This is called once the connection has been negotiated. It is used
485 * for rsyncd, remote-shell, and local connections.
487 int client_run(int f_in, int f_out, int pid, int argc, char *argv[])
489 struct file_list *flist;
490 int status = 0, status2 = 0;
491 char *local_name = NULL;
492 extern int am_sender;
493 extern int remote_version;
495 set_nonblocking(f_in);
496 set_nonblocking(f_out);
498 setup_protocol(f_out,f_in);
500 if (remote_version >= 23)
501 io_start_multiplex_in(f_in);
504 extern int cvs_exclude;
505 extern int delete_mode;
506 extern int delete_excluded;
509 if (delete_mode && !delete_excluded)
510 send_exclude_list(f_out);
511 flist = send_file_list(f_out,argc,argv);
513 rprintf(FINFO,"file list sent\n");
515 send_files(flist,f_out,f_in);
518 rprintf(FINFO,"client_run waiting on %d\n",pid);
520 wait_process(pid, &status);
522 if (remote_version >= 24) {
523 /* final goodbye message */
527 exit_cleanup(status);
531 extern int list_only;
535 send_exclude_list(f_out);
537 flist = recv_file_list(f_in);
538 if (!flist || flist->count == 0) {
539 rprintf(FINFO, "client: nothing to do: "
540 "perhaps you need to specify some filenames or "
541 "the --recursive option?\n");
545 local_name = get_local_name(flist,argv[0]);
547 status2 = do_recv(f_in,f_out,flist,local_name);
551 rprintf(FINFO,"client_run2 waiting on %d\n",pid);
553 wait_process(pid, &status);
556 return status | status2;
559 static char *find_colon(char *s)
566 /* now check to see if there is a / in the string before the : - if there is then
567 discard the colon on the assumption that the : is part of a filename */
569 if (p2 && p2 < p) return NULL;
576 * Start a client for either type of remote connection. Work out
577 * whether the arguments request a remote shell or rsyncd connection,
578 * and call the appropriate connection function, then run_client.
580 static int start_client(int argc, char *argv[])
583 char *shell_machine = NULL;
584 char *shell_path = NULL;
585 char *shell_user = NULL;
588 extern int local_server;
589 extern int am_sender;
590 extern char *shell_cmd;
591 extern int rsync_port;
592 char *argv0 = strdup(argv[0]);
594 if (strncasecmp(URL_PREFIX, argv0, strlen(URL_PREFIX)) == 0) {
597 host = argv0 + strlen(URL_PREFIX);
598 p = strchr(host,'/');
605 p = strchr(host,':');
607 rsync_port = atoi(p+1);
610 return start_socket_client(host, path, argc-1, argv+1);
613 p = find_colon(argv0);
618 return start_socket_client(argv0, p+2, argc-1, argv+1);
623 exit_cleanup(RERR_SYNTAX);
628 shell_machine = argv0;
635 p = find_colon(argv[argc-1]);
638 } else if (p[1] == ':') {
640 return start_socket_client(argv[argc-1], p+2, argc-1, argv);
645 exit_cleanup(RERR_SYNTAX);
649 shell_machine = NULL;
650 shell_path = argv[argc-1];
653 shell_machine = argv[argc-1];
660 p = strchr(shell_machine,'@');
663 shell_user = shell_machine;
669 rprintf(FINFO,"cmd=%s machine=%s user=%s path=%s\n",
670 shell_cmd?shell_cmd:"",
671 shell_machine?shell_machine:"",
672 shell_user?shell_user:"",
673 shell_path?shell_path:"");
676 if (!am_sender && argc > 1) {
678 exit_cleanup(RERR_SYNTAX);
681 if (argc == 0 && !am_sender) {
682 extern int list_only;
686 pid = do_cmd(shell_cmd,shell_machine,shell_user,shell_path,&f_in,&f_out);
688 ret = client_run(f_in, f_out, pid, argc, argv);
697 static RETSIGTYPE sigusr1_handler(int val) {
698 exit_cleanup(RERR_SIGNAL);
701 static RETSIGTYPE sigusr2_handler(int val) {
705 int main(int argc,char *argv[])
708 extern int orig_umask;
710 extern int am_daemon;
711 extern int am_server;
713 signal(SIGUSR1, sigusr1_handler);
714 signal(SIGUSR2, sigusr2_handler);
716 starttime = time(NULL);
717 am_root = (getuid() == 0);
719 memset(&stats, 0, sizeof(stats));
723 exit_cleanup(RERR_SYNTAX);
726 /* we set a 0 umask so that correct file permissions can be
728 orig_umask = (int)umask(0);
730 if (!parse_arguments(&argc, (const char ***) &argv, 1)) {
731 /* FIXME: We ought to call the same error-handling
732 * code here, rather than relying on getopt. */
734 exit_cleanup(RERR_SYNTAX);
737 signal(SIGCHLD,SIG_IGN);
738 signal(SIGINT,SIGNAL_CAST sig_int);
739 signal(SIGPIPE,SIGNAL_CAST sig_int);
740 signal(SIGHUP,SIGNAL_CAST sig_int);
741 signal(SIGTERM,SIGNAL_CAST sig_int);
743 /* Initialize push_dir here because on some old systems getcwd
744 (implemented by forking "pwd" and reading its output) doesn't
745 work when there are other child processes. Also, on all systems
746 that implement getcwd that way "pwd" can't be found after chroot. */
750 return daemon_main();
755 exit_cleanup(RERR_SYNTAX);
759 verbose = MAX(verbose,1);
761 #ifndef SUPPORT_LINKS
762 if (!am_server && preserve_links) {
763 rprintf(FERROR,"ERROR: symbolic links not supported\n");
764 exit_cleanup(RERR_UNSUPPORTED);
769 set_nonblocking(STDIN_FILENO);
770 set_nonblocking(STDOUT_FILENO);
771 start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
774 return start_client(argc, argv);