Split code out into separate files and remove some global variables to
[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
495void child_main(int argc, char *argv[])
496{
497 start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
498}
499
500
501void start_server(int f_in, int f_out, int argc, char *argv[])
502{
503 extern int cvs_exclude;
504 extern int am_sender;
505 extern int remote_version;
506 extern int read_batch;
507
508 setup_protocol(f_out, f_in);
509
510 set_nonblocking(f_in);
511 set_nonblocking(f_out);
512
513 if (remote_version >= 23)
514 io_start_multiplex_out(f_out);
515
516 if (am_sender) {
517 if (!read_batch) {
518 recv_exclude_list(f_in);
519 if (cvs_exclude)
520 add_cvs_excludes();
521 }
522 do_server_sender(f_in, f_out, argc, argv);
523 } else {
524 do_server_recv(f_in, f_out, argc, argv);
525 }
526 exit_cleanup(0);
527}
528
529
530/*
531 * This is called once the connection has been negotiated. It is used
532 * for rsyncd, remote-shell, and local connections.
533 */
534int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[])
535{
536 struct file_list *flist = NULL;
537 int status = 0, status2 = 0;
538 char *local_name = NULL;
539 extern int am_sender;
540 extern int remote_version;
541 extern pid_t cleanup_child_pid;
542 extern int write_batch;
543 extern int read_batch;
544 extern struct file_list *batch_flist;
545
546 cleanup_child_pid = pid;
547 if (read_batch)
548 flist = batch_flist;
549
550 set_nonblocking(f_in);
551 set_nonblocking(f_out);
552
553 setup_protocol(f_out,f_in);
554
555 if (remote_version >= 23)
556 io_start_multiplex_in(f_in);
557
558 if (am_sender) {
559 extern int cvs_exclude;
560 extern int delete_mode;
561 extern int delete_excluded;
562 if (cvs_exclude)
563 add_cvs_excludes();
564 if (delete_mode && !delete_excluded)
565 send_exclude_list(f_out);
566 if (!read_batch) /* dw -- don't write to pipe */
567 flist = send_file_list(f_out,argc,argv);
568 if (verbose > 3)
569 rprintf(FINFO,"file list sent\n");
570
571 send_files(flist,f_out,f_in);
572 if (remote_version >= 24) {
573 /* final goodbye message */
574 read_int(f_in);
575 }
576 if (pid != -1) {
577 if (verbose > 3)
578 rprintf(FINFO,"client_run waiting on %d\n", (int) pid);
579 io_flush();
580 wait_process(pid, &status);
581 }
582 report(-1);
583 exit_cleanup(status);
584 }
585
586 if (argc == 0) {
587 extern int list_only;
588 list_only = 1;
589 }
590
591 if (!write_batch)
592 send_exclude_list(f_out);
593
594 flist = recv_file_list(f_in);
595 if (!flist || flist->count == 0) {
596 rprintf(FINFO, "client: nothing to do: "
597 "perhaps you need to specify some filenames or "
598 "the --recursive option?\n");
599 exit_cleanup(0);
600 }
601
602 local_name = get_local_name(flist,argv[0]);
603
604 status2 = do_recv(f_in,f_out,flist,local_name);
605
606 if (pid != -1) {
607 if (verbose > 3)
608 rprintf(FINFO,"client_run2 waiting on %d\n", (int) pid);
609 io_flush();
610 wait_process(pid, &status);
611 }
612
613 return MAX(status, status2);
614}
615
616static char *find_colon(char *s)
617{
618 char *p, *p2;
619
620 p = strchr(s,':');
621 if (!p) return NULL;
622
623 /* now check to see if there is a / in the string before the : - if there is then
624 discard the colon on the assumption that the : is part of a filename */
625 p2 = strchr(s,'/');
626 if (p2 && p2 < p) return NULL;
627
628 return p;
629}
630
631
632static int copy_argv (char *argv[])
633{
634 int i;
635
636 for (i = 0; argv[i]; i++) {
637 if (!(argv[i] = strdup(argv[i]))) {
638 rprintf (FERROR, "out of memory at %s(%d)\n",
639 __FILE__, __LINE__);
640 return RERR_MALLOC;
641 }
642 }
643
644 return 0;
645}
646
647
648/**
649 * Start a client for either type of remote connection. Work out
650 * whether the arguments request a remote shell or rsyncd connection,
651 * and call the appropriate connection function, then run_client.
652 *
653 * Calls either start_socket_client (for sockets) or do_cmd and
654 * client_run (for ssh).
655 **/
656static int start_client(int argc, char *argv[])
657{
658 char *p;
659 char *shell_machine = NULL;
660 char *shell_path = NULL;
661 char *shell_user = NULL;
662 int ret;
663 pid_t pid;
664 int f_in,f_out;
665 extern int local_server;
666 extern int am_sender;
667 extern char *shell_cmd;
668 extern int rsync_port;
669 extern int whole_file;
670 extern int write_batch;
671 extern int read_batch;
672 int rc;
673
674 /* Don't clobber argv[] so that ps(1) can still show the right
675 command line. */
676 if ((rc = copy_argv (argv)))
677 return rc;
678
679 if (strncasecmp(URL_PREFIX, argv[0], strlen(URL_PREFIX)) == 0) {
680 char *host, *path;
681
682 host = argv[0] + strlen(URL_PREFIX);
683 p = strchr(host,'/');
684 if (p) {
685 *p = 0;
686 path = p+1;
687 } else {
688 path="";
689 }
690 p = strchr(host,':');
691 if (p) {
692 rsync_port = atoi(p+1);
693 *p = 0;
694 }
695 return start_socket_client(host, path, argc-1, argv+1);
696 }
697
698 if (!read_batch) {
699 p = find_colon(argv[0]);
700
701 if (p) {
702 if (p[1] == ':') { /* double colon */
703 *p = 0;
704 return start_socket_client(argv[0], p+2, argc-1, argv+1);
705 }
706
707 if (argc < 1) {
708 usage(FERROR);
709 exit_cleanup(RERR_SYNTAX);
710 }
711
712 am_sender = 0;
713 *p = 0;
714 shell_machine = argv[0];
715 shell_path = p+1;
716 argc--;
717 argv++;
718 } else {
719 am_sender = 1;
720
721 p = find_colon(argv[argc-1]);
722 if (!p) {
723 local_server = 1;
724 } else if (p[1] == ':') {
725 *p = 0;
726 return start_socket_client(argv[argc-1], p+2, argc-1, argv);
727 }
728
729 if (argc < 2) {
730 usage(FERROR);
731 exit_cleanup(RERR_SYNTAX);
732 }
733
734 if (local_server) {
735 shell_machine = NULL;
736 shell_path = argv[argc-1];
737 } else {
738 *p = 0;
739 shell_machine = argv[argc-1];
740 shell_path = p+1;
741 }
742 argc--;
743 }
744 } else {
745 am_sender = 1;
746 local_server = 1;
747 shell_path = argv[argc-1];
748 }
749
750 if (shell_machine) {
751 p = strchr(shell_machine,'@');
752 if (p) {
753 *p = 0;
754 shell_user = shell_machine;
755 shell_machine = p+1;
756 }
757 }
758
759 if (verbose > 3) {
760 rprintf(FINFO,"cmd=%s machine=%s user=%s path=%s\n",
761 shell_cmd?shell_cmd:"",
762 shell_machine?shell_machine:"",
763 shell_user?shell_user:"",
764 shell_path?shell_path:"");
765 }
766
767 if (!am_sender && argc > 1) {
768 usage(FERROR);
769 exit_cleanup(RERR_SYNTAX);
770 }
771
772 if (argc == 0 && !am_sender) {
773 extern int list_only;
774 list_only = 1;
775 }
776
777 pid = do_cmd(shell_cmd,shell_machine,shell_user,shell_path,&f_in,&f_out);
778
779 ret = client_run(f_in, f_out, pid, argc, argv);
780
781 fflush(stdout);
782 fflush(stderr);
783
784 return ret;
785}
786
787
788static RETSIGTYPE sigusr1_handler(int UNUSED(val)) {
789 exit_cleanup(RERR_SIGNAL);
790}
791
792static RETSIGTYPE sigusr2_handler(int UNUSED(val)) {
793 extern int log_got_error;
794 if (log_got_error) _exit(RERR_PARTIAL);
795 _exit(0);
796}
797
798static RETSIGTYPE sigchld_handler(int UNUSED(val)) {
799#ifdef WNOHANG
800 while (waitpid(-1, NULL, WNOHANG) > 0) ;
801#endif
802}
803
804
805/**
806 * This routine catches signals and tries to send them to gdb.
807 *
808 * Because it's called from inside a signal handler it ought not to
809 * use too many library routines.
810 *
811 * @todo Perhaps use "screen -X" instead/as well, to help people
812 * debugging without easy access to X. Perhaps use an environment
813 * variable, or just call a script?
814 *
815 * @todo The /proc/ magic probably only works on Linux (and
816 * Solaris?) Can we be more portable?
817 **/
818#ifdef MAINTAINER_MODE
819static RETSIGTYPE rsync_panic_handler(int UNUSED(whatsig))
820{
821 char cmd_buf[300];
822 int ret;
823 sprintf(cmd_buf,
824 "xterm -display :0 -T Panic -n Panic "
825 "-e gdb /proc/%d/exe %d",
826 getpid(), getpid());
827
828 /* Unless we failed to execute gdb, we allow the process to
829 * continue. I'm not sure if that's right. */
830 ret = system(cmd_buf);
831 if (ret)
832 _exit(ret);
833}
834#endif
835
836
837int main(int argc,char *argv[])
838{
839 extern int am_root;
840 extern int orig_umask;
841 extern int dry_run;
842 extern int am_daemon;
843 extern int am_server;
844 int ret;
845 extern int write_batch;
846 int orig_argc;
847 char **orig_argv;
848
849 orig_argc = argc;
850 orig_argv = argv;
851
852 signal(SIGUSR1, sigusr1_handler);
853 signal(SIGUSR2, sigusr2_handler);
854 signal(SIGCHLD, sigchld_handler);
855#ifdef MAINTAINER_MODE
856 signal(SIGSEGV, rsync_panic_handler);
857 signal(SIGFPE, rsync_panic_handler);
858 signal(SIGABRT, rsync_panic_handler);
859 signal(SIGBUS, rsync_panic_handler);
860#endif /* def MAINTAINER_MODE */
861
862 starttime = time(NULL);
863 am_root = (getuid() == 0);
864
865 memset(&stats, 0, sizeof(stats));
866
867 if (argc < 2) {
868 usage(FERROR);
869 exit_cleanup(RERR_SYNTAX);
870 }
871
872 /* we set a 0 umask so that correct file permissions can be
873 carried across */
874 orig_umask = (int)umask(0);
875
876 if (!parse_arguments(&argc, (const char ***) &argv, 1)) {
877 /* FIXME: We ought to call the same error-handling
878 * code here, rather than relying on getopt. */
879 option_error();
880 exit_cleanup(RERR_SYNTAX);
881 }
882
883 signal(SIGINT,SIGNAL_CAST sig_int);
884 signal(SIGHUP,SIGNAL_CAST sig_int);
885 signal(SIGTERM,SIGNAL_CAST sig_int);
886
887 /* Ignore SIGPIPE; we consistently check error codes and will
888 * see the EPIPE. */
889 signal(SIGPIPE, SIG_IGN);
890
891 /* Initialize push_dir here because on some old systems getcwd
892 (implemented by forking "pwd" and reading its output) doesn't
893 work when there are other child processes. Also, on all systems
894 that implement getcwd that way "pwd" can't be found after chroot. */
895 push_dir(NULL,0);
896
897 if (write_batch && !am_server) {
898 write_batch_argvs_file(orig_argc, orig_argv);
899 }
900
901 if (am_daemon) {
902 return daemon_main();
903 }
904
905 if (argc < 1) {
906 usage(FERROR);
907 exit_cleanup(RERR_SYNTAX);
908 }
909
910 if (dry_run)
911 verbose = MAX(verbose,1);
912
913#ifndef SUPPORT_LINKS
914 if (!am_server && preserve_links) {
915 rprintf(FERROR,"ERROR: symbolic links not supported\n");
916 exit_cleanup(RERR_UNSUPPORTED);
917 }
918#endif
919
920 if (am_server) {
921 set_nonblocking(STDIN_FILENO);
922 set_nonblocking(STDOUT_FILENO);
923 start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
924 }
925
926 ret = start_client(argc, argv);
927 if (ret == -1)
928 exit_cleanup(RERR_STARTCLIENT);
929 else
930 exit_cleanup(ret);
931
932 exit(ret);
933 /* NOTREACHED */
934}