don't use stderr after we become a daemon
[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
284 if (preserve_hard_links)
285 init_hard_links(flist);
286
287 if (pipe(recv_pipe) < 0) {
288 rprintf(FERROR,"pipe failed in do_recv\n");
289 exit_cleanup(RERR_SOCKETIO);
290 }
291
292 if (pipe(error_pipe) < 0) {
293 rprintf(FERROR,"error 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 close(error_pipe[0]);
302 if (f_in != f_out) close(f_out);
303
304 /* we can't let two processes write to the socket at one time */
305 io_multiplexing_close();
306
307 /* set place to send errors */
308 set_error_fd(error_pipe[1]);
309
310 recv_files(f_in,flist,local_name,recv_pipe[1]);
311 report(f_in);
312
313 io_flush();
314 _exit(0);
315 }
316
317 close(recv_pipe[1]);
318 close(error_pipe[1]);
319 io_close_input(f_in);
320 if (f_in != f_out) close(f_in);
321
322 io_start_buffering(f_out);
323
324 io_set_error_fd(error_pipe[0]);
325
326 generate_files(f_out,flist,local_name,recv_pipe[0]);
327
328 io_flush();
329 wait_process(pid, &status);
330 return status;
331}
332
333
334static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
335{
336 int status;
337 struct file_list *flist;
338 char *local_name=NULL;
339 char *dir = NULL;
340 extern int delete_mode;
341 extern int delete_excluded;
342 extern int am_daemon;
343
344 if (verbose > 2)
345 rprintf(FINFO,"server_recv(%d) starting pid=%d\n",argc,(int)getpid());
346
347 if (argc > 0) {
348 dir = argv[0];
349 argc--;
350 argv++;
351 if (!am_daemon && !push_dir(dir, 0)) {
352 rprintf(FERROR,"push_dir %s : %s (4)\n",
353 dir,strerror(errno));
354 exit_cleanup(RERR_FILESELECT);
355 }
356 }
357
358 if (delete_mode && !delete_excluded)
359 recv_exclude_list(f_in);
360
361 flist = recv_file_list(f_in);
362 if (!flist) {
363 rprintf(FERROR,"server_recv: recv_file_list error\n");
364 exit_cleanup(RERR_FILESELECT);
365 }
366
367 if (argc > 0) {
368 if (strcmp(dir,".")) {
369 argv[0] += strlen(dir);
370 if (argv[0][0] == '/') argv[0]++;
371 }
372 local_name = get_local_name(flist,argv[0]);
373 }
374
375 status = do_recv(f_in,f_out,flist,local_name);
376 exit_cleanup(status);
377}
378
379
380void start_server(int f_in, int f_out, int argc, char *argv[])
381{
382 extern int cvs_exclude;
383 extern int am_sender;
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 send_files(flist,f_out,f_in);
421 if (pid != -1) {
422 if (verbose > 3)
423 rprintf(FINFO,"client_run waiting on %d\n",pid);
424 io_flush();
425 wait_process(pid, &status);
426 }
427 report(-1);
428 exit_cleanup(status);
429 }
430
431 if (argc == 0) list_only = 1;
432
433 send_exclude_list(f_out);
434
435 flist = recv_file_list(f_in);
436 if (!flist || flist->count == 0) {
437 rprintf(FINFO,"client: nothing to do\n");
438 exit_cleanup(0);
439 }
440
441 local_name = get_local_name(flist,argv[0]);
442
443 status2 = do_recv(f_in,f_out,flist,local_name);
444
445 if (pid != -1) {
446 if (verbose > 3)
447 rprintf(FINFO,"client_run2 waiting on %d\n",pid);
448 io_flush();
449 wait_process(pid, &status);
450 }
451
452 return status | status2;
453}
454
455static char *find_colon(char *s)
456{
457 char *p, *p2;
458
459 p = strchr(s,':');
460 if (!p) return NULL;
461
462 /* now check to see if there is a / in the string before the : - if there is then
463 discard the colon on the assumption that the : is part of a filename */
464 p2 = strchr(s,'/');
465 if (p2 && p2 < p) return NULL;
466
467 return p;
468}
469
470static int start_client(int argc, char *argv[])
471{
472 char *p;
473 char *shell_machine = NULL;
474 char *shell_path = NULL;
475 char *shell_user = NULL;
476 int pid, ret;
477 int f_in,f_out;
478 extern int local_server;
479 extern int am_sender;
480 extern char *shell_cmd;
481 extern int rsync_port;
482
483 if (strncasecmp(URL_PREFIX, argv[0], strlen(URL_PREFIX)) == 0) {
484 char *host, *path;
485
486 host = argv[0] + strlen(URL_PREFIX);
487 p = strchr(host,'/');
488 if (p) {
489 *p = 0;
490 path = p+1;
491 } else {
492 path="";
493 }
494 p = strchr(host,':');
495 if (p) {
496 rsync_port = atoi(p+1);
497 *p = 0;
498 }
499 return start_socket_client(host, path, argc-1, argv+1);
500 }
501
502 p = find_colon(argv[0]);
503
504 if (p) {
505 if (p[1] == ':') {
506 *p = 0;
507 return start_socket_client(argv[0], p+2, argc-1, argv+1);
508 }
509
510 if (argc < 1) {
511 usage(FERROR);
512 exit_cleanup(RERR_SYNTAX);
513 }
514
515 am_sender = 0;
516 *p = 0;
517 shell_machine = argv[0];
518 shell_path = p+1;
519 argc--;
520 argv++;
521 } else {
522 am_sender = 1;
523
524 p = find_colon(argv[argc-1]);
525 if (!p) {
526 local_server = 1;
527 } else if (p[1] == ':') {
528 *p = 0;
529 return start_socket_client(argv[argc-1], p+2, argc-1, argv);
530 }
531
532 if (argc < 2) {
533 usage(FERROR);
534 exit_cleanup(RERR_SYNTAX);
535 }
536
537 if (local_server) {
538 shell_machine = NULL;
539 shell_path = argv[argc-1];
540 } else {
541 *p = 0;
542 shell_machine = argv[argc-1];
543 shell_path = p+1;
544 }
545 argc--;
546 }
547
548 if (shell_machine) {
549 p = strchr(shell_machine,'@');
550 if (p) {
551 *p = 0;
552 shell_user = shell_machine;
553 shell_machine = p+1;
554 }
555 }
556
557 if (verbose > 3) {
558 rprintf(FINFO,"cmd=%s machine=%s user=%s path=%s\n",
559 shell_cmd?shell_cmd:"",
560 shell_machine?shell_machine:"",
561 shell_user?shell_user:"",
562 shell_path?shell_path:"");
563 }
564
565 if (!am_sender && argc > 1) {
566 usage(FERROR);
567 exit_cleanup(RERR_SYNTAX);
568 }
569
570 pid = do_cmd(shell_cmd,shell_machine,shell_user,shell_path,&f_in,&f_out);
571
572 ret = client_run(f_in, f_out, pid, argc, argv);
573
574 fflush(stdout);
575 fflush(stderr);
576
577 return ret;
578}
579
580
581static RETSIGTYPE sigusr1_handler(int val) {
582 exit_cleanup(RERR_SIGNAL);
583}
584
585int main(int argc,char *argv[])
586{
587 extern int am_root;
588 extern int orig_umask;
589 extern int dry_run;
590 extern int am_daemon;
591 extern int am_server;
592
593 signal(SIGUSR1, sigusr1_handler);
594
595 starttime = time(NULL);
596 am_root = (getuid() == 0);
597
598 memset(&stats, 0, sizeof(stats));
599
600 if (argc < 2) {
601 usage(FERROR);
602 exit_cleanup(RERR_SYNTAX);
603 }
604
605 /* we set a 0 umask so that correct file permissions can be
606 carried across */
607 orig_umask = (int)umask(0);
608
609 if (!parse_arguments(argc, argv, 1)) {
610 exit_cleanup(RERR_SYNTAX);
611 }
612
613 argc -= optind;
614 argv += optind;
615 optind = 0;
616
617 signal(SIGCHLD,SIG_IGN);
618 signal(SIGINT,SIGNAL_CAST sig_int);
619 signal(SIGPIPE,SIGNAL_CAST sig_int);
620 signal(SIGHUP,SIGNAL_CAST sig_int);
621 signal(SIGTERM,SIGNAL_CAST sig_int);
622
623 /* Initialize push_dir here because on some old systems getcwd
624 (implemented by forking "pwd" and reading its output) doesn't
625 work when there are other child processes. Also, on all systems
626 that implement getcwd that way "pwd" can't be found after chroot. */
627 push_dir(NULL,0);
628
629 if (am_daemon) {
630 return daemon_main();
631 }
632
633 if (argc < 1) {
634 usage(FERROR);
635 exit_cleanup(RERR_SYNTAX);
636 }
637
638 if (dry_run)
639 verbose = MAX(verbose,1);
640
641#ifndef SUPPORT_LINKS
642 if (!am_server && preserve_links) {
643 rprintf(FERROR,"ERROR: symbolic links not supported\n");
644 exit_cleanup(RERR_UNSUPPORTED);
645 }
646#endif
647
648 if (am_server) {
649 start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
650 }
651
652 return start_client(argc, argv);
653}
654