damn!
[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
354 if (verbose > 2)
355 rprintf(FINFO,"server_recv(%d) starting pid=%d\n",argc,(int)getpid());
356
357 if (argc > 0) {
358 dir = argv[0];
359 argc--;
360 argv++;
361 if (!am_daemon && !push_dir(dir, 0)) {
362 rprintf(FERROR,"push_dir %s : %s (4)\n",
363 dir,strerror(errno));
364 exit_cleanup(RERR_FILESELECT);
365 }
366 }
367
368 if (delete_mode && !delete_excluded)
369 recv_exclude_list(f_in);
370
371 flist = recv_file_list(f_in);
372 if (!flist) {
373 rprintf(FERROR,"server_recv: recv_file_list error\n");
374 exit_cleanup(RERR_FILESELECT);
375 }
376
377 if (argc > 0) {
378 if (strcmp(dir,".")) {
379 argv[0] += strlen(dir);
380 if (argv[0][0] == '/') argv[0]++;
381 }
382 local_name = get_local_name(flist,argv[0]);
383 }
384
385 status = do_recv(f_in,f_out,flist,local_name);
386 exit_cleanup(status);
387}
388
389
390void start_server(int f_in, int f_out, int argc, char *argv[])
391{
392 extern int cvs_exclude;
393 extern int am_sender;
394 extern int remote_version;
395
396 setup_protocol(f_out, f_in);
397
398 if (remote_version >= 23)
399 io_start_multiplex_out(f_out);
400
401 if (am_sender) {
402 recv_exclude_list(f_in);
403 if (cvs_exclude)
404 add_cvs_excludes();
405 do_server_sender(f_in, f_out, argc, argv);
406 } else {
407 do_server_recv(f_in, f_out, argc, argv);
408 }
409 exit_cleanup(0);
410}
411
412int client_run(int f_in, int f_out, int pid, int argc, char *argv[])
413{
414 struct file_list *flist;
415 int status = 0, status2 = 0;
416 char *local_name = NULL;
417 extern int am_sender;
418 extern int list_only;
419 extern int remote_version;
420
421 setup_protocol(f_out,f_in);
422
423 if (remote_version >= 23)
424 io_start_multiplex_in(f_in);
425
426 if (am_sender) {
427 extern int cvs_exclude;
428 extern int delete_mode;
429 extern int delete_excluded;
430 if (cvs_exclude)
431 add_cvs_excludes();
432 if (delete_mode && !delete_excluded)
433 send_exclude_list(f_out);
434 flist = send_file_list(f_out,argc,argv);
435 if (verbose > 3)
436 rprintf(FINFO,"file list sent\n");
437
438 send_files(flist,f_out,f_in);
439 if (pid != -1) {
440 if (verbose > 3)
441 rprintf(FINFO,"client_run waiting on %d\n",pid);
442 io_flush();
443 wait_process(pid, &status);
444 }
445 report(-1);
446 exit_cleanup(status);
447 }
448
449 if (argc == 0) list_only = 1;
450
451 send_exclude_list(f_out);
452
453 flist = recv_file_list(f_in);
454 if (!flist || flist->count == 0) {
455 rprintf(FINFO,"client: nothing to do\n");
456 exit_cleanup(0);
457 }
458
459 local_name = get_local_name(flist,argv[0]);
460
461 status2 = do_recv(f_in,f_out,flist,local_name);
462
463 if (pid != -1) {
464 if (verbose > 3)
465 rprintf(FINFO,"client_run2 waiting on %d\n",pid);
466 io_flush();
467 wait_process(pid, &status);
468 }
469
470 return status | status2;
471}
472
473static char *find_colon(char *s)
474{
475 char *p, *p2;
476
477 p = strchr(s,':');
478 if (!p) return NULL;
479
480 /* now check to see if there is a / in the string before the : - if there is then
481 discard the colon on the assumption that the : is part of a filename */
482 p2 = strchr(s,'/');
483 if (p2 && p2 < p) return NULL;
484
485 return p;
486}
487
488static int start_client(int argc, char *argv[])
489{
490 char *p;
491 char *shell_machine = NULL;
492 char *shell_path = NULL;
493 char *shell_user = NULL;
494 int pid, ret;
495 int f_in,f_out;
496 extern int local_server;
497 extern int am_sender;
498 extern char *shell_cmd;
499 extern int rsync_port;
500
501 if (strncasecmp(URL_PREFIX, argv[0], strlen(URL_PREFIX)) == 0) {
502 char *host, *path;
503
504 host = argv[0] + strlen(URL_PREFIX);
505 p = strchr(host,'/');
506 if (p) {
507 *p = 0;
508 path = p+1;
509 } else {
510 path="";
511 }
512 p = strchr(host,':');
513 if (p) {
514 rsync_port = atoi(p+1);
515 *p = 0;
516 }
517 return start_socket_client(host, path, argc-1, argv+1);
518 }
519
520 p = find_colon(argv[0]);
521
522 if (p) {
523 if (p[1] == ':') {
524 *p = 0;
525 return start_socket_client(argv[0], p+2, argc-1, argv+1);
526 }
527
528 if (argc < 1) {
529 usage(FERROR);
530 exit_cleanup(RERR_SYNTAX);
531 }
532
533 am_sender = 0;
534 *p = 0;
535 shell_machine = argv[0];
536 shell_path = p+1;
537 argc--;
538 argv++;
539 } else {
540 am_sender = 1;
541
542 p = find_colon(argv[argc-1]);
543 if (!p) {
544 local_server = 1;
545 } else if (p[1] == ':') {
546 *p = 0;
547 return start_socket_client(argv[argc-1], p+2, argc-1, argv);
548 }
549
550 if (argc < 2) {
551 usage(FERROR);
552 exit_cleanup(RERR_SYNTAX);
553 }
554
555 if (local_server) {
556 shell_machine = NULL;
557 shell_path = argv[argc-1];
558 } else {
559 *p = 0;
560 shell_machine = argv[argc-1];
561 shell_path = p+1;
562 }
563 argc--;
564 }
565
566 if (shell_machine) {
567 p = strchr(shell_machine,'@');
568 if (p) {
569 *p = 0;
570 shell_user = shell_machine;
571 shell_machine = p+1;
572 }
573 }
574
575 if (verbose > 3) {
576 rprintf(FINFO,"cmd=%s machine=%s user=%s path=%s\n",
577 shell_cmd?shell_cmd:"",
578 shell_machine?shell_machine:"",
579 shell_user?shell_user:"",
580 shell_path?shell_path:"");
581 }
582
583 if (!am_sender && argc > 1) {
584 usage(FERROR);
585 exit_cleanup(RERR_SYNTAX);
586 }
587
588 pid = do_cmd(shell_cmd,shell_machine,shell_user,shell_path,&f_in,&f_out);
589
590 ret = client_run(f_in, f_out, pid, argc, argv);
591
592 fflush(stdout);
593 fflush(stderr);
594
595 return ret;
596}
597
598
599static RETSIGTYPE sigusr1_handler(int val) {
600 exit_cleanup(RERR_SIGNAL);
601}
602
603int main(int argc,char *argv[])
604{
605 extern int am_root;
606 extern int orig_umask;
607 extern int dry_run;
608 extern int am_daemon;
609 extern int am_server;
610
611 signal(SIGUSR1, sigusr1_handler);
612
613 starttime = time(NULL);
614 am_root = (getuid() == 0);
615
616 memset(&stats, 0, sizeof(stats));
617
618 if (argc < 2) {
619 usage(FERROR);
620 exit_cleanup(RERR_SYNTAX);
621 }
622
623 /* we set a 0 umask so that correct file permissions can be
624 carried across */
625 orig_umask = (int)umask(0);
626
627 if (!parse_arguments(argc, argv, 1)) {
628 exit_cleanup(RERR_SYNTAX);
629 }
630
631 argc -= optind;
632 argv += optind;
633 optind = 0;
634
635 signal(SIGCHLD,SIG_IGN);
636 signal(SIGINT,SIGNAL_CAST sig_int);
637 signal(SIGPIPE,SIGNAL_CAST sig_int);
638 signal(SIGHUP,SIGNAL_CAST sig_int);
639 signal(SIGTERM,SIGNAL_CAST sig_int);
640
641 /* Initialize push_dir here because on some old systems getcwd
642 (implemented by forking "pwd" and reading its output) doesn't
643 work when there are other child processes. Also, on all systems
644 that implement getcwd that way "pwd" can't be found after chroot. */
645 push_dir(NULL,0);
646
647 if (am_daemon) {
648 return daemon_main();
649 }
650
651 if (argc < 1) {
652 usage(FERROR);
653 exit_cleanup(RERR_SYNTAX);
654 }
655
656 if (dry_run)
657 verbose = MAX(verbose,1);
658
659#ifndef SUPPORT_LINKS
660 if (!am_server && preserve_links) {
661 rprintf(FERROR,"ERROR: symbolic links not supported\n");
662 exit_cleanup(RERR_UNSUPPORTED);
663 }
664#endif
665
666 if (am_server) {
667 start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
668 }
669
670 return start_client(argc, argv);
671}
672