Fix to correctly identify remote IP address and host name when using
[rsync/rsync.git] / main.c
... / ...
CommitLineData
1/* -*- c-file-style: "linux" -*-
2
3 Copyright (C) 1996-2001 by Andrew Tridgell <tridge@samba.org>
4 Copyright (C) Paul Mackerras 1996
5 Copyright (C) 2001, 2002 by Martin Pool <mbp@samba.org>
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20*/
21
22#include "rsync.h"
23
24time_t starttime = 0;
25
26extern struct stats stats;
27extern int verbose;
28
29static void show_malloc_stats(void);
30
31/****************************************************************************
32wait for a process to exit, calling io_flush while waiting
33****************************************************************************/
34void wait_process(pid_t pid, int *status)
35{
36 while (waitpid(pid, status, WNOHANG) == 0) {
37 msleep(20);
38 io_flush();
39 }
40
41 /* TODO: If the child exited on a signal, then log an
42 * appropriate error message. Perhaps we should also accept a
43 * message describing the purpose of the child. Also indicate
44 * this to the caller so that thhey know something went
45 * wrong. */
46 *status = WEXITSTATUS(*status);
47}
48
49static void report(int f)
50{
51 time_t t = time(NULL);
52 extern int am_server;
53 extern int am_sender;
54 extern int am_daemon;
55 extern int do_stats;
56 extern int remote_version;
57 int send_stats;
58
59 if (do_stats) {
60 /* These come out from every process */
61 show_malloc_stats();
62 show_flist_stats();
63 }
64
65 if (am_daemon) {
66 log_exit(0, __FILE__, __LINE__);
67 if (f == -1 || !am_sender) return;
68 }
69
70 send_stats = verbose || (remote_version >= 20);
71 if (am_server) {
72 if (am_sender && send_stats) {
73 int64 w;
74 /* store total_written in a temporary
75 because write_longint changes it */
76 w = stats.total_written;
77 write_longint(f,stats.total_read);
78 write_longint(f,w);
79 write_longint(f,stats.total_size);
80 }
81 return;
82 }
83
84 /* this is the client */
85
86 if (!am_sender && send_stats) {
87 int64 r;
88 stats.total_written = read_longint(f);
89 /* store total_read in a temporary, read_longint changes it */
90 r = read_longint(f);
91 stats.total_size = read_longint(f);
92 stats.total_read = r;
93 }
94
95 if (do_stats) {
96 if (!am_sender && !send_stats) {
97 /* missing the bytes written by the generator */
98 rprintf(FINFO, "\nCannot show stats as receiver because remote protocol version is less than 20\n");
99 rprintf(FINFO, "Use --stats -v to show stats\n");
100 return;
101 }
102 rprintf(FINFO,"\nNumber of files: %d\n", stats.num_files);
103 rprintf(FINFO,"Number of files transferred: %d\n",
104 stats.num_transferred_files);
105 rprintf(FINFO,"Total file size: %.0f bytes\n",
106 (double)stats.total_size);
107 rprintf(FINFO,"Total transferred file size: %.0f bytes\n",
108 (double)stats.total_transferred_size);
109 rprintf(FINFO,"Literal data: %.0f bytes\n",
110 (double)stats.literal_data);
111 rprintf(FINFO,"Matched data: %.0f bytes\n",
112 (double)stats.matched_data);
113 rprintf(FINFO,"File list size: %d\n", stats.flist_size);
114 rprintf(FINFO,"Total bytes written: %.0f\n",
115 (double)stats.total_written);
116 rprintf(FINFO,"Total bytes read: %.0f\n\n",
117 (double)stats.total_read);
118 }
119
120 if (verbose || do_stats) {
121 rprintf(FINFO,"wrote %.0f bytes read %.0f bytes %.2f bytes/sec\n",
122 (double)stats.total_written,
123 (double)stats.total_read,
124 (stats.total_written+stats.total_read)/(0.5 + (t-starttime)));
125 rprintf(FINFO,"total size is %.0f speedup is %.2f\n",
126 (double)stats.total_size,
127 (1.0*stats.total_size)/(stats.total_written+stats.total_read));
128 }
129
130 fflush(stdout);
131 fflush(stderr);
132}
133
134
135/**
136 * If our C library can get malloc statistics, then show them to FINFO
137 **/
138static void show_malloc_stats(void)
139{
140#ifdef HAVE_MALLINFO
141 struct mallinfo mi;
142 extern int am_server;
143 extern int am_sender;
144 extern int am_daemon;
145
146 mi = mallinfo();
147
148 rprintf(FINFO, RSYNC_NAME "[%d] (%s%s%s) heap statistics:\n",
149 getpid(),
150 am_server ? "server " : "",
151 am_daemon ? "daemon " : "",
152 am_sender ? "sender" : "receiver");
153 rprintf(FINFO, " arena: %10d (bytes from sbrk)\n", mi.arena);
154 rprintf(FINFO, " ordblks: %10d (chunks not in use)\n", mi.ordblks);
155 rprintf(FINFO, " smblks: %10d\n", mi.smblks);
156 rprintf(FINFO, " hblks: %10d (chunks from mmap)\n", mi.hblks);
157 rprintf(FINFO, " hblkhd: %10d (bytes from mmap)\n", mi.hblkhd);
158 rprintf(FINFO, " usmblks: %10d\n", mi.usmblks);
159 rprintf(FINFO, " fsmblks: %10d\n", mi.fsmblks);
160 rprintf(FINFO, " uordblks: %10d (bytes used)\n", mi.uordblks);
161 rprintf(FINFO, " fordblks: %10d (bytes free)\n", mi.fordblks);
162 rprintf(FINFO, " keepcost: %10d (bytes in releasable chunk)\n", mi.keepcost);
163#endif /* HAVE_MALLINFO */
164}
165
166
167/* Start the remote shell. cmd may be NULL to use the default. */
168static pid_t do_cmd(char *cmd,char *machine,char *user,char *path,int *f_in,int *f_out)
169{
170 char *args[100];
171 int i,argc=0;
172 pid_t ret;
173 char *tok,*dir=NULL;
174 extern int local_server;
175 extern char *rsync_path;
176 extern int blocking_io;
177 extern int daemon_over_rsh;
178 extern int read_batch;
179
180 if (!read_batch && !local_server) {
181 if (!cmd)
182 cmd = getenv(RSYNC_RSH_ENV);
183 if (!cmd)
184 cmd = RSYNC_RSH;
185 cmd = strdup(cmd);
186 if (!cmd)
187 goto oom;
188
189 for (tok=strtok(cmd," ");tok;tok=strtok(NULL," ")) {
190 args[argc++] = tok;
191 }
192
193#if HAVE_REMSH
194 /* remsh (on HPUX) takes the arguments the other way around */
195 args[argc++] = machine;
196 if (user) {
197 args[argc++] = "-l";
198 args[argc++] = user;
199 }
200#else
201 if (user) {
202 args[argc++] = "-l";
203 args[argc++] = user;
204 }
205 args[argc++] = machine;
206#endif
207
208 args[argc++] = rsync_path;
209
210 if ((blocking_io == -1) && (strcmp(cmd, RSYNC_RSH) == 0))
211 blocking_io = 1;
212
213 server_options(args,&argc);
214
215 }
216
217 args[argc++] = ".";
218
219 if (!daemon_over_rsh && path && *path)
220 args[argc++] = path;
221
222 args[argc] = NULL;
223
224 if (verbose > 3) {
225 rprintf(FINFO,"cmd=");
226 for (i=0;i<argc;i++)
227 rprintf(FINFO,"%s ",args[i]);
228 rprintf(FINFO,"\n");
229 }
230
231 if (local_server) {
232 if (read_batch)
233 create_flist_from_batch(); /* sets batch_flist */
234 ret = local_child(argc, args, f_in, f_out, child_main);
235 } else {
236 ret = piped_child(args,f_in,f_out);
237 }
238
239 if (dir) free(dir);
240
241 return ret;
242
243oom:
244 out_of_memory("do_cmd");
245 return 0; /* not reached */
246}
247
248
249
250
251static char *get_local_name(struct file_list *flist,char *name)
252{
253 STRUCT_STAT st;
254 extern int orig_umask;
255
256 if (verbose > 2)
257 rprintf(FINFO,"get_local_name count=%d %s\n",
258 flist->count, NS(name));
259
260 if (!name)
261 return NULL;
262
263 if (do_stat(name,&st) == 0) {
264 if (S_ISDIR(st.st_mode)) {
265 if (!push_dir(name, 0)) {
266 rprintf(FERROR,"push_dir %s : %s (1)\n",
267 name,strerror(errno));
268 exit_cleanup(RERR_FILESELECT);
269 }
270 return NULL;
271 }
272 if (flist->count > 1) {
273 rprintf(FERROR,"ERROR: destination must be a directory when copying more than 1 file\n");
274 exit_cleanup(RERR_FILESELECT);
275 }
276 return name;
277 }
278
279 if (flist->count <= 1)
280 return name;
281
282 if (do_mkdir(name,0777 & ~orig_umask) != 0) {
283 rprintf(FERROR, RSYNC_NAME ": mkdir %s: %s\n",
284 name, strerror(errno));
285 exit_cleanup(RERR_FILEIO);
286 } else {
287 if (verbose > 0)
288 rprintf(FINFO,"created directory %s\n",name);
289 }
290
291 if (!push_dir(name, 0)) {
292 rprintf(FERROR, RSYNC_NAME ": push_dir %s: %s\n",
293 name, strerror(errno));
294 exit_cleanup(RERR_FILESELECT);
295 }
296
297 return NULL;
298}
299
300
301
302
303static void do_server_sender(int f_in, int f_out, int argc,char *argv[])
304{
305 int i;
306 struct file_list *flist;
307 char *dir = argv[0];
308 extern int relative_paths;
309 extern int recurse;
310 extern int remote_version;
311
312 if (verbose > 2)
313 rprintf(FINFO,"server_sender starting pid=%d\n",(int)getpid());
314
315 if (!relative_paths && !push_dir(dir, 0)) {
316 rprintf(FERROR,"push_dir %s: %s (3)\n",dir,strerror(errno));
317 exit_cleanup(RERR_FILESELECT);
318 }
319 argc--;
320 argv++;
321
322 if (strcmp(dir,".")) {
323 int l = strlen(dir);
324 if (strcmp(dir,"/") == 0)
325 l = 0;
326 for (i=0;i<argc;i++)
327 argv[i] += l+1;
328 }
329
330 if (argc == 0 && recurse) {
331 argc=1;
332 argv--;
333 argv[0] = ".";
334 }
335
336 flist = send_file_list(f_out,argc,argv);
337 if (!flist || flist->count == 0) {
338 exit_cleanup(0);
339 }
340
341 send_files(flist,f_out,f_in);
342 io_flush();
343 report(f_out);
344 if (remote_version >= 24) {
345 /* final goodbye message */
346 read_int(f_in);
347 }
348 io_flush();
349 exit_cleanup(0);
350}
351
352
353static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
354{
355 int pid;
356 int status=0;
357 int recv_pipe[2];
358 int error_pipe[2];
359 extern int preserve_hard_links;
360 extern int delete_after;
361 extern int recurse;
362 extern int delete_mode;
363 extern int remote_version;
364
365 if (preserve_hard_links)
366 init_hard_links(flist);
367
368 if (!delete_after) {
369 /* I moved this here from recv_files() to prevent a race condition */
370 if (recurse && delete_mode && !local_name && flist->count>0) {
371 delete_files(flist);
372 }
373 }
374
375 if (fd_pair(recv_pipe) < 0) {
376 rprintf(FERROR,"pipe failed in do_recv\n");
377 exit_cleanup(RERR_SOCKETIO);
378 }
379
380 if (fd_pair(error_pipe) < 0) {
381 rprintf(FERROR,"error pipe failed in do_recv\n");
382 exit_cleanup(RERR_SOCKETIO);
383 }
384
385 io_flush();
386
387 if ((pid=do_fork()) == 0) {
388 close(recv_pipe[0]);
389 close(error_pipe[0]);
390 if (f_in != f_out) close(f_out);
391
392 /* we can't let two processes write to the socket at one time */
393 io_multiplexing_close();
394
395 /* set place to send errors */
396 set_error_fd(error_pipe[1]);
397
398 recv_files(f_in,flist,local_name,recv_pipe[1]);
399 io_flush();
400 report(f_in);
401
402 write_int(recv_pipe[1],1);
403 close(recv_pipe[1]);
404 io_flush();
405 /* finally we go to sleep until our parent kills us
406 with a USR2 signal. We sleep for a short time as on
407 some OSes a signal won't interrupt a sleep! */
408 while (msleep(20))
409 ;
410 }
411
412 close(recv_pipe[1]);
413 close(error_pipe[1]);
414 if (f_in != f_out) close(f_in);
415
416 io_start_buffering(f_out);
417
418 io_set_error_fd(error_pipe[0]);
419
420 generate_files(f_out,flist,local_name,recv_pipe[0]);
421
422 read_int(recv_pipe[0]);
423 close(recv_pipe[0]);
424 if (remote_version >= 24) {
425 /* send a final goodbye message */
426 write_int(f_out, -1);
427 }
428 io_flush();
429
430 kill(pid, SIGUSR2);
431 wait_process(pid, &status);
432 return status;
433}
434
435
436static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
437{
438 int status;
439 struct file_list *flist;
440 char *local_name=NULL;
441 char *dir = NULL;
442 extern int delete_mode;
443 extern int delete_excluded;
444 extern int am_daemon;
445 extern int module_id;
446 extern int am_sender;
447 extern int read_batch;
448 extern struct file_list *batch_flist;
449
450 if (verbose > 2)
451 rprintf(FINFO,"server_recv(%d) starting pid=%d\n",argc,(int)getpid());
452
453 if (am_daemon && lp_read_only(module_id) && !am_sender) {
454 rprintf(FERROR,"ERROR: module is read only\n");
455 exit_cleanup(RERR_SYNTAX);
456 return;
457 }
458
459
460 if (argc > 0) {
461 dir = argv[0];
462 argc--;
463 argv++;
464 if (!am_daemon && !push_dir(dir, 0)) {
465 rprintf(FERROR,"push_dir %s : %s (4)\n",
466 dir,strerror(errno));
467 exit_cleanup(RERR_FILESELECT);
468 }
469 }
470
471 if (delete_mode && !delete_excluded)
472 recv_exclude_list(f_in);
473
474 if (read_batch)
475 flist = batch_flist;
476 else
477 flist = recv_file_list(f_in);
478 if (!flist) {
479 rprintf(FERROR,"server_recv: recv_file_list error\n");
480 exit_cleanup(RERR_FILESELECT);
481 }
482
483 if (argc > 0) {
484 if (strcmp(dir,".")) {
485 argv[0] += strlen(dir);
486 if (argv[0][0] == '/') argv[0]++;
487 }
488 local_name = get_local_name(flist,argv[0]);
489 }
490
491 status = do_recv(f_in,f_out,flist,local_name);
492 exit_cleanup(status);
493}
494
495
496int child_main(int argc, char *argv[])
497{
498 start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
499 return 0;
500}
501
502
503void start_server(int f_in, int f_out, int argc, char *argv[])
504{
505 extern int cvs_exclude;
506 extern int am_sender;
507 extern int remote_version;
508 extern int read_batch;
509
510 setup_protocol(f_out, f_in);
511
512 set_nonblocking(f_in);
513 set_nonblocking(f_out);
514
515 if (remote_version >= 23)
516 io_start_multiplex_out(f_out);
517
518 if (am_sender) {
519 if (!read_batch) {
520 recv_exclude_list(f_in);
521 if (cvs_exclude)
522 add_cvs_excludes();
523 }
524 do_server_sender(f_in, f_out, argc, argv);
525 } else {
526 do_server_recv(f_in, f_out, argc, argv);
527 }
528 exit_cleanup(0);
529}
530
531
532/*
533 * This is called once the connection has been negotiated. It is used
534 * for rsyncd, remote-shell, and local connections.
535 */
536int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[])
537{
538 struct file_list *flist = NULL;
539 int status = 0, status2 = 0;
540 char *local_name = NULL;
541 extern int am_sender;
542 extern int remote_version;
543 extern pid_t cleanup_child_pid;
544 extern int write_batch;
545 extern int read_batch;
546 extern struct file_list *batch_flist;
547
548 cleanup_child_pid = pid;
549 if (read_batch)
550 flist = batch_flist;
551
552 set_nonblocking(f_in);
553 set_nonblocking(f_out);
554
555 setup_protocol(f_out,f_in);
556
557 if (remote_version >= 23)
558 io_start_multiplex_in(f_in);
559
560 if (am_sender) {
561 extern int cvs_exclude;
562 extern int delete_mode;
563 extern int delete_excluded;
564 if (cvs_exclude)
565 add_cvs_excludes();
566 if (delete_mode && !delete_excluded)
567 send_exclude_list(f_out);
568 if (!read_batch) /* dw -- don't write to pipe */
569 flist = send_file_list(f_out,argc,argv);
570 if (verbose > 3)
571 rprintf(FINFO,"file list sent\n");
572
573 send_files(flist,f_out,f_in);
574 if (remote_version >= 24) {
575 /* final goodbye message */
576 read_int(f_in);
577 }
578 if (pid != -1) {
579 if (verbose > 3)
580 rprintf(FINFO,"client_run waiting on %d\n", (int) pid);
581 io_flush();
582 wait_process(pid, &status);
583 }
584 report(-1);
585 exit_cleanup(status);
586 }
587
588 if (argc == 0) {
589 extern int list_only;
590 list_only = 1;
591 }
592
593 if (!write_batch)
594 send_exclude_list(f_out);
595
596 flist = recv_file_list(f_in);
597 if (!flist || flist->count == 0) {
598 rprintf(FINFO, "client: nothing to do: "
599 "perhaps you need to specify some filenames or "
600 "the --recursive option?\n");
601 exit_cleanup(0);
602 }
603
604 local_name = get_local_name(flist,argv[0]);
605
606 status2 = do_recv(f_in,f_out,flist,local_name);
607
608 if (pid != -1) {
609 if (verbose > 3)
610 rprintf(FINFO,"client_run2 waiting on %d\n", (int) pid);
611 io_flush();
612 wait_process(pid, &status);
613 }
614
615 return MAX(status, status2);
616}
617
618static char *find_colon(char *s)
619{
620 char *p, *p2;
621
622 p = strchr(s,':');
623 if (!p) return NULL;
624
625 /* now check to see if there is a / in the string before the : - if there is then
626 discard the colon on the assumption that the : is part of a filename */
627 p2 = strchr(s,'/');
628 if (p2 && p2 < p) return NULL;
629
630 return p;
631}
632
633
634static int copy_argv (char *argv[])
635{
636 int i;
637
638 for (i = 0; argv[i]; i++) {
639 if (!(argv[i] = strdup(argv[i]))) {
640 rprintf (FERROR, "out of memory at %s(%d)\n",
641 __FILE__, __LINE__);
642 return RERR_MALLOC;
643 }
644 }
645
646 return 0;
647}
648
649
650/**
651 * Start a client for either type of remote connection. Work out
652 * whether the arguments request a remote shell or rsyncd connection,
653 * and call the appropriate connection function, then run_client.
654 *
655 * Calls either start_socket_client (for sockets) or do_cmd and
656 * client_run (for ssh).
657 **/
658static int start_client(int argc, char *argv[])
659{
660 char *p;
661 char *shell_machine = NULL;
662 char *shell_path = NULL;
663 char *shell_user = NULL;
664 int ret;
665 pid_t pid;
666 int f_in,f_out;
667 extern int local_server;
668 extern int am_sender;
669 extern char *shell_cmd;
670 extern int rsync_port;
671 extern int daemon_over_rsh;
672 extern int read_batch;
673 int rc;
674
675 /* Don't clobber argv[] so that ps(1) can still show the right
676 command line. */
677 if ((rc = copy_argv(argv)))
678 return rc;
679
680 /* rsync:// always uses rsync server over direct socket connection */
681 if (strncasecmp(URL_PREFIX, argv[0], strlen(URL_PREFIX)) == 0) {
682 char *host, *path;
683
684 host = argv[0] + strlen(URL_PREFIX);
685 p = strchr(host,'/');
686 if (p) {
687 *p = 0;
688 path = p+1;
689 } else {
690 path = "";
691 }
692 p = strchr(host,':');
693 if (p) {
694 rsync_port = atoi(p+1);
695 *p = 0;
696 }
697 return start_socket_client(host, path, argc-1, argv+1);
698 }
699
700 if (!read_batch) {
701 p = find_colon(argv[0]);
702
703 if (p) {
704 if (p[1] == ':') { /* double colon */
705 *p = 0;
706 if (!shell_cmd) {
707 return start_socket_client(argv[0], p+2,
708 argc-1, argv+1);
709 }
710 p++;
711 daemon_over_rsh = 1;
712 }
713
714 if (argc < 1) {
715 usage(FERROR);
716 exit_cleanup(RERR_SYNTAX);
717 }
718
719 am_sender = 0;
720 *p = 0;
721 shell_machine = argv[0];
722 shell_path = p+1;
723 argc--;
724 argv++;
725 } else {
726 am_sender = 1;
727
728 /* rsync:// destination uses rsync server over direct socket */
729 if (strncasecmp(URL_PREFIX, argv[argc-1], strlen(URL_PREFIX)) == 0) {
730 char *host, *path;
731
732 host = argv[argc-1] + strlen(URL_PREFIX);
733 p = strchr(host,'/');
734 if (p) {
735 *p = 0;
736 path = p+1;
737 } else {
738 path = "";
739 }
740 p = strchr(host,':');
741 if (p) {
742 rsync_port = atoi(p+1);
743 *p = 0;
744 }
745 return start_socket_client(host, path, argc-1, argv);
746 }
747
748 p = find_colon(argv[argc-1]);
749 if (!p) {
750 local_server = 1;
751 } else if (p[1] == ':') { /* double colon */
752 *p = 0;
753 if (!shell_cmd) {
754 return start_socket_client(argv[argc-1], p+2,
755 argc-1, argv);
756 }
757 p++;
758 daemon_over_rsh = 1;
759 }
760
761 if (argc < 2) {
762 usage(FERROR);
763 exit_cleanup(RERR_SYNTAX);
764 }
765
766 if (local_server) {
767 shell_machine = NULL;
768 shell_path = argv[argc-1];
769 } else {
770 *p = 0;
771 shell_machine = argv[argc-1];
772 shell_path = p+1;
773 }
774 argc--;
775 }
776 } else {
777 am_sender = 1;
778 local_server = 1;
779 shell_path = argv[argc-1];
780 }
781
782 if (shell_machine) {
783 p = strchr(shell_machine,'@');
784 if (p) {
785 *p = 0;
786 shell_user = shell_machine;
787 shell_machine = p+1;
788 }
789 }
790
791 if (verbose > 3) {
792 rprintf(FINFO,"cmd=%s machine=%s user=%s path=%s\n",
793 shell_cmd?shell_cmd:"",
794 shell_machine?shell_machine:"",
795 shell_user?shell_user:"",
796 shell_path?shell_path:"");
797 }
798
799 if (!am_sender && argc > 1) {
800 usage(FERROR);
801 exit_cleanup(RERR_SYNTAX);
802 }
803
804 if (argc == 0 && !am_sender) {
805 extern int list_only;
806 list_only = 1;
807 }
808
809 pid = do_cmd(shell_cmd,shell_machine,shell_user,shell_path,
810 &f_in,&f_out);
811
812 /* if we're running an rsync server on the remote host over a
813 remote shell command, we need to do the RSYNCD protocol first */
814 if (daemon_over_rsh) {
815 int tmpret;
816 tmpret = start_inband_exchange(shell_user, shell_path,
817 f_in, f_out, argc);
818 if (tmpret < 0)
819 return tmpret;
820 }
821
822 ret = client_run(f_in, f_out, pid, argc, argv);
823
824 fflush(stdout);
825 fflush(stderr);
826
827 return ret;
828}
829
830
831static RETSIGTYPE sigusr1_handler(int UNUSED(val)) {
832 exit_cleanup(RERR_SIGNAL);
833}
834
835static RETSIGTYPE sigusr2_handler(int UNUSED(val)) {
836 extern int log_got_error;
837 if (log_got_error) _exit(RERR_PARTIAL);
838 _exit(0);
839}
840
841static RETSIGTYPE sigchld_handler(int UNUSED(val)) {
842#ifdef WNOHANG
843 while (waitpid(-1, NULL, WNOHANG) > 0) ;
844#endif
845}
846
847
848/**
849 * This routine catches signals and tries to send them to gdb.
850 *
851 * Because it's called from inside a signal handler it ought not to
852 * use too many library routines.
853 *
854 * @todo Perhaps use "screen -X" instead/as well, to help people
855 * debugging without easy access to X. Perhaps use an environment
856 * variable, or just call a script?
857 *
858 * @todo The /proc/ magic probably only works on Linux (and
859 * Solaris?) Can we be more portable?
860 **/
861#ifdef MAINTAINER_MODE
862const char *get_panic_action(void)
863{
864 const char *cmd_fmt = getenv("RSYNC_PANIC_ACTION");
865
866 if (cmd_fmt)
867 return cmd_fmt;
868 else
869 return "xterm -display :0 -T Panic -n Panic "
870 "-e gdb /proc/%d/exe %d";
871}
872
873
874/**
875 * Handle a fatal signal by launching a debugger, controlled by $RSYNC_PANIC_ACTION.
876 *
877 * This signal handler is only installed if we were configured with
878 * --enable-maintainer-mode. Perhaps it should always be on and we
879 * should just look at the environment variable, but I'm a bit leery
880 * of a signal sending us into a busy loop.
881 **/
882static RETSIGTYPE rsync_panic_handler(int UNUSED(whatsig))
883{
884 char cmd_buf[300];
885 int ret;
886
887 sprintf(cmd_buf, get_panic_action(),
888 getpid(), getpid());
889
890 /* Unless we failed to execute gdb, we allow the process to
891 * continue. I'm not sure if that's right. */
892 ret = system(cmd_buf);
893 if (ret)
894 _exit(ret);
895}
896#endif
897
898
899int main(int argc,char *argv[])
900{
901 extern int am_root;
902 extern int orig_umask;
903 extern int dry_run;
904 extern int am_daemon;
905 extern int am_server;
906 int ret;
907 extern int write_batch;
908 int orig_argc;
909 char **orig_argv;
910
911 orig_argc = argc;
912 orig_argv = argv;
913
914 signal(SIGUSR1, sigusr1_handler);
915 signal(SIGUSR2, sigusr2_handler);
916 signal(SIGCHLD, sigchld_handler);
917#ifdef MAINTAINER_MODE
918 signal(SIGSEGV, rsync_panic_handler);
919 signal(SIGFPE, rsync_panic_handler);
920 signal(SIGABRT, rsync_panic_handler);
921 signal(SIGBUS, rsync_panic_handler);
922#endif /* def MAINTAINER_MODE */
923
924 starttime = time(NULL);
925 am_root = (getuid() == 0);
926
927 memset(&stats, 0, sizeof(stats));
928
929 if (argc < 2) {
930 usage(FERROR);
931 exit_cleanup(RERR_SYNTAX);
932 }
933
934 /* we set a 0 umask so that correct file permissions can be
935 carried across */
936 orig_umask = (int)umask(0);
937
938 if (!parse_arguments(&argc, (const char ***) &argv, 1)) {
939 /* FIXME: We ought to call the same error-handling
940 * code here, rather than relying on getopt. */
941 option_error();
942 exit_cleanup(RERR_SYNTAX);
943 }
944
945 signal(SIGINT,SIGNAL_CAST sig_int);
946 signal(SIGHUP,SIGNAL_CAST sig_int);
947 signal(SIGTERM,SIGNAL_CAST sig_int);
948
949 /* Ignore SIGPIPE; we consistently check error codes and will
950 * see the EPIPE. */
951 signal(SIGPIPE, SIG_IGN);
952
953 /* Initialize push_dir here because on some old systems getcwd
954 (implemented by forking "pwd" and reading its output) doesn't
955 work when there are other child processes. Also, on all systems
956 that implement getcwd that way "pwd" can't be found after chroot. */
957 push_dir(NULL,0);
958
959 if (write_batch && !am_server) {
960 write_batch_argvs_file(orig_argc, orig_argv);
961 }
962
963 if (am_daemon && !am_server)
964 return daemon_main();
965
966 if (argc < 1) {
967 usage(FERROR);
968 exit_cleanup(RERR_SYNTAX);
969 }
970
971 if (dry_run)
972 verbose = MAX(verbose,1);
973
974#ifndef SUPPORT_LINKS
975 if (!am_server && preserve_links) {
976 rprintf(FERROR,"ERROR: symbolic links not supported\n");
977 exit_cleanup(RERR_UNSUPPORTED);
978 }
979#endif
980
981 if (am_server) {
982 set_nonblocking(STDIN_FILENO);
983 set_nonblocking(STDOUT_FILENO);
984 if (am_daemon)
985 return start_daemon(STDIN_FILENO, STDOUT_FILENO);
986 start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
987 }
988
989 ret = start_client(argc, argv);
990 if (ret == -1)
991 exit_cleanup(RERR_STARTCLIENT);
992 else
993 exit_cleanup(ret);
994
995 exit(ret);
996 /* NOTREACHED */
997}