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