Fix copyright.
[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 void child_main(int argc, char *argv[])
496 {
497         start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
498 }
499
500
501 void start_server(int f_in, int f_out, int argc, char *argv[])
502 {
503         extern int cvs_exclude;
504         extern int am_sender;
505         extern int remote_version;
506         extern int read_batch;
507
508         setup_protocol(f_out, f_in);
509
510         set_nonblocking(f_in);
511         set_nonblocking(f_out);
512
513         if (remote_version >= 23)
514                 io_start_multiplex_out(f_out);
515
516         if (am_sender) {
517                 if (!read_batch) {
518                     recv_exclude_list(f_in);
519                     if (cvs_exclude)
520                         add_cvs_excludes();
521                 }
522                 do_server_sender(f_in, f_out, argc, argv);
523         } else {
524                 do_server_recv(f_in, f_out, argc, argv);
525         }
526         exit_cleanup(0);
527 }
528
529
530 /*
531  * This is called once the connection has been negotiated.  It is used
532  * for rsyncd, remote-shell, and local connections.
533  */
534 int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[])
535 {
536         struct file_list *flist = NULL;
537         int status = 0, status2 = 0;
538         char *local_name = NULL;
539         extern int am_sender;
540         extern int remote_version;
541         extern pid_t cleanup_child_pid;
542         extern int write_batch;
543         extern int read_batch;
544         extern struct file_list *batch_flist;
545
546         cleanup_child_pid = pid;
547         if (read_batch)
548             flist = batch_flist;
549
550         set_nonblocking(f_in);
551         set_nonblocking(f_out);
552
553         setup_protocol(f_out,f_in);
554
555         if (remote_version >= 23)
556                 io_start_multiplex_in(f_in);
557         
558         if (am_sender) {
559                 extern int cvs_exclude;
560                 extern int delete_mode;
561                 extern int delete_excluded;
562                 if (cvs_exclude)
563                         add_cvs_excludes();
564                 if (delete_mode && !delete_excluded) 
565                         send_exclude_list(f_out);
566                 if (!read_batch) /*  dw -- don't write to pipe */
567                     flist = send_file_list(f_out,argc,argv);
568                 if (verbose > 3) 
569                         rprintf(FINFO,"file list sent\n");
570
571                 send_files(flist,f_out,f_in);
572                 if (remote_version >= 24) {
573                         /* final goodbye message */             
574                         read_int(f_in);
575                 }
576                 if (pid != -1) {
577                         if (verbose > 3)
578                                 rprintf(FINFO,"client_run waiting on %d\n", (int) pid);
579                         io_flush();
580                         wait_process(pid, &status);
581                 }
582                 report(-1);
583                 exit_cleanup(status);
584         }
585
586         if (argc == 0) {
587                 extern int list_only;
588                 list_only = 1;
589         }
590         
591         if (!write_batch)
592             send_exclude_list(f_out);
593         
594         flist = recv_file_list(f_in);
595         if (!flist || flist->count == 0) {
596                 rprintf(FINFO, "client: nothing to do: "
597                         "perhaps you need to specify some filenames or "
598                         "the --recursive option?\n");
599                 exit_cleanup(0);
600         }
601         
602         local_name = get_local_name(flist,argv[0]);
603         
604         status2 = do_recv(f_in,f_out,flist,local_name);
605         
606         if (pid != -1) {
607                 if (verbose > 3)
608                         rprintf(FINFO,"client_run2 waiting on %d\n", (int) pid);
609                 io_flush();
610                 wait_process(pid, &status);
611         }
612         
613         return MAX(status, status2);
614 }
615
616 static char *find_colon(char *s)
617 {
618         char *p, *p2;
619
620         p = strchr(s,':');
621         if (!p) return NULL;
622         
623         /* now check to see if there is a / in the string before the : - if there is then
624            discard the colon on the assumption that the : is part of a filename */
625         p2 = strchr(s,'/');
626         if (p2 && p2 < p) return NULL;
627
628         return p;
629 }
630
631
632 static int copy_argv (char *argv[])
633 {
634         int i;
635
636         for (i = 0; argv[i]; i++) {
637                 if (!(argv[i] = strdup(argv[i]))) {
638                         rprintf (FERROR, "out of memory at %s(%d)\n",
639                                  __FILE__, __LINE__);
640                         return RERR_MALLOC;
641                 }
642         }
643
644         return 0;
645 }
646
647
648 /**
649  * Start a client for either type of remote connection.  Work out
650  * whether the arguments request a remote shell or rsyncd connection,
651  * and call the appropriate connection function, then run_client.
652  *
653  * Calls either start_socket_client (for sockets) or do_cmd and
654  * client_run (for ssh).
655  **/
656 static int start_client(int argc, char *argv[])
657 {
658         char *p;
659         char *shell_machine = NULL;
660         char *shell_path = NULL;
661         char *shell_user = NULL;
662         int ret;
663         pid_t pid;
664         int f_in,f_out;
665         extern int local_server;
666         extern int am_sender;
667         extern char *shell_cmd;
668         extern int rsync_port;
669         extern int whole_file;
670         extern int write_batch;
671         extern int read_batch;
672         int rc;
673
674         /* Don't clobber argv[] so that ps(1) can still show the right
675            command line. */
676         if ((rc = copy_argv (argv)))
677                 return rc;
678
679         if (strncasecmp(URL_PREFIX, argv[0], strlen(URL_PREFIX)) == 0) {
680                 char *host, *path;
681
682                 host = argv[0] + strlen(URL_PREFIX);
683                 p = strchr(host,'/');
684                 if (p) {
685                         *p = 0;
686                         path = p+1;
687                 } else {
688                         path="";
689                 }
690                 p = strchr(host,':');
691                 if (p) {
692                         rsync_port = atoi(p+1);
693                         *p = 0;
694                 }
695                 return start_socket_client(host, path, argc-1, argv+1);
696         }
697
698         if (!read_batch) {
699             p = find_colon(argv[0]);
700
701         if (p) {
702                 if (p[1] == ':') { /* double colon */
703                         *p = 0;
704                         return start_socket_client(argv[0], p+2, argc-1, argv+1);
705                 }
706
707                 if (argc < 1) {
708                         usage(FERROR);
709                         exit_cleanup(RERR_SYNTAX);
710                 }
711
712                 am_sender = 0;
713                 *p = 0;
714                 shell_machine = argv[0];
715                 shell_path = p+1;
716                 argc--;
717                 argv++;
718         } else {
719                 am_sender = 1;
720
721                 p = find_colon(argv[argc-1]);
722                 if (!p) {
723                         local_server = 1;
724                 } else if (p[1] == ':') {
725                         *p = 0;
726                         return start_socket_client(argv[argc-1], p+2, argc-1, argv);
727                 }
728
729                 if (argc < 2) {
730                         usage(FERROR);
731                         exit_cleanup(RERR_SYNTAX);
732                 }
733                 
734                 if (local_server) {
735                         shell_machine = NULL;
736                         shell_path = argv[argc-1];
737                 } else {
738                         *p = 0;
739                         shell_machine = argv[argc-1];
740                         shell_path = p+1;
741                 }
742                 argc--;
743         }
744         } else {
745             am_sender = 1;
746             local_server = 1;
747             shell_path = argv[argc-1];
748         }
749
750         if (shell_machine) {
751                 p = strchr(shell_machine,'@');
752                 if (p) {
753                         *p = 0;
754                         shell_user = shell_machine;
755                         shell_machine = p+1;
756                 }
757         }
758
759         if (verbose > 3) {
760                 rprintf(FINFO,"cmd=%s machine=%s user=%s path=%s\n",
761                         shell_cmd?shell_cmd:"",
762                         shell_machine?shell_machine:"",
763                         shell_user?shell_user:"",
764                         shell_path?shell_path:"");
765         }
766         
767         if (!am_sender && argc > 1) {
768                 usage(FERROR);
769                 exit_cleanup(RERR_SYNTAX);
770         }
771
772         if (argc == 0 && !am_sender) {
773                 extern int list_only;
774                 list_only = 1;
775         }
776         
777         pid = do_cmd(shell_cmd,shell_machine,shell_user,shell_path,&f_in,&f_out);
778         
779         ret = client_run(f_in, f_out, pid, argc, argv);
780
781         fflush(stdout);
782         fflush(stderr);
783
784         return ret;
785 }
786
787
788 static RETSIGTYPE sigusr1_handler(int UNUSED(val)) {
789         exit_cleanup(RERR_SIGNAL);
790 }
791
792 static RETSIGTYPE sigusr2_handler(int UNUSED(val)) {
793         extern int log_got_error;
794         if (log_got_error) _exit(RERR_PARTIAL);
795         _exit(0);
796 }
797
798 static RETSIGTYPE sigchld_handler(int UNUSED(val)) {
799 #ifdef WNOHANG
800         while (waitpid(-1, NULL, WNOHANG) > 0) ;
801 #endif
802 }
803
804
805 /**
806  * This routine catches signals and tries to send them to gdb.
807  *
808  * Because it's called from inside a signal handler it ought not to
809  * use too many library routines.
810  *
811  * @todo Perhaps use "screen -X" instead/as well, to help people
812  * debugging without easy access to X.  Perhaps use an environment
813  * variable, or just call a script?
814  *
815  * @todo The /proc/ magic probably only works on Linux (and
816  * Solaris?)  Can we be more portable?
817  **/
818 #ifdef MAINTAINER_MODE
819 static RETSIGTYPE rsync_panic_handler(int UNUSED(whatsig))
820 {
821         char cmd_buf[300];
822         int ret;
823         sprintf(cmd_buf, 
824                 "xterm -display :0 -T Panic -n Panic "
825                 "-e gdb /proc/%d/exe %d", 
826                 getpid(), getpid());
827
828         /* Unless we failed to execute gdb, we allow the process to
829          * continue.  I'm not sure if that's right. */
830         ret = system(cmd_buf);
831         if (ret)
832                 _exit(ret);
833 }
834 #endif
835
836
837 int main(int argc,char *argv[])
838 {       
839         extern int am_root;
840         extern int orig_umask;
841         extern int dry_run;
842         extern int am_daemon;
843         extern int am_server;
844         int ret;
845         extern int write_batch;
846         int orig_argc;
847         char **orig_argv;
848
849         orig_argc = argc;
850         orig_argv = argv;
851
852         signal(SIGUSR1, sigusr1_handler);
853         signal(SIGUSR2, sigusr2_handler);
854         signal(SIGCHLD, sigchld_handler);
855 #ifdef MAINTAINER_MODE
856         signal(SIGSEGV, rsync_panic_handler);
857         signal(SIGFPE, rsync_panic_handler);
858         signal(SIGABRT, rsync_panic_handler);
859         signal(SIGBUS, rsync_panic_handler);
860 #endif /* def MAINTAINER_MODE */
861
862         starttime = time(NULL);
863         am_root = (getuid() == 0);
864
865         memset(&stats, 0, sizeof(stats));
866
867         if (argc < 2) {
868                 usage(FERROR);
869                 exit_cleanup(RERR_SYNTAX);
870         }
871
872         /* we set a 0 umask so that correct file permissions can be
873            carried across */
874         orig_umask = (int)umask(0);
875
876         if (!parse_arguments(&argc, (const char ***) &argv, 1)) {
877                 /* FIXME: We ought to call the same error-handling
878                  * code here, rather than relying on getopt. */
879                 option_error();
880                 exit_cleanup(RERR_SYNTAX);
881         }
882
883         signal(SIGINT,SIGNAL_CAST sig_int);
884         signal(SIGHUP,SIGNAL_CAST sig_int);
885         signal(SIGTERM,SIGNAL_CAST sig_int);
886
887         /* Ignore SIGPIPE; we consistently check error codes and will
888          * see the EPIPE. */
889         signal(SIGPIPE, SIG_IGN);
890
891         /* Initialize push_dir here because on some old systems getcwd
892            (implemented by forking "pwd" and reading its output) doesn't
893            work when there are other child processes.  Also, on all systems
894            that implement getcwd that way "pwd" can't be found after chroot. */
895         push_dir(NULL,0);
896
897         if (write_batch && !am_server) {
898             write_batch_argvs_file(orig_argc, orig_argv);
899         }
900
901         if (am_daemon) {
902                 return daemon_main();
903         }
904
905         if (argc < 1) {
906                 usage(FERROR);
907                 exit_cleanup(RERR_SYNTAX);
908         }
909
910         if (dry_run)
911                 verbose = MAX(verbose,1);
912
913 #ifndef SUPPORT_LINKS
914         if (!am_server && preserve_links) {
915                 rprintf(FERROR,"ERROR: symbolic links not supported\n");
916                 exit_cleanup(RERR_UNSUPPORTED);
917         }
918 #endif
919
920         if (am_server) {
921                 set_nonblocking(STDIN_FILENO);
922                 set_nonblocking(STDOUT_FILENO);
923                 start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
924         }
925
926         ret = start_client(argc, argv);
927         if (ret == -1) 
928                 exit_cleanup(RERR_STARTCLIENT);
929         else
930                 exit_cleanup(ret);
931
932         exit(ret);
933         /* NOTREACHED */
934 }