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