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