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