Allow --stats to work without -v.
[rsync/rsync.git] / main.c
CommitLineData
c627d613
AT
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
f0fca04e 22time_t starttime = 0;
a800434a
AT
23
24struct stats stats;
5d6bcd44 25
34ccb63e 26extern int csum_length;
c627d613 27
7a6421fa 28extern int verbose;
c627d613
AT
29
30static void report(int f)
31{
7a6421fa
AT
32 time_t t = time(NULL);
33 extern int am_server;
34 extern int am_sender;
248fbb8c 35 extern int am_daemon;
a800434a 36 extern int do_stats;
7a6421fa 37
248fbb8c 38 if (am_daemon) {
a9766ef1 39 log_exit(0, __FILE__, __LINE__);
7b372642 40 if (f == -1 || !am_sender) return;
248fbb8c
AT
41 }
42
e19452a9
DD
43 if (am_server) {
44 if (verbose && am_sender) {
45 write_longint(f,stats.total_read);
46 write_longint(f,stats.total_written);
47 write_longint(f,stats.total_size);
48 }
7a6421fa
AT
49 return;
50 }
e19452a9
DD
51
52 /* this is the client */
53
54 if (!am_sender && verbose) {
55 /* note that if (!verbose && do_stats) then these values will
56 be taken from the receiver side's copy. The total size
57 is identical but the bytes read and written are slightly
58 different. It's done this way to avoid modifying the
59 protocol to support --stats without -v. */
a800434a 60 stats.total_written = read_longint(f);
e19452a9 61 stats.total_read = read_longint(f);
a800434a 62 stats.total_size = read_longint(f);
e19452a9
DD
63
64 /* when the total_read was set above just now it would not
65 have included the last two longints, but the last
66 read_longint would have compensated for one of them.
67 Compensate for the other one too by adding 8. */
68 stats.total_read += sizeof(int64);
a800434a
AT
69 }
70
71 if (do_stats) {
1f658d42
AT
72 rprintf(FINFO,"\nNumber of files: %d\n", stats.num_files);
73 rprintf(FINFO,"Number of files transferred: %d\n",
a800434a 74 stats.num_transferred_files);
1f658d42 75 rprintf(FINFO,"Total file size: %.0f bytes\n",
a800434a 76 (double)stats.total_size);
1f658d42 77 rprintf(FINFO,"Total transferred file size: %.0f bytes\n",
a800434a 78 (double)stats.total_transferred_size);
1f658d42 79 rprintf(FINFO,"Literal data: %.0f bytes\n",
a800434a 80 (double)stats.literal_data);
1f658d42 81 rprintf(FINFO,"Matched data: %.0f bytes\n",
a800434a 82 (double)stats.matched_data);
1f658d42
AT
83 rprintf(FINFO,"File list size: %d\n", stats.flist_size);
84 rprintf(FINFO,"Total bytes written: %.0f\n",
a800434a 85 (double)stats.total_written);
1f658d42 86 rprintf(FINFO,"Total bytes read: %.0f\n\n",
a800434a 87 (double)stats.total_read);
7a6421fa
AT
88 }
89
e19452a9
DD
90 if (verbose || do_stats) {
91 rprintf(FINFO,"wrote %.0f bytes read %.0f bytes %.2f bytes/sec\n",
92 (double)stats.total_written,
93 (double)stats.total_read,
94 (stats.total_written+stats.total_read)/(0.5 + (t-starttime)));
95 rprintf(FINFO,"total size is %.0f speedup is %.2f\n",
96 (double)stats.total_size,
97 (1.0*stats.total_size)/(stats.total_written+stats.total_read));
98 }
fc8a6b97
AT
99
100 fflush(stdout);
101 fflush(stderr);
c627d613
AT
102}
103
104
e3cd198f 105static int do_cmd(char *cmd,char *machine,char *user,char *path,int *f_in,int *f_out)
c627d613 106{
366345fe
AT
107 char *args[100];
108 int i,argc=0, ret;
109 char *tok,*dir=NULL;
7a6421fa
AT
110 extern int local_server;
111 extern char *rsync_path;
366345fe
AT
112
113 if (!local_server) {
114 if (!cmd)
115 cmd = getenv(RSYNC_RSH_ENV);
116 if (!cmd)
117 cmd = RSYNC_RSH;
118 cmd = strdup(cmd);
119 if (!cmd)
120 goto oom;
121
122 for (tok=strtok(cmd," ");tok;tok=strtok(NULL," ")) {
123 args[argc++] = tok;
124 }
c627d613 125
7b8356d0 126#if HAVE_REMSH
366345fe
AT
127 /* remsh (on HPUX) takes the arguments the other way around */
128 args[argc++] = machine;
129 if (user) {
130 args[argc++] = "-l";
131 args[argc++] = user;
132 }
7b8356d0 133#else
366345fe
AT
134 if (user) {
135 args[argc++] = "-l";
136 args[argc++] = user;
137 }
138 args[argc++] = machine;
7b8356d0 139#endif
c627d613 140
366345fe 141 args[argc++] = rsync_path;
c627d613 142
366345fe
AT
143 server_options(args,&argc);
144 }
c627d613 145
366345fe 146 args[argc++] = ".";
76076c4b 147
366345fe
AT
148 if (path && *path)
149 args[argc++] = path;
c627d613 150
366345fe 151 args[argc] = NULL;
c627d613 152
366345fe 153 if (verbose > 3) {
9486289c 154 rprintf(FINFO,"cmd=");
366345fe 155 for (i=0;i<argc;i++)
9486289c
AT
156 rprintf(FINFO,"%s ",args[i]);
157 rprintf(FINFO,"\n");
366345fe
AT
158 }
159
160 if (local_server) {
161 ret = local_child(argc, args, f_in, f_out);
162 } else {
163 ret = piped_child(args,f_in,f_out);
164 }
c627d613 165
366345fe 166 if (dir) free(dir);
82306bf6 167
366345fe 168 return ret;
c627d613
AT
169
170oom:
366345fe
AT
171 out_of_memory("do_cmd");
172 return 0; /* not reached */
c627d613
AT
173}
174
175
176
177
178static char *get_local_name(struct file_list *flist,char *name)
179{
7a6421fa
AT
180 STRUCT_STAT st;
181 extern int orig_umask;
c627d613 182
c95da96a
AT
183 if (verbose > 2)
184 rprintf(FINFO,"get_local_name count=%d %s\n",
1f0610ef
DD
185 flist->count, NS(name));
186
187 if (!name)
188 return NULL;
c95da96a 189
1ff5450d
AT
190 if (do_stat(name,&st) == 0) {
191 if (S_ISDIR(st.st_mode)) {
5243c216
AT
192 if (!push_dir(name, 0)) {
193 rprintf(FERROR,"push_dir %s : %s (1)\n",
1ff5450d 194 name,strerror(errno));
65417579 195 exit_cleanup(RERR_FILESELECT);
1ff5450d
AT
196 }
197 return NULL;
198 }
199 if (flist->count > 1) {
200 rprintf(FERROR,"ERROR: destination must be a directory when copying more than 1 file\n");
65417579 201 exit_cleanup(RERR_FILESELECT);
1ff5450d
AT
202 }
203 return name;
204 }
205
206 if (flist->count == 1)
207 return name;
208
1ff5450d
AT
209 if (do_mkdir(name,0777 & ~orig_umask) != 0) {
210 rprintf(FERROR,"mkdir %s : %s (1)\n",name,strerror(errno));
65417579 211 exit_cleanup(RERR_FILEIO);
1ff5450d 212 } else {
b536f47e
AT
213 if (verbose > 0)
214 rprintf(FINFO,"created directory %s\n",name);
1ff5450d
AT
215 }
216
5243c216
AT
217 if (!push_dir(name, 0)) {
218 rprintf(FERROR,"push_dir %s : %s (2)\n",
219 name,strerror(errno));
65417579 220 exit_cleanup(RERR_FILESELECT);
1ff5450d
AT
221 }
222
223 return NULL;
c627d613
AT
224}
225
226
227
228
9486289c 229static void do_server_sender(int f_in, int f_out, int argc,char *argv[])
c627d613 230{
7a6421fa
AT
231 int i;
232 struct file_list *flist;
233 char *dir = argv[0];
234 extern int relative_paths;
7a6421fa 235 extern int recurse;
c627d613 236
7a6421fa
AT
237 if (verbose > 2)
238 rprintf(FINFO,"server_sender starting pid=%d\n",(int)getpid());
c627d613 239
5243c216
AT
240 if (!relative_paths && !push_dir(dir, 0)) {
241 rprintf(FERROR,"push_dir %s: %s (3)\n",dir,strerror(errno));
65417579 242 exit_cleanup(RERR_FILESELECT);
7a6421fa
AT
243 }
244 argc--;
245 argv++;
c627d613 246
7a6421fa
AT
247 if (strcmp(dir,".")) {
248 int l = strlen(dir);
249 if (strcmp(dir,"/") == 0)
250 l = 0;
251 for (i=0;i<argc;i++)
252 argv[i] += l+1;
253 }
c627d613 254
7a6421fa
AT
255 if (argc == 0 && recurse) {
256 argc=1;
257 argv--;
258 argv[0] = ".";
259 }
260
3eb38818
AT
261 set_nonblocking(f_out);
262 if (f_in != f_out)
263 set_nonblocking(f_in);
264
7a6421fa 265 flist = send_file_list(f_out,argc,argv);
8d9dc9f9
AT
266 if (!flist || flist->count == 0) {
267 exit_cleanup(0);
268 }
269
7a6421fa
AT
270 send_files(flist,f_out,f_in);
271 report(f_out);
8d9dc9f9 272 io_flush();
7a6421fa 273 exit_cleanup(0);
c627d613
AT
274}
275
276
dc5ddbcc
AT
277static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
278{
d186eb1a
AT
279 int pid;
280 int status=0;
281 int recv_pipe[2];
282 extern int preserve_hard_links;
dc5ddbcc 283
d186eb1a
AT
284 if (preserve_hard_links)
285 init_hard_links(flist);
dc5ddbcc 286
d186eb1a
AT
287 if (pipe(recv_pipe) < 0) {
288 rprintf(FERROR,"pipe failed in do_recv\n");
65417579 289 exit_cleanup(RERR_SOCKETIO);
d186eb1a 290 }
c6e7fcb4 291
8d9dc9f9 292 io_flush();
c6e7fcb4 293
d186eb1a 294 if ((pid=do_fork()) == 0) {
e08c9610
AT
295 close(recv_pipe[0]);
296 if (f_in != f_out) close(f_out);
297
e1b3d5c4 298 set_nonblocking(f_in);
3eb38818 299 set_nonblocking(recv_pipe[1]);
e1b3d5c4 300
e08c9610 301 recv_files(f_in,flist,local_name,recv_pipe[1]);
ba5e128d 302 report(f_in);
e08c9610 303
8d9dc9f9
AT
304 io_flush();
305 _exit(0);
d186eb1a 306 }
dc5ddbcc 307
e08c9610
AT
308 close(recv_pipe[1]);
309 io_close_input(f_in);
310 if (f_in != f_out) close(f_in);
e1b3d5c4
AT
311
312 set_nonblocking(f_out);
3eb38818 313 set_nonblocking(recv_pipe[0]);
e1b3d5c4 314
b3e10ed7
AT
315 io_start_buffering(f_out);
316
e08c9610 317 generate_files(f_out,flist,local_name,recv_pipe[0]);
8d9dc9f9
AT
318
319 io_flush();
d186eb1a 320 waitpid(pid, &status, 0);
d186eb1a 321 return status;
dc5ddbcc
AT
322}
323
c627d613 324
9486289c 325static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
c627d613 326{
7a6421fa
AT
327 int status;
328 struct file_list *flist;
329 char *local_name=NULL;
330 char *dir = NULL;
331 extern int delete_mode;
332 extern int am_daemon;
f0fca04e 333
7a6421fa
AT
334 if (verbose > 2)
335 rprintf(FINFO,"server_recv(%d) starting pid=%d\n",argc,(int)getpid());
336
7a6421fa
AT
337 if (argc > 0) {
338 dir = argv[0];
339 argc--;
340 argv++;
5243c216
AT
341 if (!am_daemon && !push_dir(dir, 0)) {
342 rprintf(FERROR,"push_dir %s : %s (4)\n",
7a6421fa 343 dir,strerror(errno));
65417579 344 exit_cleanup(RERR_FILESELECT);
7a6421fa
AT
345 }
346 }
c627d613 347
7a6421fa
AT
348 if (delete_mode)
349 recv_exclude_list(f_in);
c627d613 350
7a6421fa
AT
351 flist = recv_file_list(f_in);
352 if (!flist || flist->count == 0) {
8d9dc9f9 353 rprintf(FERROR,"server_recv: nothing to do\n");
65417579 354 exit_cleanup(RERR_FILESELECT);
7a6421fa
AT
355 }
356
357 if (argc > 0) {
358 if (strcmp(dir,".")) {
359 argv[0] += strlen(dir);
360 if (argv[0][0] == '/') argv[0]++;
361 }
362 local_name = get_local_name(flist,argv[0]);
363 }
c627d613 364
7a6421fa
AT
365 status = do_recv(f_in,f_out,flist,local_name);
366 exit_cleanup(status);
c627d613
AT
367}
368
369
9486289c 370void start_server(int f_in, int f_out, int argc, char *argv[])
366345fe 371{
7a6421fa
AT
372 extern int cvs_exclude;
373 extern int am_sender;
374
3eb38818
AT
375 set_nonblocking(f_out);
376 if (f_in != f_out)
377 set_nonblocking(f_in);
378
7a6421fa 379 setup_protocol(f_out, f_in);
3eb38818 380
7a6421fa
AT
381 if (am_sender) {
382 recv_exclude_list(f_in);
383 if (cvs_exclude)
384 add_cvs_excludes();
385 do_server_sender(f_in, f_out, argc, argv);
386 } else {
387 do_server_recv(f_in, f_out, argc, argv);
388 }
389 exit_cleanup(0);
366345fe
AT
390}
391
3591c066 392int client_run(int f_in, int f_out, int pid, int argc, char *argv[])
9486289c
AT
393{
394 struct file_list *flist;
395 int status = 0, status2 = 0;
396 char *local_name = NULL;
7a6421fa 397 extern int am_sender;
f7632fc6 398 extern int list_only;
9486289c
AT
399
400 setup_protocol(f_out,f_in);
401
402 if (am_sender) {
7a6421fa
AT
403 extern int cvs_exclude;
404 extern int delete_mode;
9486289c
AT
405 if (cvs_exclude)
406 add_cvs_excludes();
407 if (delete_mode)
408 send_exclude_list(f_out);
409 flist = send_file_list(f_out,argc,argv);
410 if (verbose > 3)
411 rprintf(FINFO,"file list sent\n");
e1b3d5c4
AT
412
413 set_nonblocking(f_out);
414 if (f_in != f_out)
415 set_nonblocking(f_in);
416
9486289c
AT
417 send_files(flist,f_out,f_in);
418 if (pid != -1) {
419 if (verbose > 3)
8d9dc9f9
AT
420 rprintf(FINFO,"client_run waiting on %d\n",pid);
421 io_flush();
9486289c
AT
422 waitpid(pid, &status, 0);
423 }
424 report(-1);
425 exit_cleanup(status);
426 }
f7632fc6
AT
427
428 if (argc == 0) list_only = 1;
9486289c
AT
429
430 send_exclude_list(f_out);
431
432 flist = recv_file_list(f_in);
433 if (!flist || flist->count == 0) {
8d9dc9f9 434 rprintf(FINFO,"client: nothing to do\n");
9486289c
AT
435 exit_cleanup(0);
436 }
437
438 local_name = get_local_name(flist,argv[0]);
439
440 status2 = do_recv(f_in,f_out,flist,local_name);
441
9486289c 442 if (pid != -1) {
8d9dc9f9
AT
443 if (verbose > 3)
444 rprintf(FINFO,"client_run2 waiting on %d\n",pid);
445 io_flush();
9486289c
AT
446 waitpid(pid, &status, 0);
447 }
448
449 return status | status2;
450}
451
ca6c93f8
AT
452static char *find_colon(char *s)
453{
454 char *p, *p2;
455
456 p = strchr(s,':');
457 if (!p) return NULL;
458
459 /* now check to see if there is a / in the string before the : - if there is then
460 discard the colon on the assumption that the : is part of a filename */
461 p2 = strchr(s,'/');
462 if (p2 && p2 < p) return NULL;
463
464 return p;
465}
9486289c 466
fc8a6b97 467static int start_client(int argc, char *argv[])
5d6bcd44
AT
468{
469 char *p;
470 char *shell_machine = NULL;
471 char *shell_path = NULL;
472 char *shell_user = NULL;
fc8a6b97 473 int pid, ret;
5d6bcd44 474 int f_in,f_out;
7a6421fa
AT
475 extern int local_server;
476 extern int am_sender;
477 extern char *shell_cmd;
2acf81eb 478 extern int rsync_port;
5d6bcd44 479
f7632fc6
AT
480 if (strncasecmp(URL_PREFIX, argv[0], strlen(URL_PREFIX)) == 0) {
481 char *host, *path;
482
483 host = argv[0] + strlen(URL_PREFIX);
484 p = strchr(host,'/');
485 if (p) {
486 *p = 0;
487 path = p+1;
488 } else {
489 path="";
490 }
2acf81eb
DD
491 p = strchr(host,':');
492 if (p) {
493 rsync_port = atoi(p+1);
494 *p = 0;
495 }
f7632fc6
AT
496 return start_socket_client(host, path, argc-1, argv+1);
497 }
498
ca6c93f8 499 p = find_colon(argv[0]);
5d6bcd44
AT
500
501 if (p) {
9486289c
AT
502 if (p[1] == ':') {
503 *p = 0;
504 return start_socket_client(argv[0], p+2, argc-1, argv+1);
505 }
3591c066 506
f7632fc6 507 if (argc < 1) {
3591c066 508 usage(FERROR);
65417579 509 exit_cleanup(RERR_SYNTAX);
3591c066
AT
510 }
511
5d6bcd44
AT
512 am_sender = 0;
513 *p = 0;
514 shell_machine = argv[0];
515 shell_path = p+1;
516 argc--;
517 argv++;
518 } else {
519 am_sender = 1;
9486289c 520
ca6c93f8 521 p = find_colon(argv[argc-1]);
5d6bcd44
AT
522 if (!p) {
523 local_server = 1;
9486289c
AT
524 } else if (p[1] == ':') {
525 *p = 0;
526 return start_socket_client(argv[argc-1], p+2, argc-1, argv);
5d6bcd44 527 }
3591c066
AT
528
529 if (argc < 2) {
530 usage(FERROR);
65417579 531 exit_cleanup(RERR_SYNTAX);
3591c066 532 }
9486289c 533
5d6bcd44
AT
534 if (local_server) {
535 shell_machine = NULL;
536 shell_path = argv[argc-1];
537 } else {
538 *p = 0;
539 shell_machine = argv[argc-1];
540 shell_path = p+1;
541 }
542 argc--;
543 }
544
545 if (shell_machine) {
546 p = strchr(shell_machine,'@');
547 if (p) {
548 *p = 0;
549 shell_user = shell_machine;
550 shell_machine = p+1;
551 }
552 }
553
554 if (verbose > 3) {
9486289c 555 rprintf(FINFO,"cmd=%s machine=%s user=%s path=%s\n",
5d6bcd44
AT
556 shell_cmd?shell_cmd:"",
557 shell_machine?shell_machine:"",
558 shell_user?shell_user:"",
559 shell_path?shell_path:"");
560 }
561
f7632fc6 562 if (!am_sender && argc > 1) {
5d6bcd44 563 usage(FERROR);
65417579 564 exit_cleanup(RERR_SYNTAX);
5d6bcd44
AT
565 }
566
567 pid = do_cmd(shell_cmd,shell_machine,shell_user,shell_path,&f_in,&f_out);
568
fc8a6b97
AT
569 ret = client_run(f_in, f_out, pid, argc, argv);
570
571 fflush(stdout);
572 fflush(stderr);
573
574 return ret;
5d6bcd44
AT
575}
576
366345fe 577
6e4fb64e 578static RETSIGTYPE sigusr1_handler(int val) {
65417579 579 exit_cleanup(RERR_SIGNAL);
82306bf6
AT
580}
581
5d6bcd44 582int main(int argc,char *argv[])
7a6421fa
AT
583{
584 extern int am_root;
585 extern int orig_umask;
586 extern int dry_run;
587 extern int am_daemon;
588 extern int am_server;
5d6bcd44 589
7a6421fa 590 signal(SIGUSR1, sigusr1_handler);
5d6bcd44 591
7a6421fa
AT
592 starttime = time(NULL);
593 am_root = (getuid() == 0);
c627d613 594
a800434a
AT
595 memset(&stats, 0, sizeof(stats));
596
df5e03da
AT
597 if (argc < 2) {
598 usage(FERROR);
65417579 599 exit_cleanup(RERR_SYNTAX);
df5e03da
AT
600 }
601
7a6421fa
AT
602 /* we set a 0 umask so that correct file permissions can be
603 carried across */
604 orig_umask = (int)umask(0);
5d6bcd44 605
b86f0cef 606 if (!parse_arguments(argc, argv, 1)) {
65417579 607 exit_cleanup(RERR_SYNTAX);
b11ed3b1 608 }
5d6bcd44 609
7a6421fa
AT
610 argc -= optind;
611 argv += optind;
612 optind = 0;
c627d613 613
7a6421fa
AT
614 signal(SIGCHLD,SIG_IGN);
615 signal(SIGINT,SIGNAL_CAST sig_int);
616 signal(SIGPIPE,SIGNAL_CAST sig_int);
617 signal(SIGHUP,SIGNAL_CAST sig_int);
8638dd48 618 signal(SIGTERM,SIGNAL_CAST sig_int);
6b83141d 619
c226b7c2
DD
620 /* Initialize push_dir here because on some old systems getcwd
621 (implemented by forking "pwd" and reading its output) doesn't
622 work when there are other child processes. Also, on all systems
623 that implement getcwd that way "pwd" can't be found after chroot. */
624 push_dir(NULL,0);
625
7a6421fa
AT
626 if (am_daemon) {
627 return daemon_main();
628 }
f0fca04e 629
08ac228f
AT
630 if (argc < 1) {
631 usage(FERROR);
65417579 632 exit_cleanup(RERR_SYNTAX);
08ac228f
AT
633 }
634
7a6421fa
AT
635 if (dry_run)
636 verbose = MAX(verbose,1);
c627d613 637
cbbe4892 638#ifndef SUPPORT_LINKS
7a6421fa
AT
639 if (!am_server && preserve_links) {
640 rprintf(FERROR,"ERROR: symbolic links not supported\n");
65417579 641 exit_cleanup(RERR_UNSUPPORTED);
7a6421fa 642 }
cbbe4892
AT
643#endif
644
7a6421fa
AT
645 if (am_server) {
646 start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
647 }
c627d613 648
7a6421fa 649 return start_client(argc, argv);
c627d613 650}
82306bf6 651