Add note in "secrets file" section to see "strict modes".
[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) {
a24c6870 35 msleep(20);
82980a23
AT
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 351 /* finally we go to sleep until our parent kills us
27e3e9c9 352 with a USR2 signal. We sleep for a short time as on
4a748188 353 some OSes a signal won't interrupt a sleep! */
27e3e9c9 354 while (1) msleep(20);
d186eb1a 355 }
dc5ddbcc 356
e08c9610 357 close(recv_pipe[1]);
554e0a8d 358 close(error_pipe[1]);
e08c9610 359 if (f_in != f_out) close(f_in);
e1b3d5c4 360
b3e10ed7
AT
361 io_start_buffering(f_out);
362
554e0a8d
AT
363 io_set_error_fd(error_pipe[0]);
364
e08c9610 365 generate_files(f_out,flist,local_name,recv_pipe[0]);
8d9dc9f9 366
8b35435f
AT
367 read_int(recv_pipe[0]);
368 close(recv_pipe[0]);
8ada7518
AT
369 if (remote_version >= 24) {
370 /* send a final goodbye message */
371 write_int(f_out, -1);
372 }
8d9dc9f9 373 io_flush();
8ada7518 374
8b35435f 375 kill(pid, SIGUSR2);
d79d1c69 376 wait_process(pid, &status);
d186eb1a 377 return status;
dc5ddbcc
AT
378}
379
c627d613 380
9486289c 381static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
c627d613 382{
7a6421fa
AT
383 int status;
384 struct file_list *flist;
385 char *local_name=NULL;
386 char *dir = NULL;
387 extern int delete_mode;
b33b791e 388 extern int delete_excluded;
7a6421fa 389 extern int am_daemon;
09b7f5db
AT
390 extern int module_id;
391 extern int am_sender;
f0fca04e 392
7a6421fa
AT
393 if (verbose > 2)
394 rprintf(FINFO,"server_recv(%d) starting pid=%d\n",argc,(int)getpid());
09b7f5db
AT
395
396 if (am_daemon && lp_read_only(module_id) && !am_sender) {
397 rprintf(FERROR,"ERROR: module is read only\n");
398 exit_cleanup(RERR_SYNTAX);
399 return;
400 }
401
7a6421fa 402
7a6421fa
AT
403 if (argc > 0) {
404 dir = argv[0];
405 argc--;
406 argv++;
5243c216
AT
407 if (!am_daemon && !push_dir(dir, 0)) {
408 rprintf(FERROR,"push_dir %s : %s (4)\n",
7a6421fa 409 dir,strerror(errno));
65417579 410 exit_cleanup(RERR_FILESELECT);
7a6421fa
AT
411 }
412 }
c627d613 413
b33b791e 414 if (delete_mode && !delete_excluded)
7a6421fa 415 recv_exclude_list(f_in);
c627d613 416
7a6421fa 417 flist = recv_file_list(f_in);
4c36a13e
AT
418 if (!flist) {
419 rprintf(FERROR,"server_recv: recv_file_list error\n");
65417579 420 exit_cleanup(RERR_FILESELECT);
7a6421fa
AT
421 }
422
423 if (argc > 0) {
424 if (strcmp(dir,".")) {
425 argv[0] += strlen(dir);
426 if (argv[0][0] == '/') argv[0]++;
427 }
428 local_name = get_local_name(flist,argv[0]);
429 }
c627d613 430
7a6421fa
AT
431 status = do_recv(f_in,f_out,flist,local_name);
432 exit_cleanup(status);
c627d613
AT
433}
434
435
9486289c 436void start_server(int f_in, int f_out, int argc, char *argv[])
366345fe 437{
7a6421fa
AT
438 extern int cvs_exclude;
439 extern int am_sender;
ff41a59f
AT
440 extern int remote_version;
441
6d7b6081
AT
442 setup_protocol(f_out, f_in);
443
f0359dd0
AT
444 set_nonblocking(f_in);
445 set_nonblocking(f_out);
446
ff41a59f
AT
447 if (remote_version >= 23)
448 io_start_multiplex_out(f_out);
7a6421fa 449
7a6421fa
AT
450 if (am_sender) {
451 recv_exclude_list(f_in);
452 if (cvs_exclude)
453 add_cvs_excludes();
454 do_server_sender(f_in, f_out, argc, argv);
455 } else {
456 do_server_recv(f_in, f_out, argc, argv);
457 }
458 exit_cleanup(0);
366345fe
AT
459}
460
3591c066 461int client_run(int f_in, int f_out, int pid, int argc, char *argv[])
9486289c
AT
462{
463 struct file_list *flist;
464 int status = 0, status2 = 0;
465 char *local_name = NULL;
7a6421fa 466 extern int am_sender;
ff41a59f
AT
467 extern int remote_version;
468
f0359dd0
AT
469 set_nonblocking(f_in);
470 set_nonblocking(f_out);
471
6d7b6081
AT
472 setup_protocol(f_out,f_in);
473
ff41a59f
AT
474 if (remote_version >= 23)
475 io_start_multiplex_in(f_in);
9486289c
AT
476
477 if (am_sender) {
7a6421fa
AT
478 extern int cvs_exclude;
479 extern int delete_mode;
b33b791e 480 extern int delete_excluded;
9486289c
AT
481 if (cvs_exclude)
482 add_cvs_excludes();
b33b791e 483 if (delete_mode && !delete_excluded)
9486289c
AT
484 send_exclude_list(f_out);
485 flist = send_file_list(f_out,argc,argv);
486 if (verbose > 3)
487 rprintf(FINFO,"file list sent\n");
e1b3d5c4 488
9486289c
AT
489 send_files(flist,f_out,f_in);
490 if (pid != -1) {
491 if (verbose > 3)
8d9dc9f9
AT
492 rprintf(FINFO,"client_run waiting on %d\n",pid);
493 io_flush();
d79d1c69 494 wait_process(pid, &status);
9486289c 495 }
8ada7518
AT
496 if (remote_version >= 24) {
497 /* final goodbye message */
498 read_int(f_in);
499 }
3d382777 500 report(-1);
9486289c
AT
501 exit_cleanup(status);
502 }
f7632fc6 503
27e3e9c9
AT
504 if (argc == 0) {
505 extern int list_only;
506 list_only = 1;
507 }
9486289c
AT
508
509 send_exclude_list(f_out);
510
511 flist = recv_file_list(f_in);
512 if (!flist || flist->count == 0) {
796d484b
MP
513 rprintf(FINFO, "client: nothing to do: "
514 "perhaps you need to specify some filenames or "
515 "the --recursive option?\n");
9486289c
AT
516 exit_cleanup(0);
517 }
518
519 local_name = get_local_name(flist,argv[0]);
520
521 status2 = do_recv(f_in,f_out,flist,local_name);
522
9486289c 523 if (pid != -1) {
8d9dc9f9
AT
524 if (verbose > 3)
525 rprintf(FINFO,"client_run2 waiting on %d\n",pid);
526 io_flush();
d79d1c69 527 wait_process(pid, &status);
9486289c
AT
528 }
529
530 return status | status2;
531}
532
ca6c93f8
AT
533static char *find_colon(char *s)
534{
535 char *p, *p2;
536
537 p = strchr(s,':');
538 if (!p) return NULL;
539
540 /* now check to see if there is a / in the string before the : - if there is then
541 discard the colon on the assumption that the : is part of a filename */
542 p2 = strchr(s,'/');
543 if (p2 && p2 < p) return NULL;
544
545 return p;
546}
9486289c 547
fc8a6b97 548static int start_client(int argc, char *argv[])
5d6bcd44
AT
549{
550 char *p;
551 char *shell_machine = NULL;
552 char *shell_path = NULL;
553 char *shell_user = NULL;
fc8a6b97 554 int pid, ret;
5d6bcd44 555 int f_in,f_out;
7a6421fa
AT
556 extern int local_server;
557 extern int am_sender;
558 extern char *shell_cmd;
2acf81eb 559 extern int rsync_port;
5d6bcd44 560
f7632fc6
AT
561 if (strncasecmp(URL_PREFIX, argv[0], strlen(URL_PREFIX)) == 0) {
562 char *host, *path;
563
564 host = argv[0] + strlen(URL_PREFIX);
565 p = strchr(host,'/');
566 if (p) {
567 *p = 0;
568 path = p+1;
569 } else {
570 path="";
571 }
2acf81eb
DD
572 p = strchr(host,':');
573 if (p) {
574 rsync_port = atoi(p+1);
575 *p = 0;
576 }
f7632fc6
AT
577 return start_socket_client(host, path, argc-1, argv+1);
578 }
579
ca6c93f8 580 p = find_colon(argv[0]);
5d6bcd44
AT
581
582 if (p) {
9486289c
AT
583 if (p[1] == ':') {
584 *p = 0;
585 return start_socket_client(argv[0], p+2, argc-1, argv+1);
586 }
3591c066 587
f7632fc6 588 if (argc < 1) {
3591c066 589 usage(FERROR);
65417579 590 exit_cleanup(RERR_SYNTAX);
3591c066
AT
591 }
592
5d6bcd44
AT
593 am_sender = 0;
594 *p = 0;
595 shell_machine = argv[0];
596 shell_path = p+1;
597 argc--;
598 argv++;
599 } else {
600 am_sender = 1;
9486289c 601
ca6c93f8 602 p = find_colon(argv[argc-1]);
5d6bcd44
AT
603 if (!p) {
604 local_server = 1;
9486289c
AT
605 } else if (p[1] == ':') {
606 *p = 0;
607 return start_socket_client(argv[argc-1], p+2, argc-1, argv);
5d6bcd44 608 }
3591c066
AT
609
610 if (argc < 2) {
611 usage(FERROR);
65417579 612 exit_cleanup(RERR_SYNTAX);
3591c066 613 }
9486289c 614
5d6bcd44
AT
615 if (local_server) {
616 shell_machine = NULL;
617 shell_path = argv[argc-1];
618 } else {
619 *p = 0;
620 shell_machine = argv[argc-1];
621 shell_path = p+1;
622 }
623 argc--;
624 }
625
626 if (shell_machine) {
627 p = strchr(shell_machine,'@');
628 if (p) {
629 *p = 0;
630 shell_user = shell_machine;
631 shell_machine = p+1;
632 }
633 }
634
635 if (verbose > 3) {
9486289c 636 rprintf(FINFO,"cmd=%s machine=%s user=%s path=%s\n",
5d6bcd44
AT
637 shell_cmd?shell_cmd:"",
638 shell_machine?shell_machine:"",
639 shell_user?shell_user:"",
640 shell_path?shell_path:"");
641 }
642
f7632fc6 643 if (!am_sender && argc > 1) {
5d6bcd44 644 usage(FERROR);
65417579 645 exit_cleanup(RERR_SYNTAX);
5d6bcd44 646 }
27e3e9c9
AT
647
648 if (argc == 0 && !am_sender) {
649 extern int list_only;
650 list_only = 1;
651 }
5d6bcd44
AT
652
653 pid = do_cmd(shell_cmd,shell_machine,shell_user,shell_path,&f_in,&f_out);
654
fc8a6b97
AT
655 ret = client_run(f_in, f_out, pid, argc, argv);
656
657 fflush(stdout);
658 fflush(stderr);
659
660 return ret;
5d6bcd44
AT
661}
662
366345fe 663
6e4fb64e 664static RETSIGTYPE sigusr1_handler(int val) {
65417579 665 exit_cleanup(RERR_SIGNAL);
82306bf6
AT
666}
667
8b35435f
AT
668static RETSIGTYPE sigusr2_handler(int val) {
669 _exit(0);
670}
671
5d6bcd44 672int main(int argc,char *argv[])
7a6421fa
AT
673{
674 extern int am_root;
675 extern int orig_umask;
676 extern int dry_run;
677 extern int am_daemon;
678 extern int am_server;
5d6bcd44 679
7a6421fa 680 signal(SIGUSR1, sigusr1_handler);
8b35435f 681 signal(SIGUSR2, sigusr2_handler);
5d6bcd44 682
7a6421fa
AT
683 starttime = time(NULL);
684 am_root = (getuid() == 0);
c627d613 685
a800434a
AT
686 memset(&stats, 0, sizeof(stats));
687
df5e03da
AT
688 if (argc < 2) {
689 usage(FERROR);
65417579 690 exit_cleanup(RERR_SYNTAX);
df5e03da
AT
691 }
692
7a6421fa
AT
693 /* we set a 0 umask so that correct file permissions can be
694 carried across */
695 orig_umask = (int)umask(0);
5d6bcd44 696
b86f0cef 697 if (!parse_arguments(argc, argv, 1)) {
65417579 698 exit_cleanup(RERR_SYNTAX);
b11ed3b1 699 }
5d6bcd44 700
7a6421fa
AT
701 argc -= optind;
702 argv += optind;
703 optind = 0;
c627d613 704
7a6421fa
AT
705 signal(SIGCHLD,SIG_IGN);
706 signal(SIGINT,SIGNAL_CAST sig_int);
707 signal(SIGPIPE,SIGNAL_CAST sig_int);
708 signal(SIGHUP,SIGNAL_CAST sig_int);
8638dd48 709 signal(SIGTERM,SIGNAL_CAST sig_int);
6b83141d 710
c226b7c2
DD
711 /* Initialize push_dir here because on some old systems getcwd
712 (implemented by forking "pwd" and reading its output) doesn't
713 work when there are other child processes. Also, on all systems
714 that implement getcwd that way "pwd" can't be found after chroot. */
715 push_dir(NULL,0);
716
7a6421fa
AT
717 if (am_daemon) {
718 return daemon_main();
719 }
f0fca04e 720
08ac228f
AT
721 if (argc < 1) {
722 usage(FERROR);
65417579 723 exit_cleanup(RERR_SYNTAX);
08ac228f
AT
724 }
725
7a6421fa
AT
726 if (dry_run)
727 verbose = MAX(verbose,1);
c627d613 728
cbbe4892 729#ifndef SUPPORT_LINKS
7a6421fa
AT
730 if (!am_server && preserve_links) {
731 rprintf(FERROR,"ERROR: symbolic links not supported\n");
65417579 732 exit_cleanup(RERR_UNSUPPORTED);
7a6421fa 733 }
cbbe4892
AT
734#endif
735
7a6421fa 736 if (am_server) {
f0359dd0
AT
737 set_nonblocking(STDIN_FILENO);
738 set_nonblocking(STDOUT_FILENO);
7a6421fa
AT
739 start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
740 }
c627d613 741
7a6421fa 742 return start_client(argc, argv);
c627d613 743}
82306bf6 744