fixed a bug that made us use only 16 bits of the file checksum when
[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
116 if (!local_server) {
117 if (!cmd)
118 cmd = getenv(RSYNC_RSH_ENV);
119 if (!cmd)
120 cmd = RSYNC_RSH;
121 cmd = strdup(cmd);
122 if (!cmd)
123 goto oom;
124
125 for (tok=strtok(cmd," ");tok;tok=strtok(NULL," ")) {
126 args[argc++] = tok;
127 }
128
129#if HAVE_REMSH
130 /* remsh (on HPUX) takes the arguments the other way around */
131 args[argc++] = machine;
132 if (user) {
133 args[argc++] = "-l";
134 args[argc++] = user;
135 }
136#else
137 if (user) {
138 args[argc++] = "-l";
139 args[argc++] = user;
140 }
141 args[argc++] = machine;
142#endif
143
144 args[argc++] = rsync_path;
145
146 server_options(args,&argc);
147 }
148
149 args[argc++] = ".";
150
151 if (path && *path)
152 args[argc++] = path;
153
154 args[argc] = NULL;
155
156 if (verbose > 3) {
157 rprintf(FINFO,"cmd=");
158 for (i=0;i<argc;i++)
159 rprintf(FINFO,"%s ",args[i]);
160 rprintf(FINFO,"\n");
161 }
162
163 if (local_server) {
164 ret = local_child(argc, args, f_in, f_out);
165 } else {
166 ret = piped_child(args,f_in,f_out);
167 }
168
169 if (dir) free(dir);
170
171 return ret;
172
173oom:
174 out_of_memory("do_cmd");
175 return 0; /* not reached */
176}
177
178
179
180
181static char *get_local_name(struct file_list *flist,char *name)
182{
183 STRUCT_STAT st;
184 extern int orig_umask;
185
186 if (verbose > 2)
187 rprintf(FINFO,"get_local_name count=%d %s\n",
188 flist->count, NS(name));
189
190 if (!name)
191 return NULL;
192
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);
199 }
200 return NULL;
201 }
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);
205 }
206 return name;
207 }
208
209 if (flist->count <= 1)
210 return name;
211
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);
215 } else {
216 if (verbose > 0)
217 rprintf(FINFO,"created directory %s\n",name);
218 }
219
220 if (!push_dir(name, 0)) {
221 rprintf(FERROR,"push_dir %s : %s (2)\n",
222 name,strerror(errno));
223 exit_cleanup(RERR_FILESELECT);
224 }
225
226 return NULL;
227}
228
229
230
231
232static void do_server_sender(int f_in, int f_out, int argc,char *argv[])
233{
234 int i;
235 struct file_list *flist;
236 char *dir = argv[0];
237 extern int relative_paths;
238 extern int recurse;
239
240 if (verbose > 2)
241 rprintf(FINFO,"server_sender starting pid=%d\n",(int)getpid());
242
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);
246 }
247 argc--;
248 argv++;
249
250 if (strcmp(dir,".")) {
251 int l = strlen(dir);
252 if (strcmp(dir,"/") == 0)
253 l = 0;
254 for (i=0;i<argc;i++)
255 argv[i] += l+1;
256 }
257
258 if (argc == 0 && recurse) {
259 argc=1;
260 argv--;
261 argv[0] = ".";
262 }
263
264 set_nonblocking(f_out);
265 if (f_in != f_out)
266 set_nonblocking(f_in);
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 report(f_out);
275 io_flush();
276 exit_cleanup(0);
277}
278
279
280static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
281{
282 int pid;
283 int status=0;
284 int recv_pipe[2];
285 extern int preserve_hard_links;
286
287 if (preserve_hard_links)
288 init_hard_links(flist);
289
290 if (pipe(recv_pipe) < 0) {
291 rprintf(FERROR,"pipe failed in do_recv\n");
292 exit_cleanup(RERR_SOCKETIO);
293 }
294
295 io_flush();
296
297 if ((pid=do_fork()) == 0) {
298 close(recv_pipe[0]);
299 if (f_in != f_out) close(f_out);
300
301 set_nonblocking(f_in);
302 set_nonblocking(recv_pipe[1]);
303
304 recv_files(f_in,flist,local_name,recv_pipe[1]);
305 report(f_in);
306
307 io_flush();
308 _exit(0);
309 }
310
311 close(recv_pipe[1]);
312 io_close_input(f_in);
313 if (f_in != f_out) close(f_in);
314
315 set_nonblocking(f_out);
316 set_nonblocking(recv_pipe[0]);
317
318 io_start_buffering(f_out);
319
320 generate_files(f_out,flist,local_name,recv_pipe[0]);
321
322 io_flush();
323 waitpid(pid, &status, 0);
324 return status;
325}
326
327
328static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
329{
330 int status;
331 struct file_list *flist;
332 char *local_name=NULL;
333 char *dir = NULL;
334 extern int delete_mode;
335 extern int delete_excluded;
336 extern int am_daemon;
337
338 if (verbose > 2)
339 rprintf(FINFO,"server_recv(%d) starting pid=%d\n",argc,(int)getpid());
340
341 if (argc > 0) {
342 dir = argv[0];
343 argc--;
344 argv++;
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);
349 }
350 }
351
352 if (delete_mode && !delete_excluded)
353 recv_exclude_list(f_in);
354
355 flist = recv_file_list(f_in);
356 if (!flist) {
357 rprintf(FERROR,"server_recv: recv_file_list error\n");
358 exit_cleanup(RERR_FILESELECT);
359 }
360
361 if (argc > 0) {
362 if (strcmp(dir,".")) {
363 argv[0] += strlen(dir);
364 if (argv[0][0] == '/') argv[0]++;
365 }
366 local_name = get_local_name(flist,argv[0]);
367 }
368
369 status = do_recv(f_in,f_out,flist,local_name);
370 exit_cleanup(status);
371}
372
373
374void start_server(int f_in, int f_out, int argc, char *argv[])
375{
376 extern int cvs_exclude;
377 extern int am_sender;
378
379 set_nonblocking(f_out);
380 if (f_in != f_out)
381 set_nonblocking(f_in);
382
383 setup_protocol(f_out, f_in);
384
385 if (am_sender) {
386 recv_exclude_list(f_in);
387 if (cvs_exclude)
388 add_cvs_excludes();
389 do_server_sender(f_in, f_out, argc, argv);
390 } else {
391 do_server_recv(f_in, f_out, argc, argv);
392 }
393 exit_cleanup(0);
394}
395
396int client_run(int f_in, int f_out, int pid, int argc, char *argv[])
397{
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;
403
404 setup_protocol(f_out,f_in);
405
406 if (am_sender) {
407 extern int cvs_exclude;
408 extern int delete_mode;
409 extern int delete_excluded;
410 if (cvs_exclude)
411 add_cvs_excludes();
412 if (delete_mode && !delete_excluded)
413 send_exclude_list(f_out);
414 flist = send_file_list(f_out,argc,argv);
415 if (verbose > 3)
416 rprintf(FINFO,"file list sent\n");
417
418 set_nonblocking(f_out);
419 if (f_in != f_out)
420 set_nonblocking(f_in);
421
422 send_files(flist,f_out,f_in);
423 if (pid != -1) {
424 if (verbose > 3)
425 rprintf(FINFO,"client_run waiting on %d\n",pid);
426 io_flush();
427 waitpid(pid, &status, 0);
428 }
429 report(-1);
430 exit_cleanup(status);
431 }
432
433 if (argc == 0) list_only = 1;
434
435 send_exclude_list(f_out);
436
437 flist = recv_file_list(f_in);
438 if (!flist || flist->count == 0) {
439 rprintf(FINFO,"client: nothing to do\n");
440 exit_cleanup(0);
441 }
442
443 local_name = get_local_name(flist,argv[0]);
444
445 status2 = do_recv(f_in,f_out,flist,local_name);
446
447 if (pid != -1) {
448 if (verbose > 3)
449 rprintf(FINFO,"client_run2 waiting on %d\n",pid);
450 io_flush();
451 waitpid(pid, &status, 0);
452 }
453
454 return status | status2;
455}
456
457static char *find_colon(char *s)
458{
459 char *p, *p2;
460
461 p = strchr(s,':');
462 if (!p) return NULL;
463
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 */
466 p2 = strchr(s,'/');
467 if (p2 && p2 < p) return NULL;
468
469 return p;
470}
471
472static int start_client(int argc, char *argv[])
473{
474 char *p;
475 char *shell_machine = NULL;
476 char *shell_path = NULL;
477 char *shell_user = NULL;
478 int pid, ret;
479 int f_in,f_out;
480 extern int local_server;
481 extern int am_sender;
482 extern char *shell_cmd;
483 extern int rsync_port;
484
485 if (strncasecmp(URL_PREFIX, argv[0], strlen(URL_PREFIX)) == 0) {
486 char *host, *path;
487
488 host = argv[0] + strlen(URL_PREFIX);
489 p = strchr(host,'/');
490 if (p) {
491 *p = 0;
492 path = p+1;
493 } else {
494 path="";
495 }
496 p = strchr(host,':');
497 if (p) {
498 rsync_port = atoi(p+1);
499 *p = 0;
500 }
501 return start_socket_client(host, path, argc-1, argv+1);
502 }
503
504 p = find_colon(argv[0]);
505
506 if (p) {
507 if (p[1] == ':') {
508 *p = 0;
509 return start_socket_client(argv[0], p+2, argc-1, argv+1);
510 }
511
512 if (argc < 1) {
513 usage(FERROR);
514 exit_cleanup(RERR_SYNTAX);
515 }
516
517 am_sender = 0;
518 *p = 0;
519 shell_machine = argv[0];
520 shell_path = p+1;
521 argc--;
522 argv++;
523 } else {
524 am_sender = 1;
525
526 p = find_colon(argv[argc-1]);
527 if (!p) {
528 local_server = 1;
529 } else if (p[1] == ':') {
530 *p = 0;
531 return start_socket_client(argv[argc-1], p+2, argc-1, argv);
532 }
533
534 if (argc < 2) {
535 usage(FERROR);
536 exit_cleanup(RERR_SYNTAX);
537 }
538
539 if (local_server) {
540 shell_machine = NULL;
541 shell_path = argv[argc-1];
542 } else {
543 *p = 0;
544 shell_machine = argv[argc-1];
545 shell_path = p+1;
546 }
547 argc--;
548 }
549
550 if (shell_machine) {
551 p = strchr(shell_machine,'@');
552 if (p) {
553 *p = 0;
554 shell_user = shell_machine;
555 shell_machine = p+1;
556 }
557 }
558
559 if (verbose > 3) {
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:"");
565 }
566
567 if (!am_sender && argc > 1) {
568 usage(FERROR);
569 exit_cleanup(RERR_SYNTAX);
570 }
571
572 pid = do_cmd(shell_cmd,shell_machine,shell_user,shell_path,&f_in,&f_out);
573
574 ret = client_run(f_in, f_out, pid, argc, argv);
575
576 fflush(stdout);
577 fflush(stderr);
578
579 return ret;
580}
581
582
583static RETSIGTYPE sigusr1_handler(int val) {
584 exit_cleanup(RERR_SIGNAL);
585}
586
587int main(int argc,char *argv[])
588{
589 extern int am_root;
590 extern int orig_umask;
591 extern int dry_run;
592 extern int am_daemon;
593 extern int am_server;
594
595 signal(SIGUSR1, sigusr1_handler);
596
597 starttime = time(NULL);
598 am_root = (getuid() == 0);
599
600 memset(&stats, 0, sizeof(stats));
601
602 if (argc < 2) {
603 usage(FERROR);
604 exit_cleanup(RERR_SYNTAX);
605 }
606
607 /* we set a 0 umask so that correct file permissions can be
608 carried across */
609 orig_umask = (int)umask(0);
610
611 if (!parse_arguments(argc, argv, 1)) {
612 exit_cleanup(RERR_SYNTAX);
613 }
614
615 argc -= optind;
616 argv += optind;
617 optind = 0;
618
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);
624
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. */
629 push_dir(NULL,0);
630
631 if (am_daemon) {
632 return daemon_main();
633 }
634
635 if (argc < 1) {
636 usage(FERROR);
637 exit_cleanup(RERR_SYNTAX);
638 }
639
640 if (dry_run)
641 verbose = MAX(verbose,1);
642
643#ifndef SUPPORT_LINKS
644 if (!am_server && preserve_links) {
645 rprintf(FERROR,"ERROR: symbolic links not supported\n");
646 exit_cleanup(RERR_UNSUPPORTED);
647 }
648#endif
649
650 if (am_server) {
651 start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
652 }
653
654 return start_client(argc, argv);
655}
656