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