Fixed bug introduced by calling do_open() for O_RDONLY files. Changed it
[rsync.git] / main.c
blob807409e3486b90371c96f271ee28ada6278c86ef
1 /*
2 Copyright (C) Andrew Tridgell 1996
3 Copyright (C) Paul Mackerras 1996
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.
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.
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.
20 #include "rsync.h"
22 time_t starttime = 0;
24 struct stats stats;
26 extern int verbose;
28 static void report(int f)
30 time_t t = time(NULL);
31 extern int am_server;
32 extern int am_sender;
33 extern int am_daemon;
34 extern int do_stats;
35 extern int remote_version;
36 int send_stats;
38 if (am_daemon) {
39 log_exit(0, __FILE__, __LINE__);
40 if (f == -1 || !am_sender) return;
43 send_stats = verbose || (remote_version >= 20);
44 if (am_server) {
45 if (am_sender && send_stats) {
46 int64 w;
47 /* store total_written in a temporary
48 because write_longint changes it */
49 w = stats.total_written;
50 write_longint(f,stats.total_read);
51 write_longint(f,w);
52 write_longint(f,stats.total_size);
54 return;
57 /* this is the client */
59 if (!am_sender && send_stats) {
60 int64 r;
61 stats.total_written = read_longint(f);
62 /* store total_read in a temporary, read_longint changes it */
63 r = read_longint(f);
64 stats.total_size = read_longint(f);
65 stats.total_read = r;
68 if (do_stats) {
69 if (!am_sender && !send_stats) {
70 /* missing the bytes written by the generator */
71 rprintf(FINFO, "\nCannot show stats as receiver because remote protocol version is less than 20\n");
72 rprintf(FINFO, "Use --stats -v to show stats\n");
73 return;
75 rprintf(FINFO,"\nNumber of files: %d\n", stats.num_files);
76 rprintf(FINFO,"Number of files transferred: %d\n",
77 stats.num_transferred_files);
78 rprintf(FINFO,"Total file size: %.0f bytes\n",
79 (double)stats.total_size);
80 rprintf(FINFO,"Total transferred file size: %.0f bytes\n",
81 (double)stats.total_transferred_size);
82 rprintf(FINFO,"Literal data: %.0f bytes\n",
83 (double)stats.literal_data);
84 rprintf(FINFO,"Matched data: %.0f bytes\n",
85 (double)stats.matched_data);
86 rprintf(FINFO,"File list size: %d\n", stats.flist_size);
87 rprintf(FINFO,"Total bytes written: %.0f\n",
88 (double)stats.total_written);
89 rprintf(FINFO,"Total bytes read: %.0f\n\n",
90 (double)stats.total_read);
93 if (verbose || do_stats) {
94 rprintf(FINFO,"wrote %.0f bytes read %.0f bytes %.2f bytes/sec\n",
95 (double)stats.total_written,
96 (double)stats.total_read,
97 (stats.total_written+stats.total_read)/(0.5 + (t-starttime)));
98 rprintf(FINFO,"total size is %.0f speedup is %.2f\n",
99 (double)stats.total_size,
100 (1.0*stats.total_size)/(stats.total_written+stats.total_read));
103 fflush(stdout);
104 fflush(stderr);
108 static int do_cmd(char *cmd,char *machine,char *user,char *path,int *f_in,int *f_out)
110 char *args[100];
111 int i,argc=0, ret;
112 char *tok,*dir=NULL;
113 extern int local_server;
114 extern char *rsync_path;
116 if (!local_server) {
117 if (!cmd)
118 cmd = getenv(RSYNC_RSH_ENV);
119 if (!cmd)
120 cmd = RSYNC_RSH;
121 cmd = strdup(cmd);
122 if (!cmd)
123 goto oom;
125 for (tok=strtok(cmd," ");tok;tok=strtok(NULL," ")) {
126 args[argc++] = tok;
129 #if HAVE_REMSH
130 /* remsh (on HPUX) takes the arguments the other way around */
131 args[argc++] = machine;
132 if (user) {
133 args[argc++] = "-l";
134 args[argc++] = user;
136 #else
137 if (user) {
138 args[argc++] = "-l";
139 args[argc++] = user;
141 args[argc++] = machine;
142 #endif
144 args[argc++] = rsync_path;
146 server_options(args,&argc);
149 args[argc++] = ".";
151 if (path && *path)
152 args[argc++] = path;
154 args[argc] = NULL;
156 if (verbose > 3) {
157 rprintf(FINFO,"cmd=");
158 for (i=0;i<argc;i++)
159 rprintf(FINFO,"%s ",args[i]);
160 rprintf(FINFO,"\n");
163 if (local_server) {
164 ret = local_child(argc, args, f_in, f_out);
165 } else {
166 ret = piped_child(args,f_in,f_out);
169 if (dir) free(dir);
171 return ret;
173 oom:
174 out_of_memory("do_cmd");
175 return 0; /* not reached */
181 static char *get_local_name(struct file_list *flist,char *name)
183 STRUCT_STAT st;
184 extern int orig_umask;
186 if (verbose > 2)
187 rprintf(FINFO,"get_local_name count=%d %s\n",
188 flist->count, NS(name));
190 if (!name)
191 return NULL;
193 if (do_stat(name,&st) == 0) {
194 if (S_ISDIR(st.st_mode)) {
195 if (!push_dir(name, 0)) {
196 rprintf(FERROR,"push_dir %s : %s (1)\n",
197 name,strerror(errno));
198 exit_cleanup(RERR_FILESELECT);
200 return NULL;
202 if (flist->count > 1) {
203 rprintf(FERROR,"ERROR: destination must be a directory when copying more than 1 file\n");
204 exit_cleanup(RERR_FILESELECT);
206 return name;
209 if (flist->count <= 1)
210 return name;
212 if (do_mkdir(name,0777 & ~orig_umask) != 0) {
213 rprintf(FERROR,"mkdir %s : %s (1)\n",name,strerror(errno));
214 exit_cleanup(RERR_FILEIO);
215 } else {
216 if (verbose > 0)
217 rprintf(FINFO,"created directory %s\n",name);
220 if (!push_dir(name, 0)) {
221 rprintf(FERROR,"push_dir %s : %s (2)\n",
222 name,strerror(errno));
223 exit_cleanup(RERR_FILESELECT);
226 return NULL;
232 static void do_server_sender(int f_in, int f_out, int argc,char *argv[])
234 int i;
235 struct file_list *flist;
236 char *dir = argv[0];
237 extern int relative_paths;
238 extern int recurse;
240 if (verbose > 2)
241 rprintf(FINFO,"server_sender starting pid=%d\n",(int)getpid());
243 if (!relative_paths && !push_dir(dir, 0)) {
244 rprintf(FERROR,"push_dir %s: %s (3)\n",dir,strerror(errno));
245 exit_cleanup(RERR_FILESELECT);
247 argc--;
248 argv++;
250 if (strcmp(dir,".")) {
251 int l = strlen(dir);
252 if (strcmp(dir,"/") == 0)
253 l = 0;
254 for (i=0;i<argc;i++)
255 argv[i] += l+1;
258 if (argc == 0 && recurse) {
259 argc=1;
260 argv--;
261 argv[0] = ".";
264 set_nonblocking(f_out);
265 if (f_in != f_out)
266 set_nonblocking(f_in);
268 flist = send_file_list(f_out,argc,argv);
269 if (!flist || flist->count == 0) {
270 exit_cleanup(0);
273 send_files(flist,f_out,f_in);
274 report(f_out);
275 io_flush();
276 exit_cleanup(0);
280 static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
282 int pid;
283 int status=0;
284 int recv_pipe[2];
285 extern int preserve_hard_links;
287 if (preserve_hard_links)
288 init_hard_links(flist);
290 if (pipe(recv_pipe) < 0) {
291 rprintf(FERROR,"pipe failed in do_recv\n");
292 exit_cleanup(RERR_SOCKETIO);
295 io_flush();
297 if ((pid=do_fork()) == 0) {
298 close(recv_pipe[0]);
299 if (f_in != f_out) close(f_out);
301 set_nonblocking(f_in);
302 set_nonblocking(recv_pipe[1]);
304 recv_files(f_in,flist,local_name,recv_pipe[1]);
305 report(f_in);
307 io_flush();
308 _exit(0);
311 close(recv_pipe[1]);
312 io_close_input(f_in);
313 if (f_in != f_out) close(f_in);
315 set_nonblocking(f_out);
316 set_nonblocking(recv_pipe[0]);
318 io_start_buffering(f_out);
320 generate_files(f_out,flist,local_name,recv_pipe[0]);
322 io_flush();
323 waitpid(pid, &status, 0);
324 return status;
328 static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
330 int status;
331 struct file_list *flist;
332 char *local_name=NULL;
333 char *dir = NULL;
334 extern int delete_mode;
335 extern int delete_excluded;
336 extern int am_daemon;
338 if (verbose > 2)
339 rprintf(FINFO,"server_recv(%d) starting pid=%d\n",argc,(int)getpid());
341 if (argc > 0) {
342 dir = argv[0];
343 argc--;
344 argv++;
345 if (!am_daemon && !push_dir(dir, 0)) {
346 rprintf(FERROR,"push_dir %s : %s (4)\n",
347 dir,strerror(errno));
348 exit_cleanup(RERR_FILESELECT);
352 if (delete_mode && !delete_excluded)
353 recv_exclude_list(f_in);
355 flist = recv_file_list(f_in);
356 if (!flist) {
357 rprintf(FERROR,"server_recv: recv_file_list error\n");
358 exit_cleanup(RERR_FILESELECT);
361 if (argc > 0) {
362 if (strcmp(dir,".")) {
363 argv[0] += strlen(dir);
364 if (argv[0][0] == '/') argv[0]++;
366 local_name = get_local_name(flist,argv[0]);
369 status = do_recv(f_in,f_out,flist,local_name);
370 exit_cleanup(status);
374 void start_server(int f_in, int f_out, int argc, char *argv[])
376 extern int cvs_exclude;
377 extern int am_sender;
379 set_nonblocking(f_out);
380 if (f_in != f_out)
381 set_nonblocking(f_in);
383 setup_protocol(f_out, f_in);
385 if (am_sender) {
386 recv_exclude_list(f_in);
387 if (cvs_exclude)
388 add_cvs_excludes();
389 do_server_sender(f_in, f_out, argc, argv);
390 } else {
391 do_server_recv(f_in, f_out, argc, argv);
393 exit_cleanup(0);
396 int client_run(int f_in, int f_out, int pid, int argc, char *argv[])
398 struct file_list *flist;
399 int status = 0, status2 = 0;
400 char *local_name = NULL;
401 extern int am_sender;
402 extern int list_only;
404 setup_protocol(f_out,f_in);
406 if (am_sender) {
407 extern int cvs_exclude;
408 extern int delete_mode;
409 extern int delete_excluded;
410 if (cvs_exclude)
411 add_cvs_excludes();
412 if (delete_mode && !delete_excluded)
413 send_exclude_list(f_out);
414 flist = send_file_list(f_out,argc,argv);
415 if (verbose > 3)
416 rprintf(FINFO,"file list sent\n");
418 set_nonblocking(f_out);
419 if (f_in != f_out)
420 set_nonblocking(f_in);
422 send_files(flist,f_out,f_in);
423 if (pid != -1) {
424 if (verbose > 3)
425 rprintf(FINFO,"client_run waiting on %d\n",pid);
426 io_flush();
427 waitpid(pid, &status, 0);
429 report(-1);
430 exit_cleanup(status);
433 if (argc == 0) list_only = 1;
435 send_exclude_list(f_out);
437 flist = recv_file_list(f_in);
438 if (!flist || flist->count == 0) {
439 rprintf(FINFO,"client: nothing to do\n");
440 exit_cleanup(0);
443 local_name = get_local_name(flist,argv[0]);
445 status2 = do_recv(f_in,f_out,flist,local_name);
447 if (pid != -1) {
448 if (verbose > 3)
449 rprintf(FINFO,"client_run2 waiting on %d\n",pid);
450 io_flush();
451 waitpid(pid, &status, 0);
454 return status | status2;
457 static char *find_colon(char *s)
459 char *p, *p2;
461 p = strchr(s,':');
462 if (!p) return NULL;
464 /* now check to see if there is a / in the string before the : - if there is then
465 discard the colon on the assumption that the : is part of a filename */
466 p2 = strchr(s,'/');
467 if (p2 && p2 < p) return NULL;
469 return p;
472 static int start_client(int argc, char *argv[])
474 char *p;
475 char *shell_machine = NULL;
476 char *shell_path = NULL;
477 char *shell_user = NULL;
478 int pid, ret;
479 int f_in,f_out;
480 extern int local_server;
481 extern int am_sender;
482 extern char *shell_cmd;
483 extern int rsync_port;
485 if (strncasecmp(URL_PREFIX, argv[0], strlen(URL_PREFIX)) == 0) {
486 char *host, *path;
488 host = argv[0] + strlen(URL_PREFIX);
489 p = strchr(host,'/');
490 if (p) {
491 *p = 0;
492 path = p+1;
493 } else {
494 path="";
496 p = strchr(host,':');
497 if (p) {
498 rsync_port = atoi(p+1);
499 *p = 0;
501 return start_socket_client(host, path, argc-1, argv+1);
504 p = find_colon(argv[0]);
506 if (p) {
507 if (p[1] == ':') {
508 *p = 0;
509 return start_socket_client(argv[0], p+2, argc-1, argv+1);
512 if (argc < 1) {
513 usage(FERROR);
514 exit_cleanup(RERR_SYNTAX);
517 am_sender = 0;
518 *p = 0;
519 shell_machine = argv[0];
520 shell_path = p+1;
521 argc--;
522 argv++;
523 } else {
524 am_sender = 1;
526 p = find_colon(argv[argc-1]);
527 if (!p) {
528 local_server = 1;
529 } else if (p[1] == ':') {
530 *p = 0;
531 return start_socket_client(argv[argc-1], p+2, argc-1, argv);
534 if (argc < 2) {
535 usage(FERROR);
536 exit_cleanup(RERR_SYNTAX);
539 if (local_server) {
540 shell_machine = NULL;
541 shell_path = argv[argc-1];
542 } else {
543 *p = 0;
544 shell_machine = argv[argc-1];
545 shell_path = p+1;
547 argc--;
550 if (shell_machine) {
551 p = strchr(shell_machine,'@');
552 if (p) {
553 *p = 0;
554 shell_user = shell_machine;
555 shell_machine = p+1;
559 if (verbose > 3) {
560 rprintf(FINFO,"cmd=%s machine=%s user=%s path=%s\n",
561 shell_cmd?shell_cmd:"",
562 shell_machine?shell_machine:"",
563 shell_user?shell_user:"",
564 shell_path?shell_path:"");
567 if (!am_sender && argc > 1) {
568 usage(FERROR);
569 exit_cleanup(RERR_SYNTAX);
572 pid = do_cmd(shell_cmd,shell_machine,shell_user,shell_path,&f_in,&f_out);
574 ret = client_run(f_in, f_out, pid, argc, argv);
576 fflush(stdout);
577 fflush(stderr);
579 return ret;
583 static RETSIGTYPE sigusr1_handler(int val) {
584 exit_cleanup(RERR_SIGNAL);
587 int main(int argc,char *argv[])
589 extern int am_root;
590 extern int orig_umask;
591 extern int dry_run;
592 extern int am_daemon;
593 extern int am_server;
595 signal(SIGUSR1, sigusr1_handler);
597 starttime = time(NULL);
598 am_root = (getuid() == 0);
600 memset(&stats, 0, sizeof(stats));
602 if (argc < 2) {
603 usage(FERROR);
604 exit_cleanup(RERR_SYNTAX);
607 /* we set a 0 umask so that correct file permissions can be
608 carried across */
609 orig_umask = (int)umask(0);
611 if (!parse_arguments(argc, argv, 1)) {
612 exit_cleanup(RERR_SYNTAX);
615 argc -= optind;
616 argv += optind;
617 optind = 0;
619 signal(SIGCHLD,SIG_IGN);
620 signal(SIGINT,SIGNAL_CAST sig_int);
621 signal(SIGPIPE,SIGNAL_CAST sig_int);
622 signal(SIGHUP,SIGNAL_CAST sig_int);
623 signal(SIGTERM,SIGNAL_CAST sig_int);
625 /* Initialize push_dir here because on some old systems getcwd
626 (implemented by forking "pwd" and reading its output) doesn't
627 work when there are other child processes. Also, on all systems
628 that implement getcwd that way "pwd" can't be found after chroot. */
629 push_dir(NULL,0);
631 if (am_daemon) {
632 return daemon_main();
635 if (argc < 1) {
636 usage(FERROR);
637 exit_cleanup(RERR_SYNTAX);
640 if (dry_run)
641 verbose = MAX(verbose,1);
643 #ifndef SUPPORT_LINKS
644 if (!am_server && preserve_links) {
645 rprintf(FERROR,"ERROR: symbolic links not supported\n");
646 exit_cleanup(RERR_UNSUPPORTED);
648 #endif
650 if (am_server) {
651 start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
654 return start_client(argc, argv);