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