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