dae6e790f06ed3fdedb92f9bebdecb30a9895c86
[rsync/rsync.git] / main.c
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
23 time_t starttime = 0;
24
25 struct stats stats;
26
27 extern int verbose;
28
29
30 /****************************************************************************
31 wait for a process to exit, calling io_flush while waiting
32 ****************************************************************************/
33 void 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
48 static 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. */
129 /* TODO: When the shell exits, look at its return value, as this may
130  * well tell us if something went wrong in trying to connect to the
131  * remote machine.  Although it doesn't seem to be specified anywhere,
132  * ssh and the shell seem to return these values:
133  *
134  * 124 if the command exited with status 255
135  * 125 if the command is killed by a signal
136  * 126 if the command cannot be run
137  * 127 if the command is not found
138  *
139  * and we could use this to give a better explanation if the remote
140  * command is not found.
141  */
142 static int do_cmd(char *cmd,char *machine,char *user,char *path,int *f_in,int *f_out)
143 {
144         char *args[100];
145         int i,argc=0, ret;
146         char *tok,*dir=NULL;
147         extern int local_server;
148         extern char *rsync_path;
149         extern int blocking_io;
150
151         if (!local_server) {
152                 if (!cmd)
153                         cmd = getenv(RSYNC_RSH_ENV);
154                 if (!cmd)
155                         cmd = RSYNC_RSH;
156                 cmd = strdup(cmd);
157                 if (!cmd) 
158                         goto oom;
159
160                 for (tok=strtok(cmd," ");tok;tok=strtok(NULL," ")) {
161                         args[argc++] = tok;
162                 }
163
164 #if HAVE_REMSH
165                 /* remsh (on HPUX) takes the arguments the other way around */
166                 args[argc++] = machine;
167                 if (user) {
168                         args[argc++] = "-l";
169                         args[argc++] = user;
170                 }
171 #else
172                 if (user) {
173                         args[argc++] = "-l";
174                         args[argc++] = user;
175                 }
176                 args[argc++] = machine;
177 #endif
178
179                 args[argc++] = rsync_path;
180
181                 server_options(args,&argc);
182
183
184                 if (strcmp(cmd, RSYNC_RSH) == 0) blocking_io = 1;
185         }
186
187         args[argc++] = ".";
188
189         if (path && *path) 
190                 args[argc++] = path;
191
192         args[argc] = NULL;
193
194         if (verbose > 3) {
195                 rprintf(FINFO,"cmd=");
196                 for (i=0;i<argc;i++)
197                         rprintf(FINFO,"%s ",args[i]);
198                 rprintf(FINFO,"\n");
199         }
200
201         if (local_server) {
202                 ret = local_child(argc, args, f_in, f_out);
203         } else {
204                 ret = piped_child(args,f_in,f_out);
205         }
206
207         if (dir) free(dir);
208
209         return ret;
210
211 oom:
212         out_of_memory("do_cmd");
213         return 0; /* not reached */
214 }
215
216
217
218
219 static char *get_local_name(struct file_list *flist,char *name)
220 {
221         STRUCT_STAT st;
222         extern int orig_umask;
223
224         if (verbose > 2)
225                 rprintf(FINFO,"get_local_name count=%d %s\n", 
226                         flist->count, NS(name));
227
228         if (!name) 
229                 return NULL;
230
231         if (do_stat(name,&st) == 0) {
232                 if (S_ISDIR(st.st_mode)) {
233                         if (!push_dir(name, 0)) {
234                                 rprintf(FERROR,"push_dir %s : %s (1)\n",
235                                         name,strerror(errno));
236                                 exit_cleanup(RERR_FILESELECT);
237                         }
238                         return NULL;
239                 }
240                 if (flist->count > 1) {
241                         rprintf(FERROR,"ERROR: destination must be a directory when copying more than 1 file\n");
242                         exit_cleanup(RERR_FILESELECT);
243                 }
244                 return name;
245         }
246
247         if (flist->count <= 1)
248                 return name;
249
250         if (do_mkdir(name,0777 & ~orig_umask) != 0) {
251                 rprintf(FERROR,"mkdir %s : %s (1)\n",name,strerror(errno));
252                 exit_cleanup(RERR_FILEIO);
253         } else {
254                 if (verbose > 0)
255                         rprintf(FINFO,"created directory %s\n",name);
256         }
257
258         if (!push_dir(name, 0)) {
259                 rprintf(FERROR,"push_dir %s : %s (2)\n",
260                         name,strerror(errno));
261                 exit_cleanup(RERR_FILESELECT);
262         }
263
264         return NULL;
265 }
266
267
268
269
270 static void do_server_sender(int f_in, int f_out, int argc,char *argv[])
271 {
272         int i;
273         struct file_list *flist;
274         char *dir = argv[0];
275         extern int relative_paths;
276         extern int recurse;
277         extern int remote_version;
278
279         if (verbose > 2)
280                 rprintf(FINFO,"server_sender starting pid=%d\n",(int)getpid());
281   
282         if (!relative_paths && !push_dir(dir, 0)) {
283                 rprintf(FERROR,"push_dir %s: %s (3)\n",dir,strerror(errno));
284                 exit_cleanup(RERR_FILESELECT);
285         }
286         argc--;
287         argv++;
288   
289         if (strcmp(dir,".")) {
290                 int l = strlen(dir);
291                 if (strcmp(dir,"/") == 0) 
292                         l = 0;
293                 for (i=0;i<argc;i++)
294                         argv[i] += l+1;
295         }
296
297         if (argc == 0 && recurse) {
298                 argc=1;
299                 argv--;
300                 argv[0] = ".";
301         }
302         
303         flist = send_file_list(f_out,argc,argv);
304         if (!flist || flist->count == 0) {
305                 exit_cleanup(0);
306         }
307
308         send_files(flist,f_out,f_in);
309         io_flush();
310         report(f_out);
311         if (remote_version >= 24) {
312                 /* final goodbye message */             
313                 read_int(f_in);
314         }
315         io_flush();
316         exit_cleanup(0);
317 }
318
319
320 static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
321 {
322         int pid;
323         int status=0;
324         int recv_pipe[2];
325         int error_pipe[2];
326         extern int preserve_hard_links;
327         extern int delete_after;
328         extern int recurse;
329         extern int delete_mode;
330         extern int remote_version;
331
332         if (preserve_hard_links)
333                 init_hard_links(flist);
334
335         if (!delete_after) {
336                 /* I moved this here from recv_files() to prevent a race condition */
337                 if (recurse && delete_mode && !local_name && flist->count>0) {
338                         delete_files(flist);
339                 }
340         }
341
342         if (fd_pair(recv_pipe) < 0) {
343                 rprintf(FERROR,"pipe failed in do_recv\n");
344                 exit_cleanup(RERR_SOCKETIO);
345         }
346
347         if (fd_pair(error_pipe) < 0) {
348                 rprintf(FERROR,"error pipe failed in do_recv\n");
349                 exit_cleanup(RERR_SOCKETIO);
350         }
351   
352         io_flush();
353
354         if ((pid=do_fork()) == 0) {
355                 close(recv_pipe[0]);
356                 close(error_pipe[0]);
357                 if (f_in != f_out) close(f_out);
358
359                 /* we can't let two processes write to the socket at one time */
360                 io_multiplexing_close();
361
362                 /* set place to send errors */
363                 set_error_fd(error_pipe[1]);
364
365                 recv_files(f_in,flist,local_name,recv_pipe[1]);
366                 io_flush();
367                 report(f_in);
368
369                 write_int(recv_pipe[1],1);
370                 close(recv_pipe[1]);
371                 io_flush();
372                 /* finally we go to sleep until our parent kills us
373                    with a USR2 signal. We sleep for a short time as on
374                    some OSes a signal won't interrupt a sleep! */
375                 while (1) msleep(20);
376         }
377
378         close(recv_pipe[1]);
379         close(error_pipe[1]);
380         if (f_in != f_out) close(f_in);
381
382         io_start_buffering(f_out);
383
384         io_set_error_fd(error_pipe[0]);
385
386         generate_files(f_out,flist,local_name,recv_pipe[0]);
387
388         read_int(recv_pipe[0]);
389         close(recv_pipe[0]);
390         if (remote_version >= 24) {
391                 /* send a final goodbye message */
392                 write_int(f_out, -1);
393         }
394         io_flush();
395
396         kill(pid, SIGUSR2);
397         wait_process(pid, &status);
398         return status;
399 }
400
401
402 static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
403 {
404         int status;
405         struct file_list *flist;
406         char *local_name=NULL;
407         char *dir = NULL;
408         extern int delete_mode;
409         extern int delete_excluded;
410         extern int am_daemon;
411         extern int module_id;
412         extern int am_sender;
413
414         if (verbose > 2)
415                 rprintf(FINFO,"server_recv(%d) starting pid=%d\n",argc,(int)getpid());
416
417         if (am_daemon && lp_read_only(module_id) && !am_sender) {
418                 rprintf(FERROR,"ERROR: module is read only\n");
419                 exit_cleanup(RERR_SYNTAX);
420                 return;
421         }
422
423         
424         if (argc > 0) {
425                 dir = argv[0];
426                 argc--;
427                 argv++;
428                 if (!am_daemon && !push_dir(dir, 0)) {
429                         rprintf(FERROR,"push_dir %s : %s (4)\n",
430                                 dir,strerror(errno));
431                         exit_cleanup(RERR_FILESELECT);
432                 }    
433         }
434
435         if (delete_mode && !delete_excluded)
436                 recv_exclude_list(f_in);
437
438         flist = recv_file_list(f_in);
439         if (!flist) {
440                 rprintf(FERROR,"server_recv: recv_file_list error\n");
441                 exit_cleanup(RERR_FILESELECT);
442         }
443         
444         if (argc > 0) {    
445                 if (strcmp(dir,".")) {
446                         argv[0] += strlen(dir);
447                         if (argv[0][0] == '/') argv[0]++;
448                 }
449                 local_name = get_local_name(flist,argv[0]);
450         }
451
452         status = do_recv(f_in,f_out,flist,local_name);
453         exit_cleanup(status);
454 }
455
456
457 void start_server(int f_in, int f_out, int argc, char *argv[])
458 {
459         extern int cvs_exclude;
460         extern int am_sender;
461         extern int remote_version;
462
463         setup_protocol(f_out, f_in);
464
465         set_nonblocking(f_in);
466         set_nonblocking(f_out);
467
468         if (remote_version >= 23)
469                 io_start_multiplex_out(f_out);
470
471         if (am_sender) {
472                 recv_exclude_list(f_in);
473                 if (cvs_exclude)
474                         add_cvs_excludes();
475                 do_server_sender(f_in, f_out, argc, argv);
476         } else {
477                 do_server_recv(f_in, f_out, argc, argv);
478         }
479         exit_cleanup(0);
480 }
481
482
483 /*
484  * This is called once the connection has been negotiated.  It is used
485  * for rsyncd, remote-shell, and local connections.
486  */
487 int client_run(int f_in, int f_out, int pid, int argc, char *argv[])
488 {
489         struct file_list *flist;
490         int status = 0, status2 = 0;
491         char *local_name = NULL;
492         extern int am_sender;
493         extern int remote_version;
494
495         set_nonblocking(f_in);
496         set_nonblocking(f_out);
497
498         setup_protocol(f_out,f_in);
499
500         if (remote_version >= 23)
501                 io_start_multiplex_in(f_in);
502         
503         if (am_sender) {
504                 extern int cvs_exclude;
505                 extern int delete_mode;
506                 extern int delete_excluded;
507                 if (cvs_exclude)
508                         add_cvs_excludes();
509                 if (delete_mode && !delete_excluded) 
510                         send_exclude_list(f_out);
511                 flist = send_file_list(f_out,argc,argv);
512                 if (verbose > 3) 
513                         rprintf(FINFO,"file list sent\n");
514
515                 send_files(flist,f_out,f_in);
516                 if (pid != -1) {
517                         if (verbose > 3)
518                                 rprintf(FINFO,"client_run waiting on %d\n",pid);
519                         io_flush();
520                         wait_process(pid, &status);
521                 }
522                 if (remote_version >= 24) {
523                         /* final goodbye message */             
524                         read_int(f_in);
525                 }
526                 report(-1);
527                 exit_cleanup(status);
528         }
529
530         if (argc == 0) {
531                 extern int list_only;
532                 list_only = 1;
533         }
534         
535         send_exclude_list(f_out);
536         
537         flist = recv_file_list(f_in);
538         if (!flist || flist->count == 0) {
539                 rprintf(FINFO, "client: nothing to do: "
540                         "perhaps you need to specify some filenames or "
541                         "the --recursive option?\n");
542                 exit_cleanup(0);
543         }
544         
545         local_name = get_local_name(flist,argv[0]);
546         
547         status2 = do_recv(f_in,f_out,flist,local_name);
548         
549         if (pid != -1) {
550                 if (verbose > 3)
551                         rprintf(FINFO,"client_run2 waiting on %d\n",pid);
552                 io_flush();
553                 wait_process(pid, &status);
554         }
555         
556         return MAX(status, status2);
557 }
558
559 static char *find_colon(char *s)
560 {
561         char *p, *p2;
562
563         p = strchr(s,':');
564         if (!p) return NULL;
565         
566         /* now check to see if there is a / in the string before the : - if there is then
567            discard the colon on the assumption that the : is part of a filename */
568         p2 = strchr(s,'/');
569         if (p2 && p2 < p) return NULL;
570
571         return p;
572 }
573
574
575 /*
576  * Start a client for either type of remote connection.  Work out
577  * whether the arguments request a remote shell or rsyncd connection,
578  * and call the appropriate connection function, then run_client.
579  */
580 static int start_client(int argc, char *argv[])
581 {
582         char *p;
583         char *shell_machine = NULL;
584         char *shell_path = NULL;
585         char *shell_user = NULL;
586         int pid, ret;
587         int f_in,f_out;
588         extern int local_server;
589         extern int am_sender;
590         extern char *shell_cmd;
591         extern int rsync_port;
592         char *argv0 = strdup(argv[0]);
593
594         if (strncasecmp(URL_PREFIX, argv0, strlen(URL_PREFIX)) == 0) {
595                 char *host, *path;
596
597                 host = argv0 + strlen(URL_PREFIX);
598                 p = strchr(host,'/');
599                 if (p) {
600                         *p = 0;
601                         path = p+1;
602                 } else {
603                         path="";
604                 }
605                 p = strchr(host,':');
606                 if (p) {
607                         rsync_port = atoi(p+1);
608                         *p = 0;
609                 }
610                 return start_socket_client(host, path, argc-1, argv+1);
611         }
612
613         p = find_colon(argv0);
614
615         if (p) {
616                 if (p[1] == ':') {
617                         *p = 0;
618                         return start_socket_client(argv0, p+2, argc-1, argv+1);
619                 }
620
621                 if (argc < 1) {
622                         usage(FERROR);
623                         exit_cleanup(RERR_SYNTAX);
624                 }
625
626                 am_sender = 0;
627                 *p = 0;
628                 shell_machine = argv0;
629                 shell_path = p+1;
630                 argc--;
631                 argv++;
632         } else {
633                 am_sender = 1;
634
635                 p = find_colon(argv[argc-1]);
636                 if (!p) {
637                         local_server = 1;
638                 } else if (p[1] == ':') {
639                         *p = 0;
640                         return start_socket_client(argv[argc-1], p+2, argc-1, argv);
641                 }
642
643                 if (argc < 2) {
644                         usage(FERROR);
645                         exit_cleanup(RERR_SYNTAX);
646                 }
647                 
648                 if (local_server) {
649                         shell_machine = NULL;
650                         shell_path = argv[argc-1];
651                 } else {
652                         *p = 0;
653                         shell_machine = argv[argc-1];
654                         shell_path = p+1;
655                 }
656                 argc--;
657         }
658         
659         if (shell_machine) {
660                 p = strchr(shell_machine,'@');
661                 if (p) {
662                         *p = 0;
663                         shell_user = shell_machine;
664                         shell_machine = p+1;
665                 }
666         }
667
668         if (verbose > 3) {
669                 rprintf(FINFO,"cmd=%s machine=%s user=%s path=%s\n",
670                         shell_cmd?shell_cmd:"",
671                         shell_machine?shell_machine:"",
672                         shell_user?shell_user:"",
673                         shell_path?shell_path:"");
674         }
675         
676         if (!am_sender && argc > 1) {
677                 usage(FERROR);
678                 exit_cleanup(RERR_SYNTAX);
679         }
680
681         if (argc == 0 && !am_sender) {
682                 extern int list_only;
683                 list_only = 1;
684         }
685         
686         pid = do_cmd(shell_cmd,shell_machine,shell_user,shell_path,&f_in,&f_out);
687         
688         ret = client_run(f_in, f_out, pid, argc, argv);
689
690         fflush(stdout);
691         fflush(stderr);
692
693         return ret;
694 }
695
696
697 static RETSIGTYPE sigusr1_handler(int val) {
698         exit_cleanup(RERR_SIGNAL);
699 }
700
701 static RETSIGTYPE sigusr2_handler(int val) {
702         extern int log_got_error;
703         if (log_got_error) _exit(RERR_FILEIO);
704         _exit(0);
705 }
706
707 int main(int argc,char *argv[])
708 {       
709         extern int am_root;
710         extern int orig_umask;
711         extern int dry_run;
712         extern int am_daemon;
713         extern int am_server;
714         int ret;
715
716         signal(SIGUSR1, sigusr1_handler);
717         signal(SIGUSR2, sigusr2_handler);
718
719         starttime = time(NULL);
720         am_root = (getuid() == 0);
721
722         memset(&stats, 0, sizeof(stats));
723
724         if (argc < 2) {
725                 usage(FERROR);
726                 exit_cleanup(RERR_SYNTAX);
727         }
728
729         /* we set a 0 umask so that correct file permissions can be
730            carried across */
731         orig_umask = (int)umask(0);
732
733         if (!parse_arguments(&argc, (const char ***) &argv, 1)) {
734                 /* FIXME: We ought to call the same error-handling
735                  * code here, rather than relying on getopt. */
736                 option_error();
737                 exit_cleanup(RERR_SYNTAX);
738         }
739
740         signal(SIGINT,SIGNAL_CAST sig_int);
741         signal(SIGPIPE,SIGNAL_CAST sig_int);
742         signal(SIGHUP,SIGNAL_CAST sig_int);
743         signal(SIGTERM,SIGNAL_CAST sig_int);
744
745         /* Initialize push_dir here because on some old systems getcwd
746            (implemented by forking "pwd" and reading its output) doesn't
747            work when there are other child processes.  Also, on all systems
748            that implement getcwd that way "pwd" can't be found after chroot. */
749         push_dir(NULL,0);
750
751         if (am_daemon) {
752                 return daemon_main();
753         }
754
755         if (argc < 1) {
756                 usage(FERROR);
757                 exit_cleanup(RERR_SYNTAX);
758         }
759
760         if (dry_run)
761                 verbose = MAX(verbose,1);
762
763 #ifndef SUPPORT_LINKS
764         if (!am_server && preserve_links) {
765                 rprintf(FERROR,"ERROR: symbolic links not supported\n");
766                 exit_cleanup(RERR_UNSUPPORTED);
767         }
768 #endif
769
770         if (am_server) {
771                 set_nonblocking(STDIN_FILENO);
772                 set_nonblocking(STDOUT_FILENO);
773                 start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
774         }
775
776         ret = start_client(argc, argv);
777         exit_cleanup(ret);
778         return ret;
779 }
780