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