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