Don't pass "-l user" to the remote shell if we're starting a server-daemon
[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         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
251 oom:
252         out_of_memory("do_cmd");
253         return 0; /* not reached */
254 }
255
256
257
258
259 static 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
311 static 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
361 static 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
444 static 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
504 int child_main(int argc, char *argv[])
505 {
506         start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
507         return 0;
508 }
509
510
511 void 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  */
544 int 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
626 static 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
642 static 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  **/
666 static 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
839 static RETSIGTYPE sigusr1_handler(int UNUSED(val)) {
840         exit_cleanup(RERR_SIGNAL);
841 }
842
843 static 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
849 static 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
870 const 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  **/
890 static 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
907 int 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 }