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