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