Fix typo in comment in rsync.h, suggested by bje@cygnus.com
[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
f0fca04e 22time_t starttime = 0;
a800434a
AT
23
24struct stats stats;
5d6bcd44 25
34ccb63e 26extern int csum_length;
c627d613 27
7a6421fa 28extern int verbose;
c627d613
AT
29
30static void report(int f)
31{
7a6421fa
AT
32 time_t t = time(NULL);
33 extern int am_server;
34 extern int am_sender;
248fbb8c 35 extern int am_daemon;
a800434a 36 extern int do_stats;
17d31b38
DD
37 extern int remote_version;
38 int send_stats;
7a6421fa 39
248fbb8c 40 if (am_daemon) {
a9766ef1 41 log_exit(0, __FILE__, __LINE__);
7b372642 42 if (f == -1 || !am_sender) return;
248fbb8c
AT
43 }
44
17d31b38
DD
45 send_stats = verbose ||
46 ((remote_version >= 20) && (PROTOCOL_VERSION >= 20));
e19452a9 47 if (am_server) {
17d31b38 48 if (am_sender && send_stats) {
23c5aef1
DD
49 int64 w;
50 /* store total_written in a temporary
51 because write_longint changes it */
52 w = stats.total_written;
e19452a9 53 write_longint(f,stats.total_read);
23c5aef1 54 write_longint(f,w);
e19452a9
DD
55 write_longint(f,stats.total_size);
56 }
7a6421fa
AT
57 return;
58 }
e19452a9
DD
59
60 /* this is the client */
61
17d31b38 62 if (!am_sender && send_stats) {
23c5aef1 63 int64 r;
a800434a 64 stats.total_written = read_longint(f);
23c5aef1
DD
65 /* store total_read in a temporary, read_longint changes it */
66 r = read_longint(f);
a800434a 67 stats.total_size = read_longint(f);
23c5aef1 68 stats.total_read = r;
a800434a
AT
69 }
70
71 if (do_stats) {
17d31b38
DD
72 if (!am_sender && !send_stats) {
73 /* missing the bytes written by the generator */
74 rprintf(FINFO, "\nCannot show stats as receiver because protocol version is less than 20\n");
75 rprintf(FINFO, "Use --stats -v to show stats\n");
76 return;
77 }
1f658d42
AT
78 rprintf(FINFO,"\nNumber of files: %d\n", stats.num_files);
79 rprintf(FINFO,"Number of files transferred: %d\n",
a800434a 80 stats.num_transferred_files);
1f658d42 81 rprintf(FINFO,"Total file size: %.0f bytes\n",
a800434a 82 (double)stats.total_size);
1f658d42 83 rprintf(FINFO,"Total transferred file size: %.0f bytes\n",
a800434a 84 (double)stats.total_transferred_size);
1f658d42 85 rprintf(FINFO,"Literal data: %.0f bytes\n",
a800434a 86 (double)stats.literal_data);
1f658d42 87 rprintf(FINFO,"Matched data: %.0f bytes\n",
a800434a 88 (double)stats.matched_data);
1f658d42
AT
89 rprintf(FINFO,"File list size: %d\n", stats.flist_size);
90 rprintf(FINFO,"Total bytes written: %.0f\n",
a800434a 91 (double)stats.total_written);
1f658d42 92 rprintf(FINFO,"Total bytes read: %.0f\n\n",
a800434a 93 (double)stats.total_read);
7a6421fa
AT
94 }
95
e19452a9
DD
96 if (verbose || do_stats) {
97 rprintf(FINFO,"wrote %.0f bytes read %.0f bytes %.2f bytes/sec\n",
98 (double)stats.total_written,
99 (double)stats.total_read,
100 (stats.total_written+stats.total_read)/(0.5 + (t-starttime)));
101 rprintf(FINFO,"total size is %.0f speedup is %.2f\n",
102 (double)stats.total_size,
103 (1.0*stats.total_size)/(stats.total_written+stats.total_read));
104 }
fc8a6b97
AT
105
106 fflush(stdout);
107 fflush(stderr);
c627d613
AT
108}
109
110
e3cd198f 111static int do_cmd(char *cmd,char *machine,char *user,char *path,int *f_in,int *f_out)
c627d613 112{
366345fe
AT
113 char *args[100];
114 int i,argc=0, ret;
115 char *tok,*dir=NULL;
7a6421fa
AT
116 extern int local_server;
117 extern char *rsync_path;
366345fe
AT
118
119 if (!local_server) {
120 if (!cmd)
121 cmd = getenv(RSYNC_RSH_ENV);
122 if (!cmd)
123 cmd = RSYNC_RSH;
124 cmd = strdup(cmd);
125 if (!cmd)
126 goto oom;
127
128 for (tok=strtok(cmd," ");tok;tok=strtok(NULL," ")) {
129 args[argc++] = tok;
130 }
c627d613 131
7b8356d0 132#if HAVE_REMSH
366345fe
AT
133 /* remsh (on HPUX) takes the arguments the other way around */
134 args[argc++] = machine;
135 if (user) {
136 args[argc++] = "-l";
137 args[argc++] = user;
138 }
7b8356d0 139#else
366345fe
AT
140 if (user) {
141 args[argc++] = "-l";
142 args[argc++] = user;
143 }
144 args[argc++] = machine;
7b8356d0 145#endif
c627d613 146
366345fe 147 args[argc++] = rsync_path;
c627d613 148
366345fe
AT
149 server_options(args,&argc);
150 }
c627d613 151
366345fe 152 args[argc++] = ".";
76076c4b 153
366345fe
AT
154 if (path && *path)
155 args[argc++] = path;
c627d613 156
366345fe 157 args[argc] = NULL;
c627d613 158
366345fe 159 if (verbose > 3) {
9486289c 160 rprintf(FINFO,"cmd=");
366345fe 161 for (i=0;i<argc;i++)
9486289c
AT
162 rprintf(FINFO,"%s ",args[i]);
163 rprintf(FINFO,"\n");
366345fe
AT
164 }
165
166 if (local_server) {
167 ret = local_child(argc, args, f_in, f_out);
168 } else {
169 ret = piped_child(args,f_in,f_out);
170 }
c627d613 171
366345fe 172 if (dir) free(dir);
82306bf6 173
366345fe 174 return ret;
c627d613
AT
175
176oom:
366345fe
AT
177 out_of_memory("do_cmd");
178 return 0; /* not reached */
c627d613
AT
179}
180
181
182
183
184static char *get_local_name(struct file_list *flist,char *name)
185{
7a6421fa
AT
186 STRUCT_STAT st;
187 extern int orig_umask;
c627d613 188
c95da96a
AT
189 if (verbose > 2)
190 rprintf(FINFO,"get_local_name count=%d %s\n",
1f0610ef
DD
191 flist->count, NS(name));
192
193 if (!name)
194 return NULL;
c95da96a 195
1ff5450d
AT
196 if (do_stat(name,&st) == 0) {
197 if (S_ISDIR(st.st_mode)) {
5243c216
AT
198 if (!push_dir(name, 0)) {
199 rprintf(FERROR,"push_dir %s : %s (1)\n",
1ff5450d 200 name,strerror(errno));
65417579 201 exit_cleanup(RERR_FILESELECT);
1ff5450d
AT
202 }
203 return NULL;
204 }
205 if (flist->count > 1) {
206 rprintf(FERROR,"ERROR: destination must be a directory when copying more than 1 file\n");
65417579 207 exit_cleanup(RERR_FILESELECT);
1ff5450d
AT
208 }
209 return name;
210 }
211
212 if (flist->count == 1)
213 return name;
214
1ff5450d
AT
215 if (do_mkdir(name,0777 & ~orig_umask) != 0) {
216 rprintf(FERROR,"mkdir %s : %s (1)\n",name,strerror(errno));
65417579 217 exit_cleanup(RERR_FILEIO);
1ff5450d 218 } else {
b536f47e
AT
219 if (verbose > 0)
220 rprintf(FINFO,"created directory %s\n",name);
1ff5450d
AT
221 }
222
5243c216
AT
223 if (!push_dir(name, 0)) {
224 rprintf(FERROR,"push_dir %s : %s (2)\n",
225 name,strerror(errno));
65417579 226 exit_cleanup(RERR_FILESELECT);
1ff5450d
AT
227 }
228
229 return NULL;
c627d613
AT
230}
231
232
233
234
9486289c 235static void do_server_sender(int f_in, int f_out, int argc,char *argv[])
c627d613 236{
7a6421fa
AT
237 int i;
238 struct file_list *flist;
239 char *dir = argv[0];
240 extern int relative_paths;
7a6421fa 241 extern int recurse;
c627d613 242
7a6421fa
AT
243 if (verbose > 2)
244 rprintf(FINFO,"server_sender starting pid=%d\n",(int)getpid());
c627d613 245
5243c216
AT
246 if (!relative_paths && !push_dir(dir, 0)) {
247 rprintf(FERROR,"push_dir %s: %s (3)\n",dir,strerror(errno));
65417579 248 exit_cleanup(RERR_FILESELECT);
7a6421fa
AT
249 }
250 argc--;
251 argv++;
c627d613 252
7a6421fa
AT
253 if (strcmp(dir,".")) {
254 int l = strlen(dir);
255 if (strcmp(dir,"/") == 0)
256 l = 0;
257 for (i=0;i<argc;i++)
258 argv[i] += l+1;
259 }
c627d613 260
7a6421fa
AT
261 if (argc == 0 && recurse) {
262 argc=1;
263 argv--;
264 argv[0] = ".";
265 }
266
3eb38818
AT
267 set_nonblocking(f_out);
268 if (f_in != f_out)
269 set_nonblocking(f_in);
270
7a6421fa 271 flist = send_file_list(f_out,argc,argv);
8d9dc9f9
AT
272 if (!flist || flist->count == 0) {
273 exit_cleanup(0);
274 }
275
7a6421fa
AT
276 send_files(flist,f_out,f_in);
277 report(f_out);
8d9dc9f9 278 io_flush();
7a6421fa 279 exit_cleanup(0);
c627d613
AT
280}
281
282
dc5ddbcc
AT
283static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
284{
d186eb1a
AT
285 int pid;
286 int status=0;
287 int recv_pipe[2];
288 extern int preserve_hard_links;
dc5ddbcc 289
d186eb1a
AT
290 if (preserve_hard_links)
291 init_hard_links(flist);
dc5ddbcc 292
d186eb1a
AT
293 if (pipe(recv_pipe) < 0) {
294 rprintf(FERROR,"pipe failed in do_recv\n");
65417579 295 exit_cleanup(RERR_SOCKETIO);
d186eb1a 296 }
c6e7fcb4 297
8d9dc9f9 298 io_flush();
c6e7fcb4 299
d186eb1a 300 if ((pid=do_fork()) == 0) {
e08c9610
AT
301 close(recv_pipe[0]);
302 if (f_in != f_out) close(f_out);
303
e1b3d5c4 304 set_nonblocking(f_in);
3eb38818 305 set_nonblocking(recv_pipe[1]);
e1b3d5c4 306
e08c9610 307 recv_files(f_in,flist,local_name,recv_pipe[1]);
ba5e128d 308 report(f_in);
e08c9610 309
8d9dc9f9
AT
310 io_flush();
311 _exit(0);
d186eb1a 312 }
dc5ddbcc 313
e08c9610
AT
314 close(recv_pipe[1]);
315 io_close_input(f_in);
316 if (f_in != f_out) close(f_in);
e1b3d5c4
AT
317
318 set_nonblocking(f_out);
3eb38818 319 set_nonblocking(recv_pipe[0]);
e1b3d5c4 320
b3e10ed7
AT
321 io_start_buffering(f_out);
322
e08c9610 323 generate_files(f_out,flist,local_name,recv_pipe[0]);
8d9dc9f9
AT
324
325 io_flush();
d186eb1a 326 waitpid(pid, &status, 0);
d186eb1a 327 return status;
dc5ddbcc
AT
328}
329
c627d613 330
9486289c 331static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
c627d613 332{
7a6421fa
AT
333 int status;
334 struct file_list *flist;
335 char *local_name=NULL;
336 char *dir = NULL;
337 extern int delete_mode;
b33b791e 338 extern int delete_excluded;
7a6421fa 339 extern int am_daemon;
f0fca04e 340
7a6421fa
AT
341 if (verbose > 2)
342 rprintf(FINFO,"server_recv(%d) starting pid=%d\n",argc,(int)getpid());
343
7a6421fa
AT
344 if (argc > 0) {
345 dir = argv[0];
346 argc--;
347 argv++;
5243c216
AT
348 if (!am_daemon && !push_dir(dir, 0)) {
349 rprintf(FERROR,"push_dir %s : %s (4)\n",
7a6421fa 350 dir,strerror(errno));
65417579 351 exit_cleanup(RERR_FILESELECT);
7a6421fa
AT
352 }
353 }
c627d613 354
b33b791e 355 if (delete_mode && !delete_excluded)
7a6421fa 356 recv_exclude_list(f_in);
c627d613 357
7a6421fa
AT
358 flist = recv_file_list(f_in);
359 if (!flist || flist->count == 0) {
8d9dc9f9 360 rprintf(FERROR,"server_recv: nothing to do\n");
65417579 361 exit_cleanup(RERR_FILESELECT);
7a6421fa
AT
362 }
363
364 if (argc > 0) {
365 if (strcmp(dir,".")) {
366 argv[0] += strlen(dir);
367 if (argv[0][0] == '/') argv[0]++;
368 }
369 local_name = get_local_name(flist,argv[0]);
370 }
c627d613 371
7a6421fa
AT
372 status = do_recv(f_in,f_out,flist,local_name);
373 exit_cleanup(status);
c627d613
AT
374}
375
376
9486289c 377void start_server(int f_in, int f_out, int argc, char *argv[])
366345fe 378{
7a6421fa
AT
379 extern int cvs_exclude;
380 extern int am_sender;
381
3eb38818
AT
382 set_nonblocking(f_out);
383 if (f_in != f_out)
384 set_nonblocking(f_in);
385
7a6421fa 386 setup_protocol(f_out, f_in);
3eb38818 387
7a6421fa
AT
388 if (am_sender) {
389 recv_exclude_list(f_in);
390 if (cvs_exclude)
391 add_cvs_excludes();
392 do_server_sender(f_in, f_out, argc, argv);
393 } else {
394 do_server_recv(f_in, f_out, argc, argv);
395 }
396 exit_cleanup(0);
366345fe
AT
397}
398
3591c066 399int client_run(int f_in, int f_out, int pid, int argc, char *argv[])
9486289c
AT
400{
401 struct file_list *flist;
402 int status = 0, status2 = 0;
403 char *local_name = NULL;
7a6421fa 404 extern int am_sender;
f7632fc6 405 extern int list_only;
9486289c
AT
406
407 setup_protocol(f_out,f_in);
408
409 if (am_sender) {
7a6421fa
AT
410 extern int cvs_exclude;
411 extern int delete_mode;
b33b791e 412 extern int delete_excluded;
9486289c
AT
413 if (cvs_exclude)
414 add_cvs_excludes();
b33b791e 415 if (delete_mode && !delete_excluded)
9486289c
AT
416 send_exclude_list(f_out);
417 flist = send_file_list(f_out,argc,argv);
418 if (verbose > 3)
419 rprintf(FINFO,"file list sent\n");
e1b3d5c4
AT
420
421 set_nonblocking(f_out);
422 if (f_in != f_out)
423 set_nonblocking(f_in);
424
9486289c
AT
425 send_files(flist,f_out,f_in);
426 if (pid != -1) {
427 if (verbose > 3)
8d9dc9f9
AT
428 rprintf(FINFO,"client_run waiting on %d\n",pid);
429 io_flush();
9486289c
AT
430 waitpid(pid, &status, 0);
431 }
432 report(-1);
433 exit_cleanup(status);
434 }
f7632fc6
AT
435
436 if (argc == 0) list_only = 1;
9486289c
AT
437
438 send_exclude_list(f_out);
439
440 flist = recv_file_list(f_in);
441 if (!flist || flist->count == 0) {
8d9dc9f9 442 rprintf(FINFO,"client: nothing to do\n");
9486289c
AT
443 exit_cleanup(0);
444 }
445
446 local_name = get_local_name(flist,argv[0]);
447
448 status2 = do_recv(f_in,f_out,flist,local_name);
449
9486289c 450 if (pid != -1) {
8d9dc9f9
AT
451 if (verbose > 3)
452 rprintf(FINFO,"client_run2 waiting on %d\n",pid);
453 io_flush();
9486289c
AT
454 waitpid(pid, &status, 0);
455 }
456
457 return status | status2;
458}
459
ca6c93f8
AT
460static char *find_colon(char *s)
461{
462 char *p, *p2;
463
464 p = strchr(s,':');
465 if (!p) return NULL;
466
467 /* now check to see if there is a / in the string before the : - if there is then
468 discard the colon on the assumption that the : is part of a filename */
469 p2 = strchr(s,'/');
470 if (p2 && p2 < p) return NULL;
471
472 return p;
473}
9486289c 474
fc8a6b97 475static int start_client(int argc, char *argv[])
5d6bcd44
AT
476{
477 char *p;
478 char *shell_machine = NULL;
479 char *shell_path = NULL;
480 char *shell_user = NULL;
fc8a6b97 481 int pid, ret;
5d6bcd44 482 int f_in,f_out;
7a6421fa
AT
483 extern int local_server;
484 extern int am_sender;
485 extern char *shell_cmd;
2acf81eb 486 extern int rsync_port;
5d6bcd44 487
f7632fc6
AT
488 if (strncasecmp(URL_PREFIX, argv[0], strlen(URL_PREFIX)) == 0) {
489 char *host, *path;
490
491 host = argv[0] + strlen(URL_PREFIX);
492 p = strchr(host,'/');
493 if (p) {
494 *p = 0;
495 path = p+1;
496 } else {
497 path="";
498 }
2acf81eb
DD
499 p = strchr(host,':');
500 if (p) {
501 rsync_port = atoi(p+1);
502 *p = 0;
503 }
f7632fc6
AT
504 return start_socket_client(host, path, argc-1, argv+1);
505 }
506
ca6c93f8 507 p = find_colon(argv[0]);
5d6bcd44
AT
508
509 if (p) {
9486289c
AT
510 if (p[1] == ':') {
511 *p = 0;
512 return start_socket_client(argv[0], p+2, argc-1, argv+1);
513 }
3591c066 514
f7632fc6 515 if (argc < 1) {
3591c066 516 usage(FERROR);
65417579 517 exit_cleanup(RERR_SYNTAX);
3591c066
AT
518 }
519
5d6bcd44
AT
520 am_sender = 0;
521 *p = 0;
522 shell_machine = argv[0];
523 shell_path = p+1;
524 argc--;
525 argv++;
526 } else {
527 am_sender = 1;
9486289c 528
ca6c93f8 529 p = find_colon(argv[argc-1]);
5d6bcd44
AT
530 if (!p) {
531 local_server = 1;
9486289c
AT
532 } else if (p[1] == ':') {
533 *p = 0;
534 return start_socket_client(argv[argc-1], p+2, argc-1, argv);
5d6bcd44 535 }
3591c066
AT
536
537 if (argc < 2) {
538 usage(FERROR);
65417579 539 exit_cleanup(RERR_SYNTAX);
3591c066 540 }
9486289c 541
5d6bcd44
AT
542 if (local_server) {
543 shell_machine = NULL;
544 shell_path = argv[argc-1];
545 } else {
546 *p = 0;
547 shell_machine = argv[argc-1];
548 shell_path = p+1;
549 }
550 argc--;
551 }
552
553 if (shell_machine) {
554 p = strchr(shell_machine,'@');
555 if (p) {
556 *p = 0;
557 shell_user = shell_machine;
558 shell_machine = p+1;
559 }
560 }
561
562 if (verbose > 3) {
9486289c 563 rprintf(FINFO,"cmd=%s machine=%s user=%s path=%s\n",
5d6bcd44
AT
564 shell_cmd?shell_cmd:"",
565 shell_machine?shell_machine:"",
566 shell_user?shell_user:"",
567 shell_path?shell_path:"");
568 }
569
f7632fc6 570 if (!am_sender && argc > 1) {
5d6bcd44 571 usage(FERROR);
65417579 572 exit_cleanup(RERR_SYNTAX);
5d6bcd44
AT
573 }
574
575 pid = do_cmd(shell_cmd,shell_machine,shell_user,shell_path,&f_in,&f_out);
576
fc8a6b97
AT
577 ret = client_run(f_in, f_out, pid, argc, argv);
578
579 fflush(stdout);
580 fflush(stderr);
581
582 return ret;
5d6bcd44
AT
583}
584
366345fe 585
6e4fb64e 586static RETSIGTYPE sigusr1_handler(int val) {
65417579 587 exit_cleanup(RERR_SIGNAL);
82306bf6
AT
588}
589
5d6bcd44 590int main(int argc,char *argv[])
7a6421fa
AT
591{
592 extern int am_root;
593 extern int orig_umask;
594 extern int dry_run;
595 extern int am_daemon;
596 extern int am_server;
5d6bcd44 597
7a6421fa 598 signal(SIGUSR1, sigusr1_handler);
5d6bcd44 599
7a6421fa
AT
600 starttime = time(NULL);
601 am_root = (getuid() == 0);
c627d613 602
a800434a
AT
603 memset(&stats, 0, sizeof(stats));
604
df5e03da
AT
605 if (argc < 2) {
606 usage(FERROR);
65417579 607 exit_cleanup(RERR_SYNTAX);
df5e03da
AT
608 }
609
7a6421fa
AT
610 /* we set a 0 umask so that correct file permissions can be
611 carried across */
612 orig_umask = (int)umask(0);
5d6bcd44 613
b86f0cef 614 if (!parse_arguments(argc, argv, 1)) {
65417579 615 exit_cleanup(RERR_SYNTAX);
b11ed3b1 616 }
5d6bcd44 617
7a6421fa
AT
618 argc -= optind;
619 argv += optind;
620 optind = 0;
c627d613 621
7a6421fa
AT
622 signal(SIGCHLD,SIG_IGN);
623 signal(SIGINT,SIGNAL_CAST sig_int);
624 signal(SIGPIPE,SIGNAL_CAST sig_int);
625 signal(SIGHUP,SIGNAL_CAST sig_int);
8638dd48 626 signal(SIGTERM,SIGNAL_CAST sig_int);
6b83141d 627
c226b7c2
DD
628 /* Initialize push_dir here because on some old systems getcwd
629 (implemented by forking "pwd" and reading its output) doesn't
630 work when there are other child processes. Also, on all systems
631 that implement getcwd that way "pwd" can't be found after chroot. */
632 push_dir(NULL,0);
633
7a6421fa
AT
634 if (am_daemon) {
635 return daemon_main();
636 }
f0fca04e 637
08ac228f
AT
638 if (argc < 1) {
639 usage(FERROR);
65417579 640 exit_cleanup(RERR_SYNTAX);
08ac228f
AT
641 }
642
7a6421fa
AT
643 if (dry_run)
644 verbose = MAX(verbose,1);
c627d613 645
cbbe4892 646#ifndef SUPPORT_LINKS
7a6421fa
AT
647 if (!am_server && preserve_links) {
648 rprintf(FERROR,"ERROR: symbolic links not supported\n");
65417579 649 exit_cleanup(RERR_UNSUPPORTED);
7a6421fa 650 }
cbbe4892
AT
651#endif
652
7a6421fa
AT
653 if (am_server) {
654 start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
655 }
c627d613 656
7a6421fa 657 return start_client(argc, argv);
c627d613 658}
82306bf6 659