Doc file
[rsync/rsync.git] / main.c
1 /* -*- c-file-style: "linux" -*-
2    
3    Copyright (C) 1996-2001 by Andrew Tridgell <tridge@samba.org>
4    Copyright (C) Paul Mackerras 1996
5    Copyright (C) 2001, 2002 by Martin Pool <mbp@samba.org>
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "rsync.h"
23
24 time_t starttime = 0;
25
26 extern struct stats stats;
27 extern int verbose;
28
29 static void show_malloc_stats(void);
30
31 /****************************************************************************
32 wait for a process to exit, calling io_flush while waiting
33 ****************************************************************************/
34 void wait_process(pid_t pid, int *status)
35 {
36         while (waitpid(pid, status, WNOHANG) == 0) {
37                 msleep(20);
38                 io_flush();
39         }
40         
41         /* TODO: If the child exited on a signal, then log an
42          * appropriate error message.  Perhaps we should also accept a
43          * message describing the purpose of the child.  Also indicate
44          * this to the caller so that thhey know something went
45          * wrong.  */
46         *status = WEXITSTATUS(*status);
47 }
48
49 static void report(int f)
50 {
51         time_t t = time(NULL);
52         extern int am_server;
53         extern int am_sender;
54         extern int am_daemon;
55         extern int do_stats;
56         extern int remote_version;
57         int send_stats;
58
59         if (do_stats) {
60                 /* These come out from every process */
61                 show_malloc_stats();
62                 show_flist_stats();
63         }
64
65         if (am_daemon) {
66                 log_exit(0, __FILE__, __LINE__);
67                 if (f == -1 || !am_sender) return;
68         }
69
70         send_stats = verbose || (remote_version >= 20);
71         if (am_server) {
72                 if (am_sender && send_stats) {
73                         int64 w;
74                         /* store total_written in a temporary
75                             because write_longint changes it */
76                         w = stats.total_written;
77                         write_longint(f,stats.total_read);
78                         write_longint(f,w);
79                         write_longint(f,stats.total_size);
80                 }
81                 return;
82         }
83
84         /* this is the client */
85             
86         if (!am_sender && send_stats) {
87                 int64 r;
88                 stats.total_written = read_longint(f);
89                 /* store total_read in a temporary, read_longint changes it */
90                 r = read_longint(f);
91                 stats.total_size = read_longint(f);
92                 stats.total_read = r;
93         }
94
95         if (do_stats) {
96                 if (!am_sender && !send_stats) {
97                     /* missing the bytes written by the generator */
98                     rprintf(FINFO, "\nCannot show stats as receiver because remote protocol version is less than 20\n");
99                     rprintf(FINFO, "Use --stats -v to show stats\n");
100                     return;
101                 }
102                 rprintf(FINFO,"\nNumber of files: %d\n", stats.num_files);
103                 rprintf(FINFO,"Number of files transferred: %d\n", 
104                        stats.num_transferred_files);
105                 rprintf(FINFO,"Total file size: %.0f bytes\n", 
106                        (double)stats.total_size);
107                 rprintf(FINFO,"Total transferred file size: %.0f bytes\n", 
108                        (double)stats.total_transferred_size);
109                 rprintf(FINFO,"Literal data: %.0f bytes\n", 
110                        (double)stats.literal_data);
111                 rprintf(FINFO,"Matched data: %.0f bytes\n", 
112                        (double)stats.matched_data);
113                 rprintf(FINFO,"File list size: %d\n", stats.flist_size);
114                 rprintf(FINFO,"Total bytes written: %.0f\n", 
115                        (double)stats.total_written);
116                 rprintf(FINFO,"Total bytes read: %.0f\n\n", 
117                        (double)stats.total_read);
118         }
119         
120         if (verbose || do_stats) {
121                 rprintf(FINFO,"wrote %.0f bytes  read %.0f bytes  %.2f bytes/sec\n",
122                        (double)stats.total_written,
123                        (double)stats.total_read,
124                        (stats.total_written+stats.total_read)/(0.5 + (t-starttime)));
125                 rprintf(FINFO,"total size is %.0f  speedup is %.2f\n",
126                        (double)stats.total_size,
127                        (1.0*stats.total_size)/(stats.total_written+stats.total_read));
128         }
129
130         fflush(stdout);
131         fflush(stderr);
132 }
133
134
135 /**
136  * If our C library can get malloc statistics, then show them to FINFO
137  **/
138 static void show_malloc_stats(void)
139 {
140 #ifdef HAVE_MALLINFO
141         struct mallinfo mi;
142         extern int am_server;
143         extern int am_sender;
144         extern int am_daemon;
145
146         mi = mallinfo();
147
148         rprintf(FINFO, RSYNC_NAME "[%d] (%s%s%s) heap statistics:\n",
149                 getpid(),
150                 am_server ? "server " : "",
151                 am_daemon ? "daemon " : "",
152                 am_sender ? "sender" : "receiver");
153         rprintf(FINFO, "  arena:     %10d   (bytes from sbrk)\n", mi.arena);
154         rprintf(FINFO, "  ordblks:   %10d   (chunks not in use)\n", mi.ordblks);
155         rprintf(FINFO, "  smblks:    %10d\n", mi.smblks);
156         rprintf(FINFO, "  hblks:     %10d   (chunks from mmap)\n", mi.hblks);
157         rprintf(FINFO, "  hblkhd:    %10d   (bytes from mmap)\n", mi.hblkhd);
158         rprintf(FINFO, "  usmblks:   %10d\n", mi.usmblks);
159         rprintf(FINFO, "  fsmblks:   %10d\n", mi.fsmblks);
160         rprintf(FINFO, "  uordblks:  %10d   (bytes used)\n", mi.uordblks);
161         rprintf(FINFO, "  fordblks:  %10d   (bytes free)\n", mi.fordblks);
162         rprintf(FINFO, "  keepcost:  %10d   (bytes in releasable chunk)\n", mi.keepcost);
163 #endif /* HAVE_MALLINFO */
164 }
165
166
167 /* Start the remote shell.   cmd may be NULL to use the default. */
168 static pid_t do_cmd(char *cmd,char *machine,char *user,char *path,int *f_in,int *f_out)
169 {
170         char *args[100];
171         int i,argc=0;
172         pid_t ret;
173         char *tok,*dir=NULL;
174         extern int local_server;
175         extern char *rsync_path;
176         extern int blocking_io;
177         extern int read_batch;
178
179         if (!read_batch && !local_server) {
180                 if (!cmd)
181                         cmd = getenv(RSYNC_RSH_ENV);
182                 if (!cmd)
183                         cmd = RSYNC_RSH;
184                 cmd = strdup(cmd);
185                 if (!cmd) 
186                         goto oom;
187
188                 for (tok=strtok(cmd," ");tok;tok=strtok(NULL," ")) {
189                         args[argc++] = tok;
190                 }
191
192 #if HAVE_REMSH
193                 /* remsh (on HPUX) takes the arguments the other way around */
194                 args[argc++] = machine;
195                 if (user) {
196                         args[argc++] = "-l";
197                         args[argc++] = user;
198                 }
199 #else
200                 if (user) {
201                         args[argc++] = "-l";
202                         args[argc++] = user;
203                 }
204                 args[argc++] = machine;
205 #endif
206
207                 args[argc++] = rsync_path;
208
209                 if ((blocking_io == -1) && (strcmp(cmd, RSYNC_RSH) == 0))
210                         blocking_io = 1;
211
212                 server_options(args,&argc);
213
214         }
215
216         args[argc++] = ".";
217
218         if (path && *path) 
219                 args[argc++] = path;
220
221         args[argc] = NULL;
222
223         if (verbose > 3) {
224                 rprintf(FINFO,"cmd=");
225                 for (i=0;i<argc;i++)
226                         rprintf(FINFO,"%s ",args[i]);
227                 rprintf(FINFO,"\n");
228         }
229
230         if (local_server) {
231                 if (read_batch)
232                     create_flist_from_batch(); /* sets batch_flist */
233                 ret = local_child(argc, args, f_in, f_out, child_main);
234         } else {
235                 ret = piped_child(args,f_in,f_out);
236         }
237
238         if (dir) free(dir);
239
240         return ret;
241
242 oom:
243         out_of_memory("do_cmd");
244         return 0; /* not reached */
245 }
246
247
248
249
250 static char *get_local_name(struct file_list *flist,char *name)
251 {
252         STRUCT_STAT st;
253         extern int orig_umask;
254
255         if (verbose > 2)
256                 rprintf(FINFO,"get_local_name count=%d %s\n", 
257                         flist->count, NS(name));
258
259         if (!name) 
260                 return NULL;
261
262         if (do_stat(name,&st) == 0) {
263                 if (S_ISDIR(st.st_mode)) {
264                         if (!push_dir(name, 0)) {
265                                 rprintf(FERROR,"push_dir %s : %s (1)\n",
266                                         name,strerror(errno));
267                                 exit_cleanup(RERR_FILESELECT);
268                         }
269                         return NULL;
270                 }
271                 if (flist->count > 1) {
272                         rprintf(FERROR,"ERROR: destination must be a directory when copying more than 1 file\n");
273                         exit_cleanup(RERR_FILESELECT);
274                 }
275                 return name;
276         }
277
278         if (flist->count <= 1)
279                 return name;
280
281         if (do_mkdir(name,0777 & ~orig_umask) != 0) {
282                 rprintf(FERROR, RSYNC_NAME ": mkdir %s: %s\n",
283                         name, strerror(errno));
284                 exit_cleanup(RERR_FILEIO);
285         } else {
286                 if (verbose > 0)
287                         rprintf(FINFO,"created directory %s\n",name);
288         }
289
290         if (!push_dir(name, 0)) {
291                 rprintf(FERROR, RSYNC_NAME ": push_dir %s: %s\n",
292                         name, strerror(errno));
293                 exit_cleanup(RERR_FILESELECT);
294         }
295
296         return NULL;
297 }
298
299
300
301
302 static void do_server_sender(int f_in, int f_out, int argc,char *argv[])
303 {
304         int i;
305         struct file_list *flist;
306         char *dir = argv[0];
307         extern int relative_paths;
308         extern int recurse;
309         extern int remote_version;
310
311         if (verbose > 2)
312                 rprintf(FINFO,"server_sender starting pid=%d\n",(int)getpid());
313   
314         if (!relative_paths && !push_dir(dir, 0)) {
315                 rprintf(FERROR,"push_dir %s: %s (3)\n",dir,strerror(errno));
316                 exit_cleanup(RERR_FILESELECT);
317         }
318         argc--;
319         argv++;
320   
321         if (strcmp(dir,".")) {
322                 int l = strlen(dir);
323                 if (strcmp(dir,"/") == 0) 
324                         l = 0;
325                 for (i=0;i<argc;i++)
326                         argv[i] += l+1;
327         }
328
329         if (argc == 0 && recurse) {
330                 argc=1;
331                 argv--;
332                 argv[0] = ".";
333         }
334         
335         flist = send_file_list(f_out,argc,argv);
336         if (!flist || flist->count == 0) {
337                 exit_cleanup(0);
338         }
339
340         send_files(flist,f_out,f_in);
341         io_flush();
342         report(f_out);
343         if (remote_version >= 24) {
344                 /* final goodbye message */             
345                 read_int(f_in);
346         }
347         io_flush();
348         exit_cleanup(0);
349 }
350
351
352 static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
353 {
354         int pid;
355         int status=0;
356         int recv_pipe[2];
357         int error_pipe[2];
358         extern int preserve_hard_links;
359         extern int delete_after;
360         extern int recurse;
361         extern int delete_mode;
362         extern int remote_version;
363
364         if (preserve_hard_links)
365                 init_hard_links(flist);
366
367         if (!delete_after) {
368                 /* I moved this here from recv_files() to prevent a race condition */
369                 if (recurse && delete_mode && !local_name && flist->count>0) {
370                         delete_files(flist);
371                 }
372         }
373
374         if (fd_pair(recv_pipe) < 0) {
375                 rprintf(FERROR,"pipe failed in do_recv\n");
376                 exit_cleanup(RERR_SOCKETIO);
377         }
378
379         if (fd_pair(error_pipe) < 0) {
380                 rprintf(FERROR,"error pipe failed in do_recv\n");
381                 exit_cleanup(RERR_SOCKETIO);
382         }
383   
384         io_flush();
385
386         if ((pid=do_fork()) == 0) {
387                 close(recv_pipe[0]);
388                 close(error_pipe[0]);
389                 if (f_in != f_out) close(f_out);
390
391                 /* we can't let two processes write to the socket at one time */
392                 io_multiplexing_close();
393
394                 /* set place to send errors */
395                 set_error_fd(error_pipe[1]);
396
397                 recv_files(f_in,flist,local_name,recv_pipe[1]);
398                 io_flush();
399                 report(f_in);
400
401                 write_int(recv_pipe[1],1);
402                 close(recv_pipe[1]);
403                 io_flush();
404                 /* finally we go to sleep until our parent kills us
405                    with a USR2 signal. We sleep for a short time as on
406                    some OSes a signal won't interrupt a sleep! */
407                 while (msleep(20))
408                         ;
409         }
410
411         close(recv_pipe[1]);
412         close(error_pipe[1]);
413         if (f_in != f_out) close(f_in);
414
415         io_start_buffering(f_out);
416
417         io_set_error_fd(error_pipe[0]);
418
419         generate_files(f_out,flist,local_name,recv_pipe[0]);
420
421         read_int(recv_pipe[0]);
422         close(recv_pipe[0]);
423         if (remote_version >= 24) {
424                 /* send a final goodbye message */
425                 write_int(f_out, -1);
426         }
427         io_flush();
428
429         kill(pid, SIGUSR2);
430         wait_process(pid, &status);
431         return status;
432 }
433
434
435 static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
436 {
437         int status;
438         struct file_list *flist;
439         char *local_name=NULL;
440         char *dir = NULL;
441         extern int delete_mode;
442         extern int delete_excluded;
443         extern int am_daemon;
444         extern int module_id;
445         extern int am_sender;
446         extern int read_batch;
447         extern struct file_list *batch_flist;
448
449         if (verbose > 2)
450                 rprintf(FINFO,"server_recv(%d) starting pid=%d\n",argc,(int)getpid());
451
452         if (am_daemon && lp_read_only(module_id) && !am_sender) {
453                 rprintf(FERROR,"ERROR: module is read only\n");
454                 exit_cleanup(RERR_SYNTAX);
455                 return;
456         }
457
458         
459         if (argc > 0) {
460                 dir = argv[0];
461                 argc--;
462                 argv++;
463                 if (!am_daemon && !push_dir(dir, 0)) {
464                         rprintf(FERROR,"push_dir %s : %s (4)\n",
465                                 dir,strerror(errno));
466                         exit_cleanup(RERR_FILESELECT);
467                 }    
468         }
469
470         if (delete_mode && !delete_excluded)
471                 recv_exclude_list(f_in);
472
473         if (read_batch)
474             flist = batch_flist;
475         else
476             flist = recv_file_list(f_in);
477         if (!flist) {
478                 rprintf(FERROR,"server_recv: recv_file_list error\n");
479                 exit_cleanup(RERR_FILESELECT);
480         }
481         
482         if (argc > 0) {    
483                 if (strcmp(dir,".")) {
484                         argv[0] += strlen(dir);
485                         if (argv[0][0] == '/') argv[0]++;
486                 }
487                 local_name = get_local_name(flist,argv[0]);
488         }
489
490         status = do_recv(f_in,f_out,flist,local_name);
491         exit_cleanup(status);
492 }
493
494
495 int child_main(int argc, char *argv[])
496 {
497         start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
498         return 0;
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 read_batch;
671         int rc;
672
673         /* Don't clobber argv[] so that ps(1) can still show the right
674            command line. */
675         if ((rc = copy_argv (argv)))
676                 return rc;
677
678         if (strncasecmp(URL_PREFIX, argv[0], strlen(URL_PREFIX)) == 0) {
679                 char *host, *path;
680
681                 host = argv[0] + strlen(URL_PREFIX);
682                 p = strchr(host,'/');
683                 if (p) {
684                         *p = 0;
685                         path = p+1;
686                 } else {
687                         path="";
688                 }
689                 p = strchr(host,':');
690                 if (p) {
691                         rsync_port = atoi(p+1);
692                         *p = 0;
693                 }
694                 return start_socket_client(host, path, argc-1, argv+1);
695         }
696
697         if (!read_batch) {
698             p = find_colon(argv[0]);
699
700         if (p) {
701                 if (p[1] == ':') { /* double colon */
702                         *p = 0;
703                         return start_socket_client(argv[0], p+2, argc-1, argv+1);
704                 }
705
706                 if (argc < 1) {
707                         usage(FERROR);
708                         exit_cleanup(RERR_SYNTAX);
709                 }
710
711                 am_sender = 0;
712                 *p = 0;
713                 shell_machine = argv[0];
714                 shell_path = p+1;
715                 argc--;
716                 argv++;
717         } else {
718                 am_sender = 1;
719
720                 p = find_colon(argv[argc-1]);
721                 if (!p) {
722                         local_server = 1;
723                 } else if (p[1] == ':') {
724                         *p = 0;
725                         return start_socket_client(argv[argc-1], p+2, argc-1, argv);
726                 }
727
728                 if (argc < 2) {
729                         usage(FERROR);
730                         exit_cleanup(RERR_SYNTAX);
731                 }
732                 
733                 if (local_server) {
734                         shell_machine = NULL;
735                         shell_path = argv[argc-1];
736                 } else {
737                         *p = 0;
738                         shell_machine = argv[argc-1];
739                         shell_path = p+1;
740                 }
741                 argc--;
742         }
743         } else {
744             am_sender = 1;
745             local_server = 1;
746             shell_path = argv[argc-1];
747         }
748
749         if (shell_machine) {
750                 p = strchr(shell_machine,'@');
751                 if (p) {
752                         *p = 0;
753                         shell_user = shell_machine;
754                         shell_machine = p+1;
755                 }
756         }
757
758         if (verbose > 3) {
759                 rprintf(FINFO,"cmd=%s machine=%s user=%s path=%s\n",
760                         shell_cmd?shell_cmd:"",
761                         shell_machine?shell_machine:"",
762                         shell_user?shell_user:"",
763                         shell_path?shell_path:"");
764         }
765         
766         if (!am_sender && argc > 1) {
767                 usage(FERROR);
768                 exit_cleanup(RERR_SYNTAX);
769         }
770
771         if (argc == 0 && !am_sender) {
772                 extern int list_only;
773                 list_only = 1;
774         }
775         
776         pid = do_cmd(shell_cmd,shell_machine,shell_user,shell_path,&f_in,&f_out);
777         
778         ret = client_run(f_in, f_out, pid, argc, argv);
779
780         fflush(stdout);
781         fflush(stderr);
782
783         return ret;
784 }
785
786
787 static RETSIGTYPE sigusr1_handler(int UNUSED(val)) {
788         exit_cleanup(RERR_SIGNAL);
789 }
790
791 static RETSIGTYPE sigusr2_handler(int UNUSED(val)) {
792         extern int log_got_error;
793         if (log_got_error) _exit(RERR_PARTIAL);
794         _exit(0);
795 }
796
797 static RETSIGTYPE sigchld_handler(int UNUSED(val)) {
798 #ifdef WNOHANG
799         while (waitpid(-1, NULL, WNOHANG) > 0) ;
800 #endif
801 }
802
803
804 /**
805  * This routine catches signals and tries to send them to gdb.
806  *
807  * Because it's called from inside a signal handler it ought not to
808  * use too many library routines.
809  *
810  * @todo Perhaps use "screen -X" instead/as well, to help people
811  * debugging without easy access to X.  Perhaps use an environment
812  * variable, or just call a script?
813  *
814  * @todo The /proc/ magic probably only works on Linux (and
815  * Solaris?)  Can we be more portable?
816  **/
817 #ifdef MAINTAINER_MODE
818 const char *get_panic_action(void)
819 {
820         const char *cmd_fmt = getenv("RSYNC_PANIC_ACTION");
821
822         if (cmd_fmt)
823                 return cmd_fmt;
824         else
825                 return "xterm -display :0 -T Panic -n Panic "
826                         "-e gdb /proc/%d/exe %d";
827 }
828
829
830 /**
831  * Handle a fatal signal by launching a debugger, controlled by $RSYNC_PANIC_ACTION.
832  *
833  * This signal handler is only installed if we were configured with
834  * --enable-maintainer-mode.  Perhaps it should always be on and we
835  * should just look at the environment variable, but I'm a bit leery
836  * of a signal sending us into a busy loop.
837  **/
838 static RETSIGTYPE rsync_panic_handler(int UNUSED(whatsig))
839 {
840         char cmd_buf[300];
841         int ret;
842
843         sprintf(cmd_buf, get_panic_action(),
844                 getpid(), getpid());
845
846         /* Unless we failed to execute gdb, we allow the process to
847          * continue.  I'm not sure if that's right. */
848         ret = system(cmd_buf);
849         if (ret)
850                 _exit(ret);
851 }
852 #endif
853
854
855 int main(int argc,char *argv[])
856 {       
857         extern int am_root;
858         extern int orig_umask;
859         extern int dry_run;
860         extern int am_daemon;
861         extern int am_server;
862         int ret;
863         extern int write_batch;
864         int orig_argc;
865         char **orig_argv;
866
867         orig_argc = argc;
868         orig_argv = argv;
869
870         signal(SIGUSR1, sigusr1_handler);
871         signal(SIGUSR2, sigusr2_handler);
872         signal(SIGCHLD, sigchld_handler);
873 #ifdef MAINTAINER_MODE
874         signal(SIGSEGV, rsync_panic_handler);
875         signal(SIGFPE, rsync_panic_handler);
876         signal(SIGABRT, rsync_panic_handler);
877         signal(SIGBUS, rsync_panic_handler);
878 #endif /* def MAINTAINER_MODE */
879
880         starttime = time(NULL);
881         am_root = (getuid() == 0);
882
883         memset(&stats, 0, sizeof(stats));
884
885         if (argc < 2) {
886                 usage(FERROR);
887                 exit_cleanup(RERR_SYNTAX);
888         }
889
890         /* we set a 0 umask so that correct file permissions can be
891            carried across */
892         orig_umask = (int)umask(0);
893
894         if (!parse_arguments(&argc, (const char ***) &argv, 1)) {
895                 /* FIXME: We ought to call the same error-handling
896                  * code here, rather than relying on getopt. */
897                 option_error();
898                 exit_cleanup(RERR_SYNTAX);
899         }
900
901         signal(SIGINT,SIGNAL_CAST sig_int);
902         signal(SIGHUP,SIGNAL_CAST sig_int);
903         signal(SIGTERM,SIGNAL_CAST sig_int);
904
905         /* Ignore SIGPIPE; we consistently check error codes and will
906          * see the EPIPE. */
907         signal(SIGPIPE, SIG_IGN);
908
909         /* Initialize push_dir here because on some old systems getcwd
910            (implemented by forking "pwd" and reading its output) doesn't
911            work when there are other child processes.  Also, on all systems
912            that implement getcwd that way "pwd" can't be found after chroot. */
913         push_dir(NULL,0);
914
915         if (write_batch && !am_server) {
916             write_batch_argvs_file(orig_argc, orig_argv);
917         }
918
919         if (am_daemon) {
920                 return daemon_main();
921         }
922
923         if (argc < 1) {
924                 usage(FERROR);
925                 exit_cleanup(RERR_SYNTAX);
926         }
927
928         if (dry_run)
929                 verbose = MAX(verbose,1);
930
931 #ifndef SUPPORT_LINKS
932         if (!am_server && preserve_links) {
933                 rprintf(FERROR,"ERROR: symbolic links not supported\n");
934                 exit_cleanup(RERR_UNSUPPORTED);
935         }
936 #endif
937
938         if (am_server) {
939                 set_nonblocking(STDIN_FILENO);
940                 set_nonblocking(STDOUT_FILENO);
941                 start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
942         }
943
944         ret = start_client(argc, argv);
945         if (ret == -1) 
946                 exit_cleanup(RERR_STARTCLIENT);
947         else
948                 exit_cleanup(ret);
949
950         exit(ret);
951         /* NOTREACHED */
952 }