went back to non-blokcing IO
[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                 close(recv_pipe[1]);
326                 io_flush();
327                 /* finally we go to sleep until our parent kills us with
328                    a USR2 signal */
329                 while (1) sleep(60);
330         }
331
332         close(recv_pipe[1]);
333         close(error_pipe[1]);
334         io_close_input(f_in);
335         if (f_in != f_out) close(f_in);
336
337         io_start_buffering(f_out);
338
339         io_set_error_fd(error_pipe[0]);
340
341         generate_files(f_out,flist,local_name,recv_pipe[0]);
342
343         read_int(recv_pipe[0]);
344         close(recv_pipe[0]);
345         if (remote_version >= 24) {
346                 /* send a final goodbye message */
347                 write_int(f_out, -1);
348         }
349         io_flush();
350
351         kill(pid, SIGUSR2);
352         wait_process(pid, &status);
353         return status;
354 }
355
356
357 static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
358 {
359         int status;
360         struct file_list *flist;
361         char *local_name=NULL;
362         char *dir = NULL;
363         extern int delete_mode;
364         extern int delete_excluded;
365         extern int am_daemon;
366         extern int module_id;
367         extern int am_sender;
368
369         if (verbose > 2)
370                 rprintf(FINFO,"server_recv(%d) starting pid=%d\n",argc,(int)getpid());
371
372         if (am_daemon && lp_read_only(module_id) && !am_sender) {
373                 rprintf(FERROR,"ERROR: module is read only\n");
374                 exit_cleanup(RERR_SYNTAX);
375                 return;
376         }
377
378         
379         if (argc > 0) {
380                 dir = argv[0];
381                 argc--;
382                 argv++;
383                 if (!am_daemon && !push_dir(dir, 0)) {
384                         rprintf(FERROR,"push_dir %s : %s (4)\n",
385                                 dir,strerror(errno));
386                         exit_cleanup(RERR_FILESELECT);
387                 }    
388         }
389
390         if (delete_mode && !delete_excluded)
391                 recv_exclude_list(f_in);
392
393         flist = recv_file_list(f_in);
394         if (!flist) {
395                 rprintf(FERROR,"server_recv: recv_file_list error\n");
396                 exit_cleanup(RERR_FILESELECT);
397         }
398         
399         if (argc > 0) {    
400                 if (strcmp(dir,".")) {
401                         argv[0] += strlen(dir);
402                         if (argv[0][0] == '/') argv[0]++;
403                 }
404                 local_name = get_local_name(flist,argv[0]);
405         }
406
407         status = do_recv(f_in,f_out,flist,local_name);
408         exit_cleanup(status);
409 }
410
411
412 void start_server(int f_in, int f_out, int argc, char *argv[])
413 {
414         extern int cvs_exclude;
415         extern int am_sender;
416         extern int remote_version;
417
418         setup_protocol(f_out, f_in);
419
420         set_nonblocking(f_in);
421         set_nonblocking(f_out);
422
423         if (remote_version >= 23)
424                 io_start_multiplex_out(f_out);
425
426         if (am_sender) {
427                 recv_exclude_list(f_in);
428                 if (cvs_exclude)
429                         add_cvs_excludes();
430                 do_server_sender(f_in, f_out, argc, argv);
431         } else {
432                 do_server_recv(f_in, f_out, argc, argv);
433         }
434         exit_cleanup(0);
435 }
436
437 int client_run(int f_in, int f_out, int pid, int argc, char *argv[])
438 {
439         struct file_list *flist;
440         int status = 0, status2 = 0;
441         char *local_name = NULL;
442         extern int am_sender;
443         extern int list_only;
444         extern int remote_version;
445
446         set_nonblocking(f_in);
447         set_nonblocking(f_out);
448
449         setup_protocol(f_out,f_in);
450
451         if (remote_version >= 23)
452                 io_start_multiplex_in(f_in);
453         
454         if (am_sender) {
455                 extern int cvs_exclude;
456                 extern int delete_mode;
457                 extern int delete_excluded;
458                 if (cvs_exclude)
459                         add_cvs_excludes();
460                 if (delete_mode && !delete_excluded) 
461                         send_exclude_list(f_out);
462                 flist = send_file_list(f_out,argc,argv);
463                 if (verbose > 3) 
464                         rprintf(FINFO,"file list sent\n");
465
466                 send_files(flist,f_out,f_in);
467                 if (pid != -1) {
468                         if (verbose > 3)
469                                 rprintf(FINFO,"client_run waiting on %d\n",pid);
470                         io_flush();
471                         wait_process(pid, &status);
472                 }
473                 report(-1);
474                 if (remote_version >= 24) {
475                         /* final goodbye message */             
476                         read_int(f_in);
477                 }
478                 exit_cleanup(status);
479         }
480
481         if (argc == 0) list_only = 1;
482         
483         send_exclude_list(f_out);
484         
485         flist = recv_file_list(f_in);
486         if (!flist || flist->count == 0) {
487                 rprintf(FINFO,"client: nothing to do\n");
488                 exit_cleanup(0);
489         }
490         
491         local_name = get_local_name(flist,argv[0]);
492         
493         status2 = do_recv(f_in,f_out,flist,local_name);
494         
495         if (pid != -1) {
496                 if (verbose > 3)
497                         rprintf(FINFO,"client_run2 waiting on %d\n",pid);
498                 io_flush();
499                 wait_process(pid, &status);
500         }
501         
502         return status | status2;
503 }
504
505 static char *find_colon(char *s)
506 {
507         char *p, *p2;
508
509         p = strchr(s,':');
510         if (!p) return NULL;
511         
512         /* now check to see if there is a / in the string before the : - if there is then
513            discard the colon on the assumption that the : is part of a filename */
514         p2 = strchr(s,'/');
515         if (p2 && p2 < p) return NULL;
516
517         return p;
518 }
519
520 static int start_client(int argc, char *argv[])
521 {
522         char *p;
523         char *shell_machine = NULL;
524         char *shell_path = NULL;
525         char *shell_user = NULL;
526         int pid, ret;
527         int f_in,f_out;
528         extern int local_server;
529         extern int am_sender;
530         extern char *shell_cmd;
531         extern int rsync_port;
532
533         if (strncasecmp(URL_PREFIX, argv[0], strlen(URL_PREFIX)) == 0) {
534                 char *host, *path;
535
536                 host = argv[0] + strlen(URL_PREFIX);
537                 p = strchr(host,'/');
538                 if (p) {
539                         *p = 0;
540                         path = p+1;
541                 } else {
542                         path="";
543                 }
544                 p = strchr(host,':');
545                 if (p) {
546                         rsync_port = atoi(p+1);
547                         *p = 0;
548                 }
549                 return start_socket_client(host, path, argc-1, argv+1);
550         }
551
552         p = find_colon(argv[0]);
553
554         if (p) {
555                 if (p[1] == ':') {
556                         *p = 0;
557                         return start_socket_client(argv[0], p+2, argc-1, argv+1);
558                 }
559
560                 if (argc < 1) {
561                         usage(FERROR);
562                         exit_cleanup(RERR_SYNTAX);
563                 }
564
565                 am_sender = 0;
566                 *p = 0;
567                 shell_machine = argv[0];
568                 shell_path = p+1;
569                 argc--;
570                 argv++;
571         } else {
572                 am_sender = 1;
573
574                 p = find_colon(argv[argc-1]);
575                 if (!p) {
576                         local_server = 1;
577                 } else if (p[1] == ':') {
578                         *p = 0;
579                         return start_socket_client(argv[argc-1], p+2, argc-1, argv);
580                 }
581
582                 if (argc < 2) {
583                         usage(FERROR);
584                         exit_cleanup(RERR_SYNTAX);
585                 }
586                 
587                 if (local_server) {
588                         shell_machine = NULL;
589                         shell_path = argv[argc-1];
590                 } else {
591                         *p = 0;
592                         shell_machine = argv[argc-1];
593                         shell_path = p+1;
594                 }
595                 argc--;
596         }
597         
598         if (shell_machine) {
599                 p = strchr(shell_machine,'@');
600                 if (p) {
601                         *p = 0;
602                         shell_user = shell_machine;
603                         shell_machine = p+1;
604                 }
605         }
606
607         if (verbose > 3) {
608                 rprintf(FINFO,"cmd=%s machine=%s user=%s path=%s\n",
609                         shell_cmd?shell_cmd:"",
610                         shell_machine?shell_machine:"",
611                         shell_user?shell_user:"",
612                         shell_path?shell_path:"");
613         }
614         
615         if (!am_sender && argc > 1) {
616                 usage(FERROR);
617                 exit_cleanup(RERR_SYNTAX);
618         }
619         
620         pid = do_cmd(shell_cmd,shell_machine,shell_user,shell_path,&f_in,&f_out);
621         
622         ret = client_run(f_in, f_out, pid, argc, argv);
623
624         fflush(stdout);
625         fflush(stderr);
626
627         return ret;
628 }
629
630
631 static RETSIGTYPE sigusr1_handler(int val) {
632         exit_cleanup(RERR_SIGNAL);
633 }
634
635 static RETSIGTYPE sigusr2_handler(int val) {
636         _exit(0);
637 }
638
639 int main(int argc,char *argv[])
640 {       
641         extern int am_root;
642         extern int orig_umask;
643         extern int dry_run;
644         extern int am_daemon;
645         extern int am_server;
646
647         signal(SIGUSR1, sigusr1_handler);
648         signal(SIGUSR2, sigusr2_handler);
649
650         starttime = time(NULL);
651         am_root = (getuid() == 0);
652
653         memset(&stats, 0, sizeof(stats));
654
655         if (argc < 2) {
656                 usage(FERROR);
657                 exit_cleanup(RERR_SYNTAX);
658         }
659
660         /* we set a 0 umask so that correct file permissions can be
661            carried across */
662         orig_umask = (int)umask(0);
663
664         if (!parse_arguments(argc, argv, 1)) {
665                 exit_cleanup(RERR_SYNTAX);
666         }
667
668         argc -= optind;
669         argv += optind;
670         optind = 0;
671
672         signal(SIGCHLD,SIG_IGN);
673         signal(SIGINT,SIGNAL_CAST sig_int);
674         signal(SIGPIPE,SIGNAL_CAST sig_int);
675         signal(SIGHUP,SIGNAL_CAST sig_int);
676         signal(SIGTERM,SIGNAL_CAST sig_int);
677
678         /* Initialize push_dir here because on some old systems getcwd
679            (implemented by forking "pwd" and reading its output) doesn't
680            work when there are other child processes.  Also, on all systems
681            that implement getcwd that way "pwd" can't be found after chroot. */
682         push_dir(NULL,0);
683
684         if (am_daemon) {
685                 return daemon_main();
686         }
687
688         if (argc < 1) {
689                 usage(FERROR);
690                 exit_cleanup(RERR_SYNTAX);
691         }
692
693         if (dry_run)
694                 verbose = MAX(verbose,1);
695
696 #ifndef SUPPORT_LINKS
697         if (!am_server && preserve_links) {
698                 rprintf(FERROR,"ERROR: symbolic links not supported\n");
699                 exit_cleanup(RERR_UNSUPPORTED);
700         }
701 #endif
702
703         if (am_server) {
704                 set_nonblocking(STDIN_FILENO);
705                 set_nonblocking(STDOUT_FILENO);
706                 start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
707         }
708
709         return start_client(argc, argv);
710 }
711