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