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