Moved the end of start_socket_client() into a new function called
[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 read_batch;
178
179 if (!read_batch && !local_server) {
180 if (!cmd)
181 cmd = getenv(RSYNC_RSH_ENV);
182 if (!cmd)
183 cmd = RSYNC_RSH;
184 cmd = strdup(cmd);
185 if (!cmd)
186 goto oom;
187
188 for (tok=strtok(cmd," ");tok;tok=strtok(NULL," ")) {
189 args[argc++] = tok;
190 }
191
192#if HAVE_REMSH
193 /* remsh (on HPUX) takes the arguments the other way around */
194 args[argc++] = machine;
195 if (user) {
196 args[argc++] = "-l";
197 args[argc++] = user;
198 }
199#else
200 if (user) {
201 args[argc++] = "-l";
202 args[argc++] = user;
203 }
204 args[argc++] = machine;
205#endif
206
207 args[argc++] = rsync_path;
208
209 if ((blocking_io == -1) && (strcmp(cmd, RSYNC_RSH) == 0))
210 blocking_io = 1;
211
212 server_options(args,&argc);
213
214 }
215
216 args[argc++] = ".";
217
218 if (path && *path)
219 args[argc++] = path;
220
221 args[argc] = NULL;
222
223 if (verbose > 3) {
224 rprintf(FINFO,"cmd=");
225 for (i=0;i<argc;i++)
226 rprintf(FINFO,"%s ",args[i]);
227 rprintf(FINFO,"\n");
228 }
229
230 if (local_server) {
231 if (read_batch)
232 create_flist_from_batch(); /* sets batch_flist */
233 ret = local_child(argc, args, f_in, f_out, child_main);
234 } else {
235 ret = piped_child(args,f_in,f_out);
236 }
237
238 if (dir) free(dir);
239
240 return ret;
241
242oom:
243 out_of_memory("do_cmd");
244 return 0; /* not reached */
245}
246
247
248
249
250static char *get_local_name(struct file_list *flist,char *name)
251{
252 STRUCT_STAT st;
253 extern int orig_umask;
254
255 if (verbose > 2)
256 rprintf(FINFO,"get_local_name count=%d %s\n",
257 flist->count, NS(name));
258
259 if (!name)
260 return NULL;
261
262 if (do_stat(name,&st) == 0) {
263 if (S_ISDIR(st.st_mode)) {
264 if (!push_dir(name, 0)) {
265 rprintf(FERROR,"push_dir %s : %s (1)\n",
266 name,strerror(errno));
267 exit_cleanup(RERR_FILESELECT);
268 }
269 return NULL;
270 }
271 if (flist->count > 1) {
272 rprintf(FERROR,"ERROR: destination must be a directory when copying more than 1 file\n");
273 exit_cleanup(RERR_FILESELECT);
274 }
275 return name;
276 }
277
278 if (flist->count <= 1)
279 return name;
280
281 if (do_mkdir(name,0777 & ~orig_umask) != 0) {
282 rprintf(FERROR, RSYNC_NAME ": mkdir %s: %s\n",
283 name, strerror(errno));
284 exit_cleanup(RERR_FILEIO);
285 } else {
286 if (verbose > 0)
287 rprintf(FINFO,"created directory %s\n",name);
288 }
289
290 if (!push_dir(name, 0)) {
291 rprintf(FERROR, RSYNC_NAME ": push_dir %s: %s\n",
292 name, strerror(errno));
293 exit_cleanup(RERR_FILESELECT);
294 }
295
296 return NULL;
297}
298
299
300
301
302static void do_server_sender(int f_in, int f_out, int argc,char *argv[])
303{
304 int i;
305 struct file_list *flist;
306 char *dir = argv[0];
307 extern int relative_paths;
308 extern int recurse;
309 extern int remote_version;
310
311 if (verbose > 2)
312 rprintf(FINFO,"server_sender starting pid=%d\n",(int)getpid());
313
314 if (!relative_paths && !push_dir(dir, 0)) {
315 rprintf(FERROR,"push_dir %s: %s (3)\n",dir,strerror(errno));
316 exit_cleanup(RERR_FILESELECT);
317 }
318 argc--;
319 argv++;
320
321 if (strcmp(dir,".")) {
322 int l = strlen(dir);
323 if (strcmp(dir,"/") == 0)
324 l = 0;
325 for (i=0;i<argc;i++)
326 argv[i] += l+1;
327 }
328
329 if (argc == 0 && recurse) {
330 argc=1;
331 argv--;
332 argv[0] = ".";
333 }
334
335 flist = send_file_list(f_out,argc,argv);
336 if (!flist || flist->count == 0) {
337 exit_cleanup(0);
338 }
339
340 send_files(flist,f_out,f_in);
341 io_flush();
342 report(f_out);
343 if (remote_version >= 24) {
344 /* final goodbye message */
345 read_int(f_in);
346 }
347 io_flush();
348 exit_cleanup(0);
349}
350
351
352static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
353{
354 int pid;
355 int status=0;
356 int recv_pipe[2];
357 int error_pipe[2];
358 extern int preserve_hard_links;
359 extern int delete_after;
360 extern int recurse;
361 extern int delete_mode;
362 extern int remote_version;
363
364 if (preserve_hard_links)
365 init_hard_links(flist);
366
367 if (!delete_after) {
368 /* I moved this here from recv_files() to prevent a race condition */
369 if (recurse && delete_mode && !local_name && flist->count>0) {
370 delete_files(flist);
371 }
372 }
373
374 if (fd_pair(recv_pipe) < 0) {
375 rprintf(FERROR,"pipe failed in do_recv\n");
376 exit_cleanup(RERR_SOCKETIO);
377 }
378
379 if (fd_pair(error_pipe) < 0) {
380 rprintf(FERROR,"error pipe failed in do_recv\n");
381 exit_cleanup(RERR_SOCKETIO);
382 }
383
384 io_flush();
385
386 if ((pid=do_fork()) == 0) {
387 close(recv_pipe[0]);
388 close(error_pipe[0]);
389 if (f_in != f_out) close(f_out);
390
391 /* we can't let two processes write to the socket at one time */
392 io_multiplexing_close();
393
394 /* set place to send errors */
395 set_error_fd(error_pipe[1]);
396
397 recv_files(f_in,flist,local_name,recv_pipe[1]);
398 io_flush();
399 report(f_in);
400
401 write_int(recv_pipe[1],1);
402 close(recv_pipe[1]);
403 io_flush();
404 /* finally we go to sleep until our parent kills us
405 with a USR2 signal. We sleep for a short time as on
406 some OSes a signal won't interrupt a sleep! */
407 while (msleep(20))
408 ;
409 }
410
411 close(recv_pipe[1]);
412 close(error_pipe[1]);
413 if (f_in != f_out) close(f_in);
414
415 io_start_buffering(f_out);
416
417 io_set_error_fd(error_pipe[0]);
418
419 generate_files(f_out,flist,local_name,recv_pipe[0]);
420
421 read_int(recv_pipe[0]);
422 close(recv_pipe[0]);
423 if (remote_version >= 24) {
424 /* send a final goodbye message */
425 write_int(f_out, -1);
426 }
427 io_flush();
428
429 kill(pid, SIGUSR2);
430 wait_process(pid, &status);
431 return status;
432}
433
434
435static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
436{
437 int status;
438 struct file_list *flist;
439 char *local_name=NULL;
440 char *dir = NULL;
441 extern int delete_mode;
442 extern int delete_excluded;
443 extern int am_daemon;
444 extern int module_id;
445 extern int am_sender;
446 extern int read_batch;
447 extern struct file_list *batch_flist;
448
449 if (verbose > 2)
450 rprintf(FINFO,"server_recv(%d) starting pid=%d\n",argc,(int)getpid());
451
452 if (am_daemon && lp_read_only(module_id) && !am_sender) {
453 rprintf(FERROR,"ERROR: module is read only\n");
454 exit_cleanup(RERR_SYNTAX);
455 return;
456 }
457
458
459 if (argc > 0) {
460 dir = argv[0];
461 argc--;
462 argv++;
463 if (!am_daemon && !push_dir(dir, 0)) {
464 rprintf(FERROR,"push_dir %s : %s (4)\n",
465 dir,strerror(errno));
466 exit_cleanup(RERR_FILESELECT);
467 }
468 }
469
470 if (delete_mode && !delete_excluded)
471 recv_exclude_list(f_in);
472
473 if (read_batch)
474 flist = batch_flist;
475 else
476 flist = recv_file_list(f_in);
477 if (!flist) {
478 rprintf(FERROR,"server_recv: recv_file_list error\n");
479 exit_cleanup(RERR_FILESELECT);
480 }
481
482 if (argc > 0) {
483 if (strcmp(dir,".")) {
484 argv[0] += strlen(dir);
485 if (argv[0][0] == '/') argv[0]++;
486 }
487 local_name = get_local_name(flist,argv[0]);
488 }
489
490 status = do_recv(f_in,f_out,flist,local_name);
491 exit_cleanup(status);
492}
493
494
495int child_main(int argc, char *argv[])
496{
497 start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
498 return 0;
499}
500
501
502void start_server(int f_in, int f_out, int argc, char *argv[])
503{
504 extern int cvs_exclude;
505 extern int am_sender;
506 extern int remote_version;
507 extern int read_batch;
508
509 setup_protocol(f_out, f_in);
510
511 set_nonblocking(f_in);
512 set_nonblocking(f_out);
513
514 if (remote_version >= 23)
515 io_start_multiplex_out(f_out);
516
517 if (am_sender) {
518 if (!read_batch) {
519 recv_exclude_list(f_in);
520 if (cvs_exclude)
521 add_cvs_excludes();
522 }
523 do_server_sender(f_in, f_out, argc, argv);
524 } else {
525 do_server_recv(f_in, f_out, argc, argv);
526 }
527 exit_cleanup(0);
528}
529
530
531/*
532 * This is called once the connection has been negotiated. It is used
533 * for rsyncd, remote-shell, and local connections.
534 */
535int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[])
536{
537 struct file_list *flist = NULL;
538 int status = 0, status2 = 0;
539 char *local_name = NULL;
540 extern int am_sender;
541 extern int remote_version;
542 extern pid_t cleanup_child_pid;
543 extern int write_batch;
544 extern int read_batch;
545 extern struct file_list *batch_flist;
546
547 cleanup_child_pid = pid;
548 if (read_batch)
549 flist = batch_flist;
550
551 set_nonblocking(f_in);
552 set_nonblocking(f_out);
553
554 setup_protocol(f_out,f_in);
555
556 if (remote_version >= 23)
557 io_start_multiplex_in(f_in);
558
559 if (am_sender) {
560 extern int cvs_exclude;
561 extern int delete_mode;
562 extern int delete_excluded;
563 if (cvs_exclude)
564 add_cvs_excludes();
565 if (delete_mode && !delete_excluded)
566 send_exclude_list(f_out);
567 if (!read_batch) /* dw -- don't write to pipe */
568 flist = send_file_list(f_out,argc,argv);
569 if (verbose > 3)
570 rprintf(FINFO,"file list sent\n");
571
572 send_files(flist,f_out,f_in);
573 if (remote_version >= 24) {
574 /* final goodbye message */
575 read_int(f_in);
576 }
577 if (pid != -1) {
578 if (verbose > 3)
579 rprintf(FINFO,"client_run waiting on %d\n", (int) pid);
580 io_flush();
581 wait_process(pid, &status);
582 }
583 report(-1);
584 exit_cleanup(status);
585 }
586
587 if (argc == 0) {
588 extern int list_only;
589 list_only = 1;
590 }
591
592 if (!write_batch)
593 send_exclude_list(f_out);
594
595 flist = recv_file_list(f_in);
596 if (!flist || flist->count == 0) {
597 rprintf(FINFO, "client: nothing to do: "
598 "perhaps you need to specify some filenames or "
599 "the --recursive option?\n");
600 exit_cleanup(0);
601 }
602
603 local_name = get_local_name(flist,argv[0]);
604
605 status2 = do_recv(f_in,f_out,flist,local_name);
606
607 if (pid != -1) {
608 if (verbose > 3)
609 rprintf(FINFO,"client_run2 waiting on %d\n", (int) pid);
610 io_flush();
611 wait_process(pid, &status);
612 }
613
614 return MAX(status, status2);
615}
616
617static char *find_colon(char *s)
618{
619 char *p, *p2;
620
621 p = strchr(s,':');
622 if (!p) return NULL;
623
624 /* now check to see if there is a / in the string before the : - if there is then
625 discard the colon on the assumption that the : is part of a filename */
626 p2 = strchr(s,'/');
627 if (p2 && p2 < p) return NULL;
628
629 return p;
630}
631
632
633static int copy_argv (char *argv[])
634{
635 int i;
636
637 for (i = 0; argv[i]; i++) {
638 if (!(argv[i] = strdup(argv[i]))) {
639 rprintf (FERROR, "out of memory at %s(%d)\n",
640 __FILE__, __LINE__);
641 return RERR_MALLOC;
642 }
643 }
644
645 return 0;
646}
647
648
649/**
650 * Start a client for either type of remote connection. Work out
651 * whether the arguments request a remote shell or rsyncd connection,
652 * and call the appropriate connection function, then run_client.
653 *
654 * Calls either start_socket_client (for sockets) or do_cmd and
655 * client_run (for ssh).
656 **/
657static int start_client(int argc, char *argv[])
658{
659 char *p;
660 char *shell_machine = NULL;
661 char *shell_path = NULL;
662 char *shell_user = NULL;
663 int ret;
664 pid_t pid;
665 int f_in,f_out;
666 extern int local_server;
667 extern int am_sender;
668 extern char *shell_cmd;
669 extern int rsync_port;
670 extern int read_batch;
671 int rc;
672
673 /* Don't clobber argv[] so that ps(1) can still show the right
674 command line. */
675 if ((rc = copy_argv (argv)))
676 return rc;
677
678 if (strncasecmp(URL_PREFIX, argv[0], strlen(URL_PREFIX)) == 0) {
679 char *host, *path;
680
681 host = argv[0] + strlen(URL_PREFIX);
682 p = strchr(host,'/');
683 if (p) {
684 *p = 0;
685 path = p+1;
686 } else {
687 path="";
688 }
689 p = strchr(host,':');
690 if (p) {
691 rsync_port = atoi(p+1);
692 *p = 0;
693 }
694 return start_socket_client(host, path, argc-1, argv+1);
695 }
696
697 if (!read_batch) {
698 p = find_colon(argv[0]);
699
700 if (p) {
701 if (p[1] == ':') { /* double colon */
702 *p = 0;
703 return start_socket_client(argv[0], p+2, argc-1, argv+1);
704 }
705
706 if (argc < 1) {
707 usage(FERROR);
708 exit_cleanup(RERR_SYNTAX);
709 }
710
711 am_sender = 0;
712 *p = 0;
713 shell_machine = argv[0];
714 shell_path = p+1;
715 argc--;
716 argv++;
717 } else {
718 am_sender = 1;
719
720 p = find_colon(argv[argc-1]);
721 if (!p) {
722 local_server = 1;
723 } else if (p[1] == ':') {
724 *p = 0;
725 return start_socket_client(argv[argc-1], p+2, argc-1, argv);
726 }
727
728 if (argc < 2) {
729 usage(FERROR);
730 exit_cleanup(RERR_SYNTAX);
731 }
732
733 if (local_server) {
734 shell_machine = NULL;
735 shell_path = argv[argc-1];
736 } else {
737 *p = 0;
738 shell_machine = argv[argc-1];
739 shell_path = p+1;
740 }
741 argc--;
742 }
743 } else {
744 am_sender = 1;
745 local_server = 1;
746 shell_path = argv[argc-1];
747 }
748
749 if (shell_machine) {
750 p = strchr(shell_machine,'@');
751 if (p) {
752 *p = 0;
753 shell_user = shell_machine;
754 shell_machine = p+1;
755 }
756 }
757
758 if (verbose > 3) {
759 rprintf(FINFO,"cmd=%s machine=%s user=%s path=%s\n",
760 shell_cmd?shell_cmd:"",
761 shell_machine?shell_machine:"",
762 shell_user?shell_user:"",
763 shell_path?shell_path:"");
764 }
765
766 if (!am_sender && argc > 1) {
767 usage(FERROR);
768 exit_cleanup(RERR_SYNTAX);
769 }
770
771 if (argc == 0 && !am_sender) {
772 extern int list_only;
773 list_only = 1;
774 }
775
776 pid = do_cmd(shell_cmd,shell_machine,shell_user,shell_path,&f_in,&f_out);
777
778 ret = client_run(f_in, f_out, pid, argc, argv);
779
780 fflush(stdout);
781 fflush(stderr);
782
783 return ret;
784}
785
786
787static RETSIGTYPE sigusr1_handler(int UNUSED(val)) {
788 exit_cleanup(RERR_SIGNAL);
789}
790
791static RETSIGTYPE sigusr2_handler(int UNUSED(val)) {
792 extern int log_got_error;
793 if (log_got_error) _exit(RERR_PARTIAL);
794 _exit(0);
795}
796
797static RETSIGTYPE sigchld_handler(int UNUSED(val)) {
798#ifdef WNOHANG
799 while (waitpid(-1, NULL, WNOHANG) > 0) ;
800#endif
801}
802
803
804/**
805 * This routine catches signals and tries to send them to gdb.
806 *
807 * Because it's called from inside a signal handler it ought not to
808 * use too many library routines.
809 *
810 * @todo Perhaps use "screen -X" instead/as well, to help people
811 * debugging without easy access to X. Perhaps use an environment
812 * variable, or just call a script?
813 *
814 * @todo The /proc/ magic probably only works on Linux (and
815 * Solaris?) Can we be more portable?
816 **/
817#ifdef MAINTAINER_MODE
818const char *get_panic_action(void)
819{
820 const char *cmd_fmt = getenv("RSYNC_PANIC_ACTION");
821
822 if (cmd_fmt)
823 return cmd_fmt;
824 else
825 return "xterm -display :0 -T Panic -n Panic "
826 "-e gdb /proc/%d/exe %d";
827}
828
829
830/**
831 * Handle a fatal signal by launching a debugger, controlled by $RSYNC_PANIC_ACTION.
832 *
833 * This signal handler is only installed if we were configured with
834 * --enable-maintainer-mode. Perhaps it should always be on and we
835 * should just look at the environment variable, but I'm a bit leery
836 * of a signal sending us into a busy loop.
837 **/
838static RETSIGTYPE rsync_panic_handler(int UNUSED(whatsig))
839{
840 char cmd_buf[300];
841 int ret;
842
843 sprintf(cmd_buf, get_panic_action(),
844 getpid(), getpid());
845
846 /* Unless we failed to execute gdb, we allow the process to
847 * continue. I'm not sure if that's right. */
848 ret = system(cmd_buf);
849 if (ret)
850 _exit(ret);
851}
852#endif
853
854
855int main(int argc,char *argv[])
856{
857 extern int am_root;
858 extern int orig_umask;
859 extern int dry_run;
860 extern int am_daemon;
861 extern int am_server;
862 int ret;
863 extern int write_batch;
864 int orig_argc;
865 char **orig_argv;
866
867 orig_argc = argc;
868 orig_argv = argv;
869
870 signal(SIGUSR1, sigusr1_handler);
871 signal(SIGUSR2, sigusr2_handler);
872 signal(SIGCHLD, sigchld_handler);
873#ifdef MAINTAINER_MODE
874 signal(SIGSEGV, rsync_panic_handler);
875 signal(SIGFPE, rsync_panic_handler);
876 signal(SIGABRT, rsync_panic_handler);
877 signal(SIGBUS, rsync_panic_handler);
878#endif /* def MAINTAINER_MODE */
879
880 starttime = time(NULL);
881 am_root = (getuid() == 0);
882
883 memset(&stats, 0, sizeof(stats));
884
885 if (argc < 2) {
886 usage(FERROR);
887 exit_cleanup(RERR_SYNTAX);
888 }
889
890 /* we set a 0 umask so that correct file permissions can be
891 carried across */
892 orig_umask = (int)umask(0);
893
894 if (!parse_arguments(&argc, (const char ***) &argv, 1)) {
895 /* FIXME: We ought to call the same error-handling
896 * code here, rather than relying on getopt. */
897 option_error();
898 exit_cleanup(RERR_SYNTAX);
899 }
900
901 signal(SIGINT,SIGNAL_CAST sig_int);
902 signal(SIGHUP,SIGNAL_CAST sig_int);
903 signal(SIGTERM,SIGNAL_CAST sig_int);
904
905 /* Ignore SIGPIPE; we consistently check error codes and will
906 * see the EPIPE. */
907 signal(SIGPIPE, SIG_IGN);
908
909 /* Initialize push_dir here because on some old systems getcwd
910 (implemented by forking "pwd" and reading its output) doesn't
911 work when there are other child processes. Also, on all systems
912 that implement getcwd that way "pwd" can't be found after chroot. */
913 push_dir(NULL,0);
914
915 if (write_batch && !am_server) {
916 write_batch_argvs_file(orig_argc, orig_argv);
917 }
918
919 if (am_daemon) {
920 return daemon_main();
921 }
922
923 if (argc < 1) {
924 usage(FERROR);
925 exit_cleanup(RERR_SYNTAX);
926 }
927
928 if (dry_run)
929 verbose = MAX(verbose,1);
930
931#ifndef SUPPORT_LINKS
932 if (!am_server && preserve_links) {
933 rprintf(FERROR,"ERROR: symbolic links not supported\n");
934 exit_cleanup(RERR_UNSUPPORTED);
935 }
936#endif
937
938 if (am_server) {
939 set_nonblocking(STDIN_FILENO);
940 set_nonblocking(STDOUT_FILENO);
941 start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
942 }
943
944 ret = start_client(argc, argv);
945 if (ret == -1)
946 exit_cleanup(RERR_STARTCLIENT);
947 else
948 exit_cleanup(ret);
949
950 exit(ret);
951 /* NOTREACHED */
952}