optimisations from Rich Salz <rsalz@caveosystems.com>
[rsync/rsync.git] / main.c
... / ...
CommitLineData
1/*
2 Copyright (C) Andrew Tridgell 1996
3 Copyright (C) Paul Mackerras 1996
4
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.
9
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.
14
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.
18*/
19
20#include "rsync.h"
21
22time_t starttime = 0;
23
24struct stats stats;
25
26extern int verbose;
27
28static void report(int f)
29{
30 time_t t = time(NULL);
31 extern int am_server;
32 extern int am_sender;
33 extern int am_daemon;
34 extern int do_stats;
35 extern int remote_version;
36 int send_stats;
37
38 if (am_daemon) {
39 log_exit(0, __FILE__, __LINE__);
40 if (f == -1 || !am_sender) return;
41 }
42
43 send_stats = verbose || (remote_version >= 20);
44 if (am_server) {
45 if (am_sender && send_stats) {
46 int64 w;
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);
51 write_longint(f,w);
52 write_longint(f,stats.total_size);
53 }
54 return;
55 }
56
57 /* this is the client */
58
59 if (!am_sender && send_stats) {
60 int64 r;
61 stats.total_written = read_longint(f);
62 /* store total_read in a temporary, read_longint changes it */
63 r = read_longint(f);
64 stats.total_size = read_longint(f);
65 stats.total_read = r;
66 }
67
68 if (do_stats) {
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");
73 return;
74 }
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);
91 }
92
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));
101 }
102
103 fflush(stdout);
104 fflush(stderr);
105}
106
107
108static int do_cmd(char *cmd,char *machine,char *user,char *path,int *f_in,int *f_out)
109{
110 char *args[100];
111 int i,argc=0, ret;
112 char *tok,*dir=NULL;
113 extern int local_server;
114 extern char *rsync_path;
115 extern int blocking_io;
116
117 if (!local_server) {
118 if (!cmd)
119 cmd = getenv(RSYNC_RSH_ENV);
120 if (!cmd)
121 cmd = RSYNC_RSH;
122 cmd = strdup(cmd);
123 if (!cmd)
124 goto oom;
125
126 for (tok=strtok(cmd," ");tok;tok=strtok(NULL," ")) {
127 args[argc++] = tok;
128 }
129
130#if HAVE_REMSH
131 /* remsh (on HPUX) takes the arguments the other way around */
132 args[argc++] = machine;
133 if (user) {
134 args[argc++] = "-l";
135 args[argc++] = user;
136 }
137#else
138 if (user) {
139 args[argc++] = "-l";
140 args[argc++] = user;
141 }
142 args[argc++] = machine;
143#endif
144
145 args[argc++] = rsync_path;
146
147 server_options(args,&argc);
148
149
150 if (strcmp(cmd, RSYNC_RSH) == 0) blocking_io = 1;
151 }
152
153 args[argc++] = ".";
154
155 if (path && *path)
156 args[argc++] = path;
157
158 args[argc] = NULL;
159
160 if (verbose > 3) {
161 rprintf(FINFO,"cmd=");
162 for (i=0;i<argc;i++)
163 rprintf(FINFO,"%s ",args[i]);
164 rprintf(FINFO,"\n");
165 }
166
167 if (local_server) {
168 ret = local_child(argc, args, f_in, f_out);
169 } else {
170 ret = piped_child(args,f_in,f_out);
171 }
172
173 if (dir) free(dir);
174
175 return ret;
176
177oom:
178 out_of_memory("do_cmd");
179 return 0; /* not reached */
180}
181
182
183
184
185static char *get_local_name(struct file_list *flist,char *name)
186{
187 STRUCT_STAT st;
188 extern int orig_umask;
189
190 if (verbose > 2)
191 rprintf(FINFO,"get_local_name count=%d %s\n",
192 flist->count, NS(name));
193
194 if (!name)
195 return NULL;
196
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);
203 }
204 return NULL;
205 }
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);
209 }
210 return name;
211 }
212
213 if (flist->count <= 1)
214 return name;
215
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);
219 } else {
220 if (verbose > 0)
221 rprintf(FINFO,"created directory %s\n",name);
222 }
223
224 if (!push_dir(name, 0)) {
225 rprintf(FERROR,"push_dir %s : %s (2)\n",
226 name,strerror(errno));
227 exit_cleanup(RERR_FILESELECT);
228 }
229
230 return NULL;
231}
232
233
234
235
236static void do_server_sender(int f_in, int f_out, int argc,char *argv[])
237{
238 int i;
239 struct file_list *flist;
240 char *dir = argv[0];
241 extern int relative_paths;
242 extern int recurse;
243
244 if (verbose > 2)
245 rprintf(FINFO,"server_sender starting pid=%d\n",(int)getpid());
246
247 if (!relative_paths && !push_dir(dir, 0)) {
248 rprintf(FERROR,"push_dir %s: %s (3)\n",dir,strerror(errno));
249 exit_cleanup(RERR_FILESELECT);
250 }
251 argc--;
252 argv++;
253
254 if (strcmp(dir,".")) {
255 int l = strlen(dir);
256 if (strcmp(dir,"/") == 0)
257 l = 0;
258 for (i=0;i<argc;i++)
259 argv[i] += l+1;
260 }
261
262 if (argc == 0 && recurse) {
263 argc=1;
264 argv--;
265 argv[0] = ".";
266 }
267
268 flist = send_file_list(f_out,argc,argv);
269 if (!flist || flist->count == 0) {
270 exit_cleanup(0);
271 }
272
273 send_files(flist,f_out,f_in);
274 io_flush();
275 report(f_out);
276 io_flush();
277 exit_cleanup(0);
278}
279
280
281static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
282{
283 int pid;
284 int status=0;
285 int recv_pipe[2];
286 int error_pipe[2];
287 extern int preserve_hard_links;
288 extern int delete_after;
289 extern int recurse;
290 extern int delete_mode;
291 extern int remote_version;
292
293 if (preserve_hard_links)
294 init_hard_links(flist);
295
296 if (!delete_after) {
297 /* I moved this here from recv_files() to prevent a race condition */
298 if (recurse && delete_mode && !local_name && flist->count>0) {
299 delete_files(flist);
300 }
301 }
302
303 if (fd_pair(recv_pipe) < 0) {
304 rprintf(FERROR,"pipe failed in do_recv\n");
305 exit_cleanup(RERR_SOCKETIO);
306 }
307
308 if (fd_pair(error_pipe) < 0) {
309 rprintf(FERROR,"error pipe failed in do_recv\n");
310 exit_cleanup(RERR_SOCKETIO);
311 }
312
313 io_flush();
314
315 if ((pid=do_fork()) == 0) {
316 close(recv_pipe[0]);
317 close(error_pipe[0]);
318 if (f_in != f_out) close(f_out);
319
320 /* we can't let two processes write to the socket at one time */
321 io_multiplexing_close();
322
323 /* set place to send errors */
324 set_error_fd(error_pipe[1]);
325
326 recv_files(f_in,flist,local_name,recv_pipe[1]);
327 io_flush();
328 report(f_in);
329
330 write_int(recv_pipe[1],1);
331 close(recv_pipe[1]);
332 io_flush();
333 /* finally we go to sleep until our parent kills us
334 with a USR2 signal. We sleepp for a short time as on
335 some OSes a signal won't interrupt a sleep! */
336 while (1) sleep(1);
337 }
338
339 close(recv_pipe[1]);
340 close(error_pipe[1]);
341 io_close_input(f_in);
342 if (f_in != f_out) close(f_in);
343
344 io_start_buffering(f_out);
345
346 io_set_error_fd(error_pipe[0]);
347
348 generate_files(f_out,flist,local_name,recv_pipe[0]);
349
350 read_int(recv_pipe[0]);
351 close(recv_pipe[0]);
352 if (remote_version >= 24) {
353 /* send a final goodbye message */
354 write_int(f_out, -1);
355 }
356 io_flush();
357
358 kill(pid, SIGUSR2);
359 wait_process(pid, &status);
360 return status;
361}
362
363
364static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
365{
366 int status;
367 struct file_list *flist;
368 char *local_name=NULL;
369 char *dir = NULL;
370 extern int delete_mode;
371 extern int delete_excluded;
372 extern int am_daemon;
373 extern int module_id;
374 extern int am_sender;
375
376 if (verbose > 2)
377 rprintf(FINFO,"server_recv(%d) starting pid=%d\n",argc,(int)getpid());
378
379 if (am_daemon && lp_read_only(module_id) && !am_sender) {
380 rprintf(FERROR,"ERROR: module is read only\n");
381 exit_cleanup(RERR_SYNTAX);
382 return;
383 }
384
385
386 if (argc > 0) {
387 dir = argv[0];
388 argc--;
389 argv++;
390 if (!am_daemon && !push_dir(dir, 0)) {
391 rprintf(FERROR,"push_dir %s : %s (4)\n",
392 dir,strerror(errno));
393 exit_cleanup(RERR_FILESELECT);
394 }
395 }
396
397 if (delete_mode && !delete_excluded)
398 recv_exclude_list(f_in);
399
400 flist = recv_file_list(f_in);
401 if (!flist) {
402 rprintf(FERROR,"server_recv: recv_file_list error\n");
403 exit_cleanup(RERR_FILESELECT);
404 }
405
406 if (argc > 0) {
407 if (strcmp(dir,".")) {
408 argv[0] += strlen(dir);
409 if (argv[0][0] == '/') argv[0]++;
410 }
411 local_name = get_local_name(flist,argv[0]);
412 }
413
414 status = do_recv(f_in,f_out,flist,local_name);
415 exit_cleanup(status);
416}
417
418
419void start_server(int f_in, int f_out, int argc, char *argv[])
420{
421 extern int cvs_exclude;
422 extern int am_sender;
423 extern int remote_version;
424
425 setup_protocol(f_out, f_in);
426
427 set_nonblocking(f_in);
428 set_nonblocking(f_out);
429
430 if (remote_version >= 23)
431 io_start_multiplex_out(f_out);
432
433 if (am_sender) {
434 recv_exclude_list(f_in);
435 if (cvs_exclude)
436 add_cvs_excludes();
437 do_server_sender(f_in, f_out, argc, argv);
438 } else {
439 do_server_recv(f_in, f_out, argc, argv);
440 }
441 exit_cleanup(0);
442}
443
444int client_run(int f_in, int f_out, int pid, int argc, char *argv[])
445{
446 struct file_list *flist;
447 int status = 0, status2 = 0;
448 char *local_name = NULL;
449 extern int am_sender;
450 extern int list_only;
451 extern int remote_version;
452
453 set_nonblocking(f_in);
454 set_nonblocking(f_out);
455
456 setup_protocol(f_out,f_in);
457
458 if (remote_version >= 23)
459 io_start_multiplex_in(f_in);
460
461 if (am_sender) {
462 extern int cvs_exclude;
463 extern int delete_mode;
464 extern int delete_excluded;
465 if (cvs_exclude)
466 add_cvs_excludes();
467 if (delete_mode && !delete_excluded)
468 send_exclude_list(f_out);
469 flist = send_file_list(f_out,argc,argv);
470 if (verbose > 3)
471 rprintf(FINFO,"file list sent\n");
472
473 send_files(flist,f_out,f_in);
474 if (pid != -1) {
475 if (verbose > 3)
476 rprintf(FINFO,"client_run waiting on %d\n",pid);
477 io_flush();
478 wait_process(pid, &status);
479 }
480 if (remote_version >= 24) {
481 /* final goodbye message */
482 read_int(f_in);
483 }
484 report(-1);
485 exit_cleanup(status);
486 }
487
488 if (argc == 0) list_only = 1;
489
490 send_exclude_list(f_out);
491
492 flist = recv_file_list(f_in);
493 if (!flist || flist->count == 0) {
494 rprintf(FINFO,"client: nothing to do\n");
495 exit_cleanup(0);
496 }
497
498 local_name = get_local_name(flist,argv[0]);
499
500 status2 = do_recv(f_in,f_out,flist,local_name);
501
502 if (pid != -1) {
503 if (verbose > 3)
504 rprintf(FINFO,"client_run2 waiting on %d\n",pid);
505 io_flush();
506 wait_process(pid, &status);
507 }
508
509 return status | status2;
510}
511
512static char *find_colon(char *s)
513{
514 char *p, *p2;
515
516 p = strchr(s,':');
517 if (!p) return NULL;
518
519 /* now check to see if there is a / in the string before the : - if there is then
520 discard the colon on the assumption that the : is part of a filename */
521 p2 = strchr(s,'/');
522 if (p2 && p2 < p) return NULL;
523
524 return p;
525}
526
527static int start_client(int argc, char *argv[])
528{
529 char *p;
530 char *shell_machine = NULL;
531 char *shell_path = NULL;
532 char *shell_user = NULL;
533 int pid, ret;
534 int f_in,f_out;
535 extern int local_server;
536 extern int am_sender;
537 extern char *shell_cmd;
538 extern int rsync_port;
539
540 if (strncasecmp(URL_PREFIX, argv[0], strlen(URL_PREFIX)) == 0) {
541 char *host, *path;
542
543 host = argv[0] + strlen(URL_PREFIX);
544 p = strchr(host,'/');
545 if (p) {
546 *p = 0;
547 path = p+1;
548 } else {
549 path="";
550 }
551 p = strchr(host,':');
552 if (p) {
553 rsync_port = atoi(p+1);
554 *p = 0;
555 }
556 return start_socket_client(host, path, argc-1, argv+1);
557 }
558
559 p = find_colon(argv[0]);
560
561 if (p) {
562 if (p[1] == ':') {
563 *p = 0;
564 return start_socket_client(argv[0], p+2, argc-1, argv+1);
565 }
566
567 if (argc < 1) {
568 usage(FERROR);
569 exit_cleanup(RERR_SYNTAX);
570 }
571
572 am_sender = 0;
573 *p = 0;
574 shell_machine = argv[0];
575 shell_path = p+1;
576 argc--;
577 argv++;
578 } else {
579 am_sender = 1;
580
581 p = find_colon(argv[argc-1]);
582 if (!p) {
583 local_server = 1;
584 } else if (p[1] == ':') {
585 *p = 0;
586 return start_socket_client(argv[argc-1], p+2, argc-1, argv);
587 }
588
589 if (argc < 2) {
590 usage(FERROR);
591 exit_cleanup(RERR_SYNTAX);
592 }
593
594 if (local_server) {
595 shell_machine = NULL;
596 shell_path = argv[argc-1];
597 } else {
598 *p = 0;
599 shell_machine = argv[argc-1];
600 shell_path = p+1;
601 }
602 argc--;
603 }
604
605 if (shell_machine) {
606 p = strchr(shell_machine,'@');
607 if (p) {
608 *p = 0;
609 shell_user = shell_machine;
610 shell_machine = p+1;
611 }
612 }
613
614 if (verbose > 3) {
615 rprintf(FINFO,"cmd=%s machine=%s user=%s path=%s\n",
616 shell_cmd?shell_cmd:"",
617 shell_machine?shell_machine:"",
618 shell_user?shell_user:"",
619 shell_path?shell_path:"");
620 }
621
622 if (!am_sender && argc > 1) {
623 usage(FERROR);
624 exit_cleanup(RERR_SYNTAX);
625 }
626
627 pid = do_cmd(shell_cmd,shell_machine,shell_user,shell_path,&f_in,&f_out);
628
629 ret = client_run(f_in, f_out, pid, argc, argv);
630
631 fflush(stdout);
632 fflush(stderr);
633
634 return ret;
635}
636
637
638static RETSIGTYPE sigusr1_handler(int val) {
639 exit_cleanup(RERR_SIGNAL);
640}
641
642static RETSIGTYPE sigusr2_handler(int val) {
643 _exit(0);
644}
645
646int main(int argc,char *argv[])
647{
648 extern int am_root;
649 extern int orig_umask;
650 extern int dry_run;
651 extern int am_daemon;
652 extern int am_server;
653
654 signal(SIGUSR1, sigusr1_handler);
655 signal(SIGUSR2, sigusr2_handler);
656
657 starttime = time(NULL);
658 am_root = (getuid() == 0);
659
660 memset(&stats, 0, sizeof(stats));
661
662 if (argc < 2) {
663 usage(FERROR);
664 exit_cleanup(RERR_SYNTAX);
665 }
666
667 /* we set a 0 umask so that correct file permissions can be
668 carried across */
669 orig_umask = (int)umask(0);
670
671 if (!parse_arguments(argc, argv, 1)) {
672 exit_cleanup(RERR_SYNTAX);
673 }
674
675 argc -= optind;
676 argv += optind;
677 optind = 0;
678
679 signal(SIGCHLD,SIG_IGN);
680 signal(SIGINT,SIGNAL_CAST sig_int);
681 signal(SIGPIPE,SIGNAL_CAST sig_int);
682 signal(SIGHUP,SIGNAL_CAST sig_int);
683 signal(SIGTERM,SIGNAL_CAST sig_int);
684
685 /* Initialize push_dir here because on some old systems getcwd
686 (implemented by forking "pwd" and reading its output) doesn't
687 work when there are other child processes. Also, on all systems
688 that implement getcwd that way "pwd" can't be found after chroot. */
689 push_dir(NULL,0);
690
691 if (am_daemon) {
692 return daemon_main();
693 }
694
695 if (argc < 1) {
696 usage(FERROR);
697 exit_cleanup(RERR_SYNTAX);
698 }
699
700 if (dry_run)
701 verbose = MAX(verbose,1);
702
703#ifndef SUPPORT_LINKS
704 if (!am_server && preserve_links) {
705 rprintf(FERROR,"ERROR: symbolic links not supported\n");
706 exit_cleanup(RERR_UNSUPPORTED);
707 }
708#endif
709
710 if (am_server) {
711 set_nonblocking(STDIN_FILENO);
712 set_nonblocking(STDOUT_FILENO);
713 start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
714 }
715
716 return start_client(argc, argv);
717}
718