Merge across rsync+ patch; add a little documentation to the manpage. More documenta...
[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    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "rsync.h"
22
23 time_t starttime = 0;
24
25 struct stats stats;
26
27 extern int verbose;
28
29
30 /****************************************************************************
31 wait for a process to exit, calling io_flush while waiting
32 ****************************************************************************/
33 void wait_process(pid_t pid, int *status)
34 {
35         while (waitpid(pid, status, WNOHANG) == 0) {
36                 msleep(20);
37                 io_flush();
38         }
39         
40         /* TODO: If the child exited on a signal, then log an
41          * appropriate error message.  Perhaps we should also accept a
42          * message describing the purpose of the child.  Also indicate
43          * this to the caller so that thhey know something went
44          * wrong.  */
45         *status = WEXITSTATUS(*status);
46 }
47
48 static void report(int f)
49 {
50         time_t t = time(NULL);
51         extern int am_server;
52         extern int am_sender;
53         extern int am_daemon;
54         extern int do_stats;
55         extern int remote_version;
56         int send_stats;
57
58         if (am_daemon) {
59                 log_exit(0, __FILE__, __LINE__);
60                 if (f == -1 || !am_sender) return;
61         }
62
63         send_stats = verbose || (remote_version >= 20);
64         if (am_server) {
65                 if (am_sender && send_stats) {
66                         int64 w;
67                         /* store total_written in a temporary
68                             because write_longint changes it */
69                         w = stats.total_written;
70                         write_longint(f,stats.total_read);
71                         write_longint(f,w);
72                         write_longint(f,stats.total_size);
73                 }
74                 return;
75         }
76
77         /* this is the client */
78             
79         if (!am_sender && send_stats) {
80                 int64 r;
81                 stats.total_written = read_longint(f);
82                 /* store total_read in a temporary, read_longint changes it */
83                 r = read_longint(f);
84                 stats.total_size = read_longint(f);
85                 stats.total_read = r;
86         }
87
88         if (do_stats) {
89                 if (!am_sender && !send_stats) {
90                     /* missing the bytes written by the generator */
91                     rprintf(FINFO, "\nCannot show stats as receiver because remote protocol version is less than 20\n");
92                     rprintf(FINFO, "Use --stats -v to show stats\n");
93                     return;
94                 }
95                 rprintf(FINFO,"\nNumber of files: %d\n", stats.num_files);
96                 rprintf(FINFO,"Number of files transferred: %d\n", 
97                        stats.num_transferred_files);
98                 rprintf(FINFO,"Total file size: %.0f bytes\n", 
99                        (double)stats.total_size);
100                 rprintf(FINFO,"Total transferred file size: %.0f bytes\n", 
101                        (double)stats.total_transferred_size);
102                 rprintf(FINFO,"Literal data: %.0f bytes\n", 
103                        (double)stats.literal_data);
104                 rprintf(FINFO,"Matched data: %.0f bytes\n", 
105                        (double)stats.matched_data);
106                 rprintf(FINFO,"File list size: %d\n", stats.flist_size);
107                 rprintf(FINFO,"Total bytes written: %.0f\n", 
108                        (double)stats.total_written);
109                 rprintf(FINFO,"Total bytes read: %.0f\n\n", 
110                        (double)stats.total_read);
111         }
112         
113         if (verbose || do_stats) {
114                 rprintf(FINFO,"wrote %.0f bytes  read %.0f bytes  %.2f bytes/sec\n",
115                        (double)stats.total_written,
116                        (double)stats.total_read,
117                        (stats.total_written+stats.total_read)/(0.5 + (t-starttime)));
118                 rprintf(FINFO,"total size is %.0f  speedup is %.2f\n",
119                        (double)stats.total_size,
120                        (1.0*stats.total_size)/(stats.total_written+stats.total_read));
121         }
122
123         fflush(stdout);
124         fflush(stderr);
125 }
126
127
128 /* Start the remote shell.   cmd may be NULL to use the default. */
129 static pid_t do_cmd(char *cmd,char *machine,char *user,char *path,int *f_in,int *f_out)
130 {
131         char *args[100];
132         int i,argc=0;
133         pid_t ret;
134         char *tok,*dir=NULL;
135         extern int local_server;
136         extern char *rsync_path;
137         extern int blocking_io;
138         extern int read_batch;
139
140         if (!read_batch && !local_server) { /* dw -- added read_batch */
141                 if (!cmd)
142                         cmd = getenv(RSYNC_RSH_ENV);
143                 if (!cmd)
144                         cmd = RSYNC_RSH;
145                 cmd = strdup(cmd);
146                 if (!cmd) 
147                         goto oom;
148
149                 for (tok=strtok(cmd," ");tok;tok=strtok(NULL," ")) {
150                         args[argc++] = tok;
151                 }
152
153 #if HAVE_REMSH
154                 /* remsh (on HPUX) takes the arguments the other way around */
155                 args[argc++] = machine;
156                 if (user) {
157                         args[argc++] = "-l";
158                         args[argc++] = user;
159                 }
160 #else
161                 if (user) {
162                         args[argc++] = "-l";
163                         args[argc++] = user;
164                 }
165                 args[argc++] = machine;
166 #endif
167
168                 args[argc++] = rsync_path;
169
170                 server_options(args,&argc);
171
172
173                 if (strcmp(cmd, RSYNC_RSH) == 0) blocking_io = 1;
174         }
175
176         args[argc++] = ".";
177
178         if (path && *path) 
179                 args[argc++] = path;
180
181         args[argc] = NULL;
182
183         if (verbose > 3) {
184                 rprintf(FINFO,"cmd=");
185                 for (i=0;i<argc;i++)
186                         rprintf(FINFO,"%s ",args[i]);
187                 rprintf(FINFO,"\n");
188         }
189
190         if (local_server) {
191                 if (read_batch)
192                     create_flist_from_batch();
193                 ret = local_child(argc, args, f_in, f_out);
194         } else {
195                 ret = piped_child(args,f_in,f_out);
196         }
197
198         if (dir) free(dir);
199
200         return ret;
201
202 oom:
203         out_of_memory("do_cmd");
204         return 0; /* not reached */
205 }
206
207
208
209
210 static char *get_local_name(struct file_list *flist,char *name)
211 {
212         STRUCT_STAT st;
213         extern int orig_umask;
214
215         if (verbose > 2)
216                 rprintf(FINFO,"get_local_name count=%d %s\n", 
217                         flist->count, NS(name));
218
219         if (!name) 
220                 return NULL;
221
222         if (do_stat(name,&st) == 0) {
223                 if (S_ISDIR(st.st_mode)) {
224                         if (!push_dir(name, 0)) {
225                                 rprintf(FERROR,"push_dir %s : %s (1)\n",
226                                         name,strerror(errno));
227                                 exit_cleanup(RERR_FILESELECT);
228                         }
229                         return NULL;
230                 }
231                 if (flist->count > 1) {
232                         rprintf(FERROR,"ERROR: destination must be a directory when copying more than 1 file\n");
233                         exit_cleanup(RERR_FILESELECT);
234                 }
235                 return name;
236         }
237
238         if (flist->count <= 1)
239                 return name;
240
241         if (do_mkdir(name,0777 & ~orig_umask) != 0) {
242                 rprintf(FERROR,"mkdir %s : %s (1)\n",name,strerror(errno));
243                 exit_cleanup(RERR_FILEIO);
244         } else {
245                 if (verbose > 0)
246                         rprintf(FINFO,"created directory %s\n",name);
247         }
248
249         if (!push_dir(name, 0)) {
250                 rprintf(FERROR,"push_dir %s : %s (2)\n",
251                         name,strerror(errno));
252                 exit_cleanup(RERR_FILESELECT);
253         }
254
255         return NULL;
256 }
257
258
259
260
261 static void do_server_sender(int f_in, int f_out, int argc,char *argv[])
262 {
263         int i;
264         struct file_list *flist;
265         char *dir = argv[0];
266         extern int relative_paths;
267         extern int recurse;
268         extern int remote_version;
269
270         if (verbose > 2)
271                 rprintf(FINFO,"server_sender starting pid=%d\n",(int)getpid());
272   
273         if (!relative_paths && !push_dir(dir, 0)) {
274                 rprintf(FERROR,"push_dir %s: %s (3)\n",dir,strerror(errno));
275                 exit_cleanup(RERR_FILESELECT);
276         }
277         argc--;
278         argv++;
279   
280         if (strcmp(dir,".")) {
281                 int l = strlen(dir);
282                 if (strcmp(dir,"/") == 0) 
283                         l = 0;
284                 for (i=0;i<argc;i++)
285                         argv[i] += l+1;
286         }
287
288         if (argc == 0 && recurse) {
289                 argc=1;
290                 argv--;
291                 argv[0] = ".";
292         }
293         
294         flist = send_file_list(f_out,argc,argv);
295         if (!flist || flist->count == 0) {
296                 exit_cleanup(0);
297         }
298
299         send_files(flist,f_out,f_in);
300         io_flush();
301         report(f_out);
302         if (remote_version >= 24) {
303                 /* final goodbye message */             
304                 read_int(f_in);
305         }
306         io_flush();
307         exit_cleanup(0);
308 }
309
310
311 static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
312 {
313         int pid;
314         int status=0;
315         int recv_pipe[2];
316         int error_pipe[2];
317         extern int preserve_hard_links;
318         extern int delete_after;
319         extern int recurse;
320         extern int delete_mode;
321         extern int remote_version;
322
323         if (preserve_hard_links)
324                 init_hard_links(flist);
325
326         if (!delete_after) {
327                 /* I moved this here from recv_files() to prevent a race condition */
328                 if (recurse && delete_mode && !local_name && flist->count>0) {
329                         delete_files(flist);
330                 }
331         }
332
333         if (fd_pair(recv_pipe) < 0) {
334                 rprintf(FERROR,"pipe failed in do_recv\n");
335                 exit_cleanup(RERR_SOCKETIO);
336         }
337
338         if (fd_pair(error_pipe) < 0) {
339                 rprintf(FERROR,"error pipe failed in do_recv\n");
340                 exit_cleanup(RERR_SOCKETIO);
341         }
342   
343         io_flush();
344
345         if ((pid=do_fork()) == 0) {
346                 close(recv_pipe[0]);
347                 close(error_pipe[0]);
348                 if (f_in != f_out) close(f_out);
349
350                 /* we can't let two processes write to the socket at one time */
351                 io_multiplexing_close();
352
353                 /* set place to send errors */
354                 set_error_fd(error_pipe[1]);
355
356                 recv_files(f_in,flist,local_name,recv_pipe[1]);
357                 io_flush();
358                 report(f_in);
359
360                 write_int(recv_pipe[1],1);
361                 close(recv_pipe[1]);
362                 io_flush();
363                 /* finally we go to sleep until our parent kills us
364                    with a USR2 signal. We sleep for a short time as on
365                    some OSes a signal won't interrupt a sleep! */
366                 while (msleep(20))
367                         ;
368         }
369
370         close(recv_pipe[1]);
371         close(error_pipe[1]);
372         if (f_in != f_out) close(f_in);
373
374         io_start_buffering(f_out);
375
376         io_set_error_fd(error_pipe[0]);
377
378         generate_files(f_out,flist,local_name,recv_pipe[0]);
379
380         read_int(recv_pipe[0]);
381         close(recv_pipe[0]);
382         if (remote_version >= 24) {
383                 /* send a final goodbye message */
384                 write_int(f_out, -1);
385         }
386         io_flush();
387
388         kill(pid, SIGUSR2);
389         wait_process(pid, &status);
390         return status;
391 }
392
393
394 static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
395 {
396         int status;
397         struct file_list *flist;
398         char *local_name=NULL;
399         char *dir = NULL;
400         extern int delete_mode;
401         extern int delete_excluded;
402         extern int am_daemon;
403         extern int module_id;
404         extern int am_sender;
405         extern int read_batch;   /* dw */
406         extern int write_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",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",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 /*
587  * Start a client for either type of remote connection.  Work out
588  * whether the arguments request a remote shell or rsyncd connection,
589  * and call the appropriate connection function, then run_client.
590  */
591 static int start_client(int argc, char *argv[])
592 {
593         char *p;
594         char *shell_machine = NULL;
595         char *shell_path = NULL;
596         char *shell_user = NULL;
597         int ret;
598         pid_t pid;
599         int f_in,f_out;
600         extern int local_server;
601         extern int am_sender;
602         extern char *shell_cmd;
603         extern int rsync_port;
604         extern int whole_file;
605         char *argv0 = strdup(argv[0]);
606         extern int read_batch;
607
608         if (strncasecmp(URL_PREFIX, argv0, strlen(URL_PREFIX)) == 0) {
609                 char *host, *path;
610
611                 host = argv0 + strlen(URL_PREFIX);
612                 p = strchr(host,'/');
613                 if (p) {
614                         *p = 0;
615                         path = p+1;
616                 } else {
617                         path="";
618                 }
619                 p = strchr(host,':');
620                 if (p) {
621                         rsync_port = atoi(p+1);
622                         *p = 0;
623                 }
624                 return start_socket_client(host, path, argc-1, argv+1);
625         }
626
627         if (!read_batch) { /* dw */
628             p = find_colon(argv[0]);
629
630         if (p) {
631                 if (p[1] == ':') {
632                         *p = 0;
633                         return start_socket_client(argv0, p+2, argc-1, argv+1);
634                 }
635
636                 if (argc < 1) {
637                         usage(FERROR);
638                         exit_cleanup(RERR_SYNTAX);
639                 }
640
641                 am_sender = 0;
642                 *p = 0;
643                 shell_machine = argv0;
644                 shell_path = p+1;
645                 argc--;
646                 argv++;
647         } else {
648                 am_sender = 1;
649
650                 p = find_colon(argv[argc-1]);
651                 if (!p) {
652                         local_server = 1;
653                         /* disable "rsync algorithm" when both sides local */
654                         whole_file = 1;
655                 } else if (p[1] == ':') {
656                         *p = 0;
657                         return start_socket_client(argv[argc-1], p+2, argc-1, argv);
658                 }
659
660                 if (argc < 2) {
661                         usage(FERROR);
662                         exit_cleanup(RERR_SYNTAX);
663                 }
664                 
665                 if (local_server) {
666                         shell_machine = NULL;
667                         shell_path = argv[argc-1];
668                 } else {
669                         *p = 0;
670                         shell_machine = argv[argc-1];
671                         shell_path = p+1;
672                 }
673                 argc--;
674         }
675         } else {
676             am_sender = 1;  /*  dw */
677             local_server = 1;  /* dw */
678             shell_path = argv[argc-1];  /* dw */
679         }
680
681         if (shell_machine) {
682                 p = strchr(shell_machine,'@');
683                 if (p) {
684                         *p = 0;
685                         shell_user = shell_machine;
686                         shell_machine = p+1;
687                 }
688         }
689
690         if (verbose > 3) {
691                 rprintf(FINFO,"cmd=%s machine=%s user=%s path=%s\n",
692                         shell_cmd?shell_cmd:"",
693                         shell_machine?shell_machine:"",
694                         shell_user?shell_user:"",
695                         shell_path?shell_path:"");
696         }
697         
698         if (!am_sender && argc > 1) {
699                 usage(FERROR);
700                 exit_cleanup(RERR_SYNTAX);
701         }
702
703         if (argc == 0 && !am_sender) {
704                 extern int list_only;
705                 list_only = 1;
706         }
707         
708         pid = do_cmd(shell_cmd,shell_machine,shell_user,shell_path,&f_in,&f_out);
709         
710         ret = client_run(f_in, f_out, pid, argc, argv);
711
712         fflush(stdout);
713         fflush(stderr);
714
715         return ret;
716 }
717
718
719 static RETSIGTYPE sigusr1_handler(int val) {
720         exit_cleanup(RERR_SIGNAL);
721 }
722
723 static RETSIGTYPE sigusr2_handler(int val) {
724         extern int log_got_error;
725         if (log_got_error) _exit(RERR_PARTIAL);
726         _exit(0);
727 }
728
729 static RETSIGTYPE sigchld_handler(int val) {
730 #ifdef WNOHANG
731         while (waitpid(-1, NULL, WNOHANG) > 0) ;
732 #endif
733 }
734
735 int main(int argc,char *argv[])
736 {       
737         extern int am_root;
738         extern int orig_umask;
739         extern int dry_run;
740         extern int am_daemon;
741         extern int am_server;
742         int ret;
743         extern int read_batch;   /*  dw */
744         extern int write_batch;  /*  dw */
745         extern char *batch_ext;   /*  dw */
746         int i;          /*   dw */
747         int orig_argc;  /* dw */
748
749         orig_argc = argc;   /* dw */
750
751         signal(SIGUSR1, sigusr1_handler);
752         signal(SIGUSR2, sigusr2_handler);
753         signal(SIGCHLD, sigchld_handler);
754
755         starttime = time(NULL);
756         am_root = (getuid() == 0);
757
758         memset(&stats, 0, sizeof(stats));
759
760         if (argc < 2) {
761                 usage(FERROR);
762                 exit_cleanup(RERR_SYNTAX);
763         }
764
765         /* we set a 0 umask so that correct file permissions can be
766            carried across */
767         orig_umask = (int)umask(0);
768
769         if (!parse_arguments(&argc, (const char ***) &argv, 1)) {
770                 /* FIXME: We ought to call the same error-handling
771                  * code here, rather than relying on getopt. */
772                 option_error();
773                 exit_cleanup(RERR_SYNTAX);
774         }
775
776         signal(SIGINT,SIGNAL_CAST sig_int);
777         signal(SIGPIPE,SIGNAL_CAST sig_int);
778         signal(SIGHUP,SIGNAL_CAST sig_int);
779         signal(SIGTERM,SIGNAL_CAST sig_int);
780
781         /* Initialize push_dir here because on some old systems getcwd
782            (implemented by forking "pwd" and reading its output) doesn't
783            work when there are other child processes.  Also, on all systems
784            that implement getcwd that way "pwd" can't be found after chroot. */
785         push_dir(NULL,0);
786
787         if (write_batch) { /* dw */
788             create_batch_file_ext();
789             write_batch_argvs_file(orig_argc, argc, argv);
790         }
791
792         if (read_batch) { /* dw */
793             set_batch_file_ext(batch_ext);
794         }
795
796         if (am_daemon) {
797                 return daemon_main();
798         }
799
800         if (argc < 1) {
801                 usage(FERROR);
802                 exit_cleanup(RERR_SYNTAX);
803         }
804
805         if (dry_run)
806                 verbose = MAX(verbose,1);
807
808 #ifndef SUPPORT_LINKS
809         if (!am_server && preserve_links) {
810                 rprintf(FERROR,"ERROR: symbolic links not supported\n");
811                 exit_cleanup(RERR_UNSUPPORTED);
812         }
813 #endif
814
815         if (am_server) {
816                 set_nonblocking(STDIN_FILENO);
817                 set_nonblocking(STDOUT_FILENO);
818                 start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
819         }
820
821         ret = start_client(argc, argv);
822         exit_cleanup(ret);
823         return ret;
824 }
825