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