Split code to generate "rwx-----" strings into lib/permstring.c so it
[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 4 Copyright (C) Paul Mackerras 1996
08a740ff 5 Copyright (C) 2001 by Martin Pool <mbp@samba.org>
c627d613
AT
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20*/
21
22#include "rsync.h"
23
f0fca04e 24time_t starttime = 0;
a800434a
AT
25
26struct stats stats;
5d6bcd44 27
7a6421fa 28extern int verbose;
c627d613 29
82980a23
AT
30
31/****************************************************************************
32wait for a process to exit, calling io_flush while waiting
33****************************************************************************/
34void wait_process(pid_t pid, int *status)
35{
36 while (waitpid(pid, status, WNOHANG) == 0) {
a24c6870 37 msleep(20);
82980a23
AT
38 io_flush();
39 }
50135767
MP
40
41 /* TODO: If the child exited on a signal, then log an
42 * appropriate error message. Perhaps we should also accept a
43 * message describing the purpose of the child. Also indicate
44 * this to the caller so that thhey know something went
45 * wrong. */
82980a23
AT
46 *status = WEXITSTATUS(*status);
47}
48
c627d613
AT
49static void report(int f)
50{
7a6421fa
AT
51 time_t t = time(NULL);
52 extern int am_server;
53 extern int am_sender;
248fbb8c 54 extern int am_daemon;
a800434a 55 extern int do_stats;
17d31b38
DD
56 extern int remote_version;
57 int send_stats;
7a6421fa 58
248fbb8c 59 if (am_daemon) {
a9766ef1 60 log_exit(0, __FILE__, __LINE__);
7b372642 61 if (f == -1 || !am_sender) return;
248fbb8c
AT
62 }
63
ebb00c8e 64 send_stats = verbose || (remote_version >= 20);
e19452a9 65 if (am_server) {
17d31b38 66 if (am_sender && send_stats) {
23c5aef1
DD
67 int64 w;
68 /* store total_written in a temporary
69 because write_longint changes it */
70 w = stats.total_written;
e19452a9 71 write_longint(f,stats.total_read);
23c5aef1 72 write_longint(f,w);
e19452a9
DD
73 write_longint(f,stats.total_size);
74 }
7a6421fa
AT
75 return;
76 }
e19452a9
DD
77
78 /* this is the client */
79
17d31b38 80 if (!am_sender && send_stats) {
23c5aef1 81 int64 r;
a800434a 82 stats.total_written = read_longint(f);
23c5aef1
DD
83 /* store total_read in a temporary, read_longint changes it */
84 r = read_longint(f);
a800434a 85 stats.total_size = read_longint(f);
23c5aef1 86 stats.total_read = r;
a800434a
AT
87 }
88
89 if (do_stats) {
17d31b38
DD
90 if (!am_sender && !send_stats) {
91 /* missing the bytes written by the generator */
ebb00c8e 92 rprintf(FINFO, "\nCannot show stats as receiver because remote protocol version is less than 20\n");
17d31b38
DD
93 rprintf(FINFO, "Use --stats -v to show stats\n");
94 return;
95 }
1f658d42
AT
96 rprintf(FINFO,"\nNumber of files: %d\n", stats.num_files);
97 rprintf(FINFO,"Number of files transferred: %d\n",
a800434a 98 stats.num_transferred_files);
1f658d42 99 rprintf(FINFO,"Total file size: %.0f bytes\n",
a800434a 100 (double)stats.total_size);
1f658d42 101 rprintf(FINFO,"Total transferred file size: %.0f bytes\n",
a800434a 102 (double)stats.total_transferred_size);
1f658d42 103 rprintf(FINFO,"Literal data: %.0f bytes\n",
a800434a 104 (double)stats.literal_data);
1f658d42 105 rprintf(FINFO,"Matched data: %.0f bytes\n",
a800434a 106 (double)stats.matched_data);
1f658d42
AT
107 rprintf(FINFO,"File list size: %d\n", stats.flist_size);
108 rprintf(FINFO,"Total bytes written: %.0f\n",
a800434a 109 (double)stats.total_written);
1f658d42 110 rprintf(FINFO,"Total bytes read: %.0f\n\n",
a800434a 111 (double)stats.total_read);
7a6421fa
AT
112 }
113
e19452a9
DD
114 if (verbose || do_stats) {
115 rprintf(FINFO,"wrote %.0f bytes read %.0f bytes %.2f bytes/sec\n",
116 (double)stats.total_written,
117 (double)stats.total_read,
118 (stats.total_written+stats.total_read)/(0.5 + (t-starttime)));
119 rprintf(FINFO,"total size is %.0f speedup is %.2f\n",
120 (double)stats.total_size,
121 (1.0*stats.total_size)/(stats.total_written+stats.total_read));
122 }
fc8a6b97
AT
123
124 fflush(stdout);
125 fflush(stderr);
c627d613
AT
126}
127
128
0882faa2 129/* Start the remote shell. cmd may be NULL to use the default. */
19b27a48 130static pid_t do_cmd(char *cmd,char *machine,char *user,char *path,int *f_in,int *f_out)
c627d613 131{
366345fe 132 char *args[100];
19b27a48
AT
133 int i,argc=0;
134 pid_t ret;
366345fe 135 char *tok,*dir=NULL;
7a6421fa
AT
136 extern int local_server;
137 extern char *rsync_path;
e384bfbd 138 extern int blocking_io;
6902ed17 139 extern int read_batch;
366345fe 140
6902ed17 141 if (!read_batch && !local_server) { /* dw -- added read_batch */
366345fe
AT
142 if (!cmd)
143 cmd = getenv(RSYNC_RSH_ENV);
144 if (!cmd)
145 cmd = RSYNC_RSH;
146 cmd = strdup(cmd);
147 if (!cmd)
148 goto oom;
149
150 for (tok=strtok(cmd," ");tok;tok=strtok(NULL," ")) {
151 args[argc++] = tok;
152 }
c627d613 153
7b8356d0 154#if HAVE_REMSH
366345fe
AT
155 /* remsh (on HPUX) takes the arguments the other way around */
156 args[argc++] = machine;
157 if (user) {
158 args[argc++] = "-l";
159 args[argc++] = user;
160 }
7b8356d0 161#else
366345fe
AT
162 if (user) {
163 args[argc++] = "-l";
164 args[argc++] = user;
165 }
166 args[argc++] = machine;
7b8356d0 167#endif
c627d613 168
366345fe 169 args[argc++] = rsync_path;
c627d613 170
366345fe 171 server_options(args,&argc);
e384bfbd
AT
172
173
174 if (strcmp(cmd, RSYNC_RSH) == 0) blocking_io = 1;
366345fe 175 }
c627d613 176
366345fe 177 args[argc++] = ".";
76076c4b 178
366345fe
AT
179 if (path && *path)
180 args[argc++] = path;
c627d613 181
366345fe 182 args[argc] = NULL;
c627d613 183
366345fe 184 if (verbose > 3) {
9486289c 185 rprintf(FINFO,"cmd=");
366345fe 186 for (i=0;i<argc;i++)
9486289c
AT
187 rprintf(FINFO,"%s ",args[i]);
188 rprintf(FINFO,"\n");
366345fe
AT
189 }
190
191 if (local_server) {
6902ed17
MP
192 if (read_batch)
193 create_flist_from_batch();
366345fe
AT
194 ret = local_child(argc, args, f_in, f_out);
195 } else {
196 ret = piped_child(args,f_in,f_out);
197 }
c627d613 198
366345fe 199 if (dir) free(dir);
82306bf6 200
366345fe 201 return ret;
c627d613
AT
202
203oom:
366345fe
AT
204 out_of_memory("do_cmd");
205 return 0; /* not reached */
c627d613
AT
206}
207
208
209
210
211static char *get_local_name(struct file_list *flist,char *name)
212{
7a6421fa
AT
213 STRUCT_STAT st;
214 extern int orig_umask;
c627d613 215
c95da96a
AT
216 if (verbose > 2)
217 rprintf(FINFO,"get_local_name count=%d %s\n",
1f0610ef
DD
218 flist->count, NS(name));
219
220 if (!name)
221 return NULL;
c95da96a 222
1ff5450d
AT
223 if (do_stat(name,&st) == 0) {
224 if (S_ISDIR(st.st_mode)) {
5243c216
AT
225 if (!push_dir(name, 0)) {
226 rprintf(FERROR,"push_dir %s : %s (1)\n",
1ff5450d 227 name,strerror(errno));
65417579 228 exit_cleanup(RERR_FILESELECT);
1ff5450d
AT
229 }
230 return NULL;
231 }
232 if (flist->count > 1) {
233 rprintf(FERROR,"ERROR: destination must be a directory when copying more than 1 file\n");
65417579 234 exit_cleanup(RERR_FILESELECT);
1ff5450d
AT
235 }
236 return name;
237 }
238
cec8aa77 239 if (flist->count <= 1)
1ff5450d
AT
240 return name;
241
1ff5450d
AT
242 if (do_mkdir(name,0777 & ~orig_umask) != 0) {
243 rprintf(FERROR,"mkdir %s : %s (1)\n",name,strerror(errno));
65417579 244 exit_cleanup(RERR_FILEIO);
1ff5450d 245 } else {
b536f47e
AT
246 if (verbose > 0)
247 rprintf(FINFO,"created directory %s\n",name);
1ff5450d
AT
248 }
249
5243c216
AT
250 if (!push_dir(name, 0)) {
251 rprintf(FERROR,"push_dir %s : %s (2)\n",
252 name,strerror(errno));
65417579 253 exit_cleanup(RERR_FILESELECT);
1ff5450d
AT
254 }
255
256 return NULL;
c627d613
AT
257}
258
259
260
261
9486289c 262static void do_server_sender(int f_in, int f_out, int argc,char *argv[])
c627d613 263{
7a6421fa
AT
264 int i;
265 struct file_list *flist;
266 char *dir = argv[0];
267 extern int relative_paths;
7a6421fa 268 extern int recurse;
adc19c98 269 extern int remote_version;
c627d613 270
7a6421fa
AT
271 if (verbose > 2)
272 rprintf(FINFO,"server_sender starting pid=%d\n",(int)getpid());
c627d613 273
5243c216
AT
274 if (!relative_paths && !push_dir(dir, 0)) {
275 rprintf(FERROR,"push_dir %s: %s (3)\n",dir,strerror(errno));
65417579 276 exit_cleanup(RERR_FILESELECT);
7a6421fa
AT
277 }
278 argc--;
279 argv++;
c627d613 280
7a6421fa
AT
281 if (strcmp(dir,".")) {
282 int l = strlen(dir);
283 if (strcmp(dir,"/") == 0)
284 l = 0;
285 for (i=0;i<argc;i++)
286 argv[i] += l+1;
287 }
c627d613 288
7a6421fa
AT
289 if (argc == 0 && recurse) {
290 argc=1;
291 argv--;
292 argv[0] = ".";
293 }
294
7a6421fa 295 flist = send_file_list(f_out,argc,argv);
8d9dc9f9
AT
296 if (!flist || flist->count == 0) {
297 exit_cleanup(0);
298 }
299
7a6421fa 300 send_files(flist,f_out,f_in);
3d382777 301 io_flush();
7a6421fa 302 report(f_out);
adc19c98
AT
303 if (remote_version >= 24) {
304 /* final goodbye message */
305 read_int(f_in);
306 }
8d9dc9f9 307 io_flush();
7a6421fa 308 exit_cleanup(0);
c627d613
AT
309}
310
311
dc5ddbcc
AT
312static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
313{
d186eb1a
AT
314 int pid;
315 int status=0;
316 int recv_pipe[2];
554e0a8d 317 int error_pipe[2];
d186eb1a 318 extern int preserve_hard_links;
6957ae33
AT
319 extern int delete_after;
320 extern int recurse;
321 extern int delete_mode;
8ada7518 322 extern int remote_version;
dc5ddbcc 323
d186eb1a
AT
324 if (preserve_hard_links)
325 init_hard_links(flist);
dc5ddbcc 326
6957ae33
AT
327 if (!delete_after) {
328 /* I moved this here from recv_files() to prevent a race condition */
329 if (recurse && delete_mode && !local_name && flist->count>0) {
330 delete_files(flist);
331 }
332 }
333
08f15335 334 if (fd_pair(recv_pipe) < 0) {
d186eb1a 335 rprintf(FERROR,"pipe failed in do_recv\n");
65417579 336 exit_cleanup(RERR_SOCKETIO);
d186eb1a 337 }
554e0a8d 338
08f15335 339 if (fd_pair(error_pipe) < 0) {
554e0a8d
AT
340 rprintf(FERROR,"error pipe failed in do_recv\n");
341 exit_cleanup(RERR_SOCKETIO);
342 }
c6e7fcb4 343
8d9dc9f9 344 io_flush();
c6e7fcb4 345
d186eb1a 346 if ((pid=do_fork()) == 0) {
e08c9610 347 close(recv_pipe[0]);
554e0a8d 348 close(error_pipe[0]);
e08c9610
AT
349 if (f_in != f_out) close(f_out);
350
554e0a8d
AT
351 /* we can't let two processes write to the socket at one time */
352 io_multiplexing_close();
353
354 /* set place to send errors */
355 set_error_fd(error_pipe[1]);
356
e08c9610 357 recv_files(f_in,flist,local_name,recv_pipe[1]);
3d382777 358 io_flush();
ba5e128d 359 report(f_in);
e08c9610 360
8b35435f
AT
361 write_int(recv_pipe[1],1);
362 close(recv_pipe[1]);
8d9dc9f9 363 io_flush();
4a748188 364 /* finally we go to sleep until our parent kills us
27e3e9c9 365 with a USR2 signal. We sleep for a short time as on
4a748188 366 some OSes a signal won't interrupt a sleep! */
e1bd49d6
MP
367 while (msleep(20))
368 ;
d186eb1a 369 }
dc5ddbcc 370
e08c9610 371 close(recv_pipe[1]);
554e0a8d 372 close(error_pipe[1]);
e08c9610 373 if (f_in != f_out) close(f_in);
e1b3d5c4 374
b3e10ed7
AT
375 io_start_buffering(f_out);
376
554e0a8d
AT
377 io_set_error_fd(error_pipe[0]);
378
e08c9610 379 generate_files(f_out,flist,local_name,recv_pipe[0]);
8d9dc9f9 380
8b35435f
AT
381 read_int(recv_pipe[0]);
382 close(recv_pipe[0]);
8ada7518
AT
383 if (remote_version >= 24) {
384 /* send a final goodbye message */
385 write_int(f_out, -1);
386 }
8d9dc9f9 387 io_flush();
8ada7518 388
8b35435f 389 kill(pid, SIGUSR2);
d79d1c69 390 wait_process(pid, &status);
d186eb1a 391 return status;
dc5ddbcc
AT
392}
393
c627d613 394
9486289c 395static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
c627d613 396{
7a6421fa
AT
397 int status;
398 struct file_list *flist;
399 char *local_name=NULL;
400 char *dir = NULL;
401 extern int delete_mode;
b33b791e 402 extern int delete_excluded;
7a6421fa 403 extern int am_daemon;
09b7f5db
AT
404 extern int module_id;
405 extern int am_sender;
6902ed17 406 extern int read_batch; /* dw */
6902ed17 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)
08a740ff 532 rprintf(FINFO,"client_run waiting on %d\n", (int) pid);
8d9dc9f9 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 561 if (verbose > 3)
08a740ff 562 rprintf(FINFO,"client_run2 waiting on %d\n", (int) pid);
8d9dc9f9 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 585
7169bb4a
MP
586static int copy_argv (char *argv[])
587{
588 int i;
589
590 for (i = 0; argv[i]; i++) {
591 if (!(argv[i] = strdup(argv[i]))) {
592 rprintf (FERROR, "out of memory at %s(%d)\n",
593 __FILE__, __LINE__);
594 return RERR_MALLOC;
595 }
596 }
597
598 return 0;
599}
600
601
0ba48136
MP
602/*
603 * Start a client for either type of remote connection. Work out
604 * whether the arguments request a remote shell or rsyncd connection,
605 * and call the appropriate connection function, then run_client.
606 */
fc8a6b97 607static int start_client(int argc, char *argv[])
5d6bcd44
AT
608{
609 char *p;
610 char *shell_machine = NULL;
611 char *shell_path = NULL;
612 char *shell_user = NULL;
19b27a48
AT
613 int ret;
614 pid_t pid;
5d6bcd44 615 int f_in,f_out;
7a6421fa
AT
616 extern int local_server;
617 extern int am_sender;
618 extern char *shell_cmd;
2acf81eb 619 extern int rsync_port;
a1a440c2 620 extern int whole_file;
6902ed17 621 extern int read_batch;
7169bb4a
MP
622 int rc;
623
624 /* Don't clobber argv[] so that ps(1) can still show the right
625 command line. */
626 if ((rc = copy_argv (argv)))
627 return rc;
5d6bcd44 628
7169bb4a 629 if (strncasecmp(URL_PREFIX, argv[0], strlen(URL_PREFIX)) == 0) {
f7632fc6
AT
630 char *host, *path;
631
7169bb4a 632 host = argv[0] + strlen(URL_PREFIX);
f7632fc6
AT
633 p = strchr(host,'/');
634 if (p) {
635 *p = 0;
636 path = p+1;
637 } else {
638 path="";
639 }
2acf81eb
DD
640 p = strchr(host,':');
641 if (p) {
642 rsync_port = atoi(p+1);
643 *p = 0;
644 }
f7632fc6
AT
645 return start_socket_client(host, path, argc-1, argv+1);
646 }
647
6902ed17
MP
648 if (!read_batch) { /* dw */
649 p = find_colon(argv[0]);
5d6bcd44
AT
650
651 if (p) {
9486289c
AT
652 if (p[1] == ':') {
653 *p = 0;
7169bb4a 654 return start_socket_client(argv[0], p+2, argc-1, argv+1);
9486289c 655 }
3591c066 656
f7632fc6 657 if (argc < 1) {
3591c066 658 usage(FERROR);
65417579 659 exit_cleanup(RERR_SYNTAX);
3591c066
AT
660 }
661
5d6bcd44
AT
662 am_sender = 0;
663 *p = 0;
7169bb4a 664 shell_machine = argv[0];
5d6bcd44
AT
665 shell_path = p+1;
666 argc--;
667 argv++;
668 } else {
669 am_sender = 1;
9486289c 670
ca6c93f8 671 p = find_colon(argv[argc-1]);
5d6bcd44
AT
672 if (!p) {
673 local_server = 1;
a1a440c2
DD
674 /* disable "rsync algorithm" when both sides local */
675 whole_file = 1;
9486289c
AT
676 } else if (p[1] == ':') {
677 *p = 0;
678 return start_socket_client(argv[argc-1], p+2, argc-1, argv);
5d6bcd44 679 }
3591c066
AT
680
681 if (argc < 2) {
682 usage(FERROR);
65417579 683 exit_cleanup(RERR_SYNTAX);
3591c066 684 }
9486289c 685
5d6bcd44
AT
686 if (local_server) {
687 shell_machine = NULL;
688 shell_path = argv[argc-1];
689 } else {
690 *p = 0;
691 shell_machine = argv[argc-1];
692 shell_path = p+1;
693 }
694 argc--;
695 }
6902ed17
MP
696 } else {
697 am_sender = 1; /* dw */
698 local_server = 1; /* dw */
699 shell_path = argv[argc-1]; /* dw */
700 }
701
5d6bcd44
AT
702 if (shell_machine) {
703 p = strchr(shell_machine,'@');
704 if (p) {
705 *p = 0;
706 shell_user = shell_machine;
707 shell_machine = p+1;
708 }
709 }
710
711 if (verbose > 3) {
9486289c 712 rprintf(FINFO,"cmd=%s machine=%s user=%s path=%s\n",
5d6bcd44
AT
713 shell_cmd?shell_cmd:"",
714 shell_machine?shell_machine:"",
715 shell_user?shell_user:"",
716 shell_path?shell_path:"");
717 }
718
f7632fc6 719 if (!am_sender && argc > 1) {
5d6bcd44 720 usage(FERROR);
65417579 721 exit_cleanup(RERR_SYNTAX);
5d6bcd44 722 }
27e3e9c9
AT
723
724 if (argc == 0 && !am_sender) {
725 extern int list_only;
726 list_only = 1;
727 }
5d6bcd44
AT
728
729 pid = do_cmd(shell_cmd,shell_machine,shell_user,shell_path,&f_in,&f_out);
730
fc8a6b97
AT
731 ret = client_run(f_in, f_out, pid, argc, argv);
732
733 fflush(stdout);
734 fflush(stderr);
735
736 return ret;
5d6bcd44
AT
737}
738
366345fe 739
6e4fb64e 740static RETSIGTYPE sigusr1_handler(int val) {
65417579 741 exit_cleanup(RERR_SIGNAL);
82306bf6
AT
742}
743
8b35435f 744static RETSIGTYPE sigusr2_handler(int val) {
ff81e809 745 extern int log_got_error;
19b27a48 746 if (log_got_error) _exit(RERR_PARTIAL);
8b35435f
AT
747 _exit(0);
748}
749
19b27a48 750static RETSIGTYPE sigchld_handler(int val) {
029c1713
AT
751#ifdef WNOHANG
752 while (waitpid(-1, NULL, WNOHANG) > 0) ;
753#endif
19b27a48
AT
754}
755
5d6bcd44 756int main(int argc,char *argv[])
7a6421fa
AT
757{
758 extern int am_root;
759 extern int orig_umask;
760 extern int dry_run;
761 extern int am_daemon;
762 extern int am_server;
ff81e809 763 int ret;
6902ed17
MP
764 extern int read_batch; /* dw */
765 extern int write_batch; /* dw */
766 extern char *batch_ext; /* dw */
6902ed17
MP
767 int orig_argc; /* dw */
768
769 orig_argc = argc; /* dw */
5d6bcd44 770
7a6421fa 771 signal(SIGUSR1, sigusr1_handler);
8b35435f 772 signal(SIGUSR2, sigusr2_handler);
19b27a48 773 signal(SIGCHLD, sigchld_handler);
5d6bcd44 774
7a6421fa
AT
775 starttime = time(NULL);
776 am_root = (getuid() == 0);
c627d613 777
a800434a
AT
778 memset(&stats, 0, sizeof(stats));
779
df5e03da
AT
780 if (argc < 2) {
781 usage(FERROR);
65417579 782 exit_cleanup(RERR_SYNTAX);
df5e03da
AT
783 }
784
7a6421fa
AT
785 /* we set a 0 umask so that correct file permissions can be
786 carried across */
787 orig_umask = (int)umask(0);
5d6bcd44 788
50135767 789 if (!parse_arguments(&argc, (const char ***) &argv, 1)) {
305ab133
MP
790 /* FIXME: We ought to call the same error-handling
791 * code here, rather than relying on getopt. */
50135767 792 option_error();
65417579 793 exit_cleanup(RERR_SYNTAX);
b11ed3b1 794 }
5d6bcd44 795
7a6421fa
AT
796 signal(SIGINT,SIGNAL_CAST sig_int);
797 signal(SIGPIPE,SIGNAL_CAST sig_int);
798 signal(SIGHUP,SIGNAL_CAST sig_int);
8638dd48 799 signal(SIGTERM,SIGNAL_CAST sig_int);
6b83141d 800
c226b7c2
DD
801 /* Initialize push_dir here because on some old systems getcwd
802 (implemented by forking "pwd" and reading its output) doesn't
803 work when there are other child processes. Also, on all systems
804 that implement getcwd that way "pwd" can't be found after chroot. */
805 push_dir(NULL,0);
806
6902ed17
MP
807 if (write_batch) { /* dw */
808 create_batch_file_ext();
809 write_batch_argvs_file(orig_argc, argc, argv);
810 }
811
812 if (read_batch) { /* dw */
813 set_batch_file_ext(batch_ext);
814 }
815
7a6421fa
AT
816 if (am_daemon) {
817 return daemon_main();
818 }
f0fca04e 819
08ac228f
AT
820 if (argc < 1) {
821 usage(FERROR);
65417579 822 exit_cleanup(RERR_SYNTAX);
08ac228f
AT
823 }
824
7a6421fa
AT
825 if (dry_run)
826 verbose = MAX(verbose,1);
c627d613 827
cbbe4892 828#ifndef SUPPORT_LINKS
7a6421fa
AT
829 if (!am_server && preserve_links) {
830 rprintf(FERROR,"ERROR: symbolic links not supported\n");
65417579 831 exit_cleanup(RERR_UNSUPPORTED);
7a6421fa 832 }
cbbe4892
AT
833#endif
834
7a6421fa 835 if (am_server) {
f0359dd0
AT
836 set_nonblocking(STDIN_FILENO);
837 set_nonblocking(STDOUT_FILENO);
7a6421fa
AT
838 start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
839 }
c627d613 840
ff81e809
AT
841 ret = start_client(argc, argv);
842 exit_cleanup(ret);
843 return ret;
c627d613 844}
82306bf6 845