fix bug in handling of :
[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 msleep(20);
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 sleep for a short time as on
353 some OSes a signal won't interrupt a sleep! */
354 while (1) msleep(20);
355 }
356
357 close(recv_pipe[1]);
358 close(error_pipe[1]);
359 if (f_in != f_out) close(f_in);
360
361 io_start_buffering(f_out);
362
363 io_set_error_fd(error_pipe[0]);
364
365 generate_files(f_out,flist,local_name,recv_pipe[0]);
366
367 read_int(recv_pipe[0]);
368 close(recv_pipe[0]);
369 if (remote_version >= 24) {
370 /* send a final goodbye message */
371 write_int(f_out, -1);
372 }
373 io_flush();
374
375 kill(pid, SIGUSR2);
376 wait_process(pid, &status);
377 return status;
378}
379
380
381static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
382{
383 int status;
384 struct file_list *flist;
385 char *local_name=NULL;
386 char *dir = NULL;
387 extern int delete_mode;
388 extern int delete_excluded;
389 extern int am_daemon;
390 extern int module_id;
391 extern int am_sender;
392
393 if (verbose > 2)
394 rprintf(FINFO,"server_recv(%d) starting pid=%d\n",argc,(int)getpid());
395
396 if (am_daemon && lp_read_only(module_id) && !am_sender) {
397 rprintf(FERROR,"ERROR: module is read only\n");
398 exit_cleanup(RERR_SYNTAX);
399 return;
400 }
401
402
403 if (argc > 0) {
404 dir = argv[0];
405 argc--;
406 argv++;
407 if (!am_daemon && !push_dir(dir, 0)) {
408 rprintf(FERROR,"push_dir %s : %s (4)\n",
409 dir,strerror(errno));
410 exit_cleanup(RERR_FILESELECT);
411 }
412 }
413
414 if (delete_mode && !delete_excluded)
415 recv_exclude_list(f_in);
416
417 flist = recv_file_list(f_in);
418 if (!flist) {
419 rprintf(FERROR,"server_recv: recv_file_list error\n");
420 exit_cleanup(RERR_FILESELECT);
421 }
422
423 if (argc > 0) {
424 if (strcmp(dir,".")) {
425 argv[0] += strlen(dir);
426 if (argv[0][0] == '/') argv[0]++;
427 }
428 local_name = get_local_name(flist,argv[0]);
429 }
430
431 status = do_recv(f_in,f_out,flist,local_name);
432 exit_cleanup(status);
433}
434
435
436void start_server(int f_in, int f_out, int argc, char *argv[])
437{
438 extern int cvs_exclude;
439 extern int am_sender;
440 extern int remote_version;
441
442 setup_protocol(f_out, f_in);
443
444 set_nonblocking(f_in);
445 set_nonblocking(f_out);
446
447 if (remote_version >= 23)
448 io_start_multiplex_out(f_out);
449
450 if (am_sender) {
451 recv_exclude_list(f_in);
452 if (cvs_exclude)
453 add_cvs_excludes();
454 do_server_sender(f_in, f_out, argc, argv);
455 } else {
456 do_server_recv(f_in, f_out, argc, argv);
457 }
458 exit_cleanup(0);
459}
460
461int client_run(int f_in, int f_out, int pid, int argc, char *argv[])
462{
463 struct file_list *flist;
464 int status = 0, status2 = 0;
465 char *local_name = NULL;
466 extern int am_sender;
467 extern int remote_version;
468
469 set_nonblocking(f_in);
470 set_nonblocking(f_out);
471
472 setup_protocol(f_out,f_in);
473
474 if (remote_version >= 23)
475 io_start_multiplex_in(f_in);
476
477 if (am_sender) {
478 extern int cvs_exclude;
479 extern int delete_mode;
480 extern int delete_excluded;
481 if (cvs_exclude)
482 add_cvs_excludes();
483 if (delete_mode && !delete_excluded)
484 send_exclude_list(f_out);
485 flist = send_file_list(f_out,argc,argv);
486 if (verbose > 3)
487 rprintf(FINFO,"file list sent\n");
488
489 send_files(flist,f_out,f_in);
490 if (pid != -1) {
491 if (verbose > 3)
492 rprintf(FINFO,"client_run waiting on %d\n",pid);
493 io_flush();
494 wait_process(pid, &status);
495 }
496 if (remote_version >= 24) {
497 /* final goodbye message */
498 read_int(f_in);
499 }
500 report(-1);
501 exit_cleanup(status);
502 }
503
504 if (argc == 0) {
505 extern int list_only;
506 list_only = 1;
507 }
508
509 send_exclude_list(f_out);
510
511 flist = recv_file_list(f_in);
512 if (!flist || flist->count == 0) {
513 rprintf(FINFO, "client: nothing to do: "
514 "perhaps you need to specify some filenames or "
515 "the --recursive option?\n");
516 exit_cleanup(0);
517 }
518
519 local_name = get_local_name(flist,argv[0]);
520
521 status2 = do_recv(f_in,f_out,flist,local_name);
522
523 if (pid != -1) {
524 if (verbose > 3)
525 rprintf(FINFO,"client_run2 waiting on %d\n",pid);
526 io_flush();
527 wait_process(pid, &status);
528 }
529
530 return status | status2;
531}
532
533static char *find_colon(char *s)
534{
535 char *p, *p2;
536
537 p = strchr(s,':');
538 if (!p) return NULL;
539
540 /* now check to see if there is a / in the string before the : - if there is then
541 discard the colon on the assumption that the : is part of a filename */
542 p2 = strchr(s,'/');
543 if (p2 && p2 < p) return NULL;
544
545 return p;
546}
547
548static int start_client(int argc, char *argv[])
549{
550 char *p;
551 char *shell_machine = NULL;
552 char *shell_path = NULL;
553 char *shell_user = NULL;
554 int pid, ret;
555 int f_in,f_out;
556 extern int local_server;
557 extern int am_sender;
558 extern char *shell_cmd;
559 extern int rsync_port;
560 char *argv0 = strdup(argv[0]);
561
562 if (strncasecmp(URL_PREFIX, argv0, strlen(URL_PREFIX)) == 0) {
563 char *host, *path;
564
565 host = argv0 + strlen(URL_PREFIX);
566 p = strchr(host,'/');
567 if (p) {
568 *p = 0;
569 path = p+1;
570 } else {
571 path="";
572 }
573 p = strchr(host,':');
574 if (p) {
575 rsync_port = atoi(p+1);
576 *p = 0;
577 }
578 return start_socket_client(host, path, argc-1, argv+1);
579 }
580
581 p = find_colon(argv0);
582
583 if (p) {
584 if (p[1] == ':') {
585 *p = 0;
586 return start_socket_client(argv0, p+2, argc-1, argv+1);
587 }
588
589 if (argc < 1) {
590 usage(FERROR);
591 exit_cleanup(RERR_SYNTAX);
592 }
593
594 am_sender = 0;
595 *p = 0;
596 shell_machine = argv0;
597 shell_path = p+1;
598 argc--;
599 argv++;
600 } else {
601 am_sender = 1;
602
603 p = find_colon(argv[argc-1]);
604 if (!p) {
605 local_server = 1;
606 } else if (p[1] == ':') {
607 *p = 0;
608 return start_socket_client(argv[argc-1], p+2, argc-1, argv);
609 }
610
611 if (argc < 2) {
612 usage(FERROR);
613 exit_cleanup(RERR_SYNTAX);
614 }
615
616 if (local_server) {
617 shell_machine = NULL;
618 shell_path = argv[argc-1];
619 } else {
620 *p = 0;
621 shell_machine = argv[argc-1];
622 shell_path = p+1;
623 }
624 argc--;
625 }
626
627 if (shell_machine) {
628 p = strchr(shell_machine,'@');
629 if (p) {
630 *p = 0;
631 shell_user = shell_machine;
632 shell_machine = p+1;
633 }
634 }
635
636 if (verbose > 3) {
637 rprintf(FINFO,"cmd=%s machine=%s user=%s path=%s\n",
638 shell_cmd?shell_cmd:"",
639 shell_machine?shell_machine:"",
640 shell_user?shell_user:"",
641 shell_path?shell_path:"");
642 }
643
644 if (!am_sender && argc > 1) {
645 usage(FERROR);
646 exit_cleanup(RERR_SYNTAX);
647 }
648
649 if (argc == 0 && !am_sender) {
650 extern int list_only;
651 list_only = 1;
652 }
653
654 pid = do_cmd(shell_cmd,shell_machine,shell_user,shell_path,&f_in,&f_out);
655
656 ret = client_run(f_in, f_out, pid, argc, argv);
657
658 fflush(stdout);
659 fflush(stderr);
660
661 return ret;
662}
663
664
665static RETSIGTYPE sigusr1_handler(int val) {
666 exit_cleanup(RERR_SIGNAL);
667}
668
669static RETSIGTYPE sigusr2_handler(int val) {
670 _exit(0);
671}
672
673int main(int argc,char *argv[])
674{
675 extern int am_root;
676 extern int orig_umask;
677 extern int dry_run;
678 extern int am_daemon;
679 extern int am_server;
680
681 signal(SIGUSR1, sigusr1_handler);
682 signal(SIGUSR2, sigusr2_handler);
683
684 starttime = time(NULL);
685 am_root = (getuid() == 0);
686
687 memset(&stats, 0, sizeof(stats));
688
689 if (argc < 2) {
690 usage(FERROR);
691 exit_cleanup(RERR_SYNTAX);
692 }
693
694 /* we set a 0 umask so that correct file permissions can be
695 carried across */
696 orig_umask = (int)umask(0);
697
698 if (!parse_arguments(argc, argv, 1)) {
699 exit_cleanup(RERR_SYNTAX);
700 }
701
702 argc -= optind;
703 argv += optind;
704 optind = 0;
705
706 signal(SIGCHLD,SIG_IGN);
707 signal(SIGINT,SIGNAL_CAST sig_int);
708 signal(SIGPIPE,SIGNAL_CAST sig_int);
709 signal(SIGHUP,SIGNAL_CAST sig_int);
710 signal(SIGTERM,SIGNAL_CAST sig_int);
711
712 /* Initialize push_dir here because on some old systems getcwd
713 (implemented by forking "pwd" and reading its output) doesn't
714 work when there are other child processes. Also, on all systems
715 that implement getcwd that way "pwd" can't be found after chroot. */
716 push_dir(NULL,0);
717
718 if (am_daemon) {
719 return daemon_main();
720 }
721
722 if (argc < 1) {
723 usage(FERROR);
724 exit_cleanup(RERR_SYNTAX);
725 }
726
727 if (dry_run)
728 verbose = MAX(verbose,1);
729
730#ifndef SUPPORT_LINKS
731 if (!am_server && preserve_links) {
732 rprintf(FERROR,"ERROR: symbolic links not supported\n");
733 exit_cleanup(RERR_UNSUPPORTED);
734 }
735#endif
736
737 if (am_server) {
738 set_nonblocking(STDIN_FILENO);
739 set_nonblocking(STDOUT_FILENO);
740 start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
741 }
742
743 return start_client(argc, argv);
744}
745