fix bug in handling of :
[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;
c32d0240 560 char *argv0 = strdup(argv[0]);
5d6bcd44 561
c32d0240 562 if (strncasecmp(URL_PREFIX, argv0, strlen(URL_PREFIX)) == 0) {
f7632fc6
AT
563 char *host, *path;
564
c32d0240 565 host = argv0 + strlen(URL_PREFIX);
f7632fc6
AT
566 p = strchr(host,'/');
567 if (p) {
568 *p = 0;
569 path = p+1;
570 } else {
571 path="";
572 }
2acf81eb
DD
573 p = strchr(host,':');
574 if (p) {
575 rsync_port = atoi(p+1);
576 *p = 0;
577 }
f7632fc6
AT
578 return start_socket_client(host, path, argc-1, argv+1);
579 }
580
c32d0240 581 p = find_colon(argv0);
5d6bcd44
AT
582
583 if (p) {
9486289c
AT
584 if (p[1] == ':') {
585 *p = 0;
c32d0240 586 return start_socket_client(argv0, p+2, argc-1, argv+1);
9486289c 587 }
3591c066 588
f7632fc6 589 if (argc < 1) {
3591c066 590 usage(FERROR);
65417579 591 exit_cleanup(RERR_SYNTAX);
3591c066
AT
592 }
593
5d6bcd44
AT
594 am_sender = 0;
595 *p = 0;
38bf526f 596 shell_machine = argv0;
5d6bcd44
AT
597 shell_path = p+1;
598 argc--;
599 argv++;
600 } else {
601 am_sender = 1;
9486289c 602
ca6c93f8 603 p = find_colon(argv[argc-1]);
5d6bcd44
AT
604 if (!p) {
605 local_server = 1;
9486289c
AT
606 } else if (p[1] == ':') {
607 *p = 0;
608 return start_socket_client(argv[argc-1], p+2, argc-1, argv);
5d6bcd44 609 }
3591c066
AT
610
611 if (argc < 2) {
612 usage(FERROR);
65417579 613 exit_cleanup(RERR_SYNTAX);
3591c066 614 }
9486289c 615
5d6bcd44
AT
616 if (local_server) {
617 shell_machine = NULL;
618 shell_path = argv[argc-1];
619 } else {
620 *p = 0;
621 shell_machine = argv[argc-1];
622 shell_path = p+1;
623 }
624 argc--;
625 }
626
627 if (shell_machine) {
628 p = strchr(shell_machine,'@');
629 if (p) {
630 *p = 0;
631 shell_user = shell_machine;
632 shell_machine = p+1;
633 }
634 }
635
636 if (verbose > 3) {
9486289c 637 rprintf(FINFO,"cmd=%s machine=%s user=%s path=%s\n",
5d6bcd44
AT
638 shell_cmd?shell_cmd:"",
639 shell_machine?shell_machine:"",
640 shell_user?shell_user:"",
641 shell_path?shell_path:"");
642 }
643
f7632fc6 644 if (!am_sender && argc > 1) {
5d6bcd44 645 usage(FERROR);
65417579 646 exit_cleanup(RERR_SYNTAX);
5d6bcd44 647 }
27e3e9c9
AT
648
649 if (argc == 0 && !am_sender) {
650 extern int list_only;
651 list_only = 1;
652 }
5d6bcd44
AT
653
654 pid = do_cmd(shell_cmd,shell_machine,shell_user,shell_path,&f_in,&f_out);
655
fc8a6b97
AT
656 ret = client_run(f_in, f_out, pid, argc, argv);
657
658 fflush(stdout);
659 fflush(stderr);
660
661 return ret;
5d6bcd44
AT
662}
663
366345fe 664
6e4fb64e 665static RETSIGTYPE sigusr1_handler(int val) {
65417579 666 exit_cleanup(RERR_SIGNAL);
82306bf6
AT
667}
668
8b35435f
AT
669static RETSIGTYPE sigusr2_handler(int val) {
670 _exit(0);
671}
672
5d6bcd44 673int main(int argc,char *argv[])
7a6421fa
AT
674{
675 extern int am_root;
676 extern int orig_umask;
677 extern int dry_run;
678 extern int am_daemon;
679 extern int am_server;
5d6bcd44 680
7a6421fa 681 signal(SIGUSR1, sigusr1_handler);
8b35435f 682 signal(SIGUSR2, sigusr2_handler);
5d6bcd44 683
7a6421fa
AT
684 starttime = time(NULL);
685 am_root = (getuid() == 0);
c627d613 686
a800434a
AT
687 memset(&stats, 0, sizeof(stats));
688
df5e03da
AT
689 if (argc < 2) {
690 usage(FERROR);
65417579 691 exit_cleanup(RERR_SYNTAX);
df5e03da
AT
692 }
693
7a6421fa
AT
694 /* we set a 0 umask so that correct file permissions can be
695 carried across */
696 orig_umask = (int)umask(0);
5d6bcd44 697
b86f0cef 698 if (!parse_arguments(argc, argv, 1)) {
65417579 699 exit_cleanup(RERR_SYNTAX);
b11ed3b1 700 }
5d6bcd44 701
7a6421fa
AT
702 argc -= optind;
703 argv += optind;
704 optind = 0;
c627d613 705
7a6421fa
AT
706 signal(SIGCHLD,SIG_IGN);
707 signal(SIGINT,SIGNAL_CAST sig_int);
708 signal(SIGPIPE,SIGNAL_CAST sig_int);
709 signal(SIGHUP,SIGNAL_CAST sig_int);
8638dd48 710 signal(SIGTERM,SIGNAL_CAST sig_int);
6b83141d 711
c226b7c2
DD
712 /* Initialize push_dir here because on some old systems getcwd
713 (implemented by forking "pwd" and reading its output) doesn't
714 work when there are other child processes. Also, on all systems
715 that implement getcwd that way "pwd" can't be found after chroot. */
716 push_dir(NULL,0);
717
7a6421fa
AT
718 if (am_daemon) {
719 return daemon_main();
720 }
f0fca04e 721
08ac228f
AT
722 if (argc < 1) {
723 usage(FERROR);
65417579 724 exit_cleanup(RERR_SYNTAX);
08ac228f
AT
725 }
726
7a6421fa
AT
727 if (dry_run)
728 verbose = MAX(verbose,1);
c627d613 729
cbbe4892 730#ifndef SUPPORT_LINKS
7a6421fa
AT
731 if (!am_server && preserve_links) {
732 rprintf(FERROR,"ERROR: symbolic links not supported\n");
65417579 733 exit_cleanup(RERR_UNSUPPORTED);
7a6421fa 734 }
cbbe4892
AT
735#endif
736
7a6421fa 737 if (am_server) {
f0359dd0
AT
738 set_nonblocking(STDIN_FILENO);
739 set_nonblocking(STDOUT_FILENO);
7a6421fa
AT
740 start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
741 }
c627d613 742
7a6421fa 743 return start_client(argc, argv);
c627d613 744}
82306bf6 745