some large systematic changes to make socket conversion easier. The
[rsync/rsync.git] / main.c
1 /* 
2    Copyright (C) Andrew Tridgell 1996
3    Copyright (C) Paul Mackerras 1996
4    
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2 of the License, or
8    (at your option) any later version.
9    
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14    
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 #include "rsync.h"
21
22 int verbose = 0;
23 int always_checksum = 0;
24 time_t starttime;
25 int64 total_size = 0;
26 int block_size=BLOCK_SIZE;
27
28 char *backup_suffix = BACKUP_SUFFIX;
29 char *tmpdir = NULL;
30
31 static char *rsync_path = RSYNC_NAME;
32
33 int make_backups = 0;
34 int whole_file = 0;
35 int copy_links = 0;
36 int preserve_links = 0;
37 int preserve_hard_links = 0;
38 int preserve_perms = 0;
39 int preserve_devices = 0;
40 int preserve_uid = 0;
41 int preserve_gid = 0;
42 int preserve_times = 0;
43 int update_only = 0;
44 int cvs_exclude = 0;
45 int dry_run=0;
46 int local_server=0;
47 int ignore_times=0;
48 int delete_mode=0;
49 int one_file_system=0;
50 int remote_version=0;
51 int sparse_files=0;
52 int do_compression=0;
53 int am_root=0;
54 int orig_umask=0;
55 int relative_paths=0;
56 int numeric_ids = 0;
57 int force_delete = 0;
58 int io_timeout = 0;
59 int io_error = 0;
60 static int port = RSYNC_PORT;
61
62 static char *shell_cmd;
63
64 extern int csum_length;
65
66 int am_server = 0;
67 int am_sender;
68 int recurse = 0;
69 int am_daemon;
70
71 static void usage(int fd);
72
73 static void report(int f)
74 {
75   int64 in,out,tsize;
76   time_t t = time(NULL);
77   
78   if (!verbose) return;
79
80   if (am_server && am_sender) {
81     write_longint(f,read_total());
82     write_longint(f,write_total());
83     write_longint(f,total_size);
84     write_flush(f);
85     return;
86   }
87     
88   if (am_sender) {
89     in = read_total();
90     out = write_total();
91     tsize = total_size;
92   } else {
93     in = read_longint(f);
94     out = read_longint(f);
95     tsize = read_longint(f);
96   }
97
98   printf("wrote %.0f bytes  read %.0f bytes  %.2f bytes/sec\n",
99          (double)out,(double)in,(in+out)/(0.5 + (t-starttime)));
100   printf("total size is %.0f  speedup is %.2f\n",
101          (double)tsize,(1.0*tsize)/(in+out));
102 }
103
104
105 static void server_options(char **args,int *argc)
106 {
107   int ac = *argc;
108   static char argstr[50];
109   static char bsize[30];
110   static char iotime[30];
111   int i, x;
112
113   args[ac++] = "--server";
114
115   if (!am_sender)
116     args[ac++] = "--sender";
117
118   x = 1;
119   argstr[0] = '-';
120   for (i=0;i<verbose;i++)
121     argstr[x++] = 'v';
122   if (make_backups)
123     argstr[x++] = 'b';
124   if (update_only)
125     argstr[x++] = 'u';
126   if (dry_run)
127     argstr[x++] = 'n';
128   if (preserve_links)
129     argstr[x++] = 'l';
130   if (copy_links)
131     argstr[x++] = 'L';
132   if (whole_file)
133     argstr[x++] = 'W';
134   if (preserve_hard_links)
135     argstr[x++] = 'H';
136   if (preserve_uid)
137     argstr[x++] = 'o';
138   if (preserve_gid)
139     argstr[x++] = 'g';
140   if (preserve_devices)
141     argstr[x++] = 'D';
142   if (preserve_times)
143     argstr[x++] = 't';
144   if (preserve_perms)
145     argstr[x++] = 'p';
146   if (recurse)
147     argstr[x++] = 'r';
148   if (always_checksum)
149     argstr[x++] = 'c';
150   if (cvs_exclude)
151     argstr[x++] = 'C';
152   if (ignore_times)
153     argstr[x++] = 'I';
154   if (relative_paths)
155     argstr[x++] = 'R';
156   if (one_file_system)
157     argstr[x++] = 'x';
158   if (sparse_files)
159     argstr[x++] = 'S';
160   if (do_compression)
161     argstr[x++] = 'z';
162   argstr[x] = 0;
163
164   if (x != 1) args[ac++] = argstr;
165
166   if (block_size != BLOCK_SIZE) {
167     sprintf(bsize,"-B%d",block_size);
168     args[ac++] = bsize;
169   }    
170
171   if (io_timeout) {
172     sprintf(iotime,"--timeout=%d",io_timeout);
173     args[ac++] = iotime;
174   }    
175
176   if (strcmp(backup_suffix, BACKUP_SUFFIX)) {
177           args[ac++] = "--suffix";
178           args[ac++] = backup_suffix;
179   }
180
181   if (delete_mode)
182     args[ac++] = "--delete";
183
184   if (force_delete)
185     args[ac++] = "--force";
186
187   if (numeric_ids)
188     args[ac++] = "--numeric-ids";
189
190   if (tmpdir) {
191           args[ac++] = "--temp-dir";
192           args[ac++] = tmpdir;
193   }
194
195   *argc = ac;
196 }
197
198
199
200 static int do_cmd(char *cmd,char *machine,char *user,char *path,int *f_in,int *f_out)
201 {
202         char *args[100];
203         int i,argc=0, ret;
204         char *tok,*dir=NULL;
205
206         if (!local_server) {
207                 if (!cmd)
208                         cmd = getenv(RSYNC_RSH_ENV);
209                 if (!cmd)
210                         cmd = RSYNC_RSH;
211                 cmd = strdup(cmd);
212                 if (!cmd) 
213                         goto oom;
214
215                 for (tok=strtok(cmd," ");tok;tok=strtok(NULL," ")) {
216                         args[argc++] = tok;
217                 }
218
219 #if HAVE_REMSH
220                 /* remsh (on HPUX) takes the arguments the other way around */
221                 args[argc++] = machine;
222                 if (user) {
223                         args[argc++] = "-l";
224                         args[argc++] = user;
225                 }
226 #else
227                 if (user) {
228                         args[argc++] = "-l";
229                         args[argc++] = user;
230                 }
231                 args[argc++] = machine;
232 #endif
233
234                 args[argc++] = rsync_path;
235
236                 server_options(args,&argc);
237         }
238
239         args[argc++] = ".";
240
241         if (path && *path) 
242                 args[argc++] = path;
243
244         args[argc] = NULL;
245
246         if (verbose > 3) {
247                 rprintf(FINFO,"cmd=");
248                 for (i=0;i<argc;i++)
249                         rprintf(FINFO,"%s ",args[i]);
250                 rprintf(FINFO,"\n");
251         }
252
253         if (local_server) {
254                 ret = local_child(argc, args, f_in, f_out);
255         } else {
256                 ret = piped_child(args,f_in,f_out);
257         }
258
259         if (dir) free(dir);
260
261         return ret;
262
263 oom:
264         out_of_memory("do_cmd");
265         return 0; /* not reached */
266 }
267
268
269
270
271 static char *get_local_name(struct file_list *flist,char *name)
272 {
273   STRUCT_STAT st;
274
275   if (do_stat(name,&st) == 0) {
276     if (S_ISDIR(st.st_mode)) {
277       if (chdir(name) != 0) {
278         rprintf(FERROR,"chdir %s : %s (1)\n",name,strerror(errno));
279         exit_cleanup(1);
280       }
281       return NULL;
282     }
283     if (flist->count > 1) {
284       rprintf(FERROR,"ERROR: destination must be a directory when copying more than 1 file\n");
285       exit_cleanup(1);
286     }
287     return name;
288   }
289
290   if (flist->count == 1)
291     return name;
292
293   if (!name) 
294     return NULL;
295
296   if (do_mkdir(name,0777 & ~orig_umask) != 0) {
297     rprintf(FERROR,"mkdir %s : %s (1)\n",name,strerror(errno));
298     exit_cleanup(1);
299   } else {
300     rprintf(FINFO,"created directory %s\n",name);
301   }
302
303   if (chdir(name) != 0) {
304     rprintf(FERROR,"chdir %s : %s (2)\n",name,strerror(errno));
305     exit_cleanup(1);
306   }
307
308   return NULL;
309 }
310
311
312
313
314 static void do_server_sender(int f_in, int f_out, int argc,char *argv[])
315 {
316   int i;
317   struct file_list *flist;
318   char *dir = argv[0];
319
320   if (verbose > 2)
321     rprintf(FINFO,"server_sender starting pid=%d\n",(int)getpid());
322   
323   if (!relative_paths && chdir(dir) != 0) {
324           rprintf(FERROR,"chdir %s: %s (3)\n",dir,strerror(errno));
325           exit_cleanup(1);
326   }
327   argc--;
328   argv++;
329   
330   if (strcmp(dir,".")) {
331           int l = strlen(dir);
332           if (strcmp(dir,"/") == 0) 
333                   l = 0;
334           for (i=0;i<argc;i++)
335                   argv[i] += l+1;
336   }
337
338   if (argc == 0 && recurse) {
339           argc=1;
340           argv--;
341           argv[0] = ".";
342   }
343     
344
345   flist = send_file_list(f_out,argc,argv);
346   send_files(flist,f_out,f_in);
347   report(f_out);
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
358   if (preserve_hard_links)
359     init_hard_links(flist);
360
361   if (pipe(recv_pipe) < 0) {
362     rprintf(FERROR,"pipe failed in do_recv\n");
363     exit(1);
364   }
365   
366
367   if ((pid=do_fork()) == 0) {
368     recv_files(f_in,flist,local_name,recv_pipe[1]);
369     if (verbose > 2)
370       rprintf(FINFO,"receiver read %ld\n",(long)read_total());
371     exit_cleanup(0);
372   }
373
374   generate_files(f_out,flist,local_name,recv_pipe[0]);
375
376   waitpid(pid, &status, 0);
377
378   return status;
379 }
380
381
382 static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
383 {
384   int status;
385   struct file_list *flist;
386   char *local_name=NULL;
387   char *dir = NULL;
388   
389   if (verbose > 2)
390     rprintf(FINFO,"server_recv(%d) starting pid=%d\n",argc,(int)getpid());
391
392   if (argc > 0) {
393           dir = argv[0];
394           argc--;
395           argv++;
396           if (chdir(dir) != 0) {
397                   rprintf(FERROR,"chdir %s : %s (4)\n",
398                           dir,strerror(errno));
399                   exit_cleanup(1);
400           }    
401   }
402
403   if (delete_mode)
404     recv_exclude_list(f_in);
405
406   flist = recv_file_list(f_in);
407   if (!flist || flist->count == 0) {
408     rprintf(FERROR,"nothing to do\n");
409     exit_cleanup(1);
410   }
411
412   if (argc > 0) {    
413           if (strcmp(dir,".")) {
414                   argv[0] += strlen(dir);
415                   if (argv[0][0] == '/') argv[0]++;
416           }
417           local_name = get_local_name(flist,argv[0]);
418   }
419
420   status = do_recv(f_in,f_out,flist,local_name);
421   exit_cleanup(status);
422 }
423
424
425 void start_server(int f_in, int f_out, int argc, char *argv[])
426 {
427       setup_protocol(f_out, f_in);
428         
429       if (am_sender) {
430               recv_exclude_list(f_in);
431               if (cvs_exclude)
432                       add_cvs_excludes();
433               do_server_sender(f_in, f_out, argc, argv);
434       } else {
435               do_server_recv(f_in, f_out, argc, argv);
436       }
437       exit_cleanup(0);
438 }
439
440 static int client_run(int f_in, int f_out, int pid, int argc, char *argv[])
441 {
442         struct file_list *flist;
443         int status = 0, status2 = 0;
444         char *local_name = NULL;
445
446         setup_protocol(f_out,f_in);
447         
448         if (am_sender) {
449                 if (cvs_exclude)
450                         add_cvs_excludes();
451                 if (delete_mode) 
452                         send_exclude_list(f_out);
453                 flist = send_file_list(f_out,argc,argv);
454                 if (verbose > 3) 
455                         rprintf(FINFO,"file list sent\n");
456                 send_files(flist,f_out,f_in);
457                 if (pid != -1) {
458                         if (verbose > 3)
459                                 rprintf(FINFO,"waiting on %d\n",pid);
460                         waitpid(pid, &status, 0);
461                 }
462                 report(-1);
463                 exit_cleanup(status);
464         }
465         
466         send_exclude_list(f_out);
467         
468         flist = recv_file_list(f_in);
469         if (!flist || flist->count == 0) {
470                 rprintf(FINFO,"nothing to do\n");
471                 exit_cleanup(0);
472         }
473         
474         local_name = get_local_name(flist,argv[0]);
475         
476         status2 = do_recv(f_in,f_out,flist,local_name);
477         
478         report(f_in);
479         
480         if (pid != -1) {
481                 waitpid(pid, &status, 0);
482         }
483         
484         return status | status2;
485 }
486
487
488 int start_socket_client(char *host, char *path, int argc, char *argv[])
489 {
490         int fd;
491         char *sargs[100];
492         int sargc=0;
493         
494         fd = open_socket_out(host, port);
495         if (fd == -1) {
496                 rprintf(FERROR,"failed to connect to %s - %s\n", host, strerror(errno));
497                 exit_cleanup(1);
498         }
499         
500         server_options(sargs,&sargc);
501
502         sargs[sargc++] = ".";
503
504         if (path && *path) 
505                 sargs[sargc++] = path;
506
507         sargs[sargc] = NULL;
508
509         return client_run(fd, fd, -1, argc, argv);
510 }
511
512 int start_client(int argc, char *argv[])
513 {
514         char *p;
515         char *shell_machine = NULL;
516         char *shell_path = NULL;
517         char *shell_user = NULL;
518         int pid;
519         int f_in,f_out;
520
521         p = strchr(argv[0],':');
522
523         if (p) {
524                 if (p[1] == ':') {
525                         *p = 0;
526                         return start_socket_client(argv[0], p+2, argc-1, argv+1);
527                 }
528                 am_sender = 0;
529                 *p = 0;
530                 shell_machine = argv[0];
531                 shell_path = p+1;
532                 argc--;
533                 argv++;
534         } else {
535                 am_sender = 1;
536
537                 p = strchr(argv[argc-1],':');
538                 if (!p) {
539                         local_server = 1;
540                 } else if (p[1] == ':') {
541                         *p = 0;
542                         return start_socket_client(argv[argc-1], p+2, argc-1, argv);
543                 }
544                 
545                 if (local_server) {
546                         shell_machine = NULL;
547                         shell_path = argv[argc-1];
548                 } else {
549                         *p = 0;
550                         shell_machine = argv[argc-1];
551                         shell_path = p+1;
552                 }
553                 argc--;
554         }
555         
556         if (shell_machine) {
557                 p = strchr(shell_machine,'@');
558                 if (p) {
559                         *p = 0;
560                         shell_user = shell_machine;
561                         shell_machine = p+1;
562                 }
563         }
564
565         if (verbose > 3) {
566                 rprintf(FINFO,"cmd=%s machine=%s user=%s path=%s\n",
567                         shell_cmd?shell_cmd:"",
568                         shell_machine?shell_machine:"",
569                         shell_user?shell_user:"",
570                         shell_path?shell_path:"");
571         }
572         
573         if (!am_sender && argc != 1) {
574                 usage(FERROR);
575                 exit_cleanup(1);
576         }
577         
578         pid = do_cmd(shell_cmd,shell_machine,shell_user,shell_path,&f_in,&f_out);
579         
580 #if HAVE_SETLINEBUF
581         setlinebuf(stdout);
582         setlinebuf(stderr);
583 #endif
584
585         return client_run(f_in, f_out, pid, argc, argv);
586 }
587
588
589 static void usage(int F)
590 {
591   rprintf(F,"rsync version %s Copyright Andrew Tridgell and Paul Mackerras\n\n",
592           VERSION);
593   rprintf(F,"Usage:\t%s [options] src user@host:dest\nOR",RSYNC_NAME);
594   rprintf(F,"\t%s [options] user@host:src dest\n\n",RSYNC_NAME);
595   rprintf(F,"Options:\n");
596   rprintf(F,"-v, --verbose            increase verbosity\n");
597   rprintf(F,"-c, --checksum           always checksum\n");
598   rprintf(F,"-a, --archive            archive mode (same as -rlptDog)\n");
599   rprintf(F,"-r, --recursive          recurse into directories\n");
600   rprintf(F,"-R, --relative           use relative path names\n");
601   rprintf(F,"-b, --backup             make backups (default ~ extension)\n");
602   rprintf(F,"-u, --update             update only (don't overwrite newer files)\n");
603   rprintf(F,"-l, --links              preserve soft links\n");
604   rprintf(F,"-L, --copy-links         treat soft links like regular files\n");
605   rprintf(F,"-H, --hard-links         preserve hard links\n");
606   rprintf(F,"-p, --perms              preserve permissions\n");
607   rprintf(F,"-o, --owner              preserve owner (root only)\n");
608   rprintf(F,"-g, --group              preserve group\n");
609   rprintf(F,"-D, --devices            preserve devices (root only)\n");
610   rprintf(F,"-t, --times              preserve times\n");  
611   rprintf(F,"-S, --sparse             handle sparse files efficiently\n");
612   rprintf(F,"-n, --dry-run            show what would have been transferred\n");
613   rprintf(F,"-W, --whole-file         copy whole files, no incremental checks\n");
614   rprintf(F,"-x, --one-file-system    don't cross filesystem boundaries\n");
615   rprintf(F,"-B, --block-size SIZE    checksum blocking size\n");  
616   rprintf(F,"-e, --rsh COMMAND        specify rsh replacement\n");
617   rprintf(F,"    --rsync-path PATH    specify path to rsync on the remote machine\n");
618   rprintf(F,"-C, --cvs-exclude        auto ignore files in the same way CVS does\n");
619   rprintf(F,"    --delete             delete files that don't exist on the sending side\n");
620   rprintf(F,"    --force              force deletion of directories even if not empty\n");
621   rprintf(F,"    --numeric-ids        don't map uid/gid values by user/group name\n");
622   rprintf(F,"    --timeout TIME       set IO timeout in seconds\n");
623   rprintf(F,"-I, --ignore-times       don't exclude files that match length and time\n");
624   rprintf(F,"-T  --temp-dir DIR       create temporary files in directory DIR\n");
625   rprintf(F,"-z, --compress           compress file data\n");
626   rprintf(F,"    --exclude FILE       exclude file FILE\n");
627   rprintf(F,"    --exclude-from FILE  exclude files listed in FILE\n");
628   rprintf(F,"    --suffix SUFFIX      override backup suffix\n");  
629   rprintf(F,"    --version            print version number\n");  
630
631   rprintf(F,"\n");
632   rprintf(F,"the backup suffix defaults to %s\n",BACKUP_SUFFIX);
633   rprintf(F,"the block size defaults to %d\n",BLOCK_SIZE);  
634 }
635
636 enum {OPT_VERSION,OPT_SUFFIX,OPT_SENDER,OPT_SERVER,OPT_EXCLUDE,
637       OPT_EXCLUDE_FROM,OPT_DELETE,OPT_NUMERIC_IDS,OPT_RSYNC_PATH,
638       OPT_FORCE,OPT_TIMEOUT,OPT_DAEMON};
639
640 static char *short_options = "oblLWHpguDCtcahvrRIxnSe:B:T:z";
641
642 static struct option long_options[] = {
643   {"version",     0,     0,    OPT_VERSION},
644   {"server",      0,     0,    OPT_SERVER},
645   {"sender",      0,     0,    OPT_SENDER},
646   {"delete",      0,     0,    OPT_DELETE},
647   {"force",       0,     0,    OPT_FORCE},
648   {"numeric-ids", 0,     0,    OPT_NUMERIC_IDS},
649   {"exclude",     1,     0,    OPT_EXCLUDE},
650   {"exclude-from",1,     0,    OPT_EXCLUDE_FROM},
651   {"rsync-path",  1,     0,    OPT_RSYNC_PATH},
652   {"one-file-system",0,  0,    'x'},
653   {"ignore-times",0,     0,    'I'},
654   {"help",        0,     0,    'h'},
655   {"dry-run",     0,     0,    'n'},
656   {"sparse",      0,     0,    'S'},
657   {"cvs-exclude", 0,     0,    'C'},
658   {"archive",     0,     0,    'a'},
659   {"checksum",    0,     0,    'c'},
660   {"backup",      0,     0,    'b'},
661   {"update",      0,     0,    'u'},
662   {"verbose",     0,     0,    'v'},
663   {"recursive",   0,     0,    'r'},
664   {"relative",    0,     0,    'R'},
665   {"devices",     0,     0,    'D'},
666   {"perms",       0,     0,    'p'},
667   {"links",       0,     0,    'l'},
668   {"copy-links",  0,     0,    'L'},
669   {"whole-file",  0,     0,    'W'},
670   {"hard-links",  0,     0,    'H'},
671   {"owner",       0,     0,    'o'},
672   {"group",       0,     0,    'g'},
673   {"times",       0,     0,    't'},
674   {"rsh",         1,     0,    'e'},
675   {"suffix",      1,     0,    OPT_SUFFIX},
676   {"block-size",  1,     0,    'B'},
677   {"timeout",     1,     0,    OPT_TIMEOUT},
678   {"temp-dir",    1,     0,    'T'},
679   {"compress",    0,     0,    'z'},
680   {"daemon",      0,     0,    OPT_DAEMON},
681   {0,0,0,0}};
682
683 RETSIGTYPE sigusr1_handler(int val) {
684         exit_cleanup(1);
685 }
686
687
688 static void parse_arguments(int argc, char *argv[])
689 {
690     int opt;
691     int option_index;
692
693     while ((opt = getopt_long(argc, argv, 
694                               short_options, long_options, &option_index)) 
695            != -1) {
696       switch (opt) 
697         {
698         case OPT_VERSION:
699           printf("rsync version %s  protocol version %d\n",
700                  VERSION,PROTOCOL_VERSION);
701           exit_cleanup(0);
702
703         case OPT_SUFFIX:
704           backup_suffix = optarg;
705           break;
706
707         case OPT_RSYNC_PATH:
708           rsync_path = optarg;
709           break;
710
711         case 'I':
712           ignore_times = 1;
713           break;
714
715         case 'x':
716           one_file_system=1;
717           break;
718
719         case OPT_DELETE:
720           delete_mode = 1;
721           break;
722
723         case OPT_FORCE:
724           force_delete = 1;
725           break;
726
727         case OPT_NUMERIC_IDS:
728           numeric_ids = 1;
729           break;
730
731         case OPT_EXCLUDE:
732           add_exclude(optarg);
733           break;
734
735         case OPT_EXCLUDE_FROM:
736           add_exclude_file(optarg,1);
737           break;
738
739         case 'h':
740           usage(FINFO);
741           exit_cleanup(0);
742
743         case 'b':
744           make_backups=1;
745           break;
746
747         case 'n':
748           dry_run=1;
749           break;
750
751         case 'S':
752           sparse_files=1;
753           break;
754
755         case 'C':
756           cvs_exclude=1;
757           break;
758
759         case 'u':
760           update_only=1;
761           break;
762
763         case 'l':
764           preserve_links=1;
765           break;
766
767         case 'L':
768           copy_links=1;
769           break;
770
771         case 'W':
772           whole_file=1;
773           break;
774
775         case 'H':
776 #if SUPPORT_HARD_LINKS
777           preserve_hard_links=1;
778 #else 
779           rprintf(FERROR,"ERROR: hard links not supported on this platform\n");
780           exit_cleanup(1);
781 #endif
782           break;
783
784         case 'p':
785           preserve_perms=1;
786           break;
787
788         case 'o':
789           preserve_uid=1;
790           break;
791
792         case 'g':
793           preserve_gid=1;
794           break;
795
796         case 'D':
797           preserve_devices=1;
798           break;
799
800         case 't':
801           preserve_times=1;
802           break;
803
804         case 'c':
805           always_checksum=1;
806           break;
807
808         case 'v':
809           verbose++;
810           break;
811
812         case 'a':
813           recurse=1;
814 #if SUPPORT_LINKS
815           preserve_links=1;
816 #endif
817           preserve_perms=1;
818           preserve_times=1;
819           preserve_gid=1;
820           if (am_root) {
821             preserve_devices=1;
822             preserve_uid=1;
823           }
824           break;
825
826         case OPT_SERVER:
827           am_server = 1;
828           break;
829
830         case OPT_SENDER:
831           if (!am_server) {
832             usage(FERROR);
833             exit_cleanup(1);
834           }
835           am_sender = 1;
836           break;
837
838         case 'r':
839           recurse = 1;
840           break;
841
842         case 'R':
843           relative_paths = 1;
844           break;
845
846         case 'e':
847           shell_cmd = optarg;
848           break;
849
850         case 'B':
851           block_size = atoi(optarg);
852           break;
853
854         case OPT_TIMEOUT:
855           io_timeout = atoi(optarg);
856           break;
857
858         case 'T':
859                 tmpdir = optarg;
860                 break;
861
862         case 'z':
863           do_compression = 1;
864           break;
865
866         case OPT_DAEMON:
867                 am_daemon = 1;
868                 break;
869
870         default:
871           /* rprintf(FERROR,"bad option -%c\n",opt); */
872           exit_cleanup(1);
873         }
874     }
875 }
876
877 int main(int argc,char *argv[])
878 {
879
880     signal(SIGUSR1, sigusr1_handler);
881
882     starttime = time(NULL);
883     am_root = (getuid() == 0);
884
885     /* we set a 0 umask so that correct file permissions can be
886        carried across */
887     orig_umask = (int)umask(0);
888
889     parse_arguments(argc, argv);
890
891     while (optind) {
892       argc--;
893       argv++;
894       optind--;
895     }
896
897     signal(SIGCHLD,SIG_IGN);
898     signal(SIGINT,SIGNAL_CAST sig_int);
899     signal(SIGPIPE,SIGNAL_CAST sig_int);
900     signal(SIGHUP,SIGNAL_CAST sig_int);
901
902     if (dry_run)
903       verbose = MAX(verbose,1);
904
905 #ifndef SUPPORT_LINKS
906     if (!am_server && preserve_links) {
907             rprintf(FERROR,"ERROR: symbolic links not supported\n");
908             exit_cleanup(1);
909     }
910 #endif
911
912     if (am_server) {
913             start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
914     }
915
916     if (argc < 2) {
917       usage(FERROR);
918       exit_cleanup(1);
919     }
920
921     return start_client(argc, argv);
922 }
923