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