Drop dead variables introduced in rsync+ patch.
[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 405 extern int read_batch; /* dw */
6902ed17 406 extern struct file_list *batch_flist; /* dw */
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
6902ed17
MP
432 if (read_batch) /* dw */
433 flist = batch_flist;
434 else
435 flist = recv_file_list(f_in);
4c36a13e
AT
436 if (!flist) {
437 rprintf(FERROR,"server_recv: recv_file_list error\n");
65417579 438 exit_cleanup(RERR_FILESELECT);
7a6421fa
AT
439 }
440
441 if (argc > 0) {
442 if (strcmp(dir,".")) {
443 argv[0] += strlen(dir);
444 if (argv[0][0] == '/') argv[0]++;
445 }
446 local_name = get_local_name(flist,argv[0]);
447 }
c627d613 448
7a6421fa
AT
449 status = do_recv(f_in,f_out,flist,local_name);
450 exit_cleanup(status);
c627d613
AT
451}
452
453
9486289c 454void start_server(int f_in, int f_out, int argc, char *argv[])
366345fe 455{
7a6421fa
AT
456 extern int cvs_exclude;
457 extern int am_sender;
ff41a59f 458 extern int remote_version;
6902ed17 459 extern int read_batch; /* dw */
ff41a59f 460
6d7b6081
AT
461 setup_protocol(f_out, f_in);
462
f0359dd0
AT
463 set_nonblocking(f_in);
464 set_nonblocking(f_out);
465
ff41a59f
AT
466 if (remote_version >= 23)
467 io_start_multiplex_out(f_out);
7a6421fa 468
7a6421fa 469 if (am_sender) {
6902ed17
MP
470 if (!read_batch) { /* dw */
471 recv_exclude_list(f_in);
472 if (cvs_exclude)
7a6421fa 473 add_cvs_excludes();
6902ed17 474 }
7a6421fa
AT
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 */
19b27a48 487int client_run(int f_in, int f_out, pid_t 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 493 extern int remote_version;
19b27a48 494 extern pid_t cleanup_child_pid;
6902ed17
MP
495 extern int write_batch; /* dw */
496 extern int read_batch; /* dw */
497 extern struct file_list *batch_flist; /* dw */
19b27a48
AT
498
499 cleanup_child_pid = pid;
6902ed17
MP
500 if (read_batch)
501 flist = batch_flist; /* dw */
ff41a59f 502
f0359dd0
AT
503 set_nonblocking(f_in);
504 set_nonblocking(f_out);
505
6d7b6081
AT
506 setup_protocol(f_out,f_in);
507
ff41a59f
AT
508 if (remote_version >= 23)
509 io_start_multiplex_in(f_in);
9486289c
AT
510
511 if (am_sender) {
7a6421fa
AT
512 extern int cvs_exclude;
513 extern int delete_mode;
b33b791e 514 extern int delete_excluded;
9486289c
AT
515 if (cvs_exclude)
516 add_cvs_excludes();
b33b791e 517 if (delete_mode && !delete_excluded)
9486289c 518 send_exclude_list(f_out);
6902ed17
MP
519 if (!read_batch) /* dw -- don't write to pipe */
520 flist = send_file_list(f_out,argc,argv);
9486289c
AT
521 if (verbose > 3)
522 rprintf(FINFO,"file list sent\n");
e1b3d5c4 523
9486289c 524 send_files(flist,f_out,f_in);
6c65e146
AT
525 if (remote_version >= 24) {
526 /* final goodbye message */
527 read_int(f_in);
528 }
9486289c
AT
529 if (pid != -1) {
530 if (verbose > 3)
8d9dc9f9
AT
531 rprintf(FINFO,"client_run waiting on %d\n",pid);
532 io_flush();
d79d1c69 533 wait_process(pid, &status);
9486289c 534 }
3d382777 535 report(-1);
9486289c
AT
536 exit_cleanup(status);
537 }
f7632fc6 538
27e3e9c9
AT
539 if (argc == 0) {
540 extern int list_only;
541 list_only = 1;
542 }
9486289c 543
6902ed17
MP
544 if (!write_batch) /* dw */
545 send_exclude_list(f_out);
9486289c
AT
546
547 flist = recv_file_list(f_in);
548 if (!flist || flist->count == 0) {
796d484b
MP
549 rprintf(FINFO, "client: nothing to do: "
550 "perhaps you need to specify some filenames or "
551 "the --recursive option?\n");
9486289c
AT
552 exit_cleanup(0);
553 }
554
555 local_name = get_local_name(flist,argv[0]);
556
557 status2 = do_recv(f_in,f_out,flist,local_name);
558
9486289c 559 if (pid != -1) {
8d9dc9f9
AT
560 if (verbose > 3)
561 rprintf(FINFO,"client_run2 waiting on %d\n",pid);
562 io_flush();
d79d1c69 563 wait_process(pid, &status);
9486289c
AT
564 }
565
ff81e809 566 return MAX(status, status2);
9486289c
AT
567}
568
ca6c93f8
AT
569static char *find_colon(char *s)
570{
571 char *p, *p2;
572
573 p = strchr(s,':');
574 if (!p) return NULL;
575
576 /* now check to see if there is a / in the string before the : - if there is then
577 discard the colon on the assumption that the : is part of a filename */
578 p2 = strchr(s,'/');
579 if (p2 && p2 < p) return NULL;
580
581 return p;
582}
9486289c 583
0ba48136
MP
584
585/*
586 * Start a client for either type of remote connection. Work out
587 * whether the arguments request a remote shell or rsyncd connection,
588 * and call the appropriate connection function, then run_client.
589 */
fc8a6b97 590static int start_client(int argc, char *argv[])
5d6bcd44
AT
591{
592 char *p;
593 char *shell_machine = NULL;
594 char *shell_path = NULL;
595 char *shell_user = NULL;
19b27a48
AT
596 int ret;
597 pid_t pid;
5d6bcd44 598 int f_in,f_out;
7a6421fa
AT
599 extern int local_server;
600 extern int am_sender;
601 extern char *shell_cmd;
2acf81eb 602 extern int rsync_port;
a1a440c2 603 extern int whole_file;
c32d0240 604 char *argv0 = strdup(argv[0]);
6902ed17 605 extern int read_batch;
5d6bcd44 606
c32d0240 607 if (strncasecmp(URL_PREFIX, argv0, strlen(URL_PREFIX)) == 0) {
f7632fc6
AT
608 char *host, *path;
609
c32d0240 610 host = argv0 + strlen(URL_PREFIX);
f7632fc6
AT
611 p = strchr(host,'/');
612 if (p) {
613 *p = 0;
614 path = p+1;
615 } else {
616 path="";
617 }
2acf81eb
DD
618 p = strchr(host,':');
619 if (p) {
620 rsync_port = atoi(p+1);
621 *p = 0;
622 }
f7632fc6
AT
623 return start_socket_client(host, path, argc-1, argv+1);
624 }
625
6902ed17
MP
626 if (!read_batch) { /* dw */
627 p = find_colon(argv[0]);
5d6bcd44
AT
628
629 if (p) {
9486289c
AT
630 if (p[1] == ':') {
631 *p = 0;
c32d0240 632 return start_socket_client(argv0, p+2, argc-1, argv+1);
9486289c 633 }
3591c066 634
f7632fc6 635 if (argc < 1) {
3591c066 636 usage(FERROR);
65417579 637 exit_cleanup(RERR_SYNTAX);
3591c066
AT
638 }
639
5d6bcd44
AT
640 am_sender = 0;
641 *p = 0;
38bf526f 642 shell_machine = argv0;
5d6bcd44
AT
643 shell_path = p+1;
644 argc--;
645 argv++;
646 } else {
647 am_sender = 1;
9486289c 648
ca6c93f8 649 p = find_colon(argv[argc-1]);
5d6bcd44
AT
650 if (!p) {
651 local_server = 1;
a1a440c2
DD
652 /* disable "rsync algorithm" when both sides local */
653 whole_file = 1;
9486289c
AT
654 } else if (p[1] == ':') {
655 *p = 0;
656 return start_socket_client(argv[argc-1], p+2, argc-1, argv);
5d6bcd44 657 }
3591c066
AT
658
659 if (argc < 2) {
660 usage(FERROR);
65417579 661 exit_cleanup(RERR_SYNTAX);
3591c066 662 }
9486289c 663
5d6bcd44
AT
664 if (local_server) {
665 shell_machine = NULL;
666 shell_path = argv[argc-1];
667 } else {
668 *p = 0;
669 shell_machine = argv[argc-1];
670 shell_path = p+1;
671 }
672 argc--;
673 }
6902ed17
MP
674 } else {
675 am_sender = 1; /* dw */
676 local_server = 1; /* dw */
677 shell_path = argv[argc-1]; /* dw */
678 }
679
5d6bcd44
AT
680 if (shell_machine) {
681 p = strchr(shell_machine,'@');
682 if (p) {
683 *p = 0;
684 shell_user = shell_machine;
685 shell_machine = p+1;
686 }
687 }
688
689 if (verbose > 3) {
9486289c 690 rprintf(FINFO,"cmd=%s machine=%s user=%s path=%s\n",
5d6bcd44
AT
691 shell_cmd?shell_cmd:"",
692 shell_machine?shell_machine:"",
693 shell_user?shell_user:"",
694 shell_path?shell_path:"");
695 }
696
f7632fc6 697 if (!am_sender && argc > 1) {
5d6bcd44 698 usage(FERROR);
65417579 699 exit_cleanup(RERR_SYNTAX);
5d6bcd44 700 }
27e3e9c9
AT
701
702 if (argc == 0 && !am_sender) {
703 extern int list_only;
704 list_only = 1;
705 }
5d6bcd44
AT
706
707 pid = do_cmd(shell_cmd,shell_machine,shell_user,shell_path,&f_in,&f_out);
708
fc8a6b97
AT
709 ret = client_run(f_in, f_out, pid, argc, argv);
710
711 fflush(stdout);
712 fflush(stderr);
713
714 return ret;
5d6bcd44
AT
715}
716
366345fe 717
6e4fb64e 718static RETSIGTYPE sigusr1_handler(int val) {
65417579 719 exit_cleanup(RERR_SIGNAL);
82306bf6
AT
720}
721
8b35435f 722static RETSIGTYPE sigusr2_handler(int val) {
ff81e809 723 extern int log_got_error;
19b27a48 724 if (log_got_error) _exit(RERR_PARTIAL);
8b35435f
AT
725 _exit(0);
726}
727
19b27a48 728static RETSIGTYPE sigchld_handler(int val) {
029c1713
AT
729#ifdef WNOHANG
730 while (waitpid(-1, NULL, WNOHANG) > 0) ;
731#endif
19b27a48
AT
732}
733
5d6bcd44 734int main(int argc,char *argv[])
7a6421fa
AT
735{
736 extern int am_root;
737 extern int orig_umask;
738 extern int dry_run;
739 extern int am_daemon;
740 extern int am_server;
ff81e809 741 int ret;
6902ed17
MP
742 extern int read_batch; /* dw */
743 extern int write_batch; /* dw */
744 extern char *batch_ext; /* dw */
6902ed17
MP
745 int orig_argc; /* dw */
746
747 orig_argc = argc; /* dw */
5d6bcd44 748
7a6421fa 749 signal(SIGUSR1, sigusr1_handler);
8b35435f 750 signal(SIGUSR2, sigusr2_handler);
19b27a48 751 signal(SIGCHLD, sigchld_handler);
5d6bcd44 752
7a6421fa
AT
753 starttime = time(NULL);
754 am_root = (getuid() == 0);
c627d613 755
a800434a
AT
756 memset(&stats, 0, sizeof(stats));
757
df5e03da
AT
758 if (argc < 2) {
759 usage(FERROR);
65417579 760 exit_cleanup(RERR_SYNTAX);
df5e03da
AT
761 }
762
7a6421fa
AT
763 /* we set a 0 umask so that correct file permissions can be
764 carried across */
765 orig_umask = (int)umask(0);
5d6bcd44 766
50135767 767 if (!parse_arguments(&argc, (const char ***) &argv, 1)) {
305ab133
MP
768 /* FIXME: We ought to call the same error-handling
769 * code here, rather than relying on getopt. */
50135767 770 option_error();
65417579 771 exit_cleanup(RERR_SYNTAX);
b11ed3b1 772 }
5d6bcd44 773
7a6421fa
AT
774 signal(SIGINT,SIGNAL_CAST sig_int);
775 signal(SIGPIPE,SIGNAL_CAST sig_int);
776 signal(SIGHUP,SIGNAL_CAST sig_int);
8638dd48 777 signal(SIGTERM,SIGNAL_CAST sig_int);
6b83141d 778
c226b7c2
DD
779 /* Initialize push_dir here because on some old systems getcwd
780 (implemented by forking "pwd" and reading its output) doesn't
781 work when there are other child processes. Also, on all systems
782 that implement getcwd that way "pwd" can't be found after chroot. */
783 push_dir(NULL,0);
784
6902ed17
MP
785 if (write_batch) { /* dw */
786 create_batch_file_ext();
787 write_batch_argvs_file(orig_argc, argc, argv);
788 }
789
790 if (read_batch) { /* dw */
791 set_batch_file_ext(batch_ext);
792 }
793
7a6421fa
AT
794 if (am_daemon) {
795 return daemon_main();
796 }
f0fca04e 797
08ac228f
AT
798 if (argc < 1) {
799 usage(FERROR);
65417579 800 exit_cleanup(RERR_SYNTAX);
08ac228f
AT
801 }
802
7a6421fa
AT
803 if (dry_run)
804 verbose = MAX(verbose,1);
c627d613 805
cbbe4892 806#ifndef SUPPORT_LINKS
7a6421fa
AT
807 if (!am_server && preserve_links) {
808 rprintf(FERROR,"ERROR: symbolic links not supported\n");
65417579 809 exit_cleanup(RERR_UNSUPPORTED);
7a6421fa 810 }
cbbe4892
AT
811#endif
812
7a6421fa 813 if (am_server) {
f0359dd0
AT
814 set_nonblocking(STDIN_FILENO);
815 set_nonblocking(STDOUT_FILENO);
7a6421fa
AT
816 start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
817 }
c627d613 818
ff81e809
AT
819 ret = start_client(argc, argv);
820 exit_cleanup(ret);
821 return ret;
c627d613 822}
82306bf6 823