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