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