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