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