Two more instances of socklen_t.
[rsync.git] / main.c
blobbc51571fb5a510c180afb9c3d1dc332fa285f714
1 /* -*- c-file-style: "linux" -*-
3 Copyright (C) 1996-2001 by Andrew Tridgell <tridge@samba.org>
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();
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);
48 static void report(int f)
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;
58 if (am_daemon) {
59 log_exit(0, __FILE__, __LINE__);
60 if (f == -1 || !am_sender) return;
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);
74 return;
77 /* this is the client */
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;
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;
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);
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));
123 fflush(stdout);
124 fflush(stderr);
128 /* Start the remote shell. cmd may be NULL to use the default. */
129 static pid_t do_cmd(char *cmd,char *machine,char *user,char *path,int *f_in,int *f_out)
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;
139 if (!local_server) {
140 if (!cmd)
141 cmd = getenv(RSYNC_RSH_ENV);
142 if (!cmd)
143 cmd = RSYNC_RSH;
144 cmd = strdup(cmd);
145 if (!cmd)
146 goto oom;
148 for (tok=strtok(cmd," ");tok;tok=strtok(NULL," ")) {
149 args[argc++] = tok;
152 #if HAVE_REMSH
153 /* remsh (on HPUX) takes the arguments the other way around */
154 args[argc++] = machine;
155 if (user) {
156 args[argc++] = "-l";
157 args[argc++] = user;
159 #else
160 if (user) {
161 args[argc++] = "-l";
162 args[argc++] = user;
164 args[argc++] = machine;
165 #endif
167 args[argc++] = rsync_path;
169 server_options(args,&argc);
172 if (strcmp(cmd, RSYNC_RSH) == 0) blocking_io = 1;
175 args[argc++] = ".";
177 if (path && *path)
178 args[argc++] = path;
180 args[argc] = NULL;
182 if (verbose > 3) {
183 rprintf(FINFO,"cmd=");
184 for (i=0;i<argc;i++)
185 rprintf(FINFO,"%s ",args[i]);
186 rprintf(FINFO,"\n");
189 if (local_server) {
190 ret = local_child(argc, args, f_in, f_out);
191 } else {
192 ret = piped_child(args,f_in,f_out);
195 if (dir) free(dir);
197 return ret;
199 oom:
200 out_of_memory("do_cmd");
201 return 0; /* not reached */
207 static char *get_local_name(struct file_list *flist,char *name)
209 STRUCT_STAT st;
210 extern int orig_umask;
212 if (verbose > 2)
213 rprintf(FINFO,"get_local_name count=%d %s\n",
214 flist->count, NS(name));
216 if (!name)
217 return NULL;
219 if (do_stat(name,&st) == 0) {
220 if (S_ISDIR(st.st_mode)) {
221 if (!push_dir(name, 0)) {
222 rprintf(FERROR,"push_dir %s : %s (1)\n",
223 name,strerror(errno));
224 exit_cleanup(RERR_FILESELECT);
226 return NULL;
228 if (flist->count > 1) {
229 rprintf(FERROR,"ERROR: destination must be a directory when copying more than 1 file\n");
230 exit_cleanup(RERR_FILESELECT);
232 return name;
235 if (flist->count <= 1)
236 return name;
238 if (do_mkdir(name,0777 & ~orig_umask) != 0) {
239 rprintf(FERROR,"mkdir %s : %s (1)\n",name,strerror(errno));
240 exit_cleanup(RERR_FILEIO);
241 } else {
242 if (verbose > 0)
243 rprintf(FINFO,"created directory %s\n",name);
246 if (!push_dir(name, 0)) {
247 rprintf(FERROR,"push_dir %s : %s (2)\n",
248 name,strerror(errno));
249 exit_cleanup(RERR_FILESELECT);
252 return NULL;
258 static void do_server_sender(int f_in, int f_out, int argc,char *argv[])
260 int i;
261 struct file_list *flist;
262 char *dir = argv[0];
263 extern int relative_paths;
264 extern int recurse;
265 extern int remote_version;
267 if (verbose > 2)
268 rprintf(FINFO,"server_sender starting pid=%d\n",(int)getpid());
270 if (!relative_paths && !push_dir(dir, 0)) {
271 rprintf(FERROR,"push_dir %s: %s (3)\n",dir,strerror(errno));
272 exit_cleanup(RERR_FILESELECT);
274 argc--;
275 argv++;
277 if (strcmp(dir,".")) {
278 int l = strlen(dir);
279 if (strcmp(dir,"/") == 0)
280 l = 0;
281 for (i=0;i<argc;i++)
282 argv[i] += l+1;
285 if (argc == 0 && recurse) {
286 argc=1;
287 argv--;
288 argv[0] = ".";
291 flist = send_file_list(f_out,argc,argv);
292 if (!flist || flist->count == 0) {
293 exit_cleanup(0);
296 send_files(flist,f_out,f_in);
297 io_flush();
298 report(f_out);
299 if (remote_version >= 24) {
300 /* final goodbye message */
301 read_int(f_in);
303 io_flush();
304 exit_cleanup(0);
308 static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
310 int pid;
311 int status=0;
312 int recv_pipe[2];
313 int error_pipe[2];
314 extern int preserve_hard_links;
315 extern int delete_after;
316 extern int recurse;
317 extern int delete_mode;
318 extern int remote_version;
320 if (preserve_hard_links)
321 init_hard_links(flist);
323 if (!delete_after) {
324 /* I moved this here from recv_files() to prevent a race condition */
325 if (recurse && delete_mode && !local_name && flist->count>0) {
326 delete_files(flist);
330 if (fd_pair(recv_pipe) < 0) {
331 rprintf(FERROR,"pipe failed in do_recv\n");
332 exit_cleanup(RERR_SOCKETIO);
335 if (fd_pair(error_pipe) < 0) {
336 rprintf(FERROR,"error pipe failed in do_recv\n");
337 exit_cleanup(RERR_SOCKETIO);
340 io_flush();
342 if ((pid=do_fork()) == 0) {
343 close(recv_pipe[0]);
344 close(error_pipe[0]);
345 if (f_in != f_out) close(f_out);
347 /* we can't let two processes write to the socket at one time */
348 io_multiplexing_close();
350 /* set place to send errors */
351 set_error_fd(error_pipe[1]);
353 recv_files(f_in,flist,local_name,recv_pipe[1]);
354 io_flush();
355 report(f_in);
357 write_int(recv_pipe[1],1);
358 close(recv_pipe[1]);
359 io_flush();
360 /* finally we go to sleep until our parent kills us
361 with a USR2 signal. We sleep for a short time as on
362 some OSes a signal won't interrupt a sleep! */
363 while (msleep(20))
367 close(recv_pipe[1]);
368 close(error_pipe[1]);
369 if (f_in != f_out) close(f_in);
371 io_start_buffering(f_out);
373 io_set_error_fd(error_pipe[0]);
375 generate_files(f_out,flist,local_name,recv_pipe[0]);
377 read_int(recv_pipe[0]);
378 close(recv_pipe[0]);
379 if (remote_version >= 24) {
380 /* send a final goodbye message */
381 write_int(f_out, -1);
383 io_flush();
385 kill(pid, SIGUSR2);
386 wait_process(pid, &status);
387 return status;
391 static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
393 int status;
394 struct file_list *flist;
395 char *local_name=NULL;
396 char *dir = NULL;
397 extern int delete_mode;
398 extern int delete_excluded;
399 extern int am_daemon;
400 extern int module_id;
401 extern int am_sender;
403 if (verbose > 2)
404 rprintf(FINFO,"server_recv(%d) starting pid=%d\n",argc,(int)getpid());
406 if (am_daemon && lp_read_only(module_id) && !am_sender) {
407 rprintf(FERROR,"ERROR: module is read only\n");
408 exit_cleanup(RERR_SYNTAX);
409 return;
413 if (argc > 0) {
414 dir = argv[0];
415 argc--;
416 argv++;
417 if (!am_daemon && !push_dir(dir, 0)) {
418 rprintf(FERROR,"push_dir %s : %s (4)\n",
419 dir,strerror(errno));
420 exit_cleanup(RERR_FILESELECT);
424 if (delete_mode && !delete_excluded)
425 recv_exclude_list(f_in);
427 flist = recv_file_list(f_in);
428 if (!flist) {
429 rprintf(FERROR,"server_recv: recv_file_list error\n");
430 exit_cleanup(RERR_FILESELECT);
433 if (argc > 0) {
434 if (strcmp(dir,".")) {
435 argv[0] += strlen(dir);
436 if (argv[0][0] == '/') argv[0]++;
438 local_name = get_local_name(flist,argv[0]);
441 status = do_recv(f_in,f_out,flist,local_name);
442 exit_cleanup(status);
446 void start_server(int f_in, int f_out, int argc, char *argv[])
448 extern int cvs_exclude;
449 extern int am_sender;
450 extern int remote_version;
452 setup_protocol(f_out, f_in);
454 set_nonblocking(f_in);
455 set_nonblocking(f_out);
457 if (remote_version >= 23)
458 io_start_multiplex_out(f_out);
460 if (am_sender) {
461 recv_exclude_list(f_in);
462 if (cvs_exclude)
463 add_cvs_excludes();
464 do_server_sender(f_in, f_out, argc, argv);
465 } else {
466 do_server_recv(f_in, f_out, argc, argv);
468 exit_cleanup(0);
473 * This is called once the connection has been negotiated. It is used
474 * for rsyncd, remote-shell, and local connections.
476 int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[])
478 struct file_list *flist;
479 int status = 0, status2 = 0;
480 char *local_name = NULL;
481 extern int am_sender;
482 extern int remote_version;
483 extern pid_t cleanup_child_pid;
485 cleanup_child_pid = pid;
487 set_nonblocking(f_in);
488 set_nonblocking(f_out);
490 setup_protocol(f_out,f_in);
492 if (remote_version >= 23)
493 io_start_multiplex_in(f_in);
495 if (am_sender) {
496 extern int cvs_exclude;
497 extern int delete_mode;
498 extern int delete_excluded;
499 if (cvs_exclude)
500 add_cvs_excludes();
501 if (delete_mode && !delete_excluded)
502 send_exclude_list(f_out);
503 flist = send_file_list(f_out,argc,argv);
504 if (verbose > 3)
505 rprintf(FINFO,"file list sent\n");
507 send_files(flist,f_out,f_in);
508 if (remote_version >= 24) {
509 /* final goodbye message */
510 read_int(f_in);
512 if (pid != -1) {
513 if (verbose > 3)
514 rprintf(FINFO,"client_run waiting on %d\n",pid);
515 io_flush();
516 wait_process(pid, &status);
518 report(-1);
519 exit_cleanup(status);
522 if (argc == 0) {
523 extern int list_only;
524 list_only = 1;
527 send_exclude_list(f_out);
529 flist = recv_file_list(f_in);
530 if (!flist || flist->count == 0) {
531 rprintf(FINFO, "client: nothing to do: "
532 "perhaps you need to specify some filenames or "
533 "the --recursive option?\n");
534 exit_cleanup(0);
537 local_name = get_local_name(flist,argv[0]);
539 status2 = do_recv(f_in,f_out,flist,local_name);
541 if (pid != -1) {
542 if (verbose > 3)
543 rprintf(FINFO,"client_run2 waiting on %d\n",pid);
544 io_flush();
545 wait_process(pid, &status);
548 return MAX(status, status2);
551 static char *find_colon(char *s)
553 char *p, *p2;
555 p = strchr(s,':');
556 if (!p) return NULL;
558 /* now check to see if there is a / in the string before the : - if there is then
559 discard the colon on the assumption that the : is part of a filename */
560 p2 = strchr(s,'/');
561 if (p2 && p2 < p) return NULL;
563 return p;
568 * Start a client for either type of remote connection. Work out
569 * whether the arguments request a remote shell or rsyncd connection,
570 * and call the appropriate connection function, then run_client.
572 static int start_client(int argc, char *argv[])
574 char *p;
575 char *shell_machine = NULL;
576 char *shell_path = NULL;
577 char *shell_user = NULL;
578 int ret;
579 pid_t pid;
580 int f_in,f_out;
581 extern int local_server;
582 extern int am_sender;
583 extern char *shell_cmd;
584 extern int rsync_port;
585 extern int whole_file;
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 /* disable "rsync algorithm" when both sides local */
633 whole_file = 1;
634 } else if (p[1] == ':') {
635 *p = 0;
636 return start_socket_client(argv[argc-1], p+2, argc-1, argv);
639 if (argc < 2) {
640 usage(FERROR);
641 exit_cleanup(RERR_SYNTAX);
644 if (local_server) {
645 shell_machine = NULL;
646 shell_path = argv[argc-1];
647 } else {
648 *p = 0;
649 shell_machine = argv[argc-1];
650 shell_path = p+1;
652 argc--;
655 if (shell_machine) {
656 p = strchr(shell_machine,'@');
657 if (p) {
658 *p = 0;
659 shell_user = shell_machine;
660 shell_machine = p+1;
664 if (verbose > 3) {
665 rprintf(FINFO,"cmd=%s machine=%s user=%s path=%s\n",
666 shell_cmd?shell_cmd:"",
667 shell_machine?shell_machine:"",
668 shell_user?shell_user:"",
669 shell_path?shell_path:"");
672 if (!am_sender && argc > 1) {
673 usage(FERROR);
674 exit_cleanup(RERR_SYNTAX);
677 if (argc == 0 && !am_sender) {
678 extern int list_only;
679 list_only = 1;
682 pid = do_cmd(shell_cmd,shell_machine,shell_user,shell_path,&f_in,&f_out);
684 ret = client_run(f_in, f_out, pid, argc, argv);
686 fflush(stdout);
687 fflush(stderr);
689 return ret;
693 static RETSIGTYPE sigusr1_handler(int val) {
694 exit_cleanup(RERR_SIGNAL);
697 static RETSIGTYPE sigusr2_handler(int val) {
698 extern int log_got_error;
699 if (log_got_error) _exit(RERR_PARTIAL);
700 _exit(0);
703 static RETSIGTYPE sigchld_handler(int val) {
704 #ifdef WNOHANG
705 while (waitpid(-1, NULL, WNOHANG) > 0) ;
706 #endif
709 int main(int argc,char *argv[])
711 extern int am_root;
712 extern int orig_umask;
713 extern int dry_run;
714 extern int am_daemon;
715 extern int am_server;
716 int ret;
718 signal(SIGUSR1, sigusr1_handler);
719 signal(SIGUSR2, sigusr2_handler);
720 signal(SIGCHLD, sigchld_handler);
722 starttime = time(NULL);
723 am_root = (getuid() == 0);
725 memset(&stats, 0, sizeof(stats));
727 if (argc < 2) {
728 usage(FERROR);
729 exit_cleanup(RERR_SYNTAX);
732 /* we set a 0 umask so that correct file permissions can be
733 carried across */
734 orig_umask = (int)umask(0);
736 if (!parse_arguments(&argc, (const char ***) &argv, 1)) {
737 /* FIXME: We ought to call the same error-handling
738 * code here, rather than relying on getopt. */
739 option_error();
740 exit_cleanup(RERR_SYNTAX);
743 signal(SIGINT,SIGNAL_CAST sig_int);
744 signal(SIGPIPE,SIGNAL_CAST sig_int);
745 signal(SIGHUP,SIGNAL_CAST sig_int);
746 signal(SIGTERM,SIGNAL_CAST sig_int);
748 /* Initialize push_dir here because on some old systems getcwd
749 (implemented by forking "pwd" and reading its output) doesn't
750 work when there are other child processes. Also, on all systems
751 that implement getcwd that way "pwd" can't be found after chroot. */
752 push_dir(NULL,0);
754 if (am_daemon) {
755 return daemon_main();
758 if (argc < 1) {
759 usage(FERROR);
760 exit_cleanup(RERR_SYNTAX);
763 if (dry_run)
764 verbose = MAX(verbose,1);
766 #ifndef SUPPORT_LINKS
767 if (!am_server && preserve_links) {
768 rprintf(FERROR,"ERROR: symbolic links not supported\n");
769 exit_cleanup(RERR_UNSUPPORTED);
771 #endif
773 if (am_server) {
774 set_nonblocking(STDIN_FILENO);
775 set_nonblocking(STDOUT_FILENO);
776 start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
779 ret = start_client(argc, argv);
780 exit_cleanup(ret);
781 return ret;