Add comments.
[rsync.git] / main.c
blob8e69fad3125bf06978ebee3c3a015a38fa67c2e6
1 /* -*- c-file-style: "linux" -*-
3 Copyright (C) 1996-2001 by Andrew Tridgell
4 Copyright (C) Paul Mackerras 1996
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.
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.
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.
21 #include "rsync.h"
23 time_t starttime = 0;
25 struct stats stats;
27 extern int verbose;
30 /****************************************************************************
31 wait for a process to exit, calling io_flush while waiting
32 ****************************************************************************/
33 void wait_process(pid_t pid, int *status)
35 while (waitpid(pid, status, WNOHANG) == 0) {
36 msleep(20);
37 io_flush();
39 *status = WEXITSTATUS(*status);
42 static void report(int f)
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;
52 if (am_daemon) {
53 log_exit(0, __FILE__, __LINE__);
54 if (f == -1 || !am_sender) return;
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);
68 return;
71 /* this is the client */
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;
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;
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);
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));
117 fflush(stdout);
118 fflush(stderr);
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:
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
133 * and we could use this to give a better explanation if the remote
134 * command is not found.
136 static int do_cmd(char *cmd,char *machine,char *user,char *path,int *f_in,int *f_out)
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;
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;
154 for (tok=strtok(cmd," ");tok;tok=strtok(NULL," ")) {
155 args[argc++] = tok;
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;
165 #else
166 if (user) {
167 args[argc++] = "-l";
168 args[argc++] = user;
170 args[argc++] = machine;
171 #endif
173 args[argc++] = rsync_path;
175 server_options(args,&argc);
178 if (strcmp(cmd, RSYNC_RSH) == 0) blocking_io = 1;
181 args[argc++] = ".";
183 if (path && *path)
184 args[argc++] = path;
186 args[argc] = NULL;
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");
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);
201 if (dir) free(dir);
203 return ret;
205 oom:
206 out_of_memory("do_cmd");
207 return 0; /* not reached */
213 static char *get_local_name(struct file_list *flist,char *name)
215 STRUCT_STAT st;
216 extern int orig_umask;
218 if (verbose > 2)
219 rprintf(FINFO,"get_local_name count=%d %s\n",
220 flist->count, NS(name));
222 if (!name)
223 return NULL;
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);
232 return NULL;
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);
238 return name;
241 if (flist->count <= 1)
242 return name;
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);
252 if (!push_dir(name, 0)) {
253 rprintf(FERROR,"push_dir %s : %s (2)\n",
254 name,strerror(errno));
255 exit_cleanup(RERR_FILESELECT);
258 return NULL;
264 static void do_server_sender(int f_in, int f_out, int argc,char *argv[])
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;
273 if (verbose > 2)
274 rprintf(FINFO,"server_sender starting pid=%d\n",(int)getpid());
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);
280 argc--;
281 argv++;
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;
291 if (argc == 0 && recurse) {
292 argc=1;
293 argv--;
294 argv[0] = ".";
297 flist = send_file_list(f_out,argc,argv);
298 if (!flist || flist->count == 0) {
299 exit_cleanup(0);
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);
309 io_flush();
310 exit_cleanup(0);
314 static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
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;
326 if (preserve_hard_links)
327 init_hard_links(flist);
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);
336 if (fd_pair(recv_pipe) < 0) {
337 rprintf(FERROR,"pipe failed in do_recv\n");
338 exit_cleanup(RERR_SOCKETIO);
341 if (fd_pair(error_pipe) < 0) {
342 rprintf(FERROR,"error pipe failed in do_recv\n");
343 exit_cleanup(RERR_SOCKETIO);
346 io_flush();
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);
353 /* we can't let two processes write to the socket at one time */
354 io_multiplexing_close();
356 /* set place to send errors */
357 set_error_fd(error_pipe[1]);
359 recv_files(f_in,flist,local_name,recv_pipe[1]);
360 io_flush();
361 report(f_in);
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);
372 close(recv_pipe[1]);
373 close(error_pipe[1]);
374 if (f_in != f_out) close(f_in);
376 io_start_buffering(f_out);
378 io_set_error_fd(error_pipe[0]);
380 generate_files(f_out,flist,local_name,recv_pipe[0]);
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);
388 io_flush();
390 kill(pid, SIGUSR2);
391 wait_process(pid, &status);
392 return status;
396 static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
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;
408 if (verbose > 2)
409 rprintf(FINFO,"server_recv(%d) starting pid=%d\n",argc,(int)getpid());
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;
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);
429 if (delete_mode && !delete_excluded)
430 recv_exclude_list(f_in);
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);
438 if (argc > 0) {
439 if (strcmp(dir,".")) {
440 argv[0] += strlen(dir);
441 if (argv[0][0] == '/') argv[0]++;
443 local_name = get_local_name(flist,argv[0]);
446 status = do_recv(f_in,f_out,flist,local_name);
447 exit_cleanup(status);
451 void start_server(int f_in, int f_out, int argc, char *argv[])
453 extern int cvs_exclude;
454 extern int am_sender;
455 extern int remote_version;
457 setup_protocol(f_out, f_in);
459 set_nonblocking(f_in);
460 set_nonblocking(f_out);
462 if (remote_version >= 23)
463 io_start_multiplex_out(f_out);
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);
473 exit_cleanup(0);
478 * This is called once the connection has been negotiated. It is used
479 * for rsyncd, remote-shell, and local connections.
481 int client_run(int f_in, int f_out, int pid, int argc, char *argv[])
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;
489 set_nonblocking(f_in);
490 set_nonblocking(f_out);
492 setup_protocol(f_out,f_in);
494 if (remote_version >= 23)
495 io_start_multiplex_in(f_in);
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");
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);
516 if (remote_version >= 24) {
517 /* final goodbye message */
518 read_int(f_in);
520 report(-1);
521 exit_cleanup(status);
524 if (argc == 0) {
525 extern int list_only;
526 list_only = 1;
529 send_exclude_list(f_out);
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);
539 local_name = get_local_name(flist,argv[0]);
541 status2 = do_recv(f_in,f_out,flist,local_name);
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);
550 return status | status2;
553 static char *find_colon(char *s)
555 char *p, *p2;
557 p = strchr(s,':');
558 if (!p) return NULL;
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;
565 return p;
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.
574 static int start_client(int argc, char *argv[])
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]);
588 if (strncasecmp(URL_PREFIX, argv0, strlen(URL_PREFIX)) == 0) {
589 char *host, *path;
591 host = argv0 + strlen(URL_PREFIX);
592 p = strchr(host,'/');
593 if (p) {
594 *p = 0;
595 path = p+1;
596 } else {
597 path="";
599 p = strchr(host,':');
600 if (p) {
601 rsync_port = atoi(p+1);
602 *p = 0;
604 return start_socket_client(host, path, argc-1, argv+1);
607 p = find_colon(argv0);
609 if (p) {
610 if (p[1] == ':') {
611 *p = 0;
612 return start_socket_client(argv0, p+2, argc-1, argv+1);
615 if (argc < 1) {
616 usage(FERROR);
617 exit_cleanup(RERR_SYNTAX);
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;
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);
637 if (argc < 2) {
638 usage(FERROR);
639 exit_cleanup(RERR_SYNTAX);
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;
650 argc--;
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;
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:"");
670 if (!am_sender && argc > 1) {
671 usage(FERROR);
672 exit_cleanup(RERR_SYNTAX);
675 if (argc == 0 && !am_sender) {
676 extern int list_only;
677 list_only = 1;
680 pid = do_cmd(shell_cmd,shell_machine,shell_user,shell_path,&f_in,&f_out);
682 ret = client_run(f_in, f_out, pid, argc, argv);
684 fflush(stdout);
685 fflush(stderr);
687 return ret;
691 static RETSIGTYPE sigusr1_handler(int val) {
692 exit_cleanup(RERR_SIGNAL);
695 static RETSIGTYPE sigusr2_handler(int val) {
696 _exit(0);
699 int main(int argc,char *argv[])
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;
707 signal(SIGUSR1, sigusr1_handler);
708 signal(SIGUSR2, sigusr2_handler);
710 starttime = time(NULL);
711 am_root = (getuid() == 0);
713 memset(&stats, 0, sizeof(stats));
715 if (argc < 2) {
716 usage(FERROR);
717 exit_cleanup(RERR_SYNTAX);
720 /* we set a 0 umask so that correct file permissions can be
721 carried across */
722 orig_umask = (int)umask(0);
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);
731 argc -= optind;
732 argv += optind;
733 optind = 0;
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);
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);
747 if (am_daemon) {
748 return daemon_main();
751 if (argc < 1) {
752 usage(FERROR);
753 exit_cleanup(RERR_SYNTAX);
756 if (dry_run)
757 verbose = MAX(verbose,1);
759 #ifndef SUPPORT_LINKS
760 if (!am_server && preserve_links) {
761 rprintf(FERROR,"ERROR: symbolic links not supported\n");
762 exit_cleanup(RERR_UNSUPPORTED);
764 #endif
766 if (am_server) {
767 set_nonblocking(STDIN_FILENO);
768 set_nonblocking(STDOUT_FILENO);
769 start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
772 return start_client(argc, argv);