detect list_only a bit earlier
[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 sleep for a short time as on
353 some OSes a signal won't interrupt a sleep! */
354 while (1) msleep(20);
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 remote_version;
468
469 set_nonblocking(f_in);
470 set_nonblocking(f_out);
471
472 setup_protocol(f_out,f_in);
473
474 if (remote_version >= 23)
475 io_start_multiplex_in(f_in);
476
477 if (am_sender) {
478 extern int cvs_exclude;
479 extern int delete_mode;
480 extern int delete_excluded;
481 if (cvs_exclude)
482 add_cvs_excludes();
483 if (delete_mode && !delete_excluded)
484 send_exclude_list(f_out);
485 flist = send_file_list(f_out,argc,argv);
486 if (verbose > 3)
487 rprintf(FINFO,"file list sent\n");
488
489 send_files(flist,f_out,f_in);
490 if (pid != -1) {
491 if (verbose > 3)
492 rprintf(FINFO,"client_run waiting on %d\n",pid);
493 io_flush();
494 wait_process(pid, &status);
495 }
496 if (remote_version >= 24) {
497 /* final goodbye message */
498 read_int(f_in);
499 }
500 report(-1);
501 exit_cleanup(status);
502 }
503
504 if (argc == 0) {
505 extern int list_only;
506 list_only = 1;
507 }
508
509 send_exclude_list(f_out);
510
511 flist = recv_file_list(f_in);
512 if (!flist || flist->count == 0) {
513 rprintf(FINFO,"client: nothing to do\n");
514 exit_cleanup(0);
515 }
516
517 local_name = get_local_name(flist,argv[0]);
518
519 status2 = do_recv(f_in,f_out,flist,local_name);
520
521 if (pid != -1) {
522 if (verbose > 3)
523 rprintf(FINFO,"client_run2 waiting on %d\n",pid);
524 io_flush();
525 wait_process(pid, &status);
526 }
527
528 return status | status2;
529}
530
531static char *find_colon(char *s)
532{
533 char *p, *p2;
534
535 p = strchr(s,':');
536 if (!p) return NULL;
537
538 /* now check to see if there is a / in the string before the : - if there is then
539 discard the colon on the assumption that the : is part of a filename */
540 p2 = strchr(s,'/');
541 if (p2 && p2 < p) return NULL;
542
543 return p;
544}
545
546static int start_client(int argc, char *argv[])
547{
548 char *p;
549 char *shell_machine = NULL;
550 char *shell_path = NULL;
551 char *shell_user = NULL;
552 int pid, ret;
553 int f_in,f_out;
554 extern int local_server;
555 extern int am_sender;
556 extern char *shell_cmd;
557 extern int rsync_port;
558
559 if (strncasecmp(URL_PREFIX, argv[0], strlen(URL_PREFIX)) == 0) {
560 char *host, *path;
561
562 host = argv[0] + strlen(URL_PREFIX);
563 p = strchr(host,'/');
564 if (p) {
565 *p = 0;
566 path = p+1;
567 } else {
568 path="";
569 }
570 p = strchr(host,':');
571 if (p) {
572 rsync_port = atoi(p+1);
573 *p = 0;
574 }
575 return start_socket_client(host, path, argc-1, argv+1);
576 }
577
578 p = find_colon(argv[0]);
579
580 if (p) {
581 if (p[1] == ':') {
582 *p = 0;
583 return start_socket_client(argv[0], p+2, argc-1, argv+1);
584 }
585
586 if (argc < 1) {
587 usage(FERROR);
588 exit_cleanup(RERR_SYNTAX);
589 }
590
591 am_sender = 0;
592 *p = 0;
593 shell_machine = argv[0];
594 shell_path = p+1;
595 argc--;
596 argv++;
597 } else {
598 am_sender = 1;
599
600 p = find_colon(argv[argc-1]);
601 if (!p) {
602 local_server = 1;
603 } else if (p[1] == ':') {
604 *p = 0;
605 return start_socket_client(argv[argc-1], p+2, argc-1, argv);
606 }
607
608 if (argc < 2) {
609 usage(FERROR);
610 exit_cleanup(RERR_SYNTAX);
611 }
612
613 if (local_server) {
614 shell_machine = NULL;
615 shell_path = argv[argc-1];
616 } else {
617 *p = 0;
618 shell_machine = argv[argc-1];
619 shell_path = p+1;
620 }
621 argc--;
622 }
623
624 if (shell_machine) {
625 p = strchr(shell_machine,'@');
626 if (p) {
627 *p = 0;
628 shell_user = shell_machine;
629 shell_machine = p+1;
630 }
631 }
632
633 if (verbose > 3) {
634 rprintf(FINFO,"cmd=%s machine=%s user=%s path=%s\n",
635 shell_cmd?shell_cmd:"",
636 shell_machine?shell_machine:"",
637 shell_user?shell_user:"",
638 shell_path?shell_path:"");
639 }
640
641 if (!am_sender && argc > 1) {
642 usage(FERROR);
643 exit_cleanup(RERR_SYNTAX);
644 }
645
646 if (argc == 0 && !am_sender) {
647 extern int list_only;
648 list_only = 1;
649 }
650
651 pid = do_cmd(shell_cmd,shell_machine,shell_user,shell_path,&f_in,&f_out);
652
653 ret = client_run(f_in, f_out, pid, argc, argv);
654
655 fflush(stdout);
656 fflush(stderr);
657
658 return ret;
659}
660
661
662static RETSIGTYPE sigusr1_handler(int val) {
663 exit_cleanup(RERR_SIGNAL);
664}
665
666static RETSIGTYPE sigusr2_handler(int val) {
667 _exit(0);
668}
669
670int main(int argc,char *argv[])
671{
672 extern int am_root;
673 extern int orig_umask;
674 extern int dry_run;
675 extern int am_daemon;
676 extern int am_server;
677
678 signal(SIGUSR1, sigusr1_handler);
679 signal(SIGUSR2, sigusr2_handler);
680
681 starttime = time(NULL);
682 am_root = (getuid() == 0);
683
684 memset(&stats, 0, sizeof(stats));
685
686 if (argc < 2) {
687 usage(FERROR);
688 exit_cleanup(RERR_SYNTAX);
689 }
690
691 /* we set a 0 umask so that correct file permissions can be
692 carried across */
693 orig_umask = (int)umask(0);
694
695 if (!parse_arguments(argc, argv, 1)) {
696 exit_cleanup(RERR_SYNTAX);
697 }
698
699 argc -= optind;
700 argv += optind;
701 optind = 0;
702
703 signal(SIGCHLD,SIG_IGN);
704 signal(SIGINT,SIGNAL_CAST sig_int);
705 signal(SIGPIPE,SIGNAL_CAST sig_int);
706 signal(SIGHUP,SIGNAL_CAST sig_int);
707 signal(SIGTERM,SIGNAL_CAST sig_int);
708
709 /* Initialize push_dir here because on some old systems getcwd
710 (implemented by forking "pwd" and reading its output) doesn't
711 work when there are other child processes. Also, on all systems
712 that implement getcwd that way "pwd" can't be found after chroot. */
713 push_dir(NULL,0);
714
715 if (am_daemon) {
716 return daemon_main();
717 }
718
719 if (argc < 1) {
720 usage(FERROR);
721 exit_cleanup(RERR_SYNTAX);
722 }
723
724 if (dry_run)
725 verbose = MAX(verbose,1);
726
727#ifndef SUPPORT_LINKS
728 if (!am_server && preserve_links) {
729 rprintf(FERROR,"ERROR: symbolic links not supported\n");
730 exit_cleanup(RERR_UNSUPPORTED);
731 }
732#endif
733
734 if (am_server) {
735 set_nonblocking(STDIN_FILENO);
736 set_nonblocking(STDOUT_FILENO);
737 start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
738 }
739
740 return start_client(argc, argv);
741}
742