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