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);
39 log_exit(0, __FILE__, __LINE__);
40 if (f == -1 || !am_sender) return;
44 if (verbose && am_sender) {
46 /* store total_written in a temporary
47 because write_longint changes it */
48 w = stats.total_written;
49 write_longint(f,stats.total_read);
51 write_longint(f,stats.total_size);
56 /* this is the client */
58 if (!am_sender && verbose) {
59 /* note that if (!verbose && do_stats) then these values will
60 be taken from the receiver side's copy. The total size
61 is identical but the bytes read and written are slightly
62 different. It's done this way to avoid modifying the
63 protocol to support --stats without -v. */
65 stats.total_written = read_longint(f);
66 /* store total_read in a temporary, read_longint changes it */
68 stats.total_size = read_longint(f);
73 rprintf(FINFO,"\nNumber of files: %d\n", stats.num_files);
74 rprintf(FINFO,"Number of files transferred: %d\n",
75 stats.num_transferred_files);
76 rprintf(FINFO,"Total file size: %.0f bytes\n",
77 (double)stats.total_size);
78 rprintf(FINFO,"Total transferred file size: %.0f bytes\n",
79 (double)stats.total_transferred_size);
80 rprintf(FINFO,"Literal data: %.0f bytes\n",
81 (double)stats.literal_data);
82 rprintf(FINFO,"Matched data: %.0f bytes\n",
83 (double)stats.matched_data);
84 rprintf(FINFO,"File list size: %d\n", stats.flist_size);
85 rprintf(FINFO,"Total bytes written: %.0f\n",
86 (double)stats.total_written);
87 rprintf(FINFO,"Total bytes read: %.0f\n\n",
88 (double)stats.total_read);
91 if (verbose || do_stats) {
92 rprintf(FINFO,"wrote %.0f bytes read %.0f bytes %.2f bytes/sec\n",
93 (double)stats.total_written,
94 (double)stats.total_read,
95 (stats.total_written+stats.total_read)/(0.5 + (t-starttime)));
96 rprintf(FINFO,"total size is %.0f speedup is %.2f\n",
97 (double)stats.total_size,
98 (1.0*stats.total_size)/(stats.total_written+stats.total_read));
106 static int do_cmd(char *cmd,char *machine,char *user,char *path,int *f_in,int *f_out)
111 extern int local_server;
112 extern char *rsync_path;
116 cmd = getenv(RSYNC_RSH_ENV);
123 for (tok=strtok(cmd," ");tok;tok=strtok(NULL," ")) {
128 /* remsh (on HPUX) takes the arguments the other way around */
129 args[argc++] = machine;
139 args[argc++] = machine;
142 args[argc++] = rsync_path;
144 server_options(args,&argc);
155 rprintf(FINFO,"cmd=");
157 rprintf(FINFO,"%s ",args[i]);
162 ret = local_child(argc, args, f_in, f_out);
164 ret = piped_child(args,f_in,f_out);
172 out_of_memory("do_cmd");
173 return 0; /* not reached */
179 static char *get_local_name(struct file_list *flist,char *name)
182 extern int orig_umask;
185 rprintf(FINFO,"get_local_name count=%d %s\n",
186 flist->count, NS(name));
191 if (do_stat(name,&st) == 0) {
192 if (S_ISDIR(st.st_mode)) {
193 if (!push_dir(name, 0)) {
194 rprintf(FERROR,"push_dir %s : %s (1)\n",
195 name,strerror(errno));
196 exit_cleanup(RERR_FILESELECT);
200 if (flist->count > 1) {
201 rprintf(FERROR,"ERROR: destination must be a directory when copying more than 1 file\n");
202 exit_cleanup(RERR_FILESELECT);
207 if (flist->count == 1)
210 if (do_mkdir(name,0777 & ~orig_umask) != 0) {
211 rprintf(FERROR,"mkdir %s : %s (1)\n",name,strerror(errno));
212 exit_cleanup(RERR_FILEIO);
215 rprintf(FINFO,"created directory %s\n",name);
218 if (!push_dir(name, 0)) {
219 rprintf(FERROR,"push_dir %s : %s (2)\n",
220 name,strerror(errno));
221 exit_cleanup(RERR_FILESELECT);
230 static void do_server_sender(int f_in, int f_out, int argc,char *argv[])
233 struct file_list *flist;
235 extern int relative_paths;
239 rprintf(FINFO,"server_sender starting pid=%d\n",(int)getpid());
241 if (!relative_paths && !push_dir(dir, 0)) {
242 rprintf(FERROR,"push_dir %s: %s (3)\n",dir,strerror(errno));
243 exit_cleanup(RERR_FILESELECT);
248 if (strcmp(dir,".")) {
250 if (strcmp(dir,"/") == 0)
256 if (argc == 0 && recurse) {
262 set_nonblocking(f_out);
264 set_nonblocking(f_in);
266 flist = send_file_list(f_out,argc,argv);
267 if (!flist || flist->count == 0) {
271 send_files(flist,f_out,f_in);
278 static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
283 extern int preserve_hard_links;
285 if (preserve_hard_links)
286 init_hard_links(flist);
288 if (pipe(recv_pipe) < 0) {
289 rprintf(FERROR,"pipe failed in do_recv\n");
290 exit_cleanup(RERR_SOCKETIO);
295 if ((pid=do_fork()) == 0) {
297 if (f_in != f_out) close(f_out);
299 set_nonblocking(f_in);
300 set_nonblocking(recv_pipe[1]);
302 recv_files(f_in,flist,local_name,recv_pipe[1]);
310 io_close_input(f_in);
311 if (f_in != f_out) close(f_in);
313 set_nonblocking(f_out);
314 set_nonblocking(recv_pipe[0]);
316 io_start_buffering(f_out);
318 generate_files(f_out,flist,local_name,recv_pipe[0]);
321 waitpid(pid, &status, 0);
326 static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
329 struct file_list *flist;
330 char *local_name=NULL;
332 extern int delete_mode;
333 extern int am_daemon;
336 rprintf(FINFO,"server_recv(%d) starting pid=%d\n",argc,(int)getpid());
342 if (!am_daemon && !push_dir(dir, 0)) {
343 rprintf(FERROR,"push_dir %s : %s (4)\n",
344 dir,strerror(errno));
345 exit_cleanup(RERR_FILESELECT);
350 recv_exclude_list(f_in);
352 flist = recv_file_list(f_in);
353 if (!flist || flist->count == 0) {
354 rprintf(FERROR,"server_recv: nothing to do\n");
355 exit_cleanup(RERR_FILESELECT);
359 if (strcmp(dir,".")) {
360 argv[0] += strlen(dir);
361 if (argv[0][0] == '/') argv[0]++;
363 local_name = get_local_name(flist,argv[0]);
366 status = do_recv(f_in,f_out,flist,local_name);
367 exit_cleanup(status);
371 void start_server(int f_in, int f_out, int argc, char *argv[])
373 extern int cvs_exclude;
374 extern int am_sender;
376 set_nonblocking(f_out);
378 set_nonblocking(f_in);
380 setup_protocol(f_out, f_in);
383 recv_exclude_list(f_in);
386 do_server_sender(f_in, f_out, argc, argv);
388 do_server_recv(f_in, f_out, argc, argv);
393 int client_run(int f_in, int f_out, int pid, int argc, char *argv[])
395 struct file_list *flist;
396 int status = 0, status2 = 0;
397 char *local_name = NULL;
398 extern int am_sender;
399 extern int list_only;
401 setup_protocol(f_out,f_in);
404 extern int cvs_exclude;
405 extern int delete_mode;
409 send_exclude_list(f_out);
410 flist = send_file_list(f_out,argc,argv);
412 rprintf(FINFO,"file list sent\n");
414 set_nonblocking(f_out);
416 set_nonblocking(f_in);
418 send_files(flist,f_out,f_in);
421 rprintf(FINFO,"client_run waiting on %d\n",pid);
423 waitpid(pid, &status, 0);
426 exit_cleanup(status);
429 if (argc == 0) list_only = 1;
431 send_exclude_list(f_out);
433 flist = recv_file_list(f_in);
434 if (!flist || flist->count == 0) {
435 rprintf(FINFO,"client: nothing to do\n");
439 local_name = get_local_name(flist,argv[0]);
441 status2 = do_recv(f_in,f_out,flist,local_name);
445 rprintf(FINFO,"client_run2 waiting on %d\n",pid);
447 waitpid(pid, &status, 0);
450 return status | status2;
453 static char *find_colon(char *s)
460 /* now check to see if there is a / in the string before the : - if there is then
461 discard the colon on the assumption that the : is part of a filename */
463 if (p2 && p2 < p) return NULL;
468 static int start_client(int argc, char *argv[])
471 char *shell_machine = NULL;
472 char *shell_path = NULL;
473 char *shell_user = NULL;
476 extern int local_server;
477 extern int am_sender;
478 extern char *shell_cmd;
479 extern int rsync_port;
481 if (strncasecmp(URL_PREFIX, argv[0], strlen(URL_PREFIX)) == 0) {
484 host = argv[0] + strlen(URL_PREFIX);
485 p = strchr(host,'/');
492 p = strchr(host,':');
494 rsync_port = atoi(p+1);
497 return start_socket_client(host, path, argc-1, argv+1);
500 p = find_colon(argv[0]);
505 return start_socket_client(argv[0], p+2, argc-1, argv+1);
510 exit_cleanup(RERR_SYNTAX);
515 shell_machine = argv[0];
522 p = find_colon(argv[argc-1]);
525 } else if (p[1] == ':') {
527 return start_socket_client(argv[argc-1], p+2, argc-1, argv);
532 exit_cleanup(RERR_SYNTAX);
536 shell_machine = NULL;
537 shell_path = argv[argc-1];
540 shell_machine = argv[argc-1];
547 p = strchr(shell_machine,'@');
550 shell_user = shell_machine;
556 rprintf(FINFO,"cmd=%s machine=%s user=%s path=%s\n",
557 shell_cmd?shell_cmd:"",
558 shell_machine?shell_machine:"",
559 shell_user?shell_user:"",
560 shell_path?shell_path:"");
563 if (!am_sender && argc > 1) {
565 exit_cleanup(RERR_SYNTAX);
568 pid = do_cmd(shell_cmd,shell_machine,shell_user,shell_path,&f_in,&f_out);
570 ret = client_run(f_in, f_out, pid, argc, argv);
579 static RETSIGTYPE sigusr1_handler(int val) {
580 exit_cleanup(RERR_SIGNAL);
583 int main(int argc,char *argv[])
586 extern int orig_umask;
588 extern int am_daemon;
589 extern int am_server;
591 signal(SIGUSR1, sigusr1_handler);
593 starttime = time(NULL);
594 am_root = (getuid() == 0);
596 memset(&stats, 0, sizeof(stats));
600 exit_cleanup(RERR_SYNTAX);
603 /* we set a 0 umask so that correct file permissions can be
605 orig_umask = (int)umask(0);
607 if (!parse_arguments(argc, argv, 1)) {
608 exit_cleanup(RERR_SYNTAX);
615 signal(SIGCHLD,SIG_IGN);
616 signal(SIGINT,SIGNAL_CAST sig_int);
617 signal(SIGPIPE,SIGNAL_CAST sig_int);
618 signal(SIGHUP,SIGNAL_CAST sig_int);
619 signal(SIGTERM,SIGNAL_CAST sig_int);
621 /* Initialize push_dir here because on some old systems getcwd
622 (implemented by forking "pwd" and reading its output) doesn't
623 work when there are other child processes. Also, on all systems
624 that implement getcwd that way "pwd" can't be found after chroot. */
628 return daemon_main();
633 exit_cleanup(RERR_SYNTAX);
637 verbose = MAX(verbose,1);
639 #ifndef SUPPORT_LINKS
640 if (!am_server && preserve_links) {
641 rprintf(FERROR,"ERROR: symbolic links not supported\n");
642 exit_cleanup(RERR_UNSUPPORTED);
647 start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
650 return start_client(argc, argv);