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