added blocking-io docs
[rsync/rsync.git] / main.c
... / ...
CommitLineData
1/*
2 Copyright (C) Andrew Tridgell 1996
3 Copyright (C) Paul Mackerras 1996
4
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.
9
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.
14
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.
18*/
19
20#include "rsync.h"
21
22time_t starttime = 0;
23
24struct stats stats;
25
26extern int verbose;
27
28static void report(int f)
29{
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;
37
38 if (am_daemon) {
39 log_exit(0, __FILE__, __LINE__);
40 if (f == -1 || !am_sender) return;
41 }
42
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);
53 }
54 return;
55 }
56
57 /* this is the client */
58
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;
66 }
67
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;
74 }
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);
91 }
92
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));
101 }
102
103 fflush(stdout);
104 fflush(stderr);
105}
106
107
108static int do_cmd(char *cmd,char *machine,char *user,char *path,int *f_in,int *f_out)
109{
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;
115 extern int blocking_io;
116
117 if (!local_server) {
118 if (!cmd)
119 cmd = getenv(RSYNC_RSH_ENV);
120 if (!cmd)
121 cmd = RSYNC_RSH;
122 cmd = strdup(cmd);
123 if (!cmd)
124 goto oom;
125
126 for (tok=strtok(cmd," ");tok;tok=strtok(NULL," ")) {
127 args[argc++] = tok;
128 }
129
130#if HAVE_REMSH
131 /* remsh (on HPUX) takes the arguments the other way around */
132 args[argc++] = machine;
133 if (user) {
134 args[argc++] = "-l";
135 args[argc++] = user;
136 }
137#else
138 if (user) {
139 args[argc++] = "-l";
140 args[argc++] = user;
141 }
142 args[argc++] = machine;
143#endif
144
145 args[argc++] = rsync_path;
146
147 server_options(args,&argc);
148
149
150 if (strcmp(cmd, RSYNC_RSH) == 0) blocking_io = 1;
151 }
152
153 args[argc++] = ".";
154
155 if (path && *path)
156 args[argc++] = path;
157
158 args[argc] = NULL;
159
160 if (verbose > 3) {
161 rprintf(FINFO,"cmd=");
162 for (i=0;i<argc;i++)
163 rprintf(FINFO,"%s ",args[i]);
164 rprintf(FINFO,"\n");
165 }
166
167 if (local_server) {
168 ret = local_child(argc, args, f_in, f_out);
169 } else {
170 ret = piped_child(args,f_in,f_out);
171 }
172
173 if (dir) free(dir);
174
175 return ret;
176
177oom:
178 out_of_memory("do_cmd");
179 return 0; /* not reached */
180}
181
182
183
184
185static char *get_local_name(struct file_list *flist,char *name)
186{
187 STRUCT_STAT st;
188 extern int orig_umask;
189
190 if (verbose > 2)
191 rprintf(FINFO,"get_local_name count=%d %s\n",
192 flist->count, NS(name));
193
194 if (!name)
195 return NULL;
196
197 if (do_stat(name,&st) == 0) {
198 if (S_ISDIR(st.st_mode)) {
199 if (!push_dir(name, 0)) {
200 rprintf(FERROR,"push_dir %s : %s (1)\n",
201 name,strerror(errno));
202 exit_cleanup(RERR_FILESELECT);
203 }
204 return NULL;
205 }
206 if (flist->count > 1) {
207 rprintf(FERROR,"ERROR: destination must be a directory when copying more than 1 file\n");
208 exit_cleanup(RERR_FILESELECT);
209 }
210 return name;
211 }
212
213 if (flist->count <= 1)
214 return name;
215
216 if (do_mkdir(name,0777 & ~orig_umask) != 0) {
217 rprintf(FERROR,"mkdir %s : %s (1)\n",name,strerror(errno));
218 exit_cleanup(RERR_FILEIO);
219 } else {
220 if (verbose > 0)
221 rprintf(FINFO,"created directory %s\n",name);
222 }
223
224 if (!push_dir(name, 0)) {
225 rprintf(FERROR,"push_dir %s : %s (2)\n",
226 name,strerror(errno));
227 exit_cleanup(RERR_FILESELECT);
228 }
229
230 return NULL;
231}
232
233
234
235
236static void do_server_sender(int f_in, int f_out, int argc,char *argv[])
237{
238 int i;
239 struct file_list *flist;
240 char *dir = argv[0];
241 extern int relative_paths;
242 extern int recurse;
243
244 if (verbose > 2)
245 rprintf(FINFO,"server_sender starting pid=%d\n",(int)getpid());
246
247 if (!relative_paths && !push_dir(dir, 0)) {
248 rprintf(FERROR,"push_dir %s: %s (3)\n",dir,strerror(errno));
249 exit_cleanup(RERR_FILESELECT);
250 }
251 argc--;
252 argv++;
253
254 if (strcmp(dir,".")) {
255 int l = strlen(dir);
256 if (strcmp(dir,"/") == 0)
257 l = 0;
258 for (i=0;i<argc;i++)
259 argv[i] += l+1;
260 }
261
262 if (argc == 0 && recurse) {
263 argc=1;
264 argv--;
265 argv[0] = ".";
266 }
267
268 flist = send_file_list(f_out,argc,argv);
269 if (!flist || flist->count == 0) {
270 exit_cleanup(0);
271 }
272
273 send_files(flist,f_out,f_in);
274 report(f_out);
275 io_flush();
276 exit_cleanup(0);
277}
278
279
280static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
281{
282 int pid;
283 int status=0;
284 int recv_pipe[2];
285 int error_pipe[2];
286 extern int preserve_hard_links;
287 extern int delete_after;
288 extern int recurse;
289 extern int delete_mode;
290 extern int remote_version;
291
292 if (preserve_hard_links)
293 init_hard_links(flist);
294
295 if (!delete_after) {
296 /* I moved this here from recv_files() to prevent a race condition */
297 if (recurse && delete_mode && !local_name && flist->count>0) {
298 delete_files(flist);
299 }
300 }
301
302 if (fd_pair(recv_pipe) < 0) {
303 rprintf(FERROR,"pipe failed in do_recv\n");
304 exit_cleanup(RERR_SOCKETIO);
305 }
306
307 if (fd_pair(error_pipe) < 0) {
308 rprintf(FERROR,"error pipe failed in do_recv\n");
309 exit_cleanup(RERR_SOCKETIO);
310 }
311
312 io_flush();
313
314 if ((pid=do_fork()) == 0) {
315 close(recv_pipe[0]);
316 close(error_pipe[0]);
317 if (f_in != f_out) close(f_out);
318
319 /* we can't let two processes write to the socket at one time */
320 io_multiplexing_close();
321
322 /* set place to send errors */
323 set_error_fd(error_pipe[1]);
324
325 recv_files(f_in,flist,local_name,recv_pipe[1]);
326 report(f_in);
327
328 write_int(recv_pipe[1],1);
329 close(recv_pipe[1]);
330 io_flush();
331 /* finally we go to sleep until our parent kills us
332 with a USR2 signal. We sleepp for a short time as on
333 some OSes a signal won't interrupt a sleep! */
334 while (1) sleep(1);
335 }
336
337 close(recv_pipe[1]);
338 close(error_pipe[1]);
339 io_close_input(f_in);
340 if (f_in != f_out) close(f_in);
341
342 io_start_buffering(f_out);
343
344 io_set_error_fd(error_pipe[0]);
345
346 generate_files(f_out,flist,local_name,recv_pipe[0]);
347
348 read_int(recv_pipe[0]);
349 close(recv_pipe[0]);
350 if (remote_version >= 24) {
351 /* send a final goodbye message */
352 write_int(f_out, -1);
353 }
354 io_flush();
355
356 kill(pid, SIGUSR2);
357 wait_process(pid, &status);
358 return status;
359}
360
361
362static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
363{
364 int status;
365 struct file_list *flist;
366 char *local_name=NULL;
367 char *dir = NULL;
368 extern int delete_mode;
369 extern int delete_excluded;
370 extern int am_daemon;
371 extern int module_id;
372 extern int am_sender;
373
374 if (verbose > 2)
375 rprintf(FINFO,"server_recv(%d) starting pid=%d\n",argc,(int)getpid());
376
377 if (am_daemon && lp_read_only(module_id) && !am_sender) {
378 rprintf(FERROR,"ERROR: module is read only\n");
379 exit_cleanup(RERR_SYNTAX);
380 return;
381 }
382
383
384 if (argc > 0) {
385 dir = argv[0];
386 argc--;
387 argv++;
388 if (!am_daemon && !push_dir(dir, 0)) {
389 rprintf(FERROR,"push_dir %s : %s (4)\n",
390 dir,strerror(errno));
391 exit_cleanup(RERR_FILESELECT);
392 }
393 }
394
395 if (delete_mode && !delete_excluded)
396 recv_exclude_list(f_in);
397
398 flist = recv_file_list(f_in);
399 if (!flist) {
400 rprintf(FERROR,"server_recv: recv_file_list error\n");
401 exit_cleanup(RERR_FILESELECT);
402 }
403
404 if (argc > 0) {
405 if (strcmp(dir,".")) {
406 argv[0] += strlen(dir);
407 if (argv[0][0] == '/') argv[0]++;
408 }
409 local_name = get_local_name(flist,argv[0]);
410 }
411
412 status = do_recv(f_in,f_out,flist,local_name);
413 exit_cleanup(status);
414}
415
416
417void start_server(int f_in, int f_out, int argc, char *argv[])
418{
419 extern int cvs_exclude;
420 extern int am_sender;
421 extern int remote_version;
422
423 setup_protocol(f_out, f_in);
424
425 set_nonblocking(f_in);
426 set_nonblocking(f_out);
427
428 if (remote_version >= 23)
429 io_start_multiplex_out(f_out);
430
431 if (am_sender) {
432 recv_exclude_list(f_in);
433 if (cvs_exclude)
434 add_cvs_excludes();
435 do_server_sender(f_in, f_out, argc, argv);
436 } else {
437 do_server_recv(f_in, f_out, argc, argv);
438 }
439 exit_cleanup(0);
440}
441
442int client_run(int f_in, int f_out, int pid, int argc, char *argv[])
443{
444 struct file_list *flist;
445 int status = 0, status2 = 0;
446 char *local_name = NULL;
447 extern int am_sender;
448 extern int list_only;
449 extern int remote_version;
450
451 set_nonblocking(f_in);
452 set_nonblocking(f_out);
453
454 setup_protocol(f_out,f_in);
455
456 if (remote_version >= 23)
457 io_start_multiplex_in(f_in);
458
459 if (am_sender) {
460 extern int cvs_exclude;
461 extern int delete_mode;
462 extern int delete_excluded;
463 if (cvs_exclude)
464 add_cvs_excludes();
465 if (delete_mode && !delete_excluded)
466 send_exclude_list(f_out);
467 flist = send_file_list(f_out,argc,argv);
468 if (verbose > 3)
469 rprintf(FINFO,"file list sent\n");
470
471 send_files(flist,f_out,f_in);
472 if (pid != -1) {
473 if (verbose > 3)
474 rprintf(FINFO,"client_run waiting on %d\n",pid);
475 io_flush();
476 wait_process(pid, &status);
477 }
478 report(-1);
479 if (remote_version >= 24) {
480 /* final goodbye message */
481 read_int(f_in);
482 }
483 exit_cleanup(status);
484 }
485
486 if (argc == 0) list_only = 1;
487
488 send_exclude_list(f_out);
489
490 flist = recv_file_list(f_in);
491 if (!flist || flist->count == 0) {
492 rprintf(FINFO,"client: nothing to do\n");
493 exit_cleanup(0);
494 }
495
496 local_name = get_local_name(flist,argv[0]);
497
498 status2 = do_recv(f_in,f_out,flist,local_name);
499
500 if (pid != -1) {
501 if (verbose > 3)
502 rprintf(FINFO,"client_run2 waiting on %d\n",pid);
503 io_flush();
504 wait_process(pid, &status);
505 }
506
507 return status | status2;
508}
509
510static char *find_colon(char *s)
511{
512 char *p, *p2;
513
514 p = strchr(s,':');
515 if (!p) return NULL;
516
517 /* now check to see if there is a / in the string before the : - if there is then
518 discard the colon on the assumption that the : is part of a filename */
519 p2 = strchr(s,'/');
520 if (p2 && p2 < p) return NULL;
521
522 return p;
523}
524
525static int start_client(int argc, char *argv[])
526{
527 char *p;
528 char *shell_machine = NULL;
529 char *shell_path = NULL;
530 char *shell_user = NULL;
531 int pid, ret;
532 int f_in,f_out;
533 extern int local_server;
534 extern int am_sender;
535 extern char *shell_cmd;
536 extern int rsync_port;
537
538 if (strncasecmp(URL_PREFIX, argv[0], strlen(URL_PREFIX)) == 0) {
539 char *host, *path;
540
541 host = argv[0] + strlen(URL_PREFIX);
542 p = strchr(host,'/');
543 if (p) {
544 *p = 0;
545 path = p+1;
546 } else {
547 path="";
548 }
549 p = strchr(host,':');
550 if (p) {
551 rsync_port = atoi(p+1);
552 *p = 0;
553 }
554 return start_socket_client(host, path, argc-1, argv+1);
555 }
556
557 p = find_colon(argv[0]);
558
559 if (p) {
560 if (p[1] == ':') {
561 *p = 0;
562 return start_socket_client(argv[0], p+2, argc-1, argv+1);
563 }
564
565 if (argc < 1) {
566 usage(FERROR);
567 exit_cleanup(RERR_SYNTAX);
568 }
569
570 am_sender = 0;
571 *p = 0;
572 shell_machine = argv[0];
573 shell_path = p+1;
574 argc--;
575 argv++;
576 } else {
577 am_sender = 1;
578
579 p = find_colon(argv[argc-1]);
580 if (!p) {
581 local_server = 1;
582 } else if (p[1] == ':') {
583 *p = 0;
584 return start_socket_client(argv[argc-1], p+2, argc-1, argv);
585 }
586
587 if (argc < 2) {
588 usage(FERROR);
589 exit_cleanup(RERR_SYNTAX);
590 }
591
592 if (local_server) {
593 shell_machine = NULL;
594 shell_path = argv[argc-1];
595 } else {
596 *p = 0;
597 shell_machine = argv[argc-1];
598 shell_path = p+1;
599 }
600 argc--;
601 }
602
603 if (shell_machine) {
604 p = strchr(shell_machine,'@');
605 if (p) {
606 *p = 0;
607 shell_user = shell_machine;
608 shell_machine = p+1;
609 }
610 }
611
612 if (verbose > 3) {
613 rprintf(FINFO,"cmd=%s machine=%s user=%s path=%s\n",
614 shell_cmd?shell_cmd:"",
615 shell_machine?shell_machine:"",
616 shell_user?shell_user:"",
617 shell_path?shell_path:"");
618 }
619
620 if (!am_sender && argc > 1) {
621 usage(FERROR);
622 exit_cleanup(RERR_SYNTAX);
623 }
624
625 pid = do_cmd(shell_cmd,shell_machine,shell_user,shell_path,&f_in,&f_out);
626
627 ret = client_run(f_in, f_out, pid, argc, argv);
628
629 fflush(stdout);
630 fflush(stderr);
631
632 return ret;
633}
634
635
636static RETSIGTYPE sigusr1_handler(int val) {
637 exit_cleanup(RERR_SIGNAL);
638}
639
640static RETSIGTYPE sigusr2_handler(int val) {
641 _exit(0);
642}
643
644int main(int argc,char *argv[])
645{
646 extern int am_root;
647 extern int orig_umask;
648 extern int dry_run;
649 extern int am_daemon;
650 extern int am_server;
651
652 signal(SIGUSR1, sigusr1_handler);
653 signal(SIGUSR2, sigusr2_handler);
654
655 starttime = time(NULL);
656 am_root = (getuid() == 0);
657
658 memset(&stats, 0, sizeof(stats));
659
660 if (argc < 2) {
661 usage(FERROR);
662 exit_cleanup(RERR_SYNTAX);
663 }
664
665 /* we set a 0 umask so that correct file permissions can be
666 carried across */
667 orig_umask = (int)umask(0);
668
669 if (!parse_arguments(argc, argv, 1)) {
670 exit_cleanup(RERR_SYNTAX);
671 }
672
673 argc -= optind;
674 argv += optind;
675 optind = 0;
676
677 signal(SIGCHLD,SIG_IGN);
678 signal(SIGINT,SIGNAL_CAST sig_int);
679 signal(SIGPIPE,SIGNAL_CAST sig_int);
680 signal(SIGHUP,SIGNAL_CAST sig_int);
681 signal(SIGTERM,SIGNAL_CAST sig_int);
682
683 /* Initialize push_dir here because on some old systems getcwd
684 (implemented by forking "pwd" and reading its output) doesn't
685 work when there are other child processes. Also, on all systems
686 that implement getcwd that way "pwd" can't be found after chroot. */
687 push_dir(NULL,0);
688
689 if (am_daemon) {
690 return daemon_main();
691 }
692
693 if (argc < 1) {
694 usage(FERROR);
695 exit_cleanup(RERR_SYNTAX);
696 }
697
698 if (dry_run)
699 verbose = MAX(verbose,1);
700
701#ifndef SUPPORT_LINKS
702 if (!am_server && preserve_links) {
703 rprintf(FERROR,"ERROR: symbolic links not supported\n");
704 exit_cleanup(RERR_UNSUPPORTED);
705 }
706#endif
707
708 if (am_server) {
709 set_nonblocking(STDIN_FILENO);
710 set_nonblocking(STDOUT_FILENO);
711 start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
712 }
713
714 return start_client(argc, argv);
715}
716