Fix KAME patch to use proper autoconf AC_MSG macros rather than just echo/exit.
[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 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
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 (am_daemon) {
60                 log_exit(0, __FILE__, __LINE__);
61                 if (f == -1 || !am_sender) return;
62         }
63
64         send_stats = verbose || (remote_version >= 20);
65         if (am_server) {
66                 if (am_sender && send_stats) {
67                         int64 w;
68                         /* store total_written in a temporary
69                             because write_longint changes it */
70                         w = stats.total_written;
71                         write_longint(f,stats.total_read);
72                         write_longint(f,w);
73                         write_longint(f,stats.total_size);
74                 }
75                 return;
76         }
77
78         /* this is the client */
79             
80         if (!am_sender && send_stats) {
81                 int64 r;
82                 stats.total_written = read_longint(f);
83                 /* store total_read in a temporary, read_longint changes it */
84                 r = read_longint(f);
85                 stats.total_size = read_longint(f);
86                 stats.total_read = r;
87         }
88
89         if (do_stats) {
90                 if (!am_sender && !send_stats) {
91                     /* missing the bytes written by the generator */
92                     rprintf(FINFO, "\nCannot show stats as receiver because remote protocol version is less than 20\n");
93                     rprintf(FINFO, "Use --stats -v to show stats\n");
94                     return;
95                 }
96                 rprintf(FINFO,"\nNumber of files: %d\n", stats.num_files);
97                 rprintf(FINFO,"Number of files transferred: %d\n", 
98                        stats.num_transferred_files);
99                 rprintf(FINFO,"Total file size: %.0f bytes\n", 
100                        (double)stats.total_size);
101                 rprintf(FINFO,"Total transferred file size: %.0f bytes\n", 
102                        (double)stats.total_transferred_size);
103                 rprintf(FINFO,"Literal data: %.0f bytes\n", 
104                        (double)stats.literal_data);
105                 rprintf(FINFO,"Matched data: %.0f bytes\n", 
106                        (double)stats.matched_data);
107                 rprintf(FINFO,"File list size: %d\n", stats.flist_size);
108                 rprintf(FINFO,"Total bytes written: %.0f\n", 
109                        (double)stats.total_written);
110                 rprintf(FINFO,"Total bytes read: %.0f\n\n", 
111                        (double)stats.total_read);
112         }
113         
114         if (verbose || do_stats) {
115                 rprintf(FINFO,"wrote %.0f bytes  read %.0f bytes  %.2f bytes/sec\n",
116                        (double)stats.total_written,
117                        (double)stats.total_read,
118                        (stats.total_written+stats.total_read)/(0.5 + (t-starttime)));
119                 rprintf(FINFO,"total size is %.0f  speedup is %.2f\n",
120                        (double)stats.total_size,
121                        (1.0*stats.total_size)/(stats.total_written+stats.total_read));
122         }
123
124         fflush(stdout);
125         fflush(stderr);
126 }
127
128
129 /* Start the remote shell.   cmd may be NULL to use the default. */
130 static pid_t do_cmd(char *cmd,char *machine,char *user,char *path,int *f_in,int *f_out)
131 {
132         char *args[100];
133         int i,argc=0;
134         pid_t ret;
135         char *tok,*dir=NULL;
136         extern int local_server;
137         extern char *rsync_path;
138         extern int blocking_io;
139         extern int read_batch;
140
141         if (!read_batch && !local_server) { /* dw -- added read_batch */
142                 if (!cmd)
143                         cmd = getenv(RSYNC_RSH_ENV);
144                 if (!cmd)
145                         cmd = RSYNC_RSH;
146                 cmd = strdup(cmd);
147                 if (!cmd) 
148                         goto oom;
149
150                 for (tok=strtok(cmd," ");tok;tok=strtok(NULL," ")) {
151                         args[argc++] = tok;
152                 }
153
154 #if HAVE_REMSH
155                 /* remsh (on HPUX) takes the arguments the other way around */
156                 args[argc++] = machine;
157                 if (user) {
158                         args[argc++] = "-l";
159                         args[argc++] = user;
160                 }
161 #else
162                 if (user) {
163                         args[argc++] = "-l";
164                         args[argc++] = user;
165                 }
166                 args[argc++] = machine;
167 #endif
168
169                 args[argc++] = rsync_path;
170
171                 server_options(args,&argc);
172
173
174                 if (strcmp(cmd, RSYNC_RSH) == 0) blocking_io = 1;
175         }
176
177         args[argc++] = ".";
178
179         if (path && *path) 
180                 args[argc++] = path;
181
182         args[argc] = NULL;
183
184         if (verbose > 3) {
185                 rprintf(FINFO,"cmd=");
186                 for (i=0;i<argc;i++)
187                         rprintf(FINFO,"%s ",args[i]);
188                 rprintf(FINFO,"\n");
189         }
190
191         if (local_server) {
192                 if (read_batch)
193                     create_flist_from_batch();
194                 ret = local_child(argc, args, f_in, f_out);
195         } else {
196                 ret = piped_child(args,f_in,f_out);
197         }
198
199         if (dir) free(dir);
200
201         return ret;
202
203 oom:
204         out_of_memory("do_cmd");
205         return 0; /* not reached */
206 }
207
208
209
210
211 static char *get_local_name(struct file_list *flist,char *name)
212 {
213         STRUCT_STAT st;
214         extern int orig_umask;
215
216         if (verbose > 2)
217                 rprintf(FINFO,"get_local_name count=%d %s\n", 
218                         flist->count, NS(name));
219
220         if (!name) 
221                 return NULL;
222
223         if (do_stat(name,&st) == 0) {
224                 if (S_ISDIR(st.st_mode)) {
225                         if (!push_dir(name, 0)) {
226                                 rprintf(FERROR,"push_dir %s : %s (1)\n",
227                                         name,strerror(errno));
228                                 exit_cleanup(RERR_FILESELECT);
229                         }
230                         return NULL;
231                 }
232                 if (flist->count > 1) {
233                         rprintf(FERROR,"ERROR: destination must be a directory when copying more than 1 file\n");
234                         exit_cleanup(RERR_FILESELECT);
235                 }
236                 return name;
237         }
238
239         if (flist->count <= 1)
240                 return name;
241
242         if (do_mkdir(name,0777 & ~orig_umask) != 0) {
243                 rprintf(FERROR,"mkdir %s : %s (1)\n",name,strerror(errno));
244                 exit_cleanup(RERR_FILEIO);
245         } else {
246                 if (verbose > 0)
247                         rprintf(FINFO,"created directory %s\n",name);
248         }
249
250         if (!push_dir(name, 0)) {
251                 rprintf(FERROR,"push_dir %s : %s (2)\n",
252                         name,strerror(errno));
253                 exit_cleanup(RERR_FILESELECT);
254         }
255
256         return NULL;
257 }
258
259
260
261
262 static void do_server_sender(int f_in, int f_out, int argc,char *argv[])
263 {
264         int i;
265         struct file_list *flist;
266         char *dir = argv[0];
267         extern int relative_paths;
268         extern int recurse;
269         extern int remote_version;
270
271         if (verbose > 2)
272                 rprintf(FINFO,"server_sender starting pid=%d\n",(int)getpid());
273   
274         if (!relative_paths && !push_dir(dir, 0)) {
275                 rprintf(FERROR,"push_dir %s: %s (3)\n",dir,strerror(errno));
276                 exit_cleanup(RERR_FILESELECT);
277         }
278         argc--;
279         argv++;
280   
281         if (strcmp(dir,".")) {
282                 int l = strlen(dir);
283                 if (strcmp(dir,"/") == 0) 
284                         l = 0;
285                 for (i=0;i<argc;i++)
286                         argv[i] += l+1;
287         }
288
289         if (argc == 0 && recurse) {
290                 argc=1;
291                 argv--;
292                 argv[0] = ".";
293         }
294         
295         flist = send_file_list(f_out,argc,argv);
296         if (!flist || flist->count == 0) {
297                 exit_cleanup(0);
298         }
299
300         send_files(flist,f_out,f_in);
301         io_flush();
302         report(f_out);
303         if (remote_version >= 24) {
304                 /* final goodbye message */             
305                 read_int(f_in);
306         }
307         io_flush();
308         exit_cleanup(0);
309 }
310
311
312 static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
313 {
314         int pid;
315         int status=0;
316         int recv_pipe[2];
317         int error_pipe[2];
318         extern int preserve_hard_links;
319         extern int delete_after;
320         extern int recurse;
321         extern int delete_mode;
322         extern int remote_version;
323
324         if (preserve_hard_links)
325                 init_hard_links(flist);
326
327         if (!delete_after) {
328                 /* I moved this here from recv_files() to prevent a race condition */
329                 if (recurse && delete_mode && !local_name && flist->count>0) {
330                         delete_files(flist);
331                 }
332         }
333
334         if (fd_pair(recv_pipe) < 0) {
335                 rprintf(FERROR,"pipe failed in do_recv\n");
336                 exit_cleanup(RERR_SOCKETIO);
337         }
338
339         if (fd_pair(error_pipe) < 0) {
340                 rprintf(FERROR,"error pipe failed in do_recv\n");
341                 exit_cleanup(RERR_SOCKETIO);
342         }
343   
344         io_flush();
345
346         if ((pid=do_fork()) == 0) {
347                 close(recv_pipe[0]);
348                 close(error_pipe[0]);
349                 if (f_in != f_out) close(f_out);
350
351                 /* we can't let two processes write to the socket at one time */
352                 io_multiplexing_close();
353
354                 /* set place to send errors */
355                 set_error_fd(error_pipe[1]);
356
357                 recv_files(f_in,flist,local_name,recv_pipe[1]);
358                 io_flush();
359                 report(f_in);
360
361                 write_int(recv_pipe[1],1);
362                 close(recv_pipe[1]);
363                 io_flush();
364                 /* finally we go to sleep until our parent kills us
365                    with a USR2 signal. We sleep for a short time as on
366                    some OSes a signal won't interrupt a sleep! */
367                 while (msleep(20))
368                         ;
369         }
370
371         close(recv_pipe[1]);
372         close(error_pipe[1]);
373         if (f_in != f_out) close(f_in);
374
375         io_start_buffering(f_out);
376
377         io_set_error_fd(error_pipe[0]);
378
379         generate_files(f_out,flist,local_name,recv_pipe[0]);
380
381         read_int(recv_pipe[0]);
382         close(recv_pipe[0]);
383         if (remote_version >= 24) {
384                 /* send a final goodbye message */
385                 write_int(f_out, -1);
386         }
387         io_flush();
388
389         kill(pid, SIGUSR2);
390         wait_process(pid, &status);
391         return status;
392 }
393
394
395 static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
396 {
397         int status;
398         struct file_list *flist;
399         char *local_name=NULL;
400         char *dir = NULL;
401         extern int delete_mode;
402         extern int delete_excluded;
403         extern int am_daemon;
404         extern int module_id;
405         extern int am_sender;
406         extern int read_batch;   /* dw */
407         extern struct file_list *batch_flist;  /* dw */
408
409         if (verbose > 2)
410                 rprintf(FINFO,"server_recv(%d) starting pid=%d\n",argc,(int)getpid());
411
412         if (am_daemon && lp_read_only(module_id) && !am_sender) {
413                 rprintf(FERROR,"ERROR: module is read only\n");
414                 exit_cleanup(RERR_SYNTAX);
415                 return;
416         }
417
418         
419         if (argc > 0) {
420                 dir = argv[0];
421                 argc--;
422                 argv++;
423                 if (!am_daemon && !push_dir(dir, 0)) {
424                         rprintf(FERROR,"push_dir %s : %s (4)\n",
425                                 dir,strerror(errno));
426                         exit_cleanup(RERR_FILESELECT);
427                 }    
428         }
429
430         if (delete_mode && !delete_excluded)
431                 recv_exclude_list(f_in);
432
433         if (read_batch) /*  dw  */
434             flist = batch_flist;
435         else
436             flist = recv_file_list(f_in);
437         if (!flist) {
438                 rprintf(FERROR,"server_recv: recv_file_list error\n");
439                 exit_cleanup(RERR_FILESELECT);
440         }
441         
442         if (argc > 0) {    
443                 if (strcmp(dir,".")) {
444                         argv[0] += strlen(dir);
445                         if (argv[0][0] == '/') argv[0]++;
446                 }
447                 local_name = get_local_name(flist,argv[0]);
448         }
449
450         status = do_recv(f_in,f_out,flist,local_name);
451         exit_cleanup(status);
452 }
453
454
455 void start_server(int f_in, int f_out, int argc, char *argv[])
456 {
457         extern int cvs_exclude;
458         extern int am_sender;
459         extern int remote_version;
460         extern int read_batch; /* dw */
461
462         setup_protocol(f_out, f_in);
463
464         set_nonblocking(f_in);
465         set_nonblocking(f_out);
466
467         if (remote_version >= 23)
468                 io_start_multiplex_out(f_out);
469
470         if (am_sender) {
471                 if (!read_batch) { /* dw */
472                     recv_exclude_list(f_in);
473                     if (cvs_exclude)
474                         add_cvs_excludes();
475                 }
476                 do_server_sender(f_in, f_out, argc, argv);
477         } else {
478                 do_server_recv(f_in, f_out, argc, argv);
479         }
480         exit_cleanup(0);
481 }
482
483
484 /*
485  * This is called once the connection has been negotiated.  It is used
486  * for rsyncd, remote-shell, and local connections.
487  */
488 int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[])
489 {
490         struct file_list *flist;
491         int status = 0, status2 = 0;
492         char *local_name = NULL;
493         extern int am_sender;
494         extern int remote_version;
495         extern pid_t cleanup_child_pid;
496         extern int write_batch; /* dw */
497         extern int read_batch; /* dw */
498         extern struct file_list *batch_flist; /*  dw */
499
500         cleanup_child_pid = pid;
501         if (read_batch)
502             flist = batch_flist;  /* dw */
503
504         set_nonblocking(f_in);
505         set_nonblocking(f_out);
506
507         setup_protocol(f_out,f_in);
508
509         if (remote_version >= 23)
510                 io_start_multiplex_in(f_in);
511         
512         if (am_sender) {
513                 extern int cvs_exclude;
514                 extern int delete_mode;
515                 extern int delete_excluded;
516                 if (cvs_exclude)
517                         add_cvs_excludes();
518                 if (delete_mode && !delete_excluded) 
519                         send_exclude_list(f_out);
520                 if (!read_batch) /*  dw -- don't write to pipe */
521                     flist = send_file_list(f_out,argc,argv);
522                 if (verbose > 3) 
523                         rprintf(FINFO,"file list sent\n");
524
525                 send_files(flist,f_out,f_in);
526                 if (remote_version >= 24) {
527                         /* final goodbye message */             
528                         read_int(f_in);
529                 }
530                 if (pid != -1) {
531                         if (verbose > 3)
532                                 rprintf(FINFO,"client_run waiting on %d\n", (int) pid);
533                         io_flush();
534                         wait_process(pid, &status);
535                 }
536                 report(-1);
537                 exit_cleanup(status);
538         }
539
540         if (argc == 0) {
541                 extern int list_only;
542                 list_only = 1;
543         }
544         
545         if (!write_batch) /* dw */
546             send_exclude_list(f_out);
547         
548         flist = recv_file_list(f_in);
549         if (!flist || flist->count == 0) {
550                 rprintf(FINFO, "client: nothing to do: "
551                         "perhaps you need to specify some filenames or "
552                         "the --recursive option?\n");
553                 exit_cleanup(0);
554         }
555         
556         local_name = get_local_name(flist,argv[0]);
557         
558         status2 = do_recv(f_in,f_out,flist,local_name);
559         
560         if (pid != -1) {
561                 if (verbose > 3)
562                         rprintf(FINFO,"client_run2 waiting on %d\n", (int) pid);
563                 io_flush();
564                 wait_process(pid, &status);
565         }
566         
567         return MAX(status, status2);
568 }
569
570 static char *find_colon(char *s)
571 {
572         char *p, *p2;
573
574         p = strchr(s,':');
575         if (!p) return NULL;
576         
577         /* now check to see if there is a / in the string before the : - if there is then
578            discard the colon on the assumption that the : is part of a filename */
579         p2 = strchr(s,'/');
580         if (p2 && p2 < p) return NULL;
581
582         return p;
583 }
584
585
586 static int copy_argv (char *argv[])
587 {
588         int i;
589
590         for (i = 0; argv[i]; i++) {
591                 if (!(argv[i] = strdup(argv[i]))) {
592                         rprintf (FERROR, "out of memory at %s(%d)\n",
593                                  __FILE__, __LINE__);
594                         return RERR_MALLOC;
595                 }
596         }
597
598         return 0;
599 }
600
601
602 /*
603  * Start a client for either type of remote connection.  Work out
604  * whether the arguments request a remote shell or rsyncd connection,
605  * and call the appropriate connection function, then run_client.
606  */
607 static int start_client(int argc, char *argv[])
608 {
609         char *p;
610         char *shell_machine = NULL;
611         char *shell_path = NULL;
612         char *shell_user = NULL;
613         int ret;
614         pid_t pid;
615         int f_in,f_out;
616         extern int local_server;
617         extern int am_sender;
618         extern char *shell_cmd;
619         extern int rsync_port;
620         extern int whole_file;
621         extern int read_batch;
622         int rc;
623
624         /* Don't clobber argv[] so that ps(1) can still show the right
625            command line. */
626         if ((rc = copy_argv (argv)))
627                 return rc;
628
629         if (strncasecmp(URL_PREFIX, argv[0], strlen(URL_PREFIX)) == 0) {
630                 char *host, *path;
631
632                 host = argv[0] + strlen(URL_PREFIX);
633                 p = strchr(host,'/');
634                 if (p) {
635                         *p = 0;
636                         path = p+1;
637                 } else {
638                         path="";
639                 }
640                 p = strchr(host,':');
641                 if (p) {
642                         rsync_port = atoi(p+1);
643                         *p = 0;
644                 }
645                 return start_socket_client(host, path, argc-1, argv+1);
646         }
647
648         if (!read_batch) { /* dw */
649             p = find_colon(argv[0]);
650
651         if (p) {
652                 if (p[1] == ':') {
653                         *p = 0;
654                         return start_socket_client(argv[0], p+2, argc-1, argv+1);
655                 }
656
657                 if (argc < 1) {
658                         usage(FERROR);
659                         exit_cleanup(RERR_SYNTAX);
660                 }
661
662                 am_sender = 0;
663                 *p = 0;
664                 shell_machine = argv[0];
665                 shell_path = p+1;
666                 argc--;
667                 argv++;
668         } else {
669                 am_sender = 1;
670
671                 p = find_colon(argv[argc-1]);
672                 if (!p) {
673                         local_server = 1;
674                         /* disable "rsync algorithm" when both sides local */
675                         whole_file = 1;
676                 } else if (p[1] == ':') {
677                         *p = 0;
678                         return start_socket_client(argv[argc-1], p+2, argc-1, argv);
679                 }
680
681                 if (argc < 2) {
682                         usage(FERROR);
683                         exit_cleanup(RERR_SYNTAX);
684                 }
685                 
686                 if (local_server) {
687                         shell_machine = NULL;
688                         shell_path = argv[argc-1];
689                 } else {
690                         *p = 0;
691                         shell_machine = argv[argc-1];
692                         shell_path = p+1;
693                 }
694                 argc--;
695         }
696         } else {
697             am_sender = 1;  /*  dw */
698             local_server = 1;  /* dw */
699             shell_path = argv[argc-1];  /* dw */
700         }
701
702         if (shell_machine) {
703                 p = strchr(shell_machine,'@');
704                 if (p) {
705                         *p = 0;
706                         shell_user = shell_machine;
707                         shell_machine = p+1;
708                 }
709         }
710
711         if (verbose > 3) {
712                 rprintf(FINFO,"cmd=%s machine=%s user=%s path=%s\n",
713                         shell_cmd?shell_cmd:"",
714                         shell_machine?shell_machine:"",
715                         shell_user?shell_user:"",
716                         shell_path?shell_path:"");
717         }
718         
719         if (!am_sender && argc > 1) {
720                 usage(FERROR);
721                 exit_cleanup(RERR_SYNTAX);
722         }
723
724         if (argc == 0 && !am_sender) {
725                 extern int list_only;
726                 list_only = 1;
727         }
728         
729         pid = do_cmd(shell_cmd,shell_machine,shell_user,shell_path,&f_in,&f_out);
730         
731         ret = client_run(f_in, f_out, pid, argc, argv);
732
733         fflush(stdout);
734         fflush(stderr);
735
736         return ret;
737 }
738
739
740 static RETSIGTYPE sigusr1_handler(int val) {
741         exit_cleanup(RERR_SIGNAL);
742 }
743
744 static RETSIGTYPE sigusr2_handler(int val) {
745         extern int log_got_error;
746         if (log_got_error) _exit(RERR_PARTIAL);
747         _exit(0);
748 }
749
750 static RETSIGTYPE sigchld_handler(int val) {
751 #ifdef WNOHANG
752         while (waitpid(-1, NULL, WNOHANG) > 0) ;
753 #endif
754 }
755
756 int main(int argc,char *argv[])
757 {       
758         extern int am_root;
759         extern int orig_umask;
760         extern int dry_run;
761         extern int am_daemon;
762         extern int am_server;
763         int ret;
764         extern int read_batch;   /*  dw */
765         extern int write_batch;  /*  dw */
766         extern char *batch_ext;   /*  dw */
767         int orig_argc;  /* dw */
768
769         orig_argc = argc;   /* dw */
770
771         signal(SIGUSR1, sigusr1_handler);
772         signal(SIGUSR2, sigusr2_handler);
773         signal(SIGCHLD, sigchld_handler);
774
775         starttime = time(NULL);
776         am_root = (getuid() == 0);
777
778         memset(&stats, 0, sizeof(stats));
779
780         if (argc < 2) {
781                 usage(FERROR);
782                 exit_cleanup(RERR_SYNTAX);
783         }
784
785         /* we set a 0 umask so that correct file permissions can be
786            carried across */
787         orig_umask = (int)umask(0);
788
789         if (!parse_arguments(&argc, (const char ***) &argv, 1)) {
790                 /* FIXME: We ought to call the same error-handling
791                  * code here, rather than relying on getopt. */
792                 option_error();
793                 exit_cleanup(RERR_SYNTAX);
794         }
795
796         signal(SIGINT,SIGNAL_CAST sig_int);
797         signal(SIGPIPE,SIGNAL_CAST sig_int);
798         signal(SIGHUP,SIGNAL_CAST sig_int);
799         signal(SIGTERM,SIGNAL_CAST sig_int);
800
801         /* Initialize push_dir here because on some old systems getcwd
802            (implemented by forking "pwd" and reading its output) doesn't
803            work when there are other child processes.  Also, on all systems
804            that implement getcwd that way "pwd" can't be found after chroot. */
805         push_dir(NULL,0);
806
807         if (write_batch) { /* dw */
808             create_batch_file_ext();
809             write_batch_argvs_file(orig_argc, argc, argv);
810         }
811
812         if (read_batch) { /* dw */
813             set_batch_file_ext(batch_ext);
814         }
815
816         if (am_daemon) {
817                 return daemon_main();
818         }
819
820         if (argc < 1) {
821                 usage(FERROR);
822                 exit_cleanup(RERR_SYNTAX);
823         }
824
825         if (dry_run)
826                 verbose = MAX(verbose,1);
827
828 #ifndef SUPPORT_LINKS
829         if (!am_server && preserve_links) {
830                 rprintf(FERROR,"ERROR: symbolic links not supported\n");
831                 exit_cleanup(RERR_UNSUPPORTED);
832         }
833 #endif
834
835         if (am_server) {
836                 set_nonblocking(STDIN_FILENO);
837                 set_nonblocking(STDOUT_FILENO);
838                 start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
839         }
840
841         ret = start_client(argc, argv);
842         exit_cleanup(ret);
843         return ret;
844 }
845