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