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