86eca2ca9b62f48ad97125a41555dcec76d507a2
[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 struct stats stats;
27
28 extern int verbose;
29
30 static void show_malloc_stats(void);
31
32 /****************************************************************************
33 wait for a process to exit, calling io_flush while waiting
34 ****************************************************************************/
35 void wait_process(pid_t pid, int *status)
36 {
37         while (waitpid(pid, status, WNOHANG) == 0) {
38                 msleep(20);
39                 io_flush();
40         }
41         
42         /* TODO: If the child exited on a signal, then log an
43          * appropriate error message.  Perhaps we should also accept a
44          * message describing the purpose of the child.  Also indicate
45          * this to the caller so that thhey know something went
46          * wrong.  */
47         *status = WEXITSTATUS(*status);
48 }
49
50 static void report(int f)
51 {
52         time_t t = time(NULL);
53         extern int am_server;
54         extern int am_sender;
55         extern int am_daemon;
56         extern int do_stats;
57         extern int remote_version;
58         int send_stats;
59
60         if (do_stats) {
61                 /* These come out from every process */
62                 show_malloc_stats();
63                 show_flist_stats();
64         }
65
66         if (am_daemon) {
67                 log_exit(0, __FILE__, __LINE__);
68                 if (f == -1 || !am_sender) return;
69         }
70
71         send_stats = verbose || (remote_version >= 20);
72         if (am_server) {
73                 if (am_sender && send_stats) {
74                         int64 w;
75                         /* store total_written in a temporary
76                             because write_longint changes it */
77                         w = stats.total_written;
78                         write_longint(f,stats.total_read);
79                         write_longint(f,w);
80                         write_longint(f,stats.total_size);
81                 }
82                 return;
83         }
84
85         /* this is the client */
86             
87         if (!am_sender && send_stats) {
88                 int64 r;
89                 stats.total_written = read_longint(f);
90                 /* store total_read in a temporary, read_longint changes it */
91                 r = read_longint(f);
92                 stats.total_size = read_longint(f);
93                 stats.total_read = r;
94         }
95
96         if (do_stats) {
97                 if (!am_sender && !send_stats) {
98                     /* missing the bytes written by the generator */
99                     rprintf(FINFO, "\nCannot show stats as receiver because remote protocol version is less than 20\n");
100                     rprintf(FINFO, "Use --stats -v to show stats\n");
101                     return;
102                 }
103                 rprintf(FINFO,"\nNumber of files: %d\n", stats.num_files);
104                 rprintf(FINFO,"Number of files transferred: %d\n", 
105                        stats.num_transferred_files);
106                 rprintf(FINFO,"Total file size: %.0f bytes\n", 
107                        (double)stats.total_size);
108                 rprintf(FINFO,"Total transferred file size: %.0f bytes\n", 
109                        (double)stats.total_transferred_size);
110                 rprintf(FINFO,"Literal data: %.0f bytes\n", 
111                        (double)stats.literal_data);
112                 rprintf(FINFO,"Matched data: %.0f bytes\n", 
113                        (double)stats.matched_data);
114                 rprintf(FINFO,"File list size: %d\n", stats.flist_size);
115                 rprintf(FINFO,"Total bytes written: %.0f\n", 
116                        (double)stats.total_written);
117                 rprintf(FINFO,"Total bytes read: %.0f\n\n", 
118                        (double)stats.total_read);
119         }
120         
121         if (verbose || do_stats) {
122                 rprintf(FINFO,"wrote %.0f bytes  read %.0f bytes  %.2f bytes/sec\n",
123                        (double)stats.total_written,
124                        (double)stats.total_read,
125                        (stats.total_written+stats.total_read)/(0.5 + (t-starttime)));
126                 rprintf(FINFO,"total size is %.0f  speedup is %.2f\n",
127                        (double)stats.total_size,
128                        (1.0*stats.total_size)/(stats.total_written+stats.total_read));
129         }
130
131         fflush(stdout);
132         fflush(stderr);
133 }
134
135
136 /**
137  * If our C library can get malloc statistics, then show them to FINFO
138  **/
139 static void show_malloc_stats(void)
140 {
141 #ifdef HAVE_MALLINFO
142         struct mallinfo mi;
143         extern int am_server;
144         extern int am_sender;
145         extern int am_daemon;
146
147         mi = mallinfo();
148
149         rprintf(FINFO, RSYNC_NAME "[%d] (%s%s%s) heap statistics:\n",
150                 getpid(),
151                 am_server ? "server " : "",
152                 am_daemon ? "daemon " : "",
153                 am_sender ? "sender" : "receiver");
154         rprintf(FINFO, "  arena:     %10d   (bytes from sbrk)\n", mi.arena);
155         rprintf(FINFO, "  ordblks:   %10d   (chunks not in use)\n", mi.ordblks);
156         rprintf(FINFO, "  smblks:    %10d\n", mi.smblks);
157         rprintf(FINFO, "  hblks:     %10d   (chunks from mmap)\n", mi.hblks);
158         rprintf(FINFO, "  hblkhd:    %10d   (bytes from mmap)\n", mi.hblkhd);
159         rprintf(FINFO, "  usmblks:   %10d\n", mi.usmblks);
160         rprintf(FINFO, "  fsmblks:   %10d\n", mi.fsmblks);
161         rprintf(FINFO, "  uordblks:  %10d   (bytes used)\n", mi.uordblks);
162         rprintf(FINFO, "  fordblks:  %10d   (bytes free)\n", mi.fordblks);
163         rprintf(FINFO, "  keepcost:  %10d   (bytes in releasable chunk)\n", mi.keepcost);
164 #endif /* HAVE_MALLINFO */
165 }
166
167
168 /* Start the remote shell.   cmd may be NULL to use the default. */
169 static pid_t do_cmd(char *cmd,char *machine,char *user,char *path,int *f_in,int *f_out)
170 {
171         char *args[100];
172         int i,argc=0;
173         pid_t ret;
174         char *tok,*dir=NULL;
175         extern int local_server;
176         extern char *rsync_path;
177         extern int blocking_io;
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 (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 void child_main(int argc, char *argv[])
497 {
498         start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
499 }
500
501
502 void start_server(int f_in, int f_out, int argc, char *argv[])
503 {
504         extern int cvs_exclude;
505         extern int am_sender;
506         extern int remote_version;
507         extern int read_batch;
508
509         setup_protocol(f_out, f_in);
510
511         set_nonblocking(f_in);
512         set_nonblocking(f_out);
513
514         if (remote_version >= 23)
515                 io_start_multiplex_out(f_out);
516
517         if (am_sender) {
518                 if (!read_batch) {
519                     recv_exclude_list(f_in);
520                     if (cvs_exclude)
521                         add_cvs_excludes();
522                 }
523                 do_server_sender(f_in, f_out, argc, argv);
524         } else {
525                 do_server_recv(f_in, f_out, argc, argv);
526         }
527         exit_cleanup(0);
528 }
529
530
531 /*
532  * This is called once the connection has been negotiated.  It is used
533  * for rsyncd, remote-shell, and local connections.
534  */
535 int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[])
536 {
537         struct file_list *flist = NULL;
538         int status = 0, status2 = 0;
539         char *local_name = NULL;
540         extern int am_sender;
541         extern int remote_version;
542         extern pid_t cleanup_child_pid;
543         extern int write_batch;
544         extern int read_batch;
545         extern struct file_list *batch_flist;
546
547         cleanup_child_pid = pid;
548         if (read_batch)
549             flist = batch_flist;
550
551         set_nonblocking(f_in);
552         set_nonblocking(f_out);
553
554         setup_protocol(f_out,f_in);
555
556         if (remote_version >= 23)
557                 io_start_multiplex_in(f_in);
558         
559         if (am_sender) {
560                 extern int cvs_exclude;
561                 extern int delete_mode;
562                 extern int delete_excluded;
563                 if (cvs_exclude)
564                         add_cvs_excludes();
565                 if (delete_mode && !delete_excluded) 
566                         send_exclude_list(f_out);
567                 if (!read_batch) /*  dw -- don't write to pipe */
568                     flist = send_file_list(f_out,argc,argv);
569                 if (verbose > 3) 
570                         rprintf(FINFO,"file list sent\n");
571
572                 send_files(flist,f_out,f_in);
573                 if (remote_version >= 24) {
574                         /* final goodbye message */             
575                         read_int(f_in);
576                 }
577                 if (pid != -1) {
578                         if (verbose > 3)
579                                 rprintf(FINFO,"client_run waiting on %d\n", (int) pid);
580                         io_flush();
581                         wait_process(pid, &status);
582                 }
583                 report(-1);
584                 exit_cleanup(status);
585         }
586
587         if (argc == 0) {
588                 extern int list_only;
589                 list_only = 1;
590         }
591         
592         if (!write_batch)
593             send_exclude_list(f_out);
594         
595         flist = recv_file_list(f_in);
596         if (!flist || flist->count == 0) {
597                 rprintf(FINFO, "client: nothing to do: "
598                         "perhaps you need to specify some filenames or "
599                         "the --recursive option?\n");
600                 exit_cleanup(0);
601         }
602         
603         local_name = get_local_name(flist,argv[0]);
604         
605         status2 = do_recv(f_in,f_out,flist,local_name);
606         
607         if (pid != -1) {
608                 if (verbose > 3)
609                         rprintf(FINFO,"client_run2 waiting on %d\n", (int) pid);
610                 io_flush();
611                 wait_process(pid, &status);
612         }
613         
614         return MAX(status, status2);
615 }
616
617 static char *find_colon(char *s)
618 {
619         char *p, *p2;
620
621         p = strchr(s,':');
622         if (!p) return NULL;
623         
624         /* now check to see if there is a / in the string before the : - if there is then
625            discard the colon on the assumption that the : is part of a filename */
626         p2 = strchr(s,'/');
627         if (p2 && p2 < p) return NULL;
628
629         return p;
630 }
631
632
633 static int copy_argv (char *argv[])
634 {
635         int i;
636
637         for (i = 0; argv[i]; i++) {
638                 if (!(argv[i] = strdup(argv[i]))) {
639                         rprintf (FERROR, "out of memory at %s(%d)\n",
640                                  __FILE__, __LINE__);
641                         return RERR_MALLOC;
642                 }
643         }
644
645         return 0;
646 }
647
648
649 /**
650  * Start a client for either type of remote connection.  Work out
651  * whether the arguments request a remote shell or rsyncd connection,
652  * and call the appropriate connection function, then run_client.
653  *
654  * Calls either start_socket_client (for sockets) or do_cmd and
655  * client_run (for ssh).
656  **/
657 static int start_client(int argc, char *argv[])
658 {
659         char *p;
660         char *shell_machine = NULL;
661         char *shell_path = NULL;
662         char *shell_user = NULL;
663         int ret;
664         pid_t pid;
665         int f_in,f_out;
666         extern int local_server;
667         extern int am_sender;
668         extern char *shell_cmd;
669         extern int rsync_port;
670         extern int whole_file;
671         extern int write_batch;
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         if (strncasecmp(URL_PREFIX, argv[0], strlen(URL_PREFIX)) == 0) {
681                 char *host, *path;
682
683                 host = argv[0] + strlen(URL_PREFIX);
684                 p = strchr(host,'/');
685                 if (p) {
686                         *p = 0;
687                         path = p+1;
688                 } else {
689                         path="";
690                 }
691                 p = strchr(host,':');
692                 if (p) {
693                         rsync_port = atoi(p+1);
694                         *p = 0;
695                 }
696                 return start_socket_client(host, path, argc-1, argv+1);
697         }
698
699         if (!read_batch) {
700             p = find_colon(argv[0]);
701
702         if (p) {
703                 if (p[1] == ':') { /* double colon */
704                         *p = 0;
705                         return start_socket_client(argv[0], p+2, argc-1, argv+1);
706                 }
707
708                 if (argc < 1) {
709                         usage(FERROR);
710                         exit_cleanup(RERR_SYNTAX);
711                 }
712
713                 am_sender = 0;
714                 *p = 0;
715                 shell_machine = argv[0];
716                 shell_path = p+1;
717                 argc--;
718                 argv++;
719         } else {
720                 am_sender = 1;
721
722                 p = find_colon(argv[argc-1]);
723                 if (!p) {
724                         local_server = 1;
725                 } else if (p[1] == ':') {
726                         *p = 0;
727                         return start_socket_client(argv[argc-1], p+2, argc-1, argv);
728                 }
729
730                 if (argc < 2) {
731                         usage(FERROR);
732                         exit_cleanup(RERR_SYNTAX);
733                 }
734                 
735                 if (local_server) {
736                         shell_machine = NULL;
737                         shell_path = argv[argc-1];
738                 } else {
739                         *p = 0;
740                         shell_machine = argv[argc-1];
741                         shell_path = p+1;
742                 }
743                 argc--;
744         }
745         } else {
746             am_sender = 1;
747             local_server = 1;
748             shell_path = argv[argc-1];
749         }
750
751         if (shell_machine) {
752                 p = strchr(shell_machine,'@');
753                 if (p) {
754                         *p = 0;
755                         shell_user = shell_machine;
756                         shell_machine = p+1;
757                 }
758         }
759
760         if (verbose > 3) {
761                 rprintf(FINFO,"cmd=%s machine=%s user=%s path=%s\n",
762                         shell_cmd?shell_cmd:"",
763                         shell_machine?shell_machine:"",
764                         shell_user?shell_user:"",
765                         shell_path?shell_path:"");
766         }
767         
768         if (!am_sender && argc > 1) {
769                 usage(FERROR);
770                 exit_cleanup(RERR_SYNTAX);
771         }
772
773         if (argc == 0 && !am_sender) {
774                 extern int list_only;
775                 list_only = 1;
776         }
777         
778         pid = do_cmd(shell_cmd,shell_machine,shell_user,shell_path,&f_in,&f_out);
779         
780         ret = client_run(f_in, f_out, pid, argc, argv);
781
782         fflush(stdout);
783         fflush(stderr);
784
785         return ret;
786 }
787
788
789 static RETSIGTYPE sigusr1_handler(int UNUSED(val)) {
790         exit_cleanup(RERR_SIGNAL);
791 }
792
793 static RETSIGTYPE sigusr2_handler(int UNUSED(val)) {
794         extern int log_got_error;
795         if (log_got_error) _exit(RERR_PARTIAL);
796         _exit(0);
797 }
798
799 static RETSIGTYPE sigchld_handler(int UNUSED(val)) {
800 #ifdef WNOHANG
801         while (waitpid(-1, NULL, WNOHANG) > 0) ;
802 #endif
803 }
804
805
806 /**
807  * This routine catches signals and tries to send them to gdb.
808  *
809  * Because it's called from inside a signal handler it ought not to
810  * use too many library routines.
811  *
812  * @todo Perhaps use "screen -X" instead/as well, to help people
813  * debugging without easy access to X.  Perhaps use an environment
814  * variable, or just call a script?
815  *
816  * @todo The /proc/ magic probably only works on Linux (and
817  * Solaris?)  Can we be more portable?
818  **/
819 #ifdef MAINTAINER_MODE
820 static RETSIGTYPE rsync_panic_handler(int UNUSED(whatsig))
821 {
822         char cmd_buf[300];
823         int ret;
824         sprintf(cmd_buf, 
825                 "xterm -display :0 -T Panic -n Panic "
826                 "-e gdb /proc/%d/exe %d", 
827                 getpid(), getpid());
828
829         /* Unless we failed to execute gdb, we allow the process to
830          * continue.  I'm not sure if that's right. */
831         ret = system(cmd_buf);
832         if (ret)
833                 _exit(ret);
834 }
835 #endif
836
837
838 int main(int argc,char *argv[])
839 {       
840         extern int am_root;
841         extern int orig_umask;
842         extern int dry_run;
843         extern int am_daemon;
844         extern int am_server;
845         int ret;
846         extern int write_batch;
847         int orig_argc;
848         char **orig_argv;
849
850         orig_argc = argc;
851         orig_argv = argv;
852
853         signal(SIGUSR1, sigusr1_handler);
854         signal(SIGUSR2, sigusr2_handler);
855         signal(SIGCHLD, sigchld_handler);
856 #ifdef MAINTAINER_MODE
857         signal(SIGSEGV, rsync_panic_handler);
858         signal(SIGFPE, rsync_panic_handler);
859         signal(SIGABRT, rsync_panic_handler);
860         signal(SIGBUS, rsync_panic_handler);
861 #endif /* def MAINTAINER_MODE */
862
863         starttime = time(NULL);
864         am_root = (getuid() == 0);
865
866         memset(&stats, 0, sizeof(stats));
867
868         if (argc < 2) {
869                 usage(FERROR);
870                 exit_cleanup(RERR_SYNTAX);
871         }
872
873         /* we set a 0 umask so that correct file permissions can be
874            carried across */
875         orig_umask = (int)umask(0);
876
877         if (!parse_arguments(&argc, (const char ***) &argv, 1)) {
878                 /* FIXME: We ought to call the same error-handling
879                  * code here, rather than relying on getopt. */
880                 option_error();
881                 exit_cleanup(RERR_SYNTAX);
882         }
883
884         signal(SIGINT,SIGNAL_CAST sig_int);
885         signal(SIGHUP,SIGNAL_CAST sig_int);
886         signal(SIGTERM,SIGNAL_CAST sig_int);
887
888         /* Ignore SIGPIPE; we consistently check error codes and will
889          * see the EPIPE. */
890         signal(SIGPIPE, SIG_IGN);
891
892         /* Initialize push_dir here because on some old systems getcwd
893            (implemented by forking "pwd" and reading its output) doesn't
894            work when there are other child processes.  Also, on all systems
895            that implement getcwd that way "pwd" can't be found after chroot. */
896         push_dir(NULL,0);
897
898         if (write_batch && !am_server) {
899             write_batch_argvs_file(orig_argc, orig_argv);
900         }
901
902         if (am_daemon) {
903                 return daemon_main();
904         }
905
906         if (argc < 1) {
907                 usage(FERROR);
908                 exit_cleanup(RERR_SYNTAX);
909         }
910
911         if (dry_run)
912                 verbose = MAX(verbose,1);
913
914 #ifndef SUPPORT_LINKS
915         if (!am_server && preserve_links) {
916                 rprintf(FERROR,"ERROR: symbolic links not supported\n");
917                 exit_cleanup(RERR_UNSUPPORTED);
918         }
919 #endif
920
921         if (am_server) {
922                 set_nonblocking(STDIN_FILENO);
923                 set_nonblocking(STDOUT_FILENO);
924                 start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
925         }
926
927         ret = start_client(argc, argv);
928         if (ret == -1) 
929                 exit_cleanup(RERR_STARTCLIENT);
930         else
931                 exit_cleanup(ret);
932
933         exit(ret);
934         /* NOTREACHED */
935 }