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