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