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