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