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