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