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