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