Fixed a typo in a comment.
[rsync/rsync.git] / main.c
CommitLineData
0ba48136 1/* -*- c-file-style: "linux" -*-
d9c7edf6 2
50135767 3 Copyright (C) 1996-2001 by Andrew Tridgell <tridge@samba.org>
c627d613 4 Copyright (C) Paul Mackerras 1996
e5a2b854 5 Copyright (C) 2001, 2002 by Martin Pool <mbp@samba.org>
d9c7edf6 6
c627d613
AT
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.
d9c7edf6 11
c627d613
AT
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.
d9c7edf6 16
c627d613
AT
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"
d9401514
WD
23#if defined CONFIG_LOCALE && defined HAVE_LOCALE_H
24#include <locale.h>
25#endif
c627d613 26
50839b4b
WD
27extern int verbose;
28extern int dry_run;
29extern int list_only;
32eda096 30extern int am_root;
d9c7edf6
WD
31extern int am_server;
32extern int am_sender;
b695f242 33extern int am_generator;
d9c7edf6 34extern int am_daemon;
32eda096 35extern int blocking_io;
bf26aa22 36extern int remove_sent_files;
32eda096 37extern int daemon_over_rsh;
bf26aa22 38extern int need_messages_from_generator;
051182cb 39extern int kluge_around_eof;
32eda096 40extern int do_stats;
32eda096
WD
41extern int log_got_error;
42extern int module_id;
43extern int orig_umask;
bb6721dc 44extern int copy_links;
83926d3c 45extern int keep_dirlinks;
32eda096 46extern int preserve_hard_links;
d04e9c51 47extern int protocol_version;
40e6752f 48extern int always_checksum;
32eda096
WD
49extern int recurse;
50extern int relative_paths;
51extern int rsync_port;
b1df18d7 52extern int whole_file;
32eda096
WD
53extern int read_batch;
54extern int write_batch;
b9f592fb 55extern int batch_fd;
c0d8e84c 56extern int batch_gen_fd;
32eda096
WD
57extern int filesfrom_fd;
58extern pid_t cleanup_child_pid;
50839b4b 59extern struct stats stats;
860236bf 60extern char *filesfrom_host;
32eda096
WD
61extern char *rsync_path;
62extern char *shell_cmd;
9b3318b0 63extern char *batch_name;
40e6752f 64extern char curr_dir[MAXPATHLEN];
57dee64e
WD
65
66int local_server = 0;
40e6752f 67int pre_checksum = 0;
a00628b3 68struct file_list *the_file_list;
c627d613 69
91c5833b
WD
70/* There's probably never more than at most 2 outstanding child processes,
71 * but set it higher, just in case. */
ee7118a8
DD
72#define MAXCHILDPROCS 5
73
74struct pid_status {
75 pid_t pid;
76 int status;
77} pid_stat_table[MAXCHILDPROCS];
78
33c4b445
WD
79static time_t starttime, endtime;
80static int64 total_read, total_written;
81
e5a2b854 82static void show_malloc_stats(void);
82980a23
AT
83
84/****************************************************************************
85wait for a process to exit, calling io_flush while waiting
86****************************************************************************/
dbefb6b4 87static void wait_process(pid_t pid, int *code_ptr)
82980a23 88{
ee7118a8 89 pid_t waited_pid;
dbefb6b4 90 int cnt, status;
ee7118a8 91
dbefb6b4 92 while ((waited_pid = waitpid(pid, &status, WNOHANG)) == 0) {
a24c6870 93 msleep(20);
f1e3656e 94 io_flush(FULL_FLUSH);
82980a23 95 }
d9c7edf6 96
6fb812f7 97 if (waited_pid == -1 && errno == ECHILD) {
ee7118a8
DD
98 /* status of requested child no longer available.
99 * check to see if it was processed by the sigchld_handler.
100 */
101 for (cnt = 0; cnt < MAXCHILDPROCS; cnt++) {
102 if (pid == pid_stat_table[cnt].pid) {
dbefb6b4
WD
103 waited_pid = pid;
104 status = pid_stat_table[cnt].status;
ee7118a8
DD
105 pid_stat_table[cnt].pid = 0;
106 break;
107 }
108 }
109 }
110
d9c7edf6
WD
111 /* TODO: If the child exited on a signal, then log an
112 * appropriate error message. Perhaps we should also accept a
113 * message describing the purpose of the child. Also indicate
dbefb6b4
WD
114 * this to the caller so that they know something went wrong. */
115 if (waited_pid < 0)
116 *code_ptr = RERR_WAITCHILD;
117 else if (!WIFEXITED(status)) {
40e6752f 118#ifdef WCOREDUMP
dbefb6b4
WD
119 if (WCOREDUMP(status))
120 *code_ptr = RERR_CRASHED;
40e6752f
WD
121 else
122#endif
123 if (WIFSIGNALED(status))
dbefb6b4
WD
124 *code_ptr = RERR_TERMINATED;
125 else
126 *code_ptr = RERR_WAITCHILD;
127 } else
128 *code_ptr = WEXITSTATUS(status);
82980a23
AT
129}
130
b9f592fb
WD
131/* This function gets called from all 3 processes. We want the client side
132 * to actually output the text, but the sender is the only process that has
133 * all the stats we need. So, if we're a client sender, we do the report.
134 * If we're a server sender, we write the stats on the supplied fd. If
135 * we're the client receiver we read the stats from the supplied fd and do
136 * the report. All processes might also generate a set of debug stats, if
137 * the verbose level is high enough (this is the only thing that the
138 * generator process and the server receiver ever do here). */
33c4b445 139static void handle_stats(int f)
c627d613 140{
33c4b445
WD
141 endtime = time(NULL);
142
b9f592fb 143 /* Cache two stats because the read/write code can change it. */
33c4b445
WD
144 total_read = stats.total_read;
145 total_written = stats.total_written;
7a6421fa 146
7bb7058e 147 if (do_stats && verbose > 1) {
5c15e29f 148 /* These come out from every process */
7bb7058e 149 show_malloc_stats();
86943126 150 show_flist_stats();
5c15e29f
MP
151 }
152
e5fbaa71
S
153 if (am_generator)
154 return;
155
248fbb8c 156 if (am_daemon) {
a9766ef1 157 log_exit(0, __FILE__, __LINE__);
83926d3c
WD
158 if (f == -1 || !am_sender)
159 return;
248fbb8c
AT
160 }
161
e19452a9 162 if (am_server) {
3e491682 163 if (am_sender) {
b9f592fb
WD
164 write_longint(f, total_read);
165 write_longint(f, total_written);
166 write_longint(f, stats.total_size);
f0f7e760
WD
167 if (protocol_version >= 29) {
168 write_longint(f, stats.flist_buildtime);
169 write_longint(f, stats.flist_xfertime);
170 }
e19452a9 171 }
7a6421fa
AT
172 return;
173 }
e19452a9
DD
174
175 /* this is the client */
d9c7edf6 176
9d19f8a5
WD
177 if (f < 0 && !am_sender) /* e.g. when we got an empty file list. */
178 ;
179 else if (!am_sender) {
58c5c245
WD
180 /* Read the first two in opposite order because the meaning of
181 * read/write swaps when switching from sender to receiver. */
b9f592fb
WD
182 total_written = read_longint(f);
183 total_read = read_longint(f);
a800434a 184 stats.total_size = read_longint(f);
f0f7e760
WD
185 if (protocol_version >= 29) {
186 stats.flist_buildtime = read_longint(f);
187 stats.flist_xfertime = read_longint(f);
188 }
e4676bb5 189 } else if (write_batch) {
b9f592fb
WD
190 /* The --read-batch process is going to be a client
191 * receiver, so we need to give it the stats. */
192 write_longint(batch_fd, total_read);
193 write_longint(batch_fd, total_written);
194 write_longint(batch_fd, stats.total_size);
f0f7e760
WD
195 if (protocol_version >= 29) {
196 write_longint(batch_fd, stats.flist_buildtime);
197 write_longint(batch_fd, stats.flist_xfertime);
198 }
a800434a 199 }
e4676bb5 200}
a800434a 201
e4676bb5
WD
202static void output_summary(void)
203{
a800434a 204 if (do_stats) {
1f658d42 205 rprintf(FINFO,"\nNumber of files: %d\n", stats.num_files);
d9c7edf6
WD
206 rprintf(FINFO,"Number of files transferred: %d\n",
207 stats.num_transferred_files);
208 rprintf(FINFO,"Total file size: %.0f bytes\n",
209 (double)stats.total_size);
210 rprintf(FINFO,"Total transferred file size: %.0f bytes\n",
211 (double)stats.total_transferred_size);
212 rprintf(FINFO,"Literal data: %.0f bytes\n",
213 (double)stats.literal_data);
214 rprintf(FINFO,"Matched data: %.0f bytes\n",
215 (double)stats.matched_data);
1f658d42 216 rprintf(FINFO,"File list size: %d\n", stats.flist_size);
f0f7e760
WD
217 if (stats.flist_buildtime) {
218 rprintf(FINFO,
219 "File list generation time: %.3f seconds\n",
220 (double)stats.flist_buildtime / 1000);
221 rprintf(FINFO,
222 "File list transfer time: %.3f seconds\n",
223 (double)stats.flist_xfertime / 1000);
224 }
4de2a174 225 rprintf(FINFO,"Total bytes sent: %.0f\n",
b9f592fb 226 (double)total_written);
4de2a174 227 rprintf(FINFO,"Total bytes received: %.0f\n",
b9f592fb 228 (double)total_read);
7a6421fa 229 }
d9c7edf6 230
e19452a9 231 if (verbose || do_stats) {
b9f592fb 232 rprintf(FINFO,
4de2a174 233 "\nsent %.0f bytes received %.0f bytes %.2f bytes/sec\n",
b9f592fb 234 (double)total_written, (double)total_read,
33c4b445 235 (total_written + total_read)/(0.5 + (endtime - starttime)));
b9f592fb 236 rprintf(FINFO, "total size is %.0f speedup is %.2f\n",
d9c7edf6 237 (double)stats.total_size,
b9f592fb 238 (double)stats.total_size / (total_written+total_read));
e19452a9 239 }
fc8a6b97
AT
240
241 fflush(stdout);
242 fflush(stderr);
c627d613
AT
243}
244
245
e5a2b854
MP
246/**
247 * If our C library can get malloc statistics, then show them to FINFO
248 **/
249static void show_malloc_stats(void)
250{
4f5b0756 251#ifdef HAVE_MALLINFO
e5a2b854
MP
252 struct mallinfo mi;
253
254 mi = mallinfo();
255
ce672562 256 rprintf(FINFO, "\n" RSYNC_NAME "[%d] (%s%s%s) heap statistics:\n",
f846a9bf
WD
257 getpid(), am_server ? "server " : "",
258 am_daemon ? "daemon " : "", who_am_i());
259 rprintf(FINFO, " arena: %10ld (bytes from sbrk)\n",
260 (long)mi.arena);
261 rprintf(FINFO, " ordblks: %10ld (chunks not in use)\n",
262 (long)mi.ordblks);
263 rprintf(FINFO, " smblks: %10ld\n",
264 (long)mi.smblks);
265 rprintf(FINFO, " hblks: %10ld (chunks from mmap)\n",
266 (long)mi.hblks);
267 rprintf(FINFO, " hblkhd: %10ld (bytes from mmap)\n",
268 (long)mi.hblkhd);
269 rprintf(FINFO, " allmem: %10ld (bytes from sbrk + mmap)\n",
270 (long)mi.arena + mi.hblkhd);
271 rprintf(FINFO, " usmblks: %10ld\n",
272 (long)mi.usmblks);
273 rprintf(FINFO, " fsmblks: %10ld\n",
274 (long)mi.fsmblks);
275 rprintf(FINFO, " uordblks: %10ld (bytes used)\n",
276 (long)mi.uordblks);
277 rprintf(FINFO, " fordblks: %10ld (bytes free)\n",
278 (long)mi.fordblks);
279 rprintf(FINFO, " keepcost: %10ld (bytes in releasable chunk)\n",
280 (long)mi.keepcost);
e5a2b854
MP
281#endif /* HAVE_MALLINFO */
282}
283
284
0882faa2 285/* Start the remote shell. cmd may be NULL to use the default. */
6c2e5b56
WD
286static pid_t do_cmd(char *cmd, char *machine, char *user, char *path,
287 int *f_in, int *f_out)
c627d613 288{
6c2e5b56 289 int i, argc = 0;
887e553f 290 char *args[MAX_ARGS];
19b27a48 291 pid_t ret;
6c2e5b56 292 char *tok, *dir = NULL;
bb4aa89c 293 int dash_l_set = 0;
366345fe 294
088aac85 295 if (!read_batch && !local_server) {
9af87151 296 char *rsh_env = getenv(RSYNC_RSH_ENV);
366345fe 297 if (!cmd)
9af87151 298 cmd = rsh_env;
366345fe
AT
299 if (!cmd)
300 cmd = RSYNC_RSH;
301 cmd = strdup(cmd);
d9c7edf6 302 if (!cmd)
366345fe
AT
303 goto oom;
304
887e553f 305 for (tok = strtok(cmd, " "); tok; tok = strtok(NULL, " ")) {
e7a392c7 306 /* Comparison leaves rooms for server_options(). */
d8c4d6de 307 if (argc >= MAX_ARGS - MAX_SERVER_ARGS) {
e7a392c7 308 rprintf(FERROR, "internal: args[] overflowed in do_cmd()\n");
887e553f
WD
309 exit_cleanup(RERR_SYNTAX);
310 }
366345fe 311 args[argc++] = tok;
887e553f 312 }
c627d613 313
d9c7edf6 314 /* check to see if we've already been given '-l user' in
9af87151 315 * the remote-shell command */
bb4aa89c
WD
316 for (i = 0; i < argc-1; i++) {
317 if (!strcmp(args[i], "-l") && args[i+1][0] != '-')
318 dash_l_set = 1;
319 }
320
4f5b0756 321#ifdef HAVE_REMSH
366345fe
AT
322 /* remsh (on HPUX) takes the arguments the other way around */
323 args[argc++] = machine;
bb4aa89c 324 if (user && !(daemon_over_rsh && dash_l_set)) {
366345fe
AT
325 args[argc++] = "-l";
326 args[argc++] = user;
327 }
7b8356d0 328#else
bb4aa89c 329 if (user && !(daemon_over_rsh && dash_l_set)) {
366345fe
AT
330 args[argc++] = "-l";
331 args[argc++] = user;
332 }
333 args[argc++] = machine;
7b8356d0 334#endif
c627d613 335
366345fe 336 args[argc++] = rsync_path;
c627d613 337
9af87151 338 if (blocking_io < 0) {
90e22f4b
WD
339 char *cp;
340 if ((cp = strrchr(cmd, '/')) != NULL)
341 cp++;
342 else
343 cp = cmd;
344 if (strcmp(cp, "rsh") == 0 || strcmp(cp, "remsh") == 0)
345 blocking_io = 1;
66b71163 346 }
e384bfbd 347
93689aa5 348 server_options(args,&argc);
e7a392c7
WD
349
350 if (argc >= MAX_ARGS - 2) {
351 rprintf(FERROR, "internal: args[] overflowed in do_cmd()\n");
352 exit_cleanup(RERR_SYNTAX);
353 }
366345fe 354 }
c627d613 355
366345fe 356 args[argc++] = ".";
76076c4b 357
d9c7edf6 358 if (!daemon_over_rsh && path && *path)
366345fe 359 args[argc++] = path;
c627d613 360
366345fe 361 args[argc] = NULL;
c627d613 362
366345fe 363 if (verbose > 3) {
9486289c 364 rprintf(FINFO,"cmd=");
e7a392c7 365 for (i = 0; i < argc; i++)
71903f60 366 rprintf(FINFO, "%s ", safe_fname(args[i]));
9486289c 367 rprintf(FINFO,"\n");
366345fe
AT
368 }
369
c0d8e84c
WD
370 if (read_batch) {
371 int from_gen_pipe[2];
372 if (fd_pair(from_gen_pipe) < 0) {
373 rsyserr(FERROR, errno, "pipe");
374 exit_cleanup(RERR_IPC);
375 }
376 batch_gen_fd = from_gen_pipe[0];
377 *f_out = from_gen_pipe[1];
378 *f_in = batch_fd;
379 ret = -1; /* no child pid */
380 } else if (local_server) {
b1df18d7
WD
381 /* If the user didn't request --[no-]whole-file, force
382 * it on, but only if we're not batch processing. */
c0d8e84c 383 if (whole_file < 0 && !write_batch)
b1df18d7 384 whole_file = 1;
25d34a5c 385 ret = local_child(argc, args, f_in, f_out, child_main);
c0d8e84c 386 } else
366345fe 387 ret = piped_child(args,f_in,f_out);
c627d613 388
3a69fad0
WD
389 if (dir)
390 free(dir);
82306bf6 391
366345fe 392 return ret;
c627d613
AT
393
394oom:
366345fe
AT
395 out_of_memory("do_cmd");
396 return 0; /* not reached */
c627d613
AT
397}
398
399
c627d613
AT
400static char *get_local_name(struct file_list *flist,char *name)
401{
7a6421fa 402 STRUCT_STAT st;
87cc45e1 403 int e;
c627d613 404
c95da96a 405 if (verbose > 2)
d9c7edf6 406 rprintf(FINFO,"get_local_name count=%d %s\n",
1f0610ef
DD
407 flist->count, NS(name));
408
d9c7edf6 409 if (!name)
1f0610ef 410 return NULL;
c95da96a 411
1ff5450d
AT
412 if (do_stat(name,&st) == 0) {
413 if (S_ISDIR(st.st_mode)) {
59187666 414 if (!push_dir(name)) {
982e05bb
WD
415 rsyserr(FERROR, errno, "push_dir#1 %s failed",
416 full_fname(name));
65417579 417 exit_cleanup(RERR_FILESELECT);
1ff5450d
AT
418 }
419 return NULL;
420 }
421 if (flist->count > 1) {
422 rprintf(FERROR,"ERROR: destination must be a directory when copying more than 1 file\n");
65417579 423 exit_cleanup(RERR_FILESELECT);
1ff5450d
AT
424 }
425 return name;
426 }
427
87cc45e1 428 if (flist->count <= 1 && ((e = strlen(name)) <= 1 || name[e-1] != '/'))
1ff5450d
AT
429 return name;
430
1ff5450d 431 if (do_mkdir(name,0777 & ~orig_umask) != 0) {
982e05bb 432 rsyserr(FERROR, errno, "mkdir %s failed", full_fname(name));
65417579 433 exit_cleanup(RERR_FILEIO);
e5a96f0f
WD
434 }
435 if (verbose > 0)
71903f60 436 rprintf(FINFO, "created directory %s\n", safe_fname(name));
e5a96f0f
WD
437
438 if (dry_run) {
439 dry_run++;
440 return NULL;
1ff5450d
AT
441 }
442
59187666 443 if (!push_dir(name)) {
982e05bb
WD
444 rsyserr(FERROR, errno, "push_dir#2 %s failed",
445 full_fname(name));
65417579 446 exit_cleanup(RERR_FILESELECT);
1ff5450d
AT
447 }
448
449 return NULL;
c627d613
AT
450}
451
452
1a8e5c97 453/* This is only called by the sender. */
3485ae83 454static void read_final_goodbye(int f_in, int f_out)
4e0fcd85 455{
1a8e5c97
WD
456 int i;
457
458 if (protocol_version < 29)
459 i = read_int(f_in);
460 else {
3485ae83 461 while ((i = read_int(f_in)) == the_file_list->count
1a8e5c97
WD
462 && read_shortint(f_in) == ITEM_IS_NEW) {
463 /* Forward the keep-alive (no-op) to the receiver. */
3485ae83 464 write_int(f_out, the_file_list->count);
1a8e5c97
WD
465 write_shortint(f_out, ITEM_IS_NEW);
466 }
4e0fcd85
WD
467 }
468
1a8e5c97 469 if (i != -1) {
c7791b8c
WD
470 rprintf(FERROR, "Invalid packet at end of run (%d) [%s]\n",
471 i, who_am_i());
1a8e5c97 472 exit_cleanup(RERR_PROTOCOL);
4e0fcd85
WD
473 }
474}
475
476
9486289c 477static void do_server_sender(int f_in, int f_out, int argc,char *argv[])
c627d613 478{
7a6421fa
AT
479 struct file_list *flist;
480 char *dir = argv[0];
c627d613 481
45e08edb
WD
482 if (verbose > 2) {
483 rprintf(FINFO, "server_sender starting pid=%ld\n",
484 (long)getpid());
485 }
d9c7edf6 486
2adbcdc7 487 if (am_daemon && lp_write_only(module_id)) {
7a92ded3
WD
488 rprintf(FERROR, "ERROR: module is write only\n");
489 exit_cleanup(RERR_SYNTAX);
490 return;
491 }
bf26aa22
WD
492 if (am_daemon && lp_read_only(module_id) && remove_sent_files) {
493 rprintf(FERROR,
494 "ERROR: --remove-sent-files cannot be used with a read-only module\n");
495 exit_cleanup(RERR_SYNTAX);
496 return;
497 }
7a92ded3 498
59187666 499 if (!relative_paths && !push_dir(dir)) {
982e05bb
WD
500 rsyserr(FERROR, errno, "push_dir#3 %s failed",
501 full_fname(dir));
65417579 502 exit_cleanup(RERR_FILESELECT);
7a6421fa
AT
503 }
504 argc--;
505 argv++;
d9c7edf6 506
48a1ff0d 507 if (argc == 0 && (recurse || list_only)) {
e1f67417 508 argc = 1;
7a6421fa
AT
509 argv--;
510 argv[0] = ".";
511 }
d9c7edf6 512
7a6421fa 513 flist = send_file_list(f_out,argc,argv);
8d9dc9f9
AT
514 if (!flist || flist->count == 0) {
515 exit_cleanup(0);
516 }
a00628b3 517 the_file_list = flist;
8d9dc9f9 518
da3478b2
WD
519 io_start_buffering_in();
520 io_start_buffering_out();
521
7a6421fa 522 send_files(flist,f_out,f_in);
f1e3656e 523 io_flush(FULL_FLUSH);
33c4b445 524 handle_stats(f_out);
4e0fcd85 525 if (protocol_version >= 24)
3485ae83 526 read_final_goodbye(f_in, f_out);
f1e3656e 527 io_flush(FULL_FLUSH);
7a6421fa 528 exit_cleanup(0);
c627d613
AT
529}
530
531
dc5ddbcc
AT
532static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
533{
d186eb1a 534 int pid;
e1f67417 535 int status = 0;
c70e07d9 536 int error_pipe[2];
dc5ddbcc 537
bb6721dc
WD
538 /* The receiving side mustn't obey this, or an existing symlink that
539 * points to an identical file won't be replaced by the referent. */
540 copy_links = 0;
541
d186eb1a 542 if (preserve_hard_links)
3485ae83 543 init_hard_links();
dc5ddbcc 544
c70e07d9 545 if (fd_pair(error_pipe) < 0) {
ab759cd2 546 rsyserr(FERROR, errno, "pipe failed in do_recv");
c8f2f857 547 exit_cleanup(RERR_IPC);
554e0a8d 548 }
d9c7edf6 549
f1e3656e 550 io_flush(NORMAL_FLUSH);
c6e7fcb4 551
ba449e44 552 if ((pid = do_fork()) == -1) {
c8f2f857 553 rsyserr(FERROR, errno, "fork failed in do_recv");
ba449e44
WD
554 exit_cleanup(RERR_IPC);
555 }
556
557 if (pid == 0) {
554e0a8d 558 close(error_pipe[0]);
3a69fad0
WD
559 if (f_in != f_out)
560 close(f_out);
e08c9610 561
554e0a8d 562 /* we can't let two processes write to the socket at one time */
9eeb3b9c 563 close_multiplexing_out();
554e0a8d
AT
564
565 /* set place to send errors */
f1e3656e 566 set_msg_fd_out(error_pipe[1]);
554e0a8d 567
c70e07d9 568 recv_files(f_in, flist, local_name);
f1e3656e 569 io_flush(FULL_FLUSH);
33c4b445 570 handle_stats(f_in);
e08c9610 571
f1e3656e
WD
572 send_msg(MSG_DONE, "", 0);
573 io_flush(FULL_FLUSH);
4e0fcd85 574
40df65fd
WD
575 /* Handle any keep-alive packets from the post-processing work
576 * that the generator does. */
4e0fcd85 577 if (protocol_version >= 29) {
051182cb 578 kluge_around_eof = -1;
1a8e5c97
WD
579
580 /* This should only get stopped via a USR2 signal. */
581 while (read_int(f_in) == flist->count
582 && read_shortint(f_in) == ITEM_IS_NEW) {}
583
3485ae83
WD
584 rprintf(FERROR, "Invalid packet at end of run [%s]\n",
585 who_am_i());
1a8e5c97 586 exit_cleanup(RERR_PROTOCOL);
4e0fcd85
WD
587 }
588
9e0582f9
WD
589 /* Finally, we go to sleep until our parent kills us with a
590 * USR2 signal. We sleep for a short time, as on some OSes
591 * a signal won't interrupt a sleep! */
f1e3656e
WD
592 while (1)
593 msleep(20);
d186eb1a 594 }
dc5ddbcc 595
b695f242 596 am_generator = 1;
9eeb3b9c 597 close_multiplexing_in();
e8a96e27 598 if (write_batch && !am_server)
b9f592fb 599 stop_write_batch();
b695f242 600
554e0a8d 601 close(error_pipe[1]);
3a69fad0
WD
602 if (f_in != f_out)
603 close(f_in);
e1b3d5c4 604
da3478b2 605 io_start_buffering_out();
b3e10ed7 606
f1e3656e 607 set_msg_fd_in(error_pipe[0]);
554e0a8d 608
c70e07d9 609 generate_files(f_out, flist, local_name);
8d9dc9f9 610
33c4b445 611 handle_stats(-1);
f1e3656e 612 io_flush(FULL_FLUSH);
d04e9c51 613 if (protocol_version >= 24) {
8ada7518
AT
614 /* send a final goodbye message */
615 write_int(f_out, -1);
616 }
f1e3656e 617 io_flush(FULL_FLUSH);
8ada7518 618
f1e3656e 619 set_msg_fd_in(-1);
089a2435 620 kill(pid, SIGUSR2);
d79d1c69 621 wait_process(pid, &status);
d186eb1a 622 return status;
dc5ddbcc
AT
623}
624
c627d613 625
9486289c 626static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
c627d613 627{
7a6421fa
AT
628 int status;
629 struct file_list *flist;
6c2e5b56 630 char *local_name = NULL;
7a6421fa 631 char *dir = NULL;
40e6752f 632 char olddir[sizeof curr_dir];
07bff66f
WD
633 int save_verbose = verbose;
634
635 if (filesfrom_fd >= 0) {
636 /* We can't mix messages with files-from data on the socket,
637 * so temporarily turn off verbose messages. */
638 verbose = 0;
639 }
f0fca04e 640
45e08edb
WD
641 if (verbose > 2) {
642 rprintf(FINFO, "server_recv(%d) starting pid=%ld\n",
643 argc, (long)getpid());
644 }
09b7f5db 645
2adbcdc7 646 if (am_daemon && lp_read_only(module_id)) {
09b7f5db
AT
647 rprintf(FERROR,"ERROR: module is read only\n");
648 exit_cleanup(RERR_SYNTAX);
649 return;
650 }
651
d9c7edf6 652
7a6421fa
AT
653 if (argc > 0) {
654 dir = argv[0];
655 argc--;
656 argv++;
59187666 657 if (!am_daemon && !push_dir(dir)) {
982e05bb
WD
658 rsyserr(FERROR, errno, "push_dir#4 %s failed",
659 full_fname(dir));
65417579 660 exit_cleanup(RERR_FILESELECT);
d9c7edf6 661 }
7a6421fa 662 }
c627d613 663
da3478b2 664 io_start_buffering_in();
57dee64e 665 recv_filter_list(f_in);
c627d613 666
7c2a9e76 667 if (filesfrom_fd >= 0) {
07bff66f
WD
668 /* We need to send the files-from names to the sender at the
669 * same time that we receive the file-list from them, so we
670 * need the IO routines to automatically write out the names
671 * onto our f_out socket as we read the file-list. This
672 * avoids both deadlock and extra delays/buffers. */
7c2a9e76
WD
673 io_set_filesfrom_fds(filesfrom_fd, f_out);
674 filesfrom_fd = -1;
675 }
676
40e6752f
WD
677 strlcpy(olddir, curr_dir, sizeof olddir);
678 if (always_checksum && argc > 0)
679 pre_checksum = push_dir(argv[0]);
680
b9f592fb 681 flist = recv_file_list(f_in);
07bff66f 682 verbose = save_verbose;
4c36a13e
AT
683 if (!flist) {
684 rprintf(FERROR,"server_recv: recv_file_list error\n");
65417579 685 exit_cleanup(RERR_FILESELECT);
7a6421fa 686 }
a00628b3 687 the_file_list = flist;
d9c7edf6 688
40e6752f
WD
689 if (pre_checksum)
690 pop_dir(olddir);
691
29fad7a3 692 if (argc > 0)
7a6421fa 693 local_name = get_local_name(flist,argv[0]);
c627d613 694
7a6421fa
AT
695 status = do_recv(f_in,f_out,flist,local_name);
696 exit_cleanup(status);
c627d613
AT
697}
698
699
734a94a2 700int child_main(int argc, char *argv[])
25d34a5c
MP
701{
702 start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
734a94a2 703 return 0;
25d34a5c
MP
704}
705
706
9486289c 707void start_server(int f_in, int f_out, int argc, char *argv[])
366345fe 708{
f0359dd0
AT
709 set_nonblocking(f_in);
710 set_nonblocking(f_out);
711
da3478b2
WD
712 io_set_sock_fds(f_in, f_out);
713 setup_protocol(f_out, f_in);
714
d04e9c51 715 if (protocol_version >= 23)
da3478b2 716 io_start_multiplex_out();
7a6421fa 717
7a6421fa 718 if (am_sender) {
83926d3c 719 keep_dirlinks = 0; /* Must be disabled on the sender. */
bf26aa22
WD
720 if (need_messages_from_generator)
721 io_start_multiplex_in();
9b3318b0 722
7842418b 723 recv_filter_list(f_in);
7a6421fa
AT
724 do_server_sender(f_in, f_out, argc, argv);
725 } else {
726 do_server_recv(f_in, f_out, argc, argv);
727 }
728 exit_cleanup(0);
366345fe
AT
729}
730
0ba48136
MP
731
732/*
733 * This is called once the connection has been negotiated. It is used
734 * for rsyncd, remote-shell, and local connections.
735 */
19b27a48 736int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[])
9486289c 737{
088aac85 738 struct file_list *flist = NULL;
9486289c 739 int status = 0, status2 = 0;
40e6752f 740 char olddir[sizeof curr_dir];
9486289c 741 char *local_name = NULL;
19b27a48
AT
742
743 cleanup_child_pid = pid;
67a28eb2 744 if (!read_batch) {
b9f592fb
WD
745 set_nonblocking(f_in);
746 set_nonblocking(f_out);
747 }
f0359dd0 748
da3478b2 749 io_set_sock_fds(f_in, f_out);
6d7b6081
AT
750 setup_protocol(f_out,f_in);
751
b9f592fb 752 if (protocol_version >= 23 && !read_batch)
da3478b2 753 io_start_multiplex_in();
d9c7edf6 754
18882701
WD
755 /* We set our stderr file handle to blocking because ssh might have
756 * set it to non-blocking. This can be particularly troublesome if
757 * stderr is a clone of stdout, because ssh would have set our stdout
758 * to non-blocking at the same time (which can easily cause us to lose
759 * output from our print statements). This kluge shouldn't cause ssh
760 * any problems for how we use it. Note also that we delayed setting
761 * this until after the above protocol setup so that we know for sure
762 * that ssh is done twiddling its file descriptors. */
763 set_blocking(STDERR_FILENO);
764
9486289c 765 if (am_sender) {
83926d3c 766 keep_dirlinks = 0; /* Must be disabled on the sender. */
da3478b2 767 io_start_buffering_out();
860236bf 768 if (!filesfrom_host)
a0a33ee5 769 set_msg_fd_in(f_in);
57dee64e 770 send_filter_list(f_out);
860236bf 771 if (filesfrom_host)
7c2a9e76 772 filesfrom_fd = f_in;
b9f592fb 773
e8a96e27 774 if (write_batch && !am_server)
b9f592fb 775 start_write_batch(f_out);
a00628b3 776 flist = send_file_list(f_out, argc, argv);
a0a33ee5 777 set_msg_fd_in(-1);
d9c7edf6 778 if (verbose > 3)
9486289c 779 rprintf(FINFO,"file list sent\n");
a00628b3 780 the_file_list = flist;
e1b3d5c4 781
f1e3656e 782 io_flush(NORMAL_FLUSH);
9486289c 783 send_files(flist,f_out,f_in);
f1e3656e 784 io_flush(FULL_FLUSH);
33c4b445 785 handle_stats(-1);
4e0fcd85 786 if (protocol_version >= 24)
3485ae83 787 read_final_goodbye(f_in, f_out);
9486289c
AT
788 if (pid != -1) {
789 if (verbose > 3)
08a740ff 790 rprintf(FINFO,"client_run waiting on %d\n", (int) pid);
f1e3656e 791 io_flush(FULL_FLUSH);
d79d1c69 792 wait_process(pid, &status);
9486289c 793 }
33c4b445 794 output_summary();
c87ae64a 795 io_flush(FULL_FLUSH);
9486289c
AT
796 exit_cleanup(status);
797 }
f7632fc6 798
bf26aa22
WD
799 if (need_messages_from_generator && !read_batch)
800 io_start_multiplex_out();
801
48a1ff0d
WD
802 if (argc == 0)
803 list_only |= 1;
d9c7edf6 804
57dee64e 805 send_filter_list(read_batch ? -1 : f_out);
d9c7edf6 806
7c2a9e76
WD
807 if (filesfrom_fd >= 0) {
808 io_set_filesfrom_fds(filesfrom_fd, f_out);
809 filesfrom_fd = -1;
810 }
811
40e6752f
WD
812 strlcpy(olddir, curr_dir, sizeof olddir);
813 if (always_checksum)
814 pre_checksum = push_dir(argv[0]);
815
e8a96e27 816 if (write_batch && !am_server)
b9f592fb 817 start_write_batch(f_in);
9486289c 818 flist = recv_file_list(f_in);
a00628b3 819 the_file_list = flist;
d9c7edf6 820
40e6752f
WD
821 if (pre_checksum)
822 pop_dir(olddir);
823
9d19f8a5
WD
824 if (flist && flist->count > 0) {
825 local_name = get_local_name(flist, argv[0]);
d9c7edf6 826
9d19f8a5
WD
827 status2 = do_recv(f_in, f_out, flist, local_name);
828 } else {
829 handle_stats(-1);
830 output_summary();
831 }
d9c7edf6 832
9486289c 833 if (pid != -1) {
8d9dc9f9 834 if (verbose > 3)
08a740ff 835 rprintf(FINFO,"client_run2 waiting on %d\n", (int) pid);
f1e3656e 836 io_flush(FULL_FLUSH);
d79d1c69 837 wait_process(pid, &status);
9486289c 838 }
d9c7edf6 839
ff81e809 840 return MAX(status, status2);
9486289c
AT
841}
842
7169bb4a
MP
843static int copy_argv (char *argv[])
844{
845 int i;
846
847 for (i = 0; argv[i]; i++) {
848 if (!(argv[i] = strdup(argv[i]))) {
849 rprintf (FERROR, "out of memory at %s(%d)\n",
850 __FILE__, __LINE__);
851 return RERR_MALLOC;
852 }
853 }
854
855 return 0;
856}
857
858
c1a04ecb 859/**
0ba48136
MP
860 * Start a client for either type of remote connection. Work out
861 * whether the arguments request a remote shell or rsyncd connection,
862 * and call the appropriate connection function, then run_client.
0b4af330
MP
863 *
864 * Calls either start_socket_client (for sockets) or do_cmd and
865 * client_run (for ssh).
c1a04ecb 866 **/
fc8a6b97 867static int start_client(int argc, char *argv[])
5d6bcd44
AT
868{
869 char *p;
870 char *shell_machine = NULL;
871 char *shell_path = NULL;
872 char *shell_user = NULL;
19b27a48
AT
873 int ret;
874 pid_t pid;
5d6bcd44 875 int f_in,f_out;
7169bb4a
MP
876 int rc;
877
878 /* Don't clobber argv[] so that ps(1) can still show the right
d9c7edf6 879 * command line. */
75aeac44 880 if ((rc = copy_argv(argv)))
7169bb4a 881 return rc;
5d6bcd44 882
d16c245f 883 if (!read_batch) { /* for read_batch, NO source is specified */
42ccb4c0 884 argc--;
860236bf
WD
885 shell_path = check_for_hostspec(argv[0], &shell_machine, &rsync_port);
886 if (shell_path) { /* source is remote */
9425918d
WD
887 char *dummy1;
888 int dummy2;
3f7bfac2 889 if (argc && check_for_hostspec(argv[argc], &dummy1, &dummy2)) {
9425918d
WD
890 rprintf(FERROR,
891 "The source and destination cannot both be remote.\n");
892 exit_cleanup(RERR_SYNTAX);
893 }
42ccb4c0 894 argv++;
860236bf
WD
895 if (filesfrom_host && *filesfrom_host
896 && strcmp(filesfrom_host, shell_machine) != 0) {
7c2a9e76 897 rprintf(FERROR,
50b31539 898 "--files-from hostname is not the same as the transfer hostname\n");
7c2a9e76
WD
899 exit_cleanup(RERR_SYNTAX);
900 }
860236bf 901 if (rsync_port) {
d9c7edf6 902 if (!shell_cmd) {
860236bf
WD
903 return start_socket_client(shell_machine,
904 shell_path,
42ccb4c0 905 argc, argv);
d9c7edf6 906 }
d9c7edf6 907 daemon_over_rsh = 1;
75aeac44 908 }
3591c066 909
42ccb4c0
WD
910 am_sender = 0;
911 } else { /* source is local, check dest arg */
912 am_sender = 1;
913
d16c245f 914 if (argc < 1) { /* destination required */
d9c7edf6
WD
915 usage(FERROR);
916 exit_cleanup(RERR_SYNTAX);
917 }
a125c82a 918
42ccb4c0 919 shell_path = check_for_hostspec(argv[argc], &shell_machine, &rsync_port);
860236bf
WD
920 if (shell_path && filesfrom_host && *filesfrom_host
921 && strcmp(filesfrom_host, shell_machine) != 0) {
7c2a9e76 922 rprintf(FERROR,
50b31539 923 "--files-from hostname is not the same as the transfer hostname\n");
7c2a9e76
WD
924 exit_cleanup(RERR_SYNTAX);
925 }
860236bf 926 if (!shell_path) { /* no hostspec found, so src & dest are local */
d9c7edf6 927 local_server = 1;
860236bf 928 if (filesfrom_host) {
7c2a9e76 929 rprintf(FERROR,
50b31539 930 "--files-from cannot be remote when the transfer is local\n");
7c2a9e76
WD
931 exit_cleanup(RERR_SYNTAX);
932 }
860236bf 933 shell_machine = NULL;
42ccb4c0 934 shell_path = argv[argc];
860236bf 935 } else if (rsync_port) {
d9c7edf6 936 if (!shell_cmd) {
860236bf
WD
937 return start_socket_client(shell_machine,
938 shell_path,
42ccb4c0 939 argc, argv);
d9c7edf6 940 }
d9c7edf6 941 daemon_over_rsh = 1;
a125c82a 942 }
5d6bcd44 943 }
d16c245f 944 } else { /* read_batch */
d9c7edf6
WD
945 local_server = 1;
946 shell_path = argv[argc-1];
860236bf 947 if (check_for_hostspec(shell_path, &shell_machine, &rsync_port)) {
b9f592fb
WD
948 rprintf(FERROR, "remote destination is not allowed with --read-batch\n");
949 exit_cleanup(RERR_SYNTAX);
950 }
6902ed17
MP
951 }
952
5d6bcd44 953 if (shell_machine) {
6fc048f4 954 p = strrchr(shell_machine,'@');
5d6bcd44
AT
955 if (p) {
956 *p = 0;
957 shell_user = shell_machine;
958 shell_machine = p+1;
959 }
960 }
961
962 if (verbose > 3) {
9486289c 963 rprintf(FINFO,"cmd=%s machine=%s user=%s path=%s\n",
71903f60
WD
964 shell_cmd ? safe_fname(shell_cmd) : "",
965 shell_machine ? safe_fname(shell_machine) : "",
966 shell_user ? safe_fname(shell_user) : "",
967 shell_path ? safe_fname(shell_path) : "");
5d6bcd44 968 }
d9c7edf6 969
d16c245f 970 /* for remote source, only single dest arg can remain ... */
f7632fc6 971 if (!am_sender && argc > 1) {
5d6bcd44 972 usage(FERROR);
65417579 973 exit_cleanup(RERR_SYNTAX);
5d6bcd44 974 }
27e3e9c9 975
d16c245f 976 /* ... or no dest at all */
48a1ff0d
WD
977 if (!am_sender && argc == 0)
978 list_only |= 1;
d9c7edf6 979
75aeac44
WD
980 pid = do_cmd(shell_cmd,shell_machine,shell_user,shell_path,
981 &f_in,&f_out);
982
983 /* if we're running an rsync server on the remote host over a
9af87151 984 * remote shell command, we need to do the RSYNCD protocol first */
75aeac44
WD
985 if (daemon_over_rsh) {
986 int tmpret;
987 tmpret = start_inband_exchange(shell_user, shell_path,
988 f_in, f_out, argc);
989 if (tmpret < 0)
990 return tmpret;
991 }
992
fc8a6b97
AT
993 ret = client_run(f_in, f_out, pid, argc, argv);
994
995 fflush(stdout);
996 fflush(stderr);
997
998 return ret;
5d6bcd44
AT
999}
1000
366345fe 1001
067669da
WD
1002static RETSIGTYPE sigusr1_handler(UNUSED(int val))
1003{
65417579 1004 exit_cleanup(RERR_SIGNAL);
82306bf6
AT
1005}
1006
067669da
WD
1007static RETSIGTYPE sigusr2_handler(UNUSED(int val))
1008{
33c4b445
WD
1009 if (!am_server)
1010 output_summary();
40df65fd 1011 close_all();
33c4b445
WD
1012 if (log_got_error)
1013 _exit(RERR_PARTIAL);
8b35435f
AT
1014 _exit(0);
1015}
1016
067669da
WD
1017static RETSIGTYPE sigchld_handler(UNUSED(int val))
1018{
029c1713 1019#ifdef WNOHANG
ee7118a8
DD
1020 int cnt, status;
1021 pid_t pid;
1022 /* An empty waitpid() loop was put here by Tridge and we could never
d9c7edf6 1023 * get him to explain why he put it in, so rather than taking it
ee7118a8
DD
1024 * out we're instead saving the child exit statuses for later use.
1025 * The waitpid() loop presumably eliminates all possibility of leaving
1026 * zombie children, maybe that's why he did it.
1027 */
1028 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
9af87151
WD
1029 /* save the child's exit status */
1030 for (cnt = 0; cnt < MAXCHILDPROCS; cnt++) {
1031 if (pid_stat_table[cnt].pid == 0) {
1032 pid_stat_table[cnt].pid = pid;
1033 pid_stat_table[cnt].status = status;
1034 break;
1035 }
1036 }
ee7118a8 1037 }
029c1713 1038#endif
19b27a48
AT
1039}
1040
c0531332
MP
1041
1042/**
1043 * This routine catches signals and tries to send them to gdb.
1044 *
1045 * Because it's called from inside a signal handler it ought not to
1046 * use too many library routines.
1047 *
1048 * @todo Perhaps use "screen -X" instead/as well, to help people
1049 * debugging without easy access to X. Perhaps use an environment
1050 * variable, or just call a script?
1051 *
1052 * @todo The /proc/ magic probably only works on Linux (and
1053 * Solaris?) Can we be more portable?
1054 **/
1055#ifdef MAINTAINER_MODE
4fdc39dd
MP
1056const char *get_panic_action(void)
1057{
1058 const char *cmd_fmt = getenv("RSYNC_PANIC_ACTION");
1059
1060 if (cmd_fmt)
1061 return cmd_fmt;
1062 else
1063 return "xterm -display :0 -T Panic -n Panic "
1064 "-e gdb /proc/%d/exe %d";
1065}
1066
1067
9fb3f7a9
MP
1068/**
1069 * Handle a fatal signal by launching a debugger, controlled by $RSYNC_PANIC_ACTION.
1070 *
1071 * This signal handler is only installed if we were configured with
1072 * --enable-maintainer-mode. Perhaps it should always be on and we
1073 * should just look at the environment variable, but I'm a bit leery
1074 * of a signal sending us into a busy loop.
1075 **/
067669da 1076static RETSIGTYPE rsync_panic_handler(UNUSED(int whatsig))
c0531332
MP
1077{
1078 char cmd_buf[300];
1079 int ret;
4fdc39dd
MP
1080
1081 sprintf(cmd_buf, get_panic_action(),
c0531332
MP
1082 getpid(), getpid());
1083
1084 /* Unless we failed to execute gdb, we allow the process to
1085 * continue. I'm not sure if that's right. */
1086 ret = system(cmd_buf);
1087 if (ret)
1088 _exit(ret);
1089}
1090#endif
1091
1092
5d6bcd44 1093int main(int argc,char *argv[])
d9c7edf6 1094{
ff81e809 1095 int ret;
66a9dc96
WD
1096 int orig_argc = argc;
1097 char **orig_argv = argv;
5d6bcd44 1098
7a6421fa 1099 signal(SIGUSR1, sigusr1_handler);
8b35435f 1100 signal(SIGUSR2, sigusr2_handler);
19b27a48 1101 signal(SIGCHLD, sigchld_handler);
c0531332
MP
1102#ifdef MAINTAINER_MODE
1103 signal(SIGSEGV, rsync_panic_handler);
1104 signal(SIGFPE, rsync_panic_handler);
1105 signal(SIGABRT, rsync_panic_handler);
1106 signal(SIGBUS, rsync_panic_handler);
1107#endif /* def MAINTAINER_MODE */
5d6bcd44 1108
7a6421fa 1109 starttime = time(NULL);
6fe05820 1110 am_root = (MY_UID() == 0);
c627d613 1111
a800434a
AT
1112 memset(&stats, 0, sizeof(stats));
1113
df5e03da
AT
1114 if (argc < 2) {
1115 usage(FERROR);
65417579 1116 exit_cleanup(RERR_SYNTAX);
df5e03da
AT
1117 }
1118
7a6421fa 1119 /* we set a 0 umask so that correct file permissions can be
9af87151 1120 * carried across */
7a6421fa 1121 orig_umask = (int)umask(0);
5d6bcd44 1122
50135767 1123 if (!parse_arguments(&argc, (const char ***) &argv, 1)) {
d9c7edf6
WD
1124 /* FIXME: We ought to call the same error-handling
1125 * code here, rather than relying on getopt. */
50135767 1126 option_error();
65417579 1127 exit_cleanup(RERR_SYNTAX);
b11ed3b1 1128 }
5d6bcd44 1129
7a6421fa 1130 signal(SIGINT,SIGNAL_CAST sig_int);
7a6421fa 1131 signal(SIGHUP,SIGNAL_CAST sig_int);
8638dd48 1132 signal(SIGTERM,SIGNAL_CAST sig_int);
6b83141d 1133
34758d5c
MP
1134 /* Ignore SIGPIPE; we consistently check error codes and will
1135 * see the EPIPE. */
1136 signal(SIGPIPE, SIG_IGN);
1137
d9401514
WD
1138#if defined CONFIG_LOCALE && defined HAVE_SETLOCALE
1139 setlocale(LC_CTYPE, "");
1140#endif
1141
c226b7c2 1142 /* Initialize push_dir here because on some old systems getcwd
9af87151
WD
1143 * (implemented by forking "pwd" and reading its output) doesn't
1144 * work when there are other child processes. Also, on all systems
1145 * that implement getcwd that way "pwd" can't be found after chroot. */
59187666 1146 push_dir(NULL);
c226b7c2 1147
44e9e221
WD
1148 init_flist();
1149
e8a96e27 1150 if ((write_batch || read_batch) && !am_server) {
b9f592fb 1151 if (write_batch)
66a9dc96 1152 write_batch_shell_file(orig_argc, orig_argv, argc);
b9f592fb 1153
dbbab0c4
WD
1154 if (read_batch && strcmp(batch_name, "-") == 0)
1155 batch_fd = STDIN_FILENO;
1156 else {
1157 batch_fd = do_open(batch_name,
b9f592fb
WD
1158 write_batch ? O_WRONLY | O_CREAT | O_TRUNC
1159 : O_RDONLY, S_IRUSR | S_IWUSR);
dbbab0c4 1160 }
b9f592fb
WD
1161 if (batch_fd < 0) {
1162 rsyserr(FERROR, errno, "Batch file %s open error",
71903f60 1163 full_fname(batch_name));
b9f592fb
WD
1164 exit_cleanup(RERR_FILEIO);
1165 }
9459290a
WD
1166 if (read_batch)
1167 read_stream_flags(batch_fd);
6902ed17 1168 }
e8a96e27
WD
1169 if (write_batch < 0)
1170 dry_run = 1;
6902ed17 1171
75aeac44 1172 if (am_daemon && !am_server)
7a6421fa 1173 return daemon_main();
f0fca04e 1174
08ac228f
AT
1175 if (argc < 1) {
1176 usage(FERROR);
65417579 1177 exit_cleanup(RERR_SYNTAX);
08ac228f
AT
1178 }
1179
7a6421fa 1180 if (am_server) {
f0359dd0
AT
1181 set_nonblocking(STDIN_FILENO);
1182 set_nonblocking(STDOUT_FILENO);
75aeac44
WD
1183 if (am_daemon)
1184 return start_daemon(STDIN_FILENO, STDOUT_FILENO);
7a6421fa
AT
1185 start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
1186 }
c627d613 1187
ff81e809 1188 ret = start_client(argc, argv);
d9c7edf6 1189 if (ret == -1)
9098bbf3 1190 exit_cleanup(RERR_STARTCLIENT);
088aac85 1191 else
9098bbf3
MP
1192 exit_cleanup(ret);
1193
0f5a04e3 1194 return ret;
c627d613 1195}