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