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