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