Rearrange code slightly to avoid util.c depending on main.c.
[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
26struct stats stats;
27
28extern int verbose;
29
30static void show_malloc_stats(void);
31
32/****************************************************************************
33wait for a process to exit, calling io_flush while waiting
34****************************************************************************/
35void wait_process(pid_t pid, int *status)
36{
37 while (waitpid(pid, status, WNOHANG) == 0) {
38 msleep(20);
39 io_flush();
40 }
41
42 /* TODO: If the child exited on a signal, then log an
43 * appropriate error message. Perhaps we should also accept a
44 * message describing the purpose of the child. Also indicate
45 * this to the caller so that thhey know something went
46 * wrong. */
47 *status = WEXITSTATUS(*status);
48}
49
50static void report(int f)
51{
52 time_t t = time(NULL);
53 extern int am_server;
54 extern int am_sender;
55 extern int am_daemon;
56 extern int do_stats;
57 extern int remote_version;
58 int send_stats;
59
60 if (do_stats) {
61 /* These come out from every process */
62 show_malloc_stats();
63 show_flist_stats();
64 }
65
66 if (am_daemon) {
67 log_exit(0, __FILE__, __LINE__);
68 if (f == -1 || !am_sender) return;
69 }
70
71 send_stats = verbose || (remote_version >= 20);
72 if (am_server) {
73 if (am_sender && send_stats) {
74 int64 w;
75 /* store total_written in a temporary
76 because write_longint changes it */
77 w = stats.total_written;
78 write_longint(f,stats.total_read);
79 write_longint(f,w);
80 write_longint(f,stats.total_size);
81 }
82 return;
83 }
84
85 /* this is the client */
86
87 if (!am_sender && send_stats) {
88 int64 r;
89 stats.total_written = read_longint(f);
90 /* store total_read in a temporary, read_longint changes it */
91 r = read_longint(f);
92 stats.total_size = read_longint(f);
93 stats.total_read = r;
94 }
95
96 if (do_stats) {
97 if (!am_sender && !send_stats) {
98 /* missing the bytes written by the generator */
99 rprintf(FINFO, "\nCannot show stats as receiver because remote protocol version is less than 20\n");
100 rprintf(FINFO, "Use --stats -v to show stats\n");
101 return;
102 }
103 rprintf(FINFO,"\nNumber of files: %d\n", stats.num_files);
104 rprintf(FINFO,"Number of files transferred: %d\n",
105 stats.num_transferred_files);
106 rprintf(FINFO,"Total file size: %.0f bytes\n",
107 (double)stats.total_size);
108 rprintf(FINFO,"Total transferred file size: %.0f bytes\n",
109 (double)stats.total_transferred_size);
110 rprintf(FINFO,"Literal data: %.0f bytes\n",
111 (double)stats.literal_data);
112 rprintf(FINFO,"Matched data: %.0f bytes\n",
113 (double)stats.matched_data);
114 rprintf(FINFO,"File list size: %d\n", stats.flist_size);
115 rprintf(FINFO,"Total bytes written: %.0f\n",
116 (double)stats.total_written);
117 rprintf(FINFO,"Total bytes read: %.0f\n\n",
118 (double)stats.total_read);
119 }
120
121 if (verbose || do_stats) {
122 rprintf(FINFO,"wrote %.0f bytes read %.0f bytes %.2f bytes/sec\n",
123 (double)stats.total_written,
124 (double)stats.total_read,
125 (stats.total_written+stats.total_read)/(0.5 + (t-starttime)));
126 rprintf(FINFO,"total size is %.0f speedup is %.2f\n",
127 (double)stats.total_size,
128 (1.0*stats.total_size)/(stats.total_written+stats.total_read));
129 }
130
131 fflush(stdout);
132 fflush(stderr);
133}
134
135
136/**
137 * If our C library can get malloc statistics, then show them to FINFO
138 **/
139static void show_malloc_stats(void)
140{
141#ifdef HAVE_MALLINFO
142 struct mallinfo mi;
143 extern int am_server;
144 extern int am_sender;
145 extern int am_daemon;
146
147 mi = mallinfo();
148
149 rprintf(FINFO, RSYNC_NAME "[%d] (%s%s%s) heap statistics:\n",
150 getpid(),
151 am_server ? "server " : "",
152 am_daemon ? "daemon " : "",
153 am_sender ? "sender" : "receiver");
154 rprintf(FINFO, " arena: %10d (bytes from sbrk)\n", mi.arena);
155 rprintf(FINFO, " ordblks: %10d (chunks not in use)\n", mi.ordblks);
156 rprintf(FINFO, " smblks: %10d\n", mi.smblks);
157 rprintf(FINFO, " hblks: %10d (chunks from mmap)\n", mi.hblks);
158 rprintf(FINFO, " hblkhd: %10d (bytes from mmap)\n", mi.hblkhd);
159 rprintf(FINFO, " usmblks: %10d\n", mi.usmblks);
160 rprintf(FINFO, " fsmblks: %10d\n", mi.fsmblks);
161 rprintf(FINFO, " uordblks: %10d (bytes used)\n", mi.uordblks);
162 rprintf(FINFO, " fordblks: %10d (bytes free)\n", mi.fordblks);
163 rprintf(FINFO, " keepcost: %10d (bytes in releasable chunk)\n", mi.keepcost);
164#endif /* HAVE_MALLINFO */
165}
166
167
168/* Start the remote shell. cmd may be NULL to use the default. */
169static pid_t do_cmd(char *cmd,char *machine,char *user,char *path,int *f_in,int *f_out)
170{
171 char *args[100];
172 int i,argc=0;
173 pid_t ret;
174 char *tok,*dir=NULL;
175 extern int local_server;
176 extern char *rsync_path;
177 extern int blocking_io;
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 (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
496void child_main(int argc, char *argv[])
497{
498 start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
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 whole_file;
671 extern int write_batch;
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 if (strncasecmp(URL_PREFIX, argv[0], strlen(URL_PREFIX)) == 0) {
681 char *host, *path;
682
683 host = argv[0] + strlen(URL_PREFIX);
684 p = strchr(host,'/');
685 if (p) {
686 *p = 0;
687 path = p+1;
688 } else {
689 path="";
690 }
691 p = strchr(host,':');
692 if (p) {
693 rsync_port = atoi(p+1);
694 *p = 0;
695 }
696 return start_socket_client(host, path, argc-1, argv+1);
697 }
698
699 if (!read_batch) {
700 p = find_colon(argv[0]);
701
702 if (p) {
703 if (p[1] == ':') { /* double colon */
704 *p = 0;
705 return start_socket_client(argv[0], p+2, argc-1, argv+1);
706 }
707
708 if (argc < 1) {
709 usage(FERROR);
710 exit_cleanup(RERR_SYNTAX);
711 }
712
713 am_sender = 0;
714 *p = 0;
715 shell_machine = argv[0];
716 shell_path = p+1;
717 argc--;
718 argv++;
719 } else {
720 am_sender = 1;
721
722 p = find_colon(argv[argc-1]);
723 if (!p) {
724 local_server = 1;
725 } else if (p[1] == ':') {
726 *p = 0;
727 return start_socket_client(argv[argc-1], p+2, argc-1, argv);
728 }
729
730 if (argc < 2) {
731 usage(FERROR);
732 exit_cleanup(RERR_SYNTAX);
733 }
734
735 if (local_server) {
736 shell_machine = NULL;
737 shell_path = argv[argc-1];
738 } else {
739 *p = 0;
740 shell_machine = argv[argc-1];
741 shell_path = p+1;
742 }
743 argc--;
744 }
745 } else {
746 am_sender = 1;
747 local_server = 1;
748 shell_path = argv[argc-1];
749 }
750
751 if (shell_machine) {
752 p = strchr(shell_machine,'@');
753 if (p) {
754 *p = 0;
755 shell_user = shell_machine;
756 shell_machine = p+1;
757 }
758 }
759
760 if (verbose > 3) {
761 rprintf(FINFO,"cmd=%s machine=%s user=%s path=%s\n",
762 shell_cmd?shell_cmd:"",
763 shell_machine?shell_machine:"",
764 shell_user?shell_user:"",
765 shell_path?shell_path:"");
766 }
767
768 if (!am_sender && argc > 1) {
769 usage(FERROR);
770 exit_cleanup(RERR_SYNTAX);
771 }
772
773 if (argc == 0 && !am_sender) {
774 extern int list_only;
775 list_only = 1;
776 }
777
778 pid = do_cmd(shell_cmd,shell_machine,shell_user,shell_path,&f_in,&f_out);
779
780 ret = client_run(f_in, f_out, pid, argc, argv);
781
782 fflush(stdout);
783 fflush(stderr);
784
785 return ret;
786}
787
788
789static RETSIGTYPE sigusr1_handler(int UNUSED(val)) {
790 exit_cleanup(RERR_SIGNAL);
791}
792
793static RETSIGTYPE sigusr2_handler(int UNUSED(val)) {
794 extern int log_got_error;
795 if (log_got_error) _exit(RERR_PARTIAL);
796 _exit(0);
797}
798
799static RETSIGTYPE sigchld_handler(int UNUSED(val)) {
800#ifdef WNOHANG
801 while (waitpid(-1, NULL, WNOHANG) > 0) ;
802#endif
803}
804
805
806/**
807 * This routine catches signals and tries to send them to gdb.
808 *
809 * Because it's called from inside a signal handler it ought not to
810 * use too many library routines.
811 *
812 * @todo Perhaps use "screen -X" instead/as well, to help people
813 * debugging without easy access to X. Perhaps use an environment
814 * variable, or just call a script?
815 *
816 * @todo The /proc/ magic probably only works on Linux (and
817 * Solaris?) Can we be more portable?
818 **/
819#ifdef MAINTAINER_MODE
820static RETSIGTYPE rsync_panic_handler(int UNUSED(whatsig))
821{
822 char cmd_buf[300];
823 int ret;
824 sprintf(cmd_buf,
825 "xterm -display :0 -T Panic -n Panic "
826 "-e gdb /proc/%d/exe %d",
827 getpid(), getpid());
828
829 /* Unless we failed to execute gdb, we allow the process to
830 * continue. I'm not sure if that's right. */
831 ret = system(cmd_buf);
832 if (ret)
833 _exit(ret);
834}
835#endif
836
837
838int main(int argc,char *argv[])
839{
840 extern int am_root;
841 extern int orig_umask;
842 extern int dry_run;
843 extern int am_daemon;
844 extern int am_server;
845 int ret;
846 extern int write_batch;
847 int orig_argc;
848 char **orig_argv;
849
850 orig_argc = argc;
851 orig_argv = argv;
852
853 signal(SIGUSR1, sigusr1_handler);
854 signal(SIGUSR2, sigusr2_handler);
855 signal(SIGCHLD, sigchld_handler);
856#ifdef MAINTAINER_MODE
857 signal(SIGSEGV, rsync_panic_handler);
858 signal(SIGFPE, rsync_panic_handler);
859 signal(SIGABRT, rsync_panic_handler);
860 signal(SIGBUS, rsync_panic_handler);
861#endif /* def MAINTAINER_MODE */
862
863 starttime = time(NULL);
864 am_root = (getuid() == 0);
865
866 memset(&stats, 0, sizeof(stats));
867
868 if (argc < 2) {
869 usage(FERROR);
870 exit_cleanup(RERR_SYNTAX);
871 }
872
873 /* we set a 0 umask so that correct file permissions can be
874 carried across */
875 orig_umask = (int)umask(0);
876
877 if (!parse_arguments(&argc, (const char ***) &argv, 1)) {
878 /* FIXME: We ought to call the same error-handling
879 * code here, rather than relying on getopt. */
880 option_error();
881 exit_cleanup(RERR_SYNTAX);
882 }
883
884 signal(SIGINT,SIGNAL_CAST sig_int);
885 signal(SIGHUP,SIGNAL_CAST sig_int);
886 signal(SIGTERM,SIGNAL_CAST sig_int);
887
888 /* Ignore SIGPIPE; we consistently check error codes and will
889 * see the EPIPE. */
890 signal(SIGPIPE, SIG_IGN);
891
892 /* Initialize push_dir here because on some old systems getcwd
893 (implemented by forking "pwd" and reading its output) doesn't
894 work when there are other child processes. Also, on all systems
895 that implement getcwd that way "pwd" can't be found after chroot. */
896 push_dir(NULL,0);
897
898 if (write_batch && !am_server) {
899 write_batch_argvs_file(orig_argc, orig_argv);
900 }
901
902 if (am_daemon) {
903 return daemon_main();
904 }
905
906 if (argc < 1) {
907 usage(FERROR);
908 exit_cleanup(RERR_SYNTAX);
909 }
910
911 if (dry_run)
912 verbose = MAX(verbose,1);
913
914#ifndef SUPPORT_LINKS
915 if (!am_server && preserve_links) {
916 rprintf(FERROR,"ERROR: symbolic links not supported\n");
917 exit_cleanup(RERR_UNSUPPORTED);
918 }
919#endif
920
921 if (am_server) {
922 set_nonblocking(STDIN_FILENO);
923 set_nonblocking(STDOUT_FILENO);
924 start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
925 }
926
927 ret = start_client(argc, argv);
928 if (ret == -1)
929 exit_cleanup(RERR_STARTCLIENT);
930 else
931 exit_cleanup(ret);
932
933 exit(ret);
934 /* NOTREACHED */
935}