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