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