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