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
;
118 cmd
= getenv(RSYNC_RSH_ENV
);
125 for (tok
=strtok(cmd
," ");tok
;tok
=strtok(NULL
," ")) {
130 /* remsh (on HPUX) takes the arguments the other way around */
131 args
[argc
++] = machine
;
141 args
[argc
++] = machine
;
144 args
[argc
++] = rsync_path
;
146 server_options(args
,&argc
);
157 rprintf(FINFO
,"cmd=");
159 rprintf(FINFO
,"%s ",args
[i
]);
164 ret
= local_child(argc
, args
, f_in
, f_out
);
166 ret
= piped_child(args
,f_in
,f_out
);
174 out_of_memory("do_cmd");
175 return 0; /* not reached */
181 static char *get_local_name(struct file_list
*flist
,char *name
)
184 extern int orig_umask
;
187 rprintf(FINFO
,"get_local_name count=%d %s\n",
188 flist
->count
, NS(name
));
193 if (do_stat(name
,&st
) == 0) {
194 if (S_ISDIR(st
.st_mode
)) {
195 if (!push_dir(name
, 0)) {
196 rprintf(FERROR
,"push_dir %s : %s (1)\n",
197 name
,strerror(errno
));
198 exit_cleanup(RERR_FILESELECT
);
202 if (flist
->count
> 1) {
203 rprintf(FERROR
,"ERROR: destination must be a directory when copying more than 1 file\n");
204 exit_cleanup(RERR_FILESELECT
);
209 if (flist
->count
<= 1)
212 if (do_mkdir(name
,0777 & ~orig_umask
) != 0) {
213 rprintf(FERROR
,"mkdir %s : %s (1)\n",name
,strerror(errno
));
214 exit_cleanup(RERR_FILEIO
);
217 rprintf(FINFO
,"created directory %s\n",name
);
220 if (!push_dir(name
, 0)) {
221 rprintf(FERROR
,"push_dir %s : %s (2)\n",
222 name
,strerror(errno
));
223 exit_cleanup(RERR_FILESELECT
);
232 static void do_server_sender(int f_in
, int f_out
, int argc
,char *argv
[])
235 struct file_list
*flist
;
237 extern int relative_paths
;
241 rprintf(FINFO
,"server_sender starting pid=%d\n",(int)getpid());
243 if (!relative_paths
&& !push_dir(dir
, 0)) {
244 rprintf(FERROR
,"push_dir %s: %s (3)\n",dir
,strerror(errno
));
245 exit_cleanup(RERR_FILESELECT
);
250 if (strcmp(dir
,".")) {
252 if (strcmp(dir
,"/") == 0)
258 if (argc
== 0 && recurse
) {
264 set_nonblocking(f_out
);
266 set_nonblocking(f_in
);
268 flist
= send_file_list(f_out
,argc
,argv
);
269 if (!flist
|| flist
->count
== 0) {
273 send_files(flist
,f_out
,f_in
);
280 static int do_recv(int f_in
,int f_out
,struct file_list
*flist
,char *local_name
)
285 extern int preserve_hard_links
;
287 if (preserve_hard_links
)
288 init_hard_links(flist
);
290 if (pipe(recv_pipe
) < 0) {
291 rprintf(FERROR
,"pipe failed in do_recv\n");
292 exit_cleanup(RERR_SOCKETIO
);
297 if ((pid
=do_fork()) == 0) {
299 if (f_in
!= f_out
) close(f_out
);
301 set_nonblocking(f_in
);
302 set_nonblocking(recv_pipe
[1]);
304 recv_files(f_in
,flist
,local_name
,recv_pipe
[1]);
312 io_close_input(f_in
);
313 if (f_in
!= f_out
) close(f_in
);
315 set_nonblocking(f_out
);
316 set_nonblocking(recv_pipe
[0]);
318 io_start_buffering(f_out
);
320 generate_files(f_out
,flist
,local_name
,recv_pipe
[0]);
323 waitpid(pid
, &status
, 0);
328 static void do_server_recv(int f_in
, int f_out
, int argc
,char *argv
[])
331 struct file_list
*flist
;
332 char *local_name
=NULL
;
334 extern int delete_mode
;
335 extern int delete_excluded
;
336 extern int am_daemon
;
339 rprintf(FINFO
,"server_recv(%d) starting pid=%d\n",argc
,(int)getpid());
345 if (!am_daemon
&& !push_dir(dir
, 0)) {
346 rprintf(FERROR
,"push_dir %s : %s (4)\n",
347 dir
,strerror(errno
));
348 exit_cleanup(RERR_FILESELECT
);
352 if (delete_mode
&& !delete_excluded
)
353 recv_exclude_list(f_in
);
355 flist
= recv_file_list(f_in
);
357 rprintf(FERROR
,"server_recv: recv_file_list error\n");
358 exit_cleanup(RERR_FILESELECT
);
362 if (strcmp(dir
,".")) {
363 argv
[0] += strlen(dir
);
364 if (argv
[0][0] == '/') argv
[0]++;
366 local_name
= get_local_name(flist
,argv
[0]);
369 status
= do_recv(f_in
,f_out
,flist
,local_name
);
370 exit_cleanup(status
);
374 void start_server(int f_in
, int f_out
, int argc
, char *argv
[])
376 extern int cvs_exclude
;
377 extern int am_sender
;
379 set_nonblocking(f_out
);
381 set_nonblocking(f_in
);
383 setup_protocol(f_out
, f_in
);
386 recv_exclude_list(f_in
);
389 do_server_sender(f_in
, f_out
, argc
, argv
);
391 do_server_recv(f_in
, f_out
, argc
, argv
);
396 int client_run(int f_in
, int f_out
, int pid
, int argc
, char *argv
[])
398 struct file_list
*flist
;
399 int status
= 0, status2
= 0;
400 char *local_name
= NULL
;
401 extern int am_sender
;
402 extern int list_only
;
404 setup_protocol(f_out
,f_in
);
407 extern int cvs_exclude
;
408 extern int delete_mode
;
409 extern int delete_excluded
;
412 if (delete_mode
&& !delete_excluded
)
413 send_exclude_list(f_out
);
414 flist
= send_file_list(f_out
,argc
,argv
);
416 rprintf(FINFO
,"file list sent\n");
418 set_nonblocking(f_out
);
420 set_nonblocking(f_in
);
422 send_files(flist
,f_out
,f_in
);
425 rprintf(FINFO
,"client_run waiting on %d\n",pid
);
427 waitpid(pid
, &status
, 0);
430 exit_cleanup(status
);
433 if (argc
== 0) list_only
= 1;
435 send_exclude_list(f_out
);
437 flist
= recv_file_list(f_in
);
438 if (!flist
|| flist
->count
== 0) {
439 rprintf(FINFO
,"client: nothing to do\n");
443 local_name
= get_local_name(flist
,argv
[0]);
445 status2
= do_recv(f_in
,f_out
,flist
,local_name
);
449 rprintf(FINFO
,"client_run2 waiting on %d\n",pid
);
451 waitpid(pid
, &status
, 0);
454 return status
| status2
;
457 static char *find_colon(char *s
)
464 /* now check to see if there is a / in the string before the : - if there is then
465 discard the colon on the assumption that the : is part of a filename */
467 if (p2
&& p2
< p
) return NULL
;
472 static int start_client(int argc
, char *argv
[])
475 char *shell_machine
= NULL
;
476 char *shell_path
= NULL
;
477 char *shell_user
= NULL
;
480 extern int local_server
;
481 extern int am_sender
;
482 extern char *shell_cmd
;
483 extern int rsync_port
;
485 if (strncasecmp(URL_PREFIX
, argv
[0], strlen(URL_PREFIX
)) == 0) {
488 host
= argv
[0] + strlen(URL_PREFIX
);
489 p
= strchr(host
,'/');
496 p
= strchr(host
,':');
498 rsync_port
= atoi(p
+1);
501 return start_socket_client(host
, path
, argc
-1, argv
+1);
504 p
= find_colon(argv
[0]);
509 return start_socket_client(argv
[0], p
+2, argc
-1, argv
+1);
514 exit_cleanup(RERR_SYNTAX
);
519 shell_machine
= argv
[0];
526 p
= find_colon(argv
[argc
-1]);
529 } else if (p
[1] == ':') {
531 return start_socket_client(argv
[argc
-1], p
+2, argc
-1, argv
);
536 exit_cleanup(RERR_SYNTAX
);
540 shell_machine
= NULL
;
541 shell_path
= argv
[argc
-1];
544 shell_machine
= argv
[argc
-1];
551 p
= strchr(shell_machine
,'@');
554 shell_user
= shell_machine
;
560 rprintf(FINFO
,"cmd=%s machine=%s user=%s path=%s\n",
561 shell_cmd
?shell_cmd
:"",
562 shell_machine
?shell_machine
:"",
563 shell_user
?shell_user
:"",
564 shell_path
?shell_path
:"");
567 if (!am_sender
&& argc
> 1) {
569 exit_cleanup(RERR_SYNTAX
);
572 pid
= do_cmd(shell_cmd
,shell_machine
,shell_user
,shell_path
,&f_in
,&f_out
);
574 ret
= client_run(f_in
, f_out
, pid
, argc
, argv
);
583 static RETSIGTYPE
sigusr1_handler(int val
) {
584 exit_cleanup(RERR_SIGNAL
);
587 int main(int argc
,char *argv
[])
590 extern int orig_umask
;
592 extern int am_daemon
;
593 extern int am_server
;
595 signal(SIGUSR1
, sigusr1_handler
);
597 starttime
= time(NULL
);
598 am_root
= (getuid() == 0);
600 memset(&stats
, 0, sizeof(stats
));
604 exit_cleanup(RERR_SYNTAX
);
607 /* we set a 0 umask so that correct file permissions can be
609 orig_umask
= (int)umask(0);
611 if (!parse_arguments(argc
, argv
, 1)) {
612 exit_cleanup(RERR_SYNTAX
);
619 signal(SIGCHLD
,SIG_IGN
);
620 signal(SIGINT
,SIGNAL_CAST sig_int
);
621 signal(SIGPIPE
,SIGNAL_CAST sig_int
);
622 signal(SIGHUP
,SIGNAL_CAST sig_int
);
623 signal(SIGTERM
,SIGNAL_CAST sig_int
);
625 /* Initialize push_dir here because on some old systems getcwd
626 (implemented by forking "pwd" and reading its output) doesn't
627 work when there are other child processes. Also, on all systems
628 that implement getcwd that way "pwd" can't be found after chroot. */
632 return daemon_main();
637 exit_cleanup(RERR_SYNTAX
);
641 verbose
= MAX(verbose
,1);
643 #ifndef SUPPORT_LINKS
644 if (!am_server
&& preserve_links
) {
645 rprintf(FERROR
,"ERROR: symbolic links not supported\n");
646 exit_cleanup(RERR_UNSUPPORTED
);
651 start_server(STDIN_FILENO
, STDOUT_FILENO
, argc
, argv
);
654 return start_client(argc
, argv
);