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