Fix casts when some variables are printed out.
[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 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 /*
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 orig_argc;  /* dw */
747
748         orig_argc = argc;   /* dw */
749
750         signal(SIGUSR1, sigusr1_handler);
751         signal(SIGUSR2, sigusr2_handler);
752         signal(SIGCHLD, sigchld_handler);
753
754         starttime = time(NULL);
755         am_root = (getuid() == 0);
756
757         memset(&stats, 0, sizeof(stats));
758
759         if (argc < 2) {
760                 usage(FERROR);
761                 exit_cleanup(RERR_SYNTAX);
762         }
763
764         /* we set a 0 umask so that correct file permissions can be
765            carried across */
766         orig_umask = (int)umask(0);
767
768         if (!parse_arguments(&argc, (const char ***) &argv, 1)) {
769                 /* FIXME: We ought to call the same error-handling
770                  * code here, rather than relying on getopt. */
771                 option_error();
772                 exit_cleanup(RERR_SYNTAX);
773         }
774
775         signal(SIGINT,SIGNAL_CAST sig_int);
776         signal(SIGPIPE,SIGNAL_CAST sig_int);
777         signal(SIGHUP,SIGNAL_CAST sig_int);
778         signal(SIGTERM,SIGNAL_CAST sig_int);
779
780         /* Initialize push_dir here because on some old systems getcwd
781            (implemented by forking "pwd" and reading its output) doesn't
782            work when there are other child processes.  Also, on all systems
783            that implement getcwd that way "pwd" can't be found after chroot. */
784         push_dir(NULL,0);
785
786         if (write_batch) { /* dw */
787             create_batch_file_ext();
788             write_batch_argvs_file(orig_argc, argc, argv);
789         }
790
791         if (read_batch) { /* dw */
792             set_batch_file_ext(batch_ext);
793         }
794
795         if (am_daemon) {
796                 return daemon_main();
797         }
798
799         if (argc < 1) {
800                 usage(FERROR);
801                 exit_cleanup(RERR_SYNTAX);
802         }
803
804         if (dry_run)
805                 verbose = MAX(verbose,1);
806
807 #ifndef SUPPORT_LINKS
808         if (!am_server && preserve_links) {
809                 rprintf(FERROR,"ERROR: symbolic links not supported\n");
810                 exit_cleanup(RERR_UNSUPPORTED);
811         }
812 #endif
813
814         if (am_server) {
815                 set_nonblocking(STDIN_FILENO);
816                 set_nonblocking(STDOUT_FILENO);
817                 start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
818         }
819
820         ret = start_client(argc, argv);
821         exit_cleanup(ret);
822         return ret;
823 }
824