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