Another try at socklen_t: just check for it, and otherwise use int.
[rsync/rsync.git] / main.c
... / ...
CommitLineData
1/* -*- c-file-style: "linux" -*-
2
3 Copyright (C) 1996-2001 by Andrew Tridgell <tridge@samba.org>
4 Copyright (C) Paul Mackerras 1996
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19*/
20
21#include "rsync.h"
22
23time_t starttime = 0;
24
25struct stats stats;
26
27extern int verbose;
28
29
30/****************************************************************************
31wait for a process to exit, calling io_flush while waiting
32****************************************************************************/
33void wait_process(pid_t pid, int *status)
34{
35 while (waitpid(pid, status, WNOHANG) == 0) {
36 msleep(20);
37 io_flush();
38 }
39
40 /* TODO: If the child exited on a signal, then log an
41 * appropriate error message. Perhaps we should also accept a
42 * message describing the purpose of the child. Also indicate
43 * this to the caller so that thhey know something went
44 * wrong. */
45 *status = WEXITSTATUS(*status);
46}
47
48static void report(int f)
49{
50 time_t t = time(NULL);
51 extern int am_server;
52 extern int am_sender;
53 extern int am_daemon;
54 extern int do_stats;
55 extern int remote_version;
56 int send_stats;
57
58 if (am_daemon) {
59 log_exit(0, __FILE__, __LINE__);
60 if (f == -1 || !am_sender) return;
61 }
62
63 send_stats = verbose || (remote_version >= 20);
64 if (am_server) {
65 if (am_sender && send_stats) {
66 int64 w;
67 /* store total_written in a temporary
68 because write_longint changes it */
69 w = stats.total_written;
70 write_longint(f,stats.total_read);
71 write_longint(f,w);
72 write_longint(f,stats.total_size);
73 }
74 return;
75 }
76
77 /* this is the client */
78
79 if (!am_sender && send_stats) {
80 int64 r;
81 stats.total_written = read_longint(f);
82 /* store total_read in a temporary, read_longint changes it */
83 r = read_longint(f);
84 stats.total_size = read_longint(f);
85 stats.total_read = r;
86 }
87
88 if (do_stats) {
89 if (!am_sender && !send_stats) {
90 /* missing the bytes written by the generator */
91 rprintf(FINFO, "\nCannot show stats as receiver because remote protocol version is less than 20\n");
92 rprintf(FINFO, "Use --stats -v to show stats\n");
93 return;
94 }
95 rprintf(FINFO,"\nNumber of files: %d\n", stats.num_files);
96 rprintf(FINFO,"Number of files transferred: %d\n",
97 stats.num_transferred_files);
98 rprintf(FINFO,"Total file size: %.0f bytes\n",
99 (double)stats.total_size);
100 rprintf(FINFO,"Total transferred file size: %.0f bytes\n",
101 (double)stats.total_transferred_size);
102 rprintf(FINFO,"Literal data: %.0f bytes\n",
103 (double)stats.literal_data);
104 rprintf(FINFO,"Matched data: %.0f bytes\n",
105 (double)stats.matched_data);
106 rprintf(FINFO,"File list size: %d\n", stats.flist_size);
107 rprintf(FINFO,"Total bytes written: %.0f\n",
108 (double)stats.total_written);
109 rprintf(FINFO,"Total bytes read: %.0f\n\n",
110 (double)stats.total_read);
111 }
112
113 if (verbose || do_stats) {
114 rprintf(FINFO,"wrote %.0f bytes read %.0f bytes %.2f bytes/sec\n",
115 (double)stats.total_written,
116 (double)stats.total_read,
117 (stats.total_written+stats.total_read)/(0.5 + (t-starttime)));
118 rprintf(FINFO,"total size is %.0f speedup is %.2f\n",
119 (double)stats.total_size,
120 (1.0*stats.total_size)/(stats.total_written+stats.total_read));
121 }
122
123 fflush(stdout);
124 fflush(stderr);
125}
126
127
128/* Start the remote shell. cmd may be NULL to use the default. */
129static pid_t do_cmd(char *cmd,char *machine,char *user,char *path,int *f_in,int *f_out)
130{
131 char *args[100];
132 int i,argc=0;
133 pid_t ret;
134 char *tok,*dir=NULL;
135 extern int local_server;
136 extern char *rsync_path;
137 extern int blocking_io;
138
139 if (!local_server) {
140 if (!cmd)
141 cmd = getenv(RSYNC_RSH_ENV);
142 if (!cmd)
143 cmd = RSYNC_RSH;
144 cmd = strdup(cmd);
145 if (!cmd)
146 goto oom;
147
148 for (tok=strtok(cmd," ");tok;tok=strtok(NULL," ")) {
149 args[argc++] = tok;
150 }
151
152#if HAVE_REMSH
153 /* remsh (on HPUX) takes the arguments the other way around */
154 args[argc++] = machine;
155 if (user) {
156 args[argc++] = "-l";
157 args[argc++] = user;
158 }
159#else
160 if (user) {
161 args[argc++] = "-l";
162 args[argc++] = user;
163 }
164 args[argc++] = machine;
165#endif
166
167 args[argc++] = rsync_path;
168
169 server_options(args,&argc);
170
171
172 if (strcmp(cmd, RSYNC_RSH) == 0) blocking_io = 1;
173 }
174
175 args[argc++] = ".";
176
177 if (path && *path)
178 args[argc++] = path;
179
180 args[argc] = NULL;
181
182 if (verbose > 3) {
183 rprintf(FINFO,"cmd=");
184 for (i=0;i<argc;i++)
185 rprintf(FINFO,"%s ",args[i]);
186 rprintf(FINFO,"\n");
187 }
188
189 if (local_server) {
190 ret = local_child(argc, args, f_in, f_out);
191 } else {
192 ret = piped_child(args,f_in,f_out);
193 }
194
195 if (dir) free(dir);
196
197 return ret;
198
199oom:
200 out_of_memory("do_cmd");
201 return 0; /* not reached */
202}
203
204
205
206
207static char *get_local_name(struct file_list *flist,char *name)
208{
209 STRUCT_STAT st;
210 extern int orig_umask;
211
212 if (verbose > 2)
213 rprintf(FINFO,"get_local_name count=%d %s\n",
214 flist->count, NS(name));
215
216 if (!name)
217 return NULL;
218
219 if (do_stat(name,&st) == 0) {
220 if (S_ISDIR(st.st_mode)) {
221 if (!push_dir(name, 0)) {
222 rprintf(FERROR,"push_dir %s : %s (1)\n",
223 name,strerror(errno));
224 exit_cleanup(RERR_FILESELECT);
225 }
226 return NULL;
227 }
228 if (flist->count > 1) {
229 rprintf(FERROR,"ERROR: destination must be a directory when copying more than 1 file\n");
230 exit_cleanup(RERR_FILESELECT);
231 }
232 return name;
233 }
234
235 if (flist->count <= 1)
236 return name;
237
238 if (do_mkdir(name,0777 & ~orig_umask) != 0) {
239 rprintf(FERROR,"mkdir %s : %s (1)\n",name,strerror(errno));
240 exit_cleanup(RERR_FILEIO);
241 } else {
242 if (verbose > 0)
243 rprintf(FINFO,"created directory %s\n",name);
244 }
245
246 if (!push_dir(name, 0)) {
247 rprintf(FERROR,"push_dir %s : %s (2)\n",
248 name,strerror(errno));
249 exit_cleanup(RERR_FILESELECT);
250 }
251
252 return NULL;
253}
254
255
256
257
258static void do_server_sender(int f_in, int f_out, int argc,char *argv[])
259{
260 int i;
261 struct file_list *flist;
262 char *dir = argv[0];
263 extern int relative_paths;
264 extern int recurse;
265 extern int remote_version;
266
267 if (verbose > 2)
268 rprintf(FINFO,"server_sender starting pid=%d\n",(int)getpid());
269
270 if (!relative_paths && !push_dir(dir, 0)) {
271 rprintf(FERROR,"push_dir %s: %s (3)\n",dir,strerror(errno));
272 exit_cleanup(RERR_FILESELECT);
273 }
274 argc--;
275 argv++;
276
277 if (strcmp(dir,".")) {
278 int l = strlen(dir);
279 if (strcmp(dir,"/") == 0)
280 l = 0;
281 for (i=0;i<argc;i++)
282 argv[i] += l+1;
283 }
284
285 if (argc == 0 && recurse) {
286 argc=1;
287 argv--;
288 argv[0] = ".";
289 }
290
291 flist = send_file_list(f_out,argc,argv);
292 if (!flist || flist->count == 0) {
293 exit_cleanup(0);
294 }
295
296 send_files(flist,f_out,f_in);
297 io_flush();
298 report(f_out);
299 if (remote_version >= 24) {
300 /* final goodbye message */
301 read_int(f_in);
302 }
303 io_flush();
304 exit_cleanup(0);
305}
306
307
308static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
309{
310 int pid;
311 int status=0;
312 int recv_pipe[2];
313 int error_pipe[2];
314 extern int preserve_hard_links;
315 extern int delete_after;
316 extern int recurse;
317 extern int delete_mode;
318 extern int remote_version;
319
320 if (preserve_hard_links)
321 init_hard_links(flist);
322
323 if (!delete_after) {
324 /* I moved this here from recv_files() to prevent a race condition */
325 if (recurse && delete_mode && !local_name && flist->count>0) {
326 delete_files(flist);
327 }
328 }
329
330 if (fd_pair(recv_pipe) < 0) {
331 rprintf(FERROR,"pipe failed in do_recv\n");
332 exit_cleanup(RERR_SOCKETIO);
333 }
334
335 if (fd_pair(error_pipe) < 0) {
336 rprintf(FERROR,"error pipe failed in do_recv\n");
337 exit_cleanup(RERR_SOCKETIO);
338 }
339
340 io_flush();
341
342 if ((pid=do_fork()) == 0) {
343 close(recv_pipe[0]);
344 close(error_pipe[0]);
345 if (f_in != f_out) close(f_out);
346
347 /* we can't let two processes write to the socket at one time */
348 io_multiplexing_close();
349
350 /* set place to send errors */
351 set_error_fd(error_pipe[1]);
352
353 recv_files(f_in,flist,local_name,recv_pipe[1]);
354 io_flush();
355 report(f_in);
356
357 write_int(recv_pipe[1],1);
358 close(recv_pipe[1]);
359 io_flush();
360 /* finally we go to sleep until our parent kills us
361 with a USR2 signal. We sleep for a short time as on
362 some OSes a signal won't interrupt a sleep! */
363 while (msleep(20))
364 ;
365 }
366
367 close(recv_pipe[1]);
368 close(error_pipe[1]);
369 if (f_in != f_out) close(f_in);
370
371 io_start_buffering(f_out);
372
373 io_set_error_fd(error_pipe[0]);
374
375 generate_files(f_out,flist,local_name,recv_pipe[0]);
376
377 read_int(recv_pipe[0]);
378 close(recv_pipe[0]);
379 if (remote_version >= 24) {
380 /* send a final goodbye message */
381 write_int(f_out, -1);
382 }
383 io_flush();
384
385 kill(pid, SIGUSR2);
386 wait_process(pid, &status);
387 return status;
388}
389
390
391static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
392{
393 int status;
394 struct file_list *flist;
395 char *local_name=NULL;
396 char *dir = NULL;
397 extern int delete_mode;
398 extern int delete_excluded;
399 extern int am_daemon;
400 extern int module_id;
401 extern int am_sender;
402
403 if (verbose > 2)
404 rprintf(FINFO,"server_recv(%d) starting pid=%d\n",argc,(int)getpid());
405
406 if (am_daemon && lp_read_only(module_id) && !am_sender) {
407 rprintf(FERROR,"ERROR: module is read only\n");
408 exit_cleanup(RERR_SYNTAX);
409 return;
410 }
411
412
413 if (argc > 0) {
414 dir = argv[0];
415 argc--;
416 argv++;
417 if (!am_daemon && !push_dir(dir, 0)) {
418 rprintf(FERROR,"push_dir %s : %s (4)\n",
419 dir,strerror(errno));
420 exit_cleanup(RERR_FILESELECT);
421 }
422 }
423
424 if (delete_mode && !delete_excluded)
425 recv_exclude_list(f_in);
426
427 flist = recv_file_list(f_in);
428 if (!flist) {
429 rprintf(FERROR,"server_recv: recv_file_list error\n");
430 exit_cleanup(RERR_FILESELECT);
431 }
432
433 if (argc > 0) {
434 if (strcmp(dir,".")) {
435 argv[0] += strlen(dir);
436 if (argv[0][0] == '/') argv[0]++;
437 }
438 local_name = get_local_name(flist,argv[0]);
439 }
440
441 status = do_recv(f_in,f_out,flist,local_name);
442 exit_cleanup(status);
443}
444
445
446void start_server(int f_in, int f_out, int argc, char *argv[])
447{
448 extern int cvs_exclude;
449 extern int am_sender;
450 extern int remote_version;
451
452 setup_protocol(f_out, f_in);
453
454 set_nonblocking(f_in);
455 set_nonblocking(f_out);
456
457 if (remote_version >= 23)
458 io_start_multiplex_out(f_out);
459
460 if (am_sender) {
461 recv_exclude_list(f_in);
462 if (cvs_exclude)
463 add_cvs_excludes();
464 do_server_sender(f_in, f_out, argc, argv);
465 } else {
466 do_server_recv(f_in, f_out, argc, argv);
467 }
468 exit_cleanup(0);
469}
470
471
472/*
473 * This is called once the connection has been negotiated. It is used
474 * for rsyncd, remote-shell, and local connections.
475 */
476int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[])
477{
478 struct file_list *flist;
479 int status = 0, status2 = 0;
480 char *local_name = NULL;
481 extern int am_sender;
482 extern int remote_version;
483 extern pid_t cleanup_child_pid;
484
485 cleanup_child_pid = pid;
486
487 set_nonblocking(f_in);
488 set_nonblocking(f_out);
489
490 setup_protocol(f_out,f_in);
491
492 if (remote_version >= 23)
493 io_start_multiplex_in(f_in);
494
495 if (am_sender) {
496 extern int cvs_exclude;
497 extern int delete_mode;
498 extern int delete_excluded;
499 if (cvs_exclude)
500 add_cvs_excludes();
501 if (delete_mode && !delete_excluded)
502 send_exclude_list(f_out);
503 flist = send_file_list(f_out,argc,argv);
504 if (verbose > 3)
505 rprintf(FINFO,"file list sent\n");
506
507 send_files(flist,f_out,f_in);
508 if (remote_version >= 24) {
509 /* final goodbye message */
510 read_int(f_in);
511 }
512 if (pid != -1) {
513 if (verbose > 3)
514 rprintf(FINFO,"client_run waiting on %d\n",pid);
515 io_flush();
516 wait_process(pid, &status);
517 }
518 report(-1);
519 exit_cleanup(status);
520 }
521
522 if (argc == 0) {
523 extern int list_only;
524 list_only = 1;
525 }
526
527 send_exclude_list(f_out);
528
529 flist = recv_file_list(f_in);
530 if (!flist || flist->count == 0) {
531 rprintf(FINFO, "client: nothing to do: "
532 "perhaps you need to specify some filenames or "
533 "the --recursive option?\n");
534 exit_cleanup(0);
535 }
536
537 local_name = get_local_name(flist,argv[0]);
538
539 status2 = do_recv(f_in,f_out,flist,local_name);
540
541 if (pid != -1) {
542 if (verbose > 3)
543 rprintf(FINFO,"client_run2 waiting on %d\n",pid);
544 io_flush();
545 wait_process(pid, &status);
546 }
547
548 return MAX(status, status2);
549}
550
551static char *find_colon(char *s)
552{
553 char *p, *p2;
554
555 p = strchr(s,':');
556 if (!p) return NULL;
557
558 /* now check to see if there is a / in the string before the : - if there is then
559 discard the colon on the assumption that the : is part of a filename */
560 p2 = strchr(s,'/');
561 if (p2 && p2 < p) return NULL;
562
563 return p;
564}
565
566
567/*
568 * Start a client for either type of remote connection. Work out
569 * whether the arguments request a remote shell or rsyncd connection,
570 * and call the appropriate connection function, then run_client.
571 */
572static int start_client(int argc, char *argv[])
573{
574 char *p;
575 char *shell_machine = NULL;
576 char *shell_path = NULL;
577 char *shell_user = NULL;
578 int ret;
579 pid_t pid;
580 int f_in,f_out;
581 extern int local_server;
582 extern int am_sender;
583 extern char *shell_cmd;
584 extern int rsync_port;
585 extern int whole_file;
586 char *argv0 = strdup(argv[0]);
587
588 if (strncasecmp(URL_PREFIX, argv0, strlen(URL_PREFIX)) == 0) {
589 char *host, *path;
590
591 host = argv0 + strlen(URL_PREFIX);
592 p = strchr(host,'/');
593 if (p) {
594 *p = 0;
595 path = p+1;
596 } else {
597 path="";
598 }
599 p = strchr(host,':');
600 if (p) {
601 rsync_port = atoi(p+1);
602 *p = 0;
603 }
604 return start_socket_client(host, path, argc-1, argv+1);
605 }
606
607 p = find_colon(argv0);
608
609 if (p) {
610 if (p[1] == ':') {
611 *p = 0;
612 return start_socket_client(argv0, p+2, argc-1, argv+1);
613 }
614
615 if (argc < 1) {
616 usage(FERROR);
617 exit_cleanup(RERR_SYNTAX);
618 }
619
620 am_sender = 0;
621 *p = 0;
622 shell_machine = argv0;
623 shell_path = p+1;
624 argc--;
625 argv++;
626 } else {
627 am_sender = 1;
628
629 p = find_colon(argv[argc-1]);
630 if (!p) {
631 local_server = 1;
632 /* disable "rsync algorithm" when both sides local */
633 whole_file = 1;
634 } else if (p[1] == ':') {
635 *p = 0;
636 return start_socket_client(argv[argc-1], p+2, argc-1, argv);
637 }
638
639 if (argc < 2) {
640 usage(FERROR);
641 exit_cleanup(RERR_SYNTAX);
642 }
643
644 if (local_server) {
645 shell_machine = NULL;
646 shell_path = argv[argc-1];
647 } else {
648 *p = 0;
649 shell_machine = argv[argc-1];
650 shell_path = p+1;
651 }
652 argc--;
653 }
654
655 if (shell_machine) {
656 p = strchr(shell_machine,'@');
657 if (p) {
658 *p = 0;
659 shell_user = shell_machine;
660 shell_machine = p+1;
661 }
662 }
663
664 if (verbose > 3) {
665 rprintf(FINFO,"cmd=%s machine=%s user=%s path=%s\n",
666 shell_cmd?shell_cmd:"",
667 shell_machine?shell_machine:"",
668 shell_user?shell_user:"",
669 shell_path?shell_path:"");
670 }
671
672 if (!am_sender && argc > 1) {
673 usage(FERROR);
674 exit_cleanup(RERR_SYNTAX);
675 }
676
677 if (argc == 0 && !am_sender) {
678 extern int list_only;
679 list_only = 1;
680 }
681
682 pid = do_cmd(shell_cmd,shell_machine,shell_user,shell_path,&f_in,&f_out);
683
684 ret = client_run(f_in, f_out, pid, argc, argv);
685
686 fflush(stdout);
687 fflush(stderr);
688
689 return ret;
690}
691
692
693static RETSIGTYPE sigusr1_handler(int val) {
694 exit_cleanup(RERR_SIGNAL);
695}
696
697static RETSIGTYPE sigusr2_handler(int val) {
698 extern int log_got_error;
699 if (log_got_error) _exit(RERR_PARTIAL);
700 _exit(0);
701}
702
703static RETSIGTYPE sigchld_handler(int val) {
704#ifdef WNOHANG
705 while (waitpid(-1, NULL, WNOHANG) > 0) ;
706#endif
707}
708
709int main(int argc,char *argv[])
710{
711 extern int am_root;
712 extern int orig_umask;
713 extern int dry_run;
714 extern int am_daemon;
715 extern int am_server;
716 int ret;
717
718 signal(SIGUSR1, sigusr1_handler);
719 signal(SIGUSR2, sigusr2_handler);
720 signal(SIGCHLD, sigchld_handler);
721
722 starttime = time(NULL);
723 am_root = (getuid() == 0);
724
725 memset(&stats, 0, sizeof(stats));
726
727 if (argc < 2) {
728 usage(FERROR);
729 exit_cleanup(RERR_SYNTAX);
730 }
731
732 /* we set a 0 umask so that correct file permissions can be
733 carried across */
734 orig_umask = (int)umask(0);
735
736 if (!parse_arguments(&argc, (const char ***) &argv, 1)) {
737 /* FIXME: We ought to call the same error-handling
738 * code here, rather than relying on getopt. */
739 option_error();
740 exit_cleanup(RERR_SYNTAX);
741 }
742
743 signal(SIGINT,SIGNAL_CAST sig_int);
744 signal(SIGPIPE,SIGNAL_CAST sig_int);
745 signal(SIGHUP,SIGNAL_CAST sig_int);
746 signal(SIGTERM,SIGNAL_CAST sig_int);
747
748 /* Initialize push_dir here because on some old systems getcwd
749 (implemented by forking "pwd" and reading its output) doesn't
750 work when there are other child processes. Also, on all systems
751 that implement getcwd that way "pwd" can't be found after chroot. */
752 push_dir(NULL,0);
753
754 if (am_daemon) {
755 return daemon_main();
756 }
757
758 if (argc < 1) {
759 usage(FERROR);
760 exit_cleanup(RERR_SYNTAX);
761 }
762
763 if (dry_run)
764 verbose = MAX(verbose,1);
765
766#ifndef SUPPORT_LINKS
767 if (!am_server && preserve_links) {
768 rprintf(FERROR,"ERROR: symbolic links not supported\n");
769 exit_cleanup(RERR_UNSUPPORTED);
770 }
771#endif
772
773 if (am_server) {
774 set_nonblocking(STDIN_FILENO);
775 set_nonblocking(STDOUT_FILENO);
776 start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
777 }
778
779 ret = start_client(argc, argv);
780 exit_cleanup(ret);
781 return ret;
782}
783