optimisations from Rich Salz <rsalz@caveosystems.com>
[rsync/rsync.git] / main.c
CommitLineData
c627d613
AT
1/*
2 Copyright (C) Andrew Tridgell 1996
3 Copyright (C) Paul Mackerras 1996
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18*/
19
20#include "rsync.h"
21
f0fca04e 22time_t starttime = 0;
a800434a
AT
23
24struct stats stats;
5d6bcd44 25
7a6421fa 26extern int verbose;
c627d613
AT
27
28static void report(int f)
29{
7a6421fa
AT
30 time_t t = time(NULL);
31 extern int am_server;
32 extern int am_sender;
248fbb8c 33 extern int am_daemon;
a800434a 34 extern int do_stats;
17d31b38
DD
35 extern int remote_version;
36 int send_stats;
7a6421fa 37
248fbb8c 38 if (am_daemon) {
a9766ef1 39 log_exit(0, __FILE__, __LINE__);
7b372642 40 if (f == -1 || !am_sender) return;
248fbb8c
AT
41 }
42
ebb00c8e 43 send_stats = verbose || (remote_version >= 20);
e19452a9 44 if (am_server) {
17d31b38 45 if (am_sender && send_stats) {
23c5aef1
DD
46 int64 w;
47 /* store total_written in a temporary
48 because write_longint changes it */
49 w = stats.total_written;
e19452a9 50 write_longint(f,stats.total_read);
23c5aef1 51 write_longint(f,w);
e19452a9
DD
52 write_longint(f,stats.total_size);
53 }
7a6421fa
AT
54 return;
55 }
e19452a9
DD
56
57 /* this is the client */
58
17d31b38 59 if (!am_sender && send_stats) {
23c5aef1 60 int64 r;
a800434a 61 stats.total_written = read_longint(f);
23c5aef1
DD
62 /* store total_read in a temporary, read_longint changes it */
63 r = read_longint(f);
a800434a 64 stats.total_size = read_longint(f);
23c5aef1 65 stats.total_read = r;
a800434a
AT
66 }
67
68 if (do_stats) {
17d31b38
DD
69 if (!am_sender && !send_stats) {
70 /* missing the bytes written by the generator */
ebb00c8e 71 rprintf(FINFO, "\nCannot show stats as receiver because remote protocol version is less than 20\n");
17d31b38
DD
72 rprintf(FINFO, "Use --stats -v to show stats\n");
73 return;
74 }
1f658d42
AT
75 rprintf(FINFO,"\nNumber of files: %d\n", stats.num_files);
76 rprintf(FINFO,"Number of files transferred: %d\n",
a800434a 77 stats.num_transferred_files);
1f658d42 78 rprintf(FINFO,"Total file size: %.0f bytes\n",
a800434a 79 (double)stats.total_size);
1f658d42 80 rprintf(FINFO,"Total transferred file size: %.0f bytes\n",
a800434a 81 (double)stats.total_transferred_size);
1f658d42 82 rprintf(FINFO,"Literal data: %.0f bytes\n",
a800434a 83 (double)stats.literal_data);
1f658d42 84 rprintf(FINFO,"Matched data: %.0f bytes\n",
a800434a 85 (double)stats.matched_data);
1f658d42
AT
86 rprintf(FINFO,"File list size: %d\n", stats.flist_size);
87 rprintf(FINFO,"Total bytes written: %.0f\n",
a800434a 88 (double)stats.total_written);
1f658d42 89 rprintf(FINFO,"Total bytes read: %.0f\n\n",
a800434a 90 (double)stats.total_read);
7a6421fa
AT
91 }
92
e19452a9
DD
93 if (verbose || do_stats) {
94 rprintf(FINFO,"wrote %.0f bytes read %.0f bytes %.2f bytes/sec\n",
95 (double)stats.total_written,
96 (double)stats.total_read,
97 (stats.total_written+stats.total_read)/(0.5 + (t-starttime)));
98 rprintf(FINFO,"total size is %.0f speedup is %.2f\n",
99 (double)stats.total_size,
100 (1.0*stats.total_size)/(stats.total_written+stats.total_read));
101 }
fc8a6b97
AT
102
103 fflush(stdout);
104 fflush(stderr);
c627d613
AT
105}
106
107
e3cd198f 108static int do_cmd(char *cmd,char *machine,char *user,char *path,int *f_in,int *f_out)
c627d613 109{
366345fe
AT
110 char *args[100];
111 int i,argc=0, ret;
112 char *tok,*dir=NULL;
7a6421fa
AT
113 extern int local_server;
114 extern char *rsync_path;
e384bfbd 115 extern int blocking_io;
366345fe
AT
116
117 if (!local_server) {
118 if (!cmd)
119 cmd = getenv(RSYNC_RSH_ENV);
120 if (!cmd)
121 cmd = RSYNC_RSH;
122 cmd = strdup(cmd);
123 if (!cmd)
124 goto oom;
125
126 for (tok=strtok(cmd," ");tok;tok=strtok(NULL," ")) {
127 args[argc++] = tok;
128 }
c627d613 129
7b8356d0 130#if HAVE_REMSH
366345fe
AT
131 /* remsh (on HPUX) takes the arguments the other way around */
132 args[argc++] = machine;
133 if (user) {
134 args[argc++] = "-l";
135 args[argc++] = user;
136 }
7b8356d0 137#else
366345fe
AT
138 if (user) {
139 args[argc++] = "-l";
140 args[argc++] = user;
141 }
142 args[argc++] = machine;
7b8356d0 143#endif
c627d613 144
366345fe 145 args[argc++] = rsync_path;
c627d613 146
366345fe 147 server_options(args,&argc);
e384bfbd
AT
148
149
150 if (strcmp(cmd, RSYNC_RSH) == 0) blocking_io = 1;
366345fe 151 }
c627d613 152
366345fe 153 args[argc++] = ".";
76076c4b 154
366345fe
AT
155 if (path && *path)
156 args[argc++] = path;
c627d613 157
366345fe 158 args[argc] = NULL;
c627d613 159
366345fe 160 if (verbose > 3) {
9486289c 161 rprintf(FINFO,"cmd=");
366345fe 162 for (i=0;i<argc;i++)
9486289c
AT
163 rprintf(FINFO,"%s ",args[i]);
164 rprintf(FINFO,"\n");
366345fe
AT
165 }
166
167 if (local_server) {
168 ret = local_child(argc, args, f_in, f_out);
169 } else {
170 ret = piped_child(args,f_in,f_out);
171 }
c627d613 172
366345fe 173 if (dir) free(dir);
82306bf6 174
366345fe 175 return ret;
c627d613
AT
176
177oom:
366345fe
AT
178 out_of_memory("do_cmd");
179 return 0; /* not reached */
c627d613
AT
180}
181
182
183
184
185static char *get_local_name(struct file_list *flist,char *name)
186{
7a6421fa
AT
187 STRUCT_STAT st;
188 extern int orig_umask;
c627d613 189
c95da96a
AT
190 if (verbose > 2)
191 rprintf(FINFO,"get_local_name count=%d %s\n",
1f0610ef
DD
192 flist->count, NS(name));
193
194 if (!name)
195 return NULL;
c95da96a 196
1ff5450d
AT
197 if (do_stat(name,&st) == 0) {
198 if (S_ISDIR(st.st_mode)) {
5243c216
AT
199 if (!push_dir(name, 0)) {
200 rprintf(FERROR,"push_dir %s : %s (1)\n",
1ff5450d 201 name,strerror(errno));
65417579 202 exit_cleanup(RERR_FILESELECT);
1ff5450d
AT
203 }
204 return NULL;
205 }
206 if (flist->count > 1) {
207 rprintf(FERROR,"ERROR: destination must be a directory when copying more than 1 file\n");
65417579 208 exit_cleanup(RERR_FILESELECT);
1ff5450d
AT
209 }
210 return name;
211 }
212
cec8aa77 213 if (flist->count <= 1)
1ff5450d
AT
214 return name;
215
1ff5450d
AT
216 if (do_mkdir(name,0777 & ~orig_umask) != 0) {
217 rprintf(FERROR,"mkdir %s : %s (1)\n",name,strerror(errno));
65417579 218 exit_cleanup(RERR_FILEIO);
1ff5450d 219 } else {
b536f47e
AT
220 if (verbose > 0)
221 rprintf(FINFO,"created directory %s\n",name);
1ff5450d
AT
222 }
223
5243c216
AT
224 if (!push_dir(name, 0)) {
225 rprintf(FERROR,"push_dir %s : %s (2)\n",
226 name,strerror(errno));
65417579 227 exit_cleanup(RERR_FILESELECT);
1ff5450d
AT
228 }
229
230 return NULL;
c627d613
AT
231}
232
233
234
235
9486289c 236static void do_server_sender(int f_in, int f_out, int argc,char *argv[])
c627d613 237{
7a6421fa
AT
238 int i;
239 struct file_list *flist;
240 char *dir = argv[0];
241 extern int relative_paths;
7a6421fa 242 extern int recurse;
c627d613 243
7a6421fa
AT
244 if (verbose > 2)
245 rprintf(FINFO,"server_sender starting pid=%d\n",(int)getpid());
c627d613 246
5243c216
AT
247 if (!relative_paths && !push_dir(dir, 0)) {
248 rprintf(FERROR,"push_dir %s: %s (3)\n",dir,strerror(errno));
65417579 249 exit_cleanup(RERR_FILESELECT);
7a6421fa
AT
250 }
251 argc--;
252 argv++;
c627d613 253
7a6421fa
AT
254 if (strcmp(dir,".")) {
255 int l = strlen(dir);
256 if (strcmp(dir,"/") == 0)
257 l = 0;
258 for (i=0;i<argc;i++)
259 argv[i] += l+1;
260 }
c627d613 261
7a6421fa
AT
262 if (argc == 0 && recurse) {
263 argc=1;
264 argv--;
265 argv[0] = ".";
266 }
267
7a6421fa 268 flist = send_file_list(f_out,argc,argv);
8d9dc9f9
AT
269 if (!flist || flist->count == 0) {
270 exit_cleanup(0);
271 }
272
7a6421fa 273 send_files(flist,f_out,f_in);
3d382777 274 io_flush();
7a6421fa 275 report(f_out);
8d9dc9f9 276 io_flush();
7a6421fa 277 exit_cleanup(0);
c627d613
AT
278}
279
280
dc5ddbcc
AT
281static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
282{
d186eb1a
AT
283 int pid;
284 int status=0;
285 int recv_pipe[2];
554e0a8d 286 int error_pipe[2];
d186eb1a 287 extern int preserve_hard_links;
6957ae33
AT
288 extern int delete_after;
289 extern int recurse;
290 extern int delete_mode;
8ada7518 291 extern int remote_version;
dc5ddbcc 292
d186eb1a
AT
293 if (preserve_hard_links)
294 init_hard_links(flist);
dc5ddbcc 295
6957ae33
AT
296 if (!delete_after) {
297 /* I moved this here from recv_files() to prevent a race condition */
298 if (recurse && delete_mode && !local_name && flist->count>0) {
299 delete_files(flist);
300 }
301 }
302
08f15335 303 if (fd_pair(recv_pipe) < 0) {
d186eb1a 304 rprintf(FERROR,"pipe failed in do_recv\n");
65417579 305 exit_cleanup(RERR_SOCKETIO);
d186eb1a 306 }
554e0a8d 307
08f15335 308 if (fd_pair(error_pipe) < 0) {
554e0a8d
AT
309 rprintf(FERROR,"error pipe failed in do_recv\n");
310 exit_cleanup(RERR_SOCKETIO);
311 }
c6e7fcb4 312
8d9dc9f9 313 io_flush();
c6e7fcb4 314
d186eb1a 315 if ((pid=do_fork()) == 0) {
e08c9610 316 close(recv_pipe[0]);
554e0a8d 317 close(error_pipe[0]);
e08c9610
AT
318 if (f_in != f_out) close(f_out);
319
554e0a8d
AT
320 /* we can't let two processes write to the socket at one time */
321 io_multiplexing_close();
322
323 /* set place to send errors */
324 set_error_fd(error_pipe[1]);
325
e08c9610 326 recv_files(f_in,flist,local_name,recv_pipe[1]);
3d382777 327 io_flush();
ba5e128d 328 report(f_in);
e08c9610 329
8b35435f
AT
330 write_int(recv_pipe[1],1);
331 close(recv_pipe[1]);
8d9dc9f9 332 io_flush();
4a748188
AT
333 /* finally we go to sleep until our parent kills us
334 with a USR2 signal. We sleepp for a short time as on
335 some OSes a signal won't interrupt a sleep! */
336 while (1) sleep(1);
d186eb1a 337 }
dc5ddbcc 338
e08c9610 339 close(recv_pipe[1]);
554e0a8d 340 close(error_pipe[1]);
e08c9610
AT
341 io_close_input(f_in);
342 if (f_in != f_out) close(f_in);
e1b3d5c4 343
b3e10ed7
AT
344 io_start_buffering(f_out);
345
554e0a8d
AT
346 io_set_error_fd(error_pipe[0]);
347
e08c9610 348 generate_files(f_out,flist,local_name,recv_pipe[0]);
8d9dc9f9 349
8b35435f
AT
350 read_int(recv_pipe[0]);
351 close(recv_pipe[0]);
8ada7518
AT
352 if (remote_version >= 24) {
353 /* send a final goodbye message */
354 write_int(f_out, -1);
355 }
8d9dc9f9 356 io_flush();
8ada7518 357
8b35435f 358 kill(pid, SIGUSR2);
d79d1c69 359 wait_process(pid, &status);
d186eb1a 360 return status;
dc5ddbcc
AT
361}
362
c627d613 363
9486289c 364static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
c627d613 365{
7a6421fa
AT
366 int status;
367 struct file_list *flist;
368 char *local_name=NULL;
369 char *dir = NULL;
370 extern int delete_mode;
b33b791e 371 extern int delete_excluded;
7a6421fa 372 extern int am_daemon;
09b7f5db
AT
373 extern int module_id;
374 extern int am_sender;
f0fca04e 375
7a6421fa
AT
376 if (verbose > 2)
377 rprintf(FINFO,"server_recv(%d) starting pid=%d\n",argc,(int)getpid());
09b7f5db
AT
378
379 if (am_daemon && lp_read_only(module_id) && !am_sender) {
380 rprintf(FERROR,"ERROR: module is read only\n");
381 exit_cleanup(RERR_SYNTAX);
382 return;
383 }
384
7a6421fa 385
7a6421fa
AT
386 if (argc > 0) {
387 dir = argv[0];
388 argc--;
389 argv++;
5243c216
AT
390 if (!am_daemon && !push_dir(dir, 0)) {
391 rprintf(FERROR,"push_dir %s : %s (4)\n",
7a6421fa 392 dir,strerror(errno));
65417579 393 exit_cleanup(RERR_FILESELECT);
7a6421fa
AT
394 }
395 }
c627d613 396
b33b791e 397 if (delete_mode && !delete_excluded)
7a6421fa 398 recv_exclude_list(f_in);
c627d613 399
7a6421fa 400 flist = recv_file_list(f_in);
4c36a13e
AT
401 if (!flist) {
402 rprintf(FERROR,"server_recv: recv_file_list error\n");
65417579 403 exit_cleanup(RERR_FILESELECT);
7a6421fa
AT
404 }
405
406 if (argc > 0) {
407 if (strcmp(dir,".")) {
408 argv[0] += strlen(dir);
409 if (argv[0][0] == '/') argv[0]++;
410 }
411 local_name = get_local_name(flist,argv[0]);
412 }
c627d613 413
7a6421fa
AT
414 status = do_recv(f_in,f_out,flist,local_name);
415 exit_cleanup(status);
c627d613
AT
416}
417
418
9486289c 419void start_server(int f_in, int f_out, int argc, char *argv[])
366345fe 420{
7a6421fa
AT
421 extern int cvs_exclude;
422 extern int am_sender;
ff41a59f
AT
423 extern int remote_version;
424
6d7b6081
AT
425 setup_protocol(f_out, f_in);
426
f0359dd0
AT
427 set_nonblocking(f_in);
428 set_nonblocking(f_out);
429
ff41a59f
AT
430 if (remote_version >= 23)
431 io_start_multiplex_out(f_out);
7a6421fa 432
7a6421fa
AT
433 if (am_sender) {
434 recv_exclude_list(f_in);
435 if (cvs_exclude)
436 add_cvs_excludes();
437 do_server_sender(f_in, f_out, argc, argv);
438 } else {
439 do_server_recv(f_in, f_out, argc, argv);
440 }
441 exit_cleanup(0);
366345fe
AT
442}
443
3591c066 444int client_run(int f_in, int f_out, int pid, int argc, char *argv[])
9486289c
AT
445{
446 struct file_list *flist;
447 int status = 0, status2 = 0;
448 char *local_name = NULL;
7a6421fa 449 extern int am_sender;
f7632fc6 450 extern int list_only;
ff41a59f
AT
451 extern int remote_version;
452
f0359dd0
AT
453 set_nonblocking(f_in);
454 set_nonblocking(f_out);
455
6d7b6081
AT
456 setup_protocol(f_out,f_in);
457
ff41a59f
AT
458 if (remote_version >= 23)
459 io_start_multiplex_in(f_in);
9486289c
AT
460
461 if (am_sender) {
7a6421fa
AT
462 extern int cvs_exclude;
463 extern int delete_mode;
b33b791e 464 extern int delete_excluded;
9486289c
AT
465 if (cvs_exclude)
466 add_cvs_excludes();
b33b791e 467 if (delete_mode && !delete_excluded)
9486289c
AT
468 send_exclude_list(f_out);
469 flist = send_file_list(f_out,argc,argv);
470 if (verbose > 3)
471 rprintf(FINFO,"file list sent\n");
e1b3d5c4 472
9486289c
AT
473 send_files(flist,f_out,f_in);
474 if (pid != -1) {
475 if (verbose > 3)
8d9dc9f9
AT
476 rprintf(FINFO,"client_run waiting on %d\n",pid);
477 io_flush();
d79d1c69 478 wait_process(pid, &status);
9486289c 479 }
8ada7518
AT
480 if (remote_version >= 24) {
481 /* final goodbye message */
482 read_int(f_in);
483 }
3d382777 484 report(-1);
9486289c
AT
485 exit_cleanup(status);
486 }
f7632fc6
AT
487
488 if (argc == 0) list_only = 1;
9486289c
AT
489
490 send_exclude_list(f_out);
491
492 flist = recv_file_list(f_in);
493 if (!flist || flist->count == 0) {
8d9dc9f9 494 rprintf(FINFO,"client: nothing to do\n");
9486289c
AT
495 exit_cleanup(0);
496 }
497
498 local_name = get_local_name(flist,argv[0]);
499
500 status2 = do_recv(f_in,f_out,flist,local_name);
501
9486289c 502 if (pid != -1) {
8d9dc9f9
AT
503 if (verbose > 3)
504 rprintf(FINFO,"client_run2 waiting on %d\n",pid);
505 io_flush();
d79d1c69 506 wait_process(pid, &status);
9486289c
AT
507 }
508
509 return status | status2;
510}
511
ca6c93f8
AT
512static char *find_colon(char *s)
513{
514 char *p, *p2;
515
516 p = strchr(s,':');
517 if (!p) return NULL;
518
519 /* now check to see if there is a / in the string before the : - if there is then
520 discard the colon on the assumption that the : is part of a filename */
521 p2 = strchr(s,'/');
522 if (p2 && p2 < p) return NULL;
523
524 return p;
525}
9486289c 526
fc8a6b97 527static int start_client(int argc, char *argv[])
5d6bcd44
AT
528{
529 char *p;
530 char *shell_machine = NULL;
531 char *shell_path = NULL;
532 char *shell_user = NULL;
fc8a6b97 533 int pid, ret;
5d6bcd44 534 int f_in,f_out;
7a6421fa
AT
535 extern int local_server;
536 extern int am_sender;
537 extern char *shell_cmd;
2acf81eb 538 extern int rsync_port;
5d6bcd44 539
f7632fc6
AT
540 if (strncasecmp(URL_PREFIX, argv[0], strlen(URL_PREFIX)) == 0) {
541 char *host, *path;
542
543 host = argv[0] + strlen(URL_PREFIX);
544 p = strchr(host,'/');
545 if (p) {
546 *p = 0;
547 path = p+1;
548 } else {
549 path="";
550 }
2acf81eb
DD
551 p = strchr(host,':');
552 if (p) {
553 rsync_port = atoi(p+1);
554 *p = 0;
555 }
f7632fc6
AT
556 return start_socket_client(host, path, argc-1, argv+1);
557 }
558
ca6c93f8 559 p = find_colon(argv[0]);
5d6bcd44
AT
560
561 if (p) {
9486289c
AT
562 if (p[1] == ':') {
563 *p = 0;
564 return start_socket_client(argv[0], p+2, argc-1, argv+1);
565 }
3591c066 566
f7632fc6 567 if (argc < 1) {
3591c066 568 usage(FERROR);
65417579 569 exit_cleanup(RERR_SYNTAX);
3591c066
AT
570 }
571
5d6bcd44
AT
572 am_sender = 0;
573 *p = 0;
574 shell_machine = argv[0];
575 shell_path = p+1;
576 argc--;
577 argv++;
578 } else {
579 am_sender = 1;
9486289c 580
ca6c93f8 581 p = find_colon(argv[argc-1]);
5d6bcd44
AT
582 if (!p) {
583 local_server = 1;
9486289c
AT
584 } else if (p[1] == ':') {
585 *p = 0;
586 return start_socket_client(argv[argc-1], p+2, argc-1, argv);
5d6bcd44 587 }
3591c066
AT
588
589 if (argc < 2) {
590 usage(FERROR);
65417579 591 exit_cleanup(RERR_SYNTAX);
3591c066 592 }
9486289c 593
5d6bcd44
AT
594 if (local_server) {
595 shell_machine = NULL;
596 shell_path = argv[argc-1];
597 } else {
598 *p = 0;
599 shell_machine = argv[argc-1];
600 shell_path = p+1;
601 }
602 argc--;
603 }
604
605 if (shell_machine) {
606 p = strchr(shell_machine,'@');
607 if (p) {
608 *p = 0;
609 shell_user = shell_machine;
610 shell_machine = p+1;
611 }
612 }
613
614 if (verbose > 3) {
9486289c 615 rprintf(FINFO,"cmd=%s machine=%s user=%s path=%s\n",
5d6bcd44
AT
616 shell_cmd?shell_cmd:"",
617 shell_machine?shell_machine:"",
618 shell_user?shell_user:"",
619 shell_path?shell_path:"");
620 }
621
f7632fc6 622 if (!am_sender && argc > 1) {
5d6bcd44 623 usage(FERROR);
65417579 624 exit_cleanup(RERR_SYNTAX);
5d6bcd44
AT
625 }
626
627 pid = do_cmd(shell_cmd,shell_machine,shell_user,shell_path,&f_in,&f_out);
628
fc8a6b97
AT
629 ret = client_run(f_in, f_out, pid, argc, argv);
630
631 fflush(stdout);
632 fflush(stderr);
633
634 return ret;
5d6bcd44
AT
635}
636
366345fe 637
6e4fb64e 638static RETSIGTYPE sigusr1_handler(int val) {
65417579 639 exit_cleanup(RERR_SIGNAL);
82306bf6
AT
640}
641
8b35435f
AT
642static RETSIGTYPE sigusr2_handler(int val) {
643 _exit(0);
644}
645
5d6bcd44 646int main(int argc,char *argv[])
7a6421fa
AT
647{
648 extern int am_root;
649 extern int orig_umask;
650 extern int dry_run;
651 extern int am_daemon;
652 extern int am_server;
5d6bcd44 653
7a6421fa 654 signal(SIGUSR1, sigusr1_handler);
8b35435f 655 signal(SIGUSR2, sigusr2_handler);
5d6bcd44 656
7a6421fa
AT
657 starttime = time(NULL);
658 am_root = (getuid() == 0);
c627d613 659
a800434a
AT
660 memset(&stats, 0, sizeof(stats));
661
df5e03da
AT
662 if (argc < 2) {
663 usage(FERROR);
65417579 664 exit_cleanup(RERR_SYNTAX);
df5e03da
AT
665 }
666
7a6421fa
AT
667 /* we set a 0 umask so that correct file permissions can be
668 carried across */
669 orig_umask = (int)umask(0);
5d6bcd44 670
b86f0cef 671 if (!parse_arguments(argc, argv, 1)) {
65417579 672 exit_cleanup(RERR_SYNTAX);
b11ed3b1 673 }
5d6bcd44 674
7a6421fa
AT
675 argc -= optind;
676 argv += optind;
677 optind = 0;
c627d613 678
7a6421fa
AT
679 signal(SIGCHLD,SIG_IGN);
680 signal(SIGINT,SIGNAL_CAST sig_int);
681 signal(SIGPIPE,SIGNAL_CAST sig_int);
682 signal(SIGHUP,SIGNAL_CAST sig_int);
8638dd48 683 signal(SIGTERM,SIGNAL_CAST sig_int);
6b83141d 684
c226b7c2
DD
685 /* Initialize push_dir here because on some old systems getcwd
686 (implemented by forking "pwd" and reading its output) doesn't
687 work when there are other child processes. Also, on all systems
688 that implement getcwd that way "pwd" can't be found after chroot. */
689 push_dir(NULL,0);
690
7a6421fa
AT
691 if (am_daemon) {
692 return daemon_main();
693 }
f0fca04e 694
08ac228f
AT
695 if (argc < 1) {
696 usage(FERROR);
65417579 697 exit_cleanup(RERR_SYNTAX);
08ac228f
AT
698 }
699
7a6421fa
AT
700 if (dry_run)
701 verbose = MAX(verbose,1);
c627d613 702
cbbe4892 703#ifndef SUPPORT_LINKS
7a6421fa
AT
704 if (!am_server && preserve_links) {
705 rprintf(FERROR,"ERROR: symbolic links not supported\n");
65417579 706 exit_cleanup(RERR_UNSUPPORTED);
7a6421fa 707 }
cbbe4892
AT
708#endif
709
7a6421fa 710 if (am_server) {
f0359dd0
AT
711 set_nonblocking(STDIN_FILENO);
712 set_nonblocking(STDOUT_FILENO);
7a6421fa
AT
713 start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
714 }
c627d613 715
7a6421fa 716 return start_client(argc, argv);
c627d613 717}
82306bf6 718