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