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