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