- improved filename packing
[rsync/rsync.git] / main.c
CommitLineData
c627d613
AT
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
22int verbose = 0;
23int always_checksum = 0;
24time_t starttime;
25off_t total_size = 0;
26int block_size=BLOCK_SIZE;
27
28char *backup_suffix = BACKUP_SUFFIX;
29
30static char *rsync_path = RSYNC_NAME;
31
32int make_backups = 0;
33int preserve_links = 0;
34int preserve_perms = 0;
35int preserve_devices = 0;
36int preserve_uid = 0;
37int preserve_gid = 0;
38int preserve_times = 0;
39int update_only = 0;
40int cvs_exclude = 0;
41int dry_run=0;
42int local_server=0;
43int ignore_times=0;
44int delete_mode=0;
45int one_file_system=0;
4fe159a8 46int remote_version=0;
c627d613
AT
47
48int am_server = 0;
49static int sender = 0;
50int recurse = 0;
51
52static void usage(FILE *f);
53
54static void report(int f)
55{
56 int in,out,tsize;
57 time_t t = time(NULL);
58
59 if (!verbose) return;
60
61 if (am_server && sender) {
62 write_int(f,read_total());
63 write_int(f,write_total());
64 write_int(f,total_size);
65 write_flush(f);
66 return;
67 }
68
69 if (sender) {
70 in = read_total();
71 out = write_total();
72 tsize = (int)total_size;
73 } else {
74 in = read_int(f);
75 out = read_int(f);
76 tsize = read_int(f);
77 }
78
79 printf("wrote %d bytes read %d bytes %g bytes/sec\n",
80 out,in,(in+out)/(0.5 + (t-starttime)));
81 printf("total size is %d speedup is %g\n",
82 tsize,(1.0*tsize)/(in+out));
83}
84
85
86static void server_options(char **args,int *argc)
87{
88 int ac = *argc;
89 static char argstr[50];
90 static char bsize[30];
91 int i, x;
92
93 args[ac++] = "--server";
94
95 if (!sender)
96 args[ac++] = "--sender";
97
98 x = 1;
99 argstr[0] = '-';
100 for (i=0;i<verbose;i++)
101 argstr[x++] = 'v';
102 if (make_backups)
103 argstr[x++] = 'b';
104 if (update_only)
105 argstr[x++] = 'u';
106 if (dry_run)
107 argstr[x++] = 'n';
108 if (preserve_links)
109 argstr[x++] = 'l';
110 if (preserve_uid)
111 argstr[x++] = 'o';
112 if (preserve_gid)
113 argstr[x++] = 'g';
114 if (preserve_devices)
115 argstr[x++] = 'D';
116 if (preserve_times)
117 argstr[x++] = 't';
118 if (preserve_perms)
119 argstr[x++] = 'p';
120 if (recurse)
121 argstr[x++] = 'r';
122 if (always_checksum)
123 argstr[x++] = 'c';
124 if (cvs_exclude)
125 argstr[x++] = 'C';
126 if (ignore_times)
127 argstr[x++] = 'I';
128 if (one_file_system)
129 argstr[x++] = 'x';
130 argstr[x] = 0;
131
132 if (x != 1) args[ac++] = argstr;
133
134 if (block_size != BLOCK_SIZE) {
135 sprintf(bsize,"-B%d",block_size);
136 args[ac++] = bsize;
137 }
138
139 if (delete_mode)
140 args[ac++] = "--delete";
141
142 *argc = ac;
143}
144
145
146
147int do_cmd(char *cmd,char *machine,char *user,char *path,int *f_in,int *f_out)
148{
149 char *args[100];
150 int i,argc=0;
151 char *tok,*p;
152
153 if (!local_server) {
154 if (!cmd)
155 cmd = getenv(RSYNC_RSH_ENV);
156 if (!cmd)
157 cmd = RSYNC_RSH;
158 cmd = strdup(cmd);
159 if (!cmd)
160 goto oom;
161
162 for (tok=strtok(cmd," ");tok;tok=strtok(NULL," ")) {
163 args[argc++] = tok;
164 }
165
166 if (user) {
167 args[argc++] = "-l";
168 args[argc++] = user;
169 }
170 args[argc++] = machine;
171 }
172
173 args[argc++] = rsync_path;
174
175 server_options(args,&argc);
176
177 if (path && *path) {
178 char *dir = strdup(path);
179 p = strrchr(dir,'/');
180 if (p) {
181 *p = 0;
182 args[argc++] = dir;
183 p++;
184 } else {
185 args[argc++] = ".";
186 p = dir;
187 }
188 if (p[0])
189 args[argc++] = path;
190 }
191
192 args[argc] = NULL;
193
194 if (verbose > 3) {
195 fprintf(stderr,"cmd=");
196 for (i=0;i<argc;i++)
197 fprintf(stderr,"%s ",args[i]);
198 fprintf(stderr,"\n");
199 }
200
201 return piped_child(args,f_in,f_out);
202
203oom:
204 out_of_memory("do_cmd");
205 return 0; /* not reached */
206}
207
208
209
210
211static char *get_local_name(struct file_list *flist,char *name)
212{
213 struct stat st;
214
215 if (stat(name,&st) == 0) {
216 if (S_ISDIR(st.st_mode)) {
217 if (chdir(name) != 0) {
218 fprintf(stderr,"chdir %s : %s\n",name,strerror(errno));
219 exit(1);
220 }
221 return NULL;
222 }
223 if (flist->count > 1) {
224 fprintf(stderr,"ERROR: destination must be a directory when copying more than 1 file\n");
225 exit(1);
226 }
227 return name;
228 }
229
230 if (flist->count == 1)
231 return name;
232
233 if (!name)
234 return NULL;
235
236 if (mkdir(name,0777) != 0) {
237 fprintf(stderr,"mkdir %s : %s\n",name,strerror(errno));
238 exit(1);
94481d91
AT
239 } else {
240 fprintf(am_server?stderr:stdout,"created directory %s\n",name);
c627d613
AT
241 }
242
243 if (chdir(name) != 0) {
244 fprintf(stderr,"chdir %s : %s\n",name,strerror(errno));
245 exit(1);
246 }
247
248 return NULL;
249}
250
251
252
253
254void do_server_sender(int argc,char *argv[])
255{
256 int i;
257 char *dir = argv[0];
258 struct file_list *flist;
259
260 if (verbose > 2)
261 fprintf(stderr,"server_sender starting pid=%d\n",(int)getpid());
262
263 if (chdir(dir) != 0) {
264 fprintf(stderr,"chdir %s: %s\n",dir,strerror(errno));
265 exit(1);
266 }
267 argc--;
268 argv++;
269
270 if (strcmp(dir,".")) {
271 int l = strlen(dir);
272 for (i=0;i<argc;i++)
273 argv[i] += l+1;
274 }
275
276 if (argc == 0 && recurse) {
277 argc=1;
278 argv--;
279 argv[0] = ".";
280 }
281
282
283 flist = send_file_list(STDOUT_FILENO,recurse,argc,argv);
284 send_files(flist,STDOUT_FILENO,STDIN_FILENO);
285 report(STDOUT_FILENO);
286 exit(0);
287}
288
289
290
291void do_server_recv(int argc,char *argv[])
292{
293 int pid,status;
294 char *dir = NULL;
295 struct file_list *flist;
296 char *local_name=NULL;
297
298 if (verbose > 2)
299 fprintf(stderr,"server_recv(%d) starting pid=%d\n",argc,(int)getpid());
300
301 if (argc > 0) {
302 dir = argv[0];
303 argc--;
304 argv++;
305 if (chdir(dir) != 0) {
306 fprintf(stderr,"chdir %s : %s\n",dir,strerror(errno));
307 exit(1);
308 }
309 }
310
311 if (delete_mode)
312 recv_exclude_list(STDIN_FILENO);
313
314 flist = recv_file_list(STDIN_FILENO);
315 if (!flist || flist->count == 0) {
316 fprintf(stderr,"nothing to do\n");
317 exit(1);
318 }
319
320 if (argc > 0) {
321 if (strcmp(dir,".")) {
322 argv[0] += strlen(dir);
323 if (argv[0][0] == '/') argv[0]++;
324 }
325 local_name = get_local_name(flist,argv[0]);
326 }
327
328 if ((pid=fork()) == 0) {
329 recv_files(STDIN_FILENO,flist,local_name);
330 if (verbose > 2)
331 fprintf(stderr,"receiver read %d\n",read_total());
332 exit(0);
333 }
334
335 generate_files(STDOUT_FILENO,flist,local_name);
336
337 waitpid(pid, &status, 0);
338 exit(status);
339}
340
341
342static void usage(FILE *f)
343{
344 fprintf(f,"rsync version %s Copyright Andrew Tridgell and Paul Mackerras\n\n",
345 VERSION);
346 fprintf(f,"Usage:\t%s [options] src user@host:dest\nOR",RSYNC_NAME);
347 fprintf(f,"\t%s [options] user@host:src dest\n\n",RSYNC_NAME);
348 fprintf(f,"Options:\n");
349 fprintf(f,"-v, --verbose increase verbosity\n");
350 fprintf(f,"-c, --checksum always checksum\n");
351 fprintf(f,"-a, --archive archive mode (same as -rlptDog)\n");
352 fprintf(f,"-r, --recursive recurse into directories\n");
353 fprintf(f,"-b, --backup make backups (default ~ extension)\n");
354 fprintf(f,"-u, --update update only (don't overwrite newer files)\n");
355 fprintf(f,"-l, --links preserve soft links\n");
356 fprintf(f,"-p, --perms preserve permissions\n");
357 fprintf(f,"-o, --owner preserve owner (root only)\n");
358 fprintf(f,"-g, --group preserve group\n");
359 fprintf(f,"-D, --devices preserve devices (root only)\n");
360 fprintf(f,"-t, --times preserve times\n");
361 fprintf(f,"-n, --dry-run show what would have been transferred\n");
362 fprintf(f,"-x, --one-file-system don't cross filesystem boundaries\n");
363 fprintf(f,"-B, --block-size SIZE checksum blocking size\n");
364 fprintf(f,"-e, --rsh COMMAND specify rsh replacement\n");
365 fprintf(f," --rsync-path PATH specify path to rsync on the remote machine\n");
366 fprintf(f,"-C, --cvs-exclude auto ignore files in the same way CVS does\n");
367 fprintf(f," --delete delete files that don't exist on the sending side\n");
368 fprintf(f,"-I, --ignore-times don't exclude files that match length and time\n");
369 fprintf(f," --exclude FILE exclude file FILE\n");
370 fprintf(f," --exclude-from FILE exclude files listed in FILE\n");
371 fprintf(f," --suffix SUFFIX override backup suffix\n");
372 fprintf(f," --version print version number\n");
373
374 fprintf(f,"\n");
375 fprintf(f,"the backup suffix defaults to %s\n",BACKUP_SUFFIX);
376 fprintf(f,"the block size defaults to %d\n",BLOCK_SIZE);
377}
378
379enum {OPT_VERSION,OPT_SUFFIX,OPT_SENDER,OPT_SERVER,OPT_EXCLUDE,
380 OPT_EXCLUDE_FROM,OPT_DELETE,OPT_RSYNC_PATH};
381
382static char *short_options = "oblpguDCtcahvrIxne:B:";
383
384static struct option long_options[] = {
385 {"version", 0, 0, OPT_VERSION},
386 {"server", 0, 0, OPT_SERVER},
387 {"sender", 0, 0, OPT_SENDER},
388 {"delete", 0, 0, OPT_DELETE},
389 {"exclude", 1, 0, OPT_EXCLUDE},
390 {"exclude-from",1, 0, OPT_EXCLUDE_FROM},
391 {"rsync-path", 1, 0, OPT_RSYNC_PATH},
392 {"one-file-system",0, 0, 'x'},
393 {"ignore-times",0, 0, 'I'},
394 {"help", 0, 0, 'h'},
395 {"dry-run", 0, 0, 'n'},
396 {"cvs-exclude", 0, 0, 'C'},
397 {"archive", 0, 0, 'a'},
398 {"checksum", 0, 0, 'c'},
399 {"backup", 0, 0, 'b'},
400 {"update", 0, 0, 'u'},
401 {"verbose", 0, 0, 'v'},
402 {"recursive", 0, 0, 'r'},
403 {"devices", 0, 0, 'D'},
404 {"perms", 0, 0, 'p'},
405 {"links", 0, 0, 'l'},
406 {"owner", 0, 0, 'o'},
407 {"group", 0, 0, 'g'},
408 {"times", 0, 0, 't'},
409 {"rsh", 1, 0, 'e'},
410 {"suffix", 1, 0, OPT_SUFFIX},
411 {"block-size", 1, 0, 'B'},
412 {0,0,0,0}};
413
414int main(int argc,char *argv[])
415{
416 int pid, status, pid2, status2;
417 int opt;
418 int option_index;
419 char *shell_cmd = NULL;
420 char *shell_machine = NULL;
421 char *shell_path = NULL;
422 char *shell_user = NULL;
423 char *p;
424 int f_in,f_out;
425 struct file_list *flist;
426 char *local_name = NULL;
427
428 starttime = time(NULL);
429
430 while ((opt = getopt_long(argc, argv,
431 short_options, long_options, &option_index))
432 != -1) {
433 switch (opt)
434 {
435 case OPT_VERSION:
436 printf("rsync version %s protocol version %d\n",
437 VERSION,PROTOCOL_VERSION);
438 exit(0);
439
440 case OPT_SUFFIX:
441 backup_suffix = optarg;
442 break;
443
444 case OPT_RSYNC_PATH:
445 rsync_path = optarg;
446 break;
447
448 case 'I':
449 ignore_times = 1;
450 break;
451
452 case 'x':
453 one_file_system=1;
454 break;
455
456 case OPT_DELETE:
457 delete_mode = 1;
458 break;
459
460 case OPT_EXCLUDE:
461 add_exclude(optarg);
462 break;
463
464 case OPT_EXCLUDE_FROM:
465 add_exclude_file(optarg,1);
466 break;
467
468 case 'h':
469 usage(stdout);
470 exit(0);
471
472 case 'b':
473 make_backups=1;
474 break;
475
476 case 'n':
477 dry_run=1;
478 break;
479
480 case 'C':
481 cvs_exclude=1;
482 break;
483
484 case 'u':
485 update_only=1;
486 break;
487
488#if SUPPORT_LINKS
489 case 'l':
490 preserve_links=1;
491 break;
492#endif
493
494 case 'p':
495 preserve_perms=1;
496 break;
497
498 case 'o':
499 if (getuid() == 0) {
500 preserve_uid=1;
501 } else {
502 fprintf(stderr,"-o only allowed for root\n");
503 exit(1);
504 }
505 break;
506
507 case 'g':
508 preserve_gid=1;
509 break;
510
511 case 'D':
512 if (getuid() == 0) {
513 preserve_devices=1;
514 } else {
515 fprintf(stderr,"-D only allowed for root\n");
516 exit(1);
517 }
518 break;
519
520 case 't':
521 preserve_times=1;
522 break;
523
524 case 'c':
525 always_checksum=1;
526 break;
527
528 case 'v':
529 verbose++;
530 break;
531
532 case 'a':
533 recurse=1;
534#if SUPPORT_LINKS
535 preserve_links=1;
536#endif
537 preserve_perms=1;
538 preserve_times=1;
539 preserve_gid=1;
540 if (getuid() == 0) {
541 preserve_devices=1;
542 preserve_uid=1;
543 }
544 break;
545
546 case OPT_SERVER:
547 am_server = 1;
548 break;
549
550 case OPT_SENDER:
551 if (!am_server) {
552 usage(stderr);
553 exit(1);
554 }
555 sender = 1;
556 break;
557
558 case 'r':
559 recurse = 1;
560 break;
561
562 case 'e':
563 shell_cmd = optarg;
564 break;
565
566 case 'B':
567 block_size = atoi(optarg);
568 break;
569
570 default:
571 fprintf(stderr,"bad option -%c\n",opt);
572 exit(1);
573 }
574 }
575
576 while (optind--) {
577 argc--;
578 argv++;
579 }
580
581 if (dry_run)
582 verbose = MAX(verbose,1);
583
584 if (am_server) {
4fe159a8
AT
585 remote_version = read_int(STDIN_FILENO);
586 if (remote_version < MIN_PROTOCOL_VERSION) {
c627d613 587 fprintf(stderr,"protocol version mismatch %d %d\n",
4fe159a8 588 remote_version,PROTOCOL_VERSION);
c627d613
AT
589 exit(1);
590 }
591 write_int(STDOUT_FILENO,PROTOCOL_VERSION);
592 write_flush(STDOUT_FILENO);
4fe159a8
AT
593
594 setup_protocol();
c627d613
AT
595
596 if (sender) {
597 recv_exclude_list(STDIN_FILENO);
598 if (cvs_exclude)
599 add_cvs_excludes();
600 do_server_sender(argc,argv);
601 } else {
602 do_server_recv(argc,argv);
603 }
604 exit(0);
605 }
606
607 if (argc < 2) {
608 usage(stderr);
609 exit(1);
610 }
611
612 p = strchr(argv[0],':');
613
614 if (p) {
615 sender = 0;
616 *p = 0;
617 shell_machine = argv[0];
618 shell_path = p+1;
619 argc--;
620 argv++;
621 } else {
622 sender = 1;
623
624 p = strchr(argv[argc-1],':');
625 if (!p) {
626 local_server = 1;
627 }
628
629 if (local_server) {
630 shell_machine = NULL;
631 shell_path = argv[argc-1];
632 } else {
633 *p = 0;
634 shell_machine = argv[argc-1];
635 shell_path = p+1;
636 }
637 argc--;
638 }
639
640 if (shell_machine) {
641 p = strchr(shell_machine,'@');
642 if (p) {
643 *p = 0;
644 shell_user = shell_machine;
645 shell_machine = p+1;
646 }
647 }
648
649 if (verbose > 3) {
650 fprintf(stderr,"cmd=%s machine=%s user=%s path=%s\n",
651 shell_cmd?shell_cmd:"",
652 shell_machine?shell_machine:"",
653 shell_user?shell_user:"",
654 shell_path?shell_path:"");
655 }
656
657 signal(SIGCHLD,SIG_IGN);
ac1eb754 658 signal(SIGINT,SIGNAL_CAST sig_int);
58d433ab 659 signal(SIGPIPE,SIGNAL_CAST sig_int);
c627d613
AT
660
661 if (!sender && argc != 1) {
662 usage(stderr);
663 exit(1);
664 }
665
666 pid = do_cmd(shell_cmd,shell_machine,shell_user,shell_path,&f_in,&f_out);
667
668 write_int(f_out,PROTOCOL_VERSION);
669 write_flush(f_out);
670 {
4fe159a8
AT
671 remote_version = read_int(f_in);
672 if (remote_version < MIN_PROTOCOL_VERSION) {
c627d613
AT
673 fprintf(stderr,"protocol version mismatch\n");
674 exit(1);
675 }
676 }
677
4fe159a8
AT
678 setup_protocol();
679
c627d613
AT
680 if (verbose > 3)
681 fprintf(stderr,"parent=%d child=%d sender=%d recurse=%d\n",
682 (int)getpid(),pid,sender,recurse);
683
684 if (sender) {
685 if (cvs_exclude)
686 add_cvs_excludes();
687 if (delete_mode)
688 send_exclude_list(f_out);
689 flist = send_file_list(f_out,recurse,argc,argv);
690 if (verbose > 3)
691 fprintf(stderr,"file list sent\n");
692 send_files(flist,f_out,f_in);
693 if (verbose > 3)
694 fprintf(stderr,"waiting on %d\n",pid);
695 waitpid(pid, &status, 0);
696 report(-1);
697 exit(status);
698 }
699
700 send_exclude_list(f_out);
701
702 flist = recv_file_list(f_in);
703 if (!flist || flist->count == 0) {
704 fprintf(stderr,"nothing to do\n");
705 exit(0);
706 }
707
708 local_name = get_local_name(flist,argv[0]);
709
710 if ((pid2=fork()) == 0) {
711 recv_files(f_in,flist,local_name);
712 if (verbose > 1)
713 fprintf(stderr,"receiver read %d\n",read_total());
714 exit(0);
715 }
716
717 generate_files(f_out,flist,local_name);
718
719 waitpid(pid2, &status2, 0);
720
721 report(f_in);
722
723 waitpid(pid, &status, 0);
724
725 return status | status2;
726}