Implement --privacy option, though apparently not working yet.
[rsync.git] / main.c
1 /* -*- c-file-style: "linux" -*-
2    
3    Copyright (C) 1996-2000 by Andrew Tridgell
4    Copyright (C) Paul Mackerras 1996
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "rsync.h"
22
23 time_t starttime = 0;
24
25 struct stats stats;
26
27 extern int verbose;
28
29
30 /****************************************************************************
31 wait for a process to exit, calling io_flush while waiting
32 ****************************************************************************/
33 void wait_process(pid_t pid, int *status)
34 {
35         while (waitpid(pid, status, WNOHANG) == 0) {
36                 msleep(20);
37                 io_flush();
38         }
39         *status = WEXITSTATUS(*status);
40 }
41
42 static void report(int f)
43 {
44         time_t t = time(NULL);
45         extern int am_server;
46         extern int am_sender;
47         extern int am_daemon;
48         extern int do_stats;
49         extern int remote_version;
50         int send_stats;
51
52         if (am_daemon) {
53                 log_exit(0, __FILE__, __LINE__);
54                 if (f == -1 || !am_sender) return;
55         }
56
57         send_stats = verbose || (remote_version >= 20);
58         if (am_server) {
59                 if (am_sender && send_stats) {
60                         int64 w;
61                         /* store total_written in a temporary
62                             because write_longint changes it */
63                         w = stats.total_written;
64                         write_longint(f,stats.total_read);
65                         write_longint(f,w);
66                         write_longint(f,stats.total_size);
67                 }
68                 return;
69         }
70
71         /* this is the client */
72             
73         if (!am_sender && send_stats) {
74                 int64 r;
75                 stats.total_written = read_longint(f);
76                 /* store total_read in a temporary, read_longint changes it */
77                 r = read_longint(f);
78                 stats.total_size = read_longint(f);
79                 stats.total_read = r;
80         }
81
82         if (do_stats) {
83                 if (!am_sender && !send_stats) {
84                     /* missing the bytes written by the generator */
85                     rprintf(FINFO, "\nCannot show stats as receiver because remote protocol version is less than 20\n");
86                     rprintf(FINFO, "Use --stats -v to show stats\n");
87                     return;
88                 }
89                 rprintf(FINFO,"\nNumber of files: %d\n", stats.num_files);
90                 rprintf(FINFO,"Number of files transferred: %d\n", 
91                        stats.num_transferred_files);
92                 rprintf(FINFO,"Total file size: %.0f bytes\n", 
93                        (double)stats.total_size);
94                 rprintf(FINFO,"Total transferred file size: %.0f bytes\n", 
95                        (double)stats.total_transferred_size);
96                 rprintf(FINFO,"Literal data: %.0f bytes\n", 
97                        (double)stats.literal_data);
98                 rprintf(FINFO,"Matched data: %.0f bytes\n", 
99                        (double)stats.matched_data);
100                 rprintf(FINFO,"File list size: %d\n", stats.flist_size);
101                 rprintf(FINFO,"Total bytes written: %.0f\n", 
102                        (double)stats.total_written);
103                 rprintf(FINFO,"Total bytes read: %.0f\n\n", 
104                        (double)stats.total_read);
105         }
106         
107         if (verbose || do_stats) {
108                 rprintf(FINFO,"wrote %.0f bytes  read %.0f bytes  %.2f bytes/sec\n",
109                        (double)stats.total_written,
110                        (double)stats.total_read,
111                        (stats.total_written+stats.total_read)/(0.5 + (t-starttime)));
112                 rprintf(FINFO,"total size is %.0f  speedup is %.2f\n",
113                        (double)stats.total_size,
114                        (1.0*stats.total_size)/(stats.total_written+stats.total_read));
115         }
116
117         fflush(stdout);
118         fflush(stderr);
119 }
120
121
122 static int do_cmd(char *cmd,char *machine,char *user,char *path,int *f_in,int *f_out)
123 {
124         char *args[100];
125         int i,argc=0, ret;
126         char *tok,*dir=NULL;
127         extern int local_server;
128         extern char *rsync_path;
129         extern int blocking_io;
130
131         if (!local_server) {
132                 if (!cmd)
133                         cmd = getenv(RSYNC_RSH_ENV);
134                 if (!cmd)
135                         cmd = RSYNC_RSH;
136                 cmd = strdup(cmd);
137                 if (!cmd) 
138                         goto oom;
139
140                 for (tok=strtok(cmd," ");tok;tok=strtok(NULL," ")) {
141                         args[argc++] = tok;
142                 }
143
144 #if HAVE_REMSH
145                 /* remsh (on HPUX) takes the arguments the other way around */
146                 args[argc++] = machine;
147                 if (user) {
148                         args[argc++] = "-l";
149                         args[argc++] = user;
150                 }
151 #else
152                 if (user) {
153                         args[argc++] = "-l";
154                         args[argc++] = user;
155                 }
156                 args[argc++] = machine;
157 #endif
158
159                 args[argc++] = rsync_path;
160
161                 server_options(args,&argc);
162
163
164                 if (strcmp(cmd, RSYNC_RSH) == 0) blocking_io = 1;
165         }
166
167         args[argc++] = ".";
168
169         if (path && *path) 
170                 args[argc++] = path;
171
172         args[argc] = NULL;
173
174         if (verbose > 3) {
175                 rprintf(FINFO,"cmd=");
176                 for (i=0;i<argc;i++)
177                         rprintf(FINFO,"%s ",args[i]);
178                 rprintf(FINFO,"\n");
179         }
180
181         if (local_server) {
182                 ret = local_child(argc, args, f_in, f_out);
183         } else {
184                 ret = piped_child(args,f_in,f_out);
185         }
186
187         if (dir) free(dir);
188
189         return ret;
190
191 oom:
192         out_of_memory("do_cmd");
193         return 0; /* not reached */
194 }
195
196
197
198
199 static char *get_local_name(struct file_list *flist,char *name)
200 {
201         STRUCT_STAT st;
202         extern int orig_umask;
203
204         if (verbose > 2)
205                 rprintf(FINFO,"get_local_name count=%d %s\n", 
206                         flist->count, NS(name));
207
208         if (!name) 
209                 return NULL;
210
211         if (do_stat(name,&st) == 0) {
212                 if (S_ISDIR(st.st_mode)) {
213                         if (!push_dir(name, 0)) {
214                                 rprintf(FERROR,"push_dir %s : %s (1)\n",
215                                         name,strerror(errno));
216                                 exit_cleanup(RERR_FILESELECT);
217                         }
218                         return NULL;
219                 }
220                 if (flist->count > 1) {
221                         rprintf(FERROR,"ERROR: destination must be a directory when copying more than 1 file\n");
222                         exit_cleanup(RERR_FILESELECT);
223                 }
224                 return name;
225         }
226
227         if (flist->count <= 1)
228                 return name;
229
230         if (do_mkdir(name,0777 & ~orig_umask) != 0) {
231                 rprintf(FERROR,"mkdir %s : %s (1)\n",name,strerror(errno));
232                 exit_cleanup(RERR_FILEIO);
233         } else {
234                 if (verbose > 0)
235                         rprintf(FINFO,"created directory %s\n",name);
236         }
237
238         if (!push_dir(name, 0)) {
239                 rprintf(FERROR,"push_dir %s : %s (2)\n",
240                         name,strerror(errno));
241                 exit_cleanup(RERR_FILESELECT);
242         }
243
244         return NULL;
245 }
246
247
248
249
250 static void do_server_sender(int f_in, int f_out, int argc,char *argv[])
251 {
252         int i;
253         struct file_list *flist;
254         char *dir = argv[0];
255         extern int relative_paths;
256         extern int recurse;
257         extern int remote_version;
258
259         if (verbose > 2)
260                 rprintf(FINFO,"server_sender starting pid=%d\n",(int)getpid());
261   
262         if (!relative_paths && !push_dir(dir, 0)) {
263                 rprintf(FERROR,"push_dir %s: %s (3)\n",dir,strerror(errno));
264                 exit_cleanup(RERR_FILESELECT);
265         }
266         argc--;
267         argv++;
268   
269         if (strcmp(dir,".")) {
270                 int l = strlen(dir);
271                 if (strcmp(dir,"/") == 0) 
272                         l = 0;
273                 for (i=0;i<argc;i++)
274                         argv[i] += l+1;
275         }
276
277         if (argc == 0 && recurse) {
278                 argc=1;
279                 argv--;
280                 argv[0] = ".";
281         }
282         
283         flist = send_file_list(f_out,argc,argv);
284         if (!flist || flist->count == 0) {
285                 exit_cleanup(0);
286         }
287
288         send_files(flist,f_out,f_in);
289         io_flush();
290         report(f_out);
291         if (remote_version >= 24) {
292                 /* final goodbye message */             
293                 read_int(f_in);
294         }
295         io_flush();
296         exit_cleanup(0);
297 }
298
299
300 static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
301 {
302         int pid;
303         int status=0;
304         int recv_pipe[2];
305         int error_pipe[2];
306         extern int preserve_hard_links;
307         extern int delete_after;
308         extern int recurse;
309         extern int delete_mode;
310         extern int remote_version;
311
312         if (preserve_hard_links)
313                 init_hard_links(flist);
314
315         if (!delete_after) {
316                 /* I moved this here from recv_files() to prevent a race condition */
317                 if (recurse && delete_mode && !local_name && flist->count>0) {
318                         delete_files(flist);
319                 }
320         }
321
322         if (fd_pair(recv_pipe) < 0) {
323                 rprintf(FERROR,"pipe failed in do_recv\n");
324                 exit_cleanup(RERR_SOCKETIO);
325         }
326
327         if (fd_pair(error_pipe) < 0) {
328                 rprintf(FERROR,"error pipe failed in do_recv\n");
329                 exit_cleanup(RERR_SOCKETIO);
330         }
331   
332         io_flush();
333
334         if ((pid=do_fork()) == 0) {
335                 close(recv_pipe[0]);
336                 close(error_pipe[0]);
337                 if (f_in != f_out) close(f_out);
338
339                 /* we can't let two processes write to the socket at one time */
340                 io_multiplexing_close();
341
342                 /* set place to send errors */
343                 set_error_fd(error_pipe[1]);
344
345                 recv_files(f_in,flist,local_name,recv_pipe[1]);
346                 io_flush();
347                 report(f_in);
348
349                 write_int(recv_pipe[1],1);
350                 close(recv_pipe[1]);
351                 io_flush();
352                 /* finally we go to sleep until our parent kills us
353                    with a USR2 signal. We sleep for a short time as on
354                    some OSes a signal won't interrupt a sleep! */
355                 while (1) msleep(20);
356         }
357
358         close(recv_pipe[1]);
359         close(error_pipe[1]);
360         if (f_in != f_out) close(f_in);
361
362         io_start_buffering(f_out);
363
364         io_set_error_fd(error_pipe[0]);
365
366         generate_files(f_out,flist,local_name,recv_pipe[0]);
367
368         read_int(recv_pipe[0]);
369         close(recv_pipe[0]);
370         if (remote_version >= 24) {
371                 /* send a final goodbye message */
372                 write_int(f_out, -1);
373         }
374         io_flush();
375
376         kill(pid, SIGUSR2);
377         wait_process(pid, &status);
378         return status;
379 }
380
381
382 static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
383 {
384         int status;
385         struct file_list *flist;
386         char *local_name=NULL;
387         char *dir = NULL;
388         extern int delete_mode;
389         extern int delete_excluded;
390         extern int am_daemon;
391         extern int module_id;
392         extern int am_sender;
393
394         if (verbose > 2)
395                 rprintf(FINFO,"server_recv(%d) starting pid=%d\n",argc,(int)getpid());
396
397         if (am_daemon && lp_read_only(module_id) && !am_sender) {
398                 rprintf(FERROR,"ERROR: module is read only\n");
399                 exit_cleanup(RERR_SYNTAX);
400                 return;
401         }
402
403         
404         if (argc > 0) {
405                 dir = argv[0];
406                 argc--;
407                 argv++;
408                 if (!am_daemon && !push_dir(dir, 0)) {
409                         rprintf(FERROR,"push_dir %s : %s (4)\n",
410                                 dir,strerror(errno));
411                         exit_cleanup(RERR_FILESELECT);
412                 }    
413         }
414
415         if (delete_mode && !delete_excluded)
416                 recv_exclude_list(f_in);
417
418         flist = recv_file_list(f_in);
419         if (!flist) {
420                 rprintf(FERROR,"server_recv: recv_file_list error\n");
421                 exit_cleanup(RERR_FILESELECT);
422         }
423         
424         if (argc > 0) {    
425                 if (strcmp(dir,".")) {
426                         argv[0] += strlen(dir);
427                         if (argv[0][0] == '/') argv[0]++;
428                 }
429                 local_name = get_local_name(flist,argv[0]);
430         }
431
432         status = do_recv(f_in,f_out,flist,local_name);
433         exit_cleanup(status);
434 }
435
436
437 void start_server(int f_in, int f_out, int argc, char *argv[])
438 {
439         extern int cvs_exclude;
440         extern int am_sender;
441         extern int remote_version;
442         extern int want_privacy;
443
444         if (want_privacy)
445                 arcfour_enabled = 1;
446
447         setup_protocol(f_out, f_in);
448
449         set_nonblocking(f_in);
450         set_nonblocking(f_out);
451
452         if (remote_version >= 23)
453                 io_start_multiplex_out(f_out);
454
455         if (am_sender) {
456                 recv_exclude_list(f_in);
457                 if (cvs_exclude)
458                         add_cvs_excludes();
459                 do_server_sender(f_in, f_out, argc, argv);
460         } else {
461                 do_server_recv(f_in, f_out, argc, argv);
462         }
463         exit_cleanup(0);
464 }
465
466 int client_run(int f_in, int f_out, int pid, int argc, char *argv[])
467 {
468         struct file_list *flist;
469         int status = 0, status2 = 0;
470         char *local_name = NULL;
471         extern int am_sender;
472         extern int remote_version;
473         extern int want_privacy;
474
475         set_nonblocking(f_in);
476         set_nonblocking(f_out);
477
478         if (want_privacy)
479                 arcfour_enabled = 1;
480
481         setup_protocol(f_out,f_in);
482
483         if (remote_version >= 23)
484                 io_start_multiplex_in(f_in);
485         
486         if (am_sender) {
487                 extern int cvs_exclude;
488                 extern int delete_mode;
489                 extern int delete_excluded;
490                 if (cvs_exclude)
491                         add_cvs_excludes();
492                 if (delete_mode && !delete_excluded) 
493                         send_exclude_list(f_out);
494                 flist = send_file_list(f_out,argc,argv);
495                 if (verbose > 3) 
496                         rprintf(FINFO,"file list sent\n");
497
498                 send_files(flist,f_out,f_in);
499                 if (pid != -1) {
500                         if (verbose > 3)
501                                 rprintf(FINFO,"client_run waiting on %d\n",pid);
502                         io_flush();
503                         wait_process(pid, &status);
504                 }
505                 if (remote_version >= 24) {
506                         /* final goodbye message */             
507                         read_int(f_in);
508                 }
509                 report(-1);
510                 exit_cleanup(status);
511         }
512
513         if (argc == 0) {
514                 extern int list_only;
515                 list_only = 1;
516         }
517         
518         send_exclude_list(f_out);
519         
520         flist = recv_file_list(f_in);
521         if (!flist || flist->count == 0) {
522                 rprintf(FINFO, "client: nothing to do: "
523                         "perhaps you need to specify some filenames or "
524                         "the --recursive option?\n");
525                 exit_cleanup(0);
526         }
527         
528         local_name = get_local_name(flist,argv[0]);
529         
530         status2 = do_recv(f_in,f_out,flist,local_name);
531         
532         if (pid != -1) {
533                 if (verbose > 3)
534                         rprintf(FINFO,"client_run2 waiting on %d\n",pid);
535                 io_flush();
536                 wait_process(pid, &status);
537         }
538         
539         return status | status2;
540 }
541
542 static char *find_colon(char *s)
543 {
544         char *p, *p2;
545
546         p = strchr(s,':');
547         if (!p) return NULL;
548         
549         /* now check to see if there is a / in the string before the : - if there is then
550            discard the colon on the assumption that the : is part of a filename */
551         p2 = strchr(s,'/');
552         if (p2 && p2 < p) return NULL;
553
554         return p;
555 }
556
557 static int start_client(int argc, char *argv[])
558 {
559         char *p;
560         char *shell_machine = NULL;
561         char *shell_path = NULL;
562         char *shell_user = NULL;
563         int pid, ret;
564         int f_in,f_out;
565         extern int local_server;
566         extern int am_sender;
567         extern char *shell_cmd;
568         extern int rsync_port;
569         char *argv0 = strdup(argv[0]);
570
571         if (strncasecmp(URL_PREFIX, argv0, strlen(URL_PREFIX)) == 0) {
572                 char *host, *path;
573
574                 host = argv0 + strlen(URL_PREFIX);
575                 p = strchr(host,'/');
576                 if (p) {
577                         *p = 0;
578                         path = p+1;
579                 } else {
580                         path="";
581                 }
582                 p = strchr(host,':');
583                 if (p) {
584                         rsync_port = atoi(p+1);
585                         *p = 0;
586                 }
587                 return start_socket_client(host, path, argc-1, argv+1);
588         }
589
590         p = find_colon(argv0);
591
592         if (p) {
593                 if (p[1] == ':') {
594                         *p = 0;
595                         return start_socket_client(argv0, p+2, argc-1, argv+1);
596                 }
597
598                 if (argc < 1) {
599                         usage(FERROR);
600                         exit_cleanup(RERR_SYNTAX);
601                 }
602
603                 am_sender = 0;
604                 *p = 0;
605                 shell_machine = argv0;
606                 shell_path = p+1;
607                 argc--;
608                 argv++;
609         } else {
610                 am_sender = 1;
611
612                 p = find_colon(argv[argc-1]);
613                 if (!p) {
614                         local_server = 1;
615                 } else if (p[1] == ':') {
616                         *p = 0;
617                         return start_socket_client(argv[argc-1], p+2, argc-1, argv);
618                 }
619
620                 if (argc < 2) {
621                         usage(FERROR);
622                         exit_cleanup(RERR_SYNTAX);
623                 }
624                 
625                 if (local_server) {
626                         shell_machine = NULL;
627                         shell_path = argv[argc-1];
628                 } else {
629                         *p = 0;
630                         shell_machine = argv[argc-1];
631                         shell_path = p+1;
632                 }
633                 argc--;
634         }
635         
636         if (shell_machine) {
637                 p = strchr(shell_machine,'@');
638                 if (p) {
639                         *p = 0;
640                         shell_user = shell_machine;
641                         shell_machine = p+1;
642                 }
643         }
644
645         if (verbose > 3) {
646                 rprintf(FINFO,"cmd=%s machine=%s user=%s path=%s\n",
647                         shell_cmd?shell_cmd:"",
648                         shell_machine?shell_machine:"",
649                         shell_user?shell_user:"",
650                         shell_path?shell_path:"");
651         }
652         
653         if (!am_sender && argc > 1) {
654                 usage(FERROR);
655                 exit_cleanup(RERR_SYNTAX);
656         }
657
658         if (argc == 0 && !am_sender) {
659                 extern int list_only;
660                 list_only = 1;
661         }
662         
663         pid = do_cmd(shell_cmd,shell_machine,shell_user,shell_path,&f_in,&f_out);
664         
665         ret = client_run(f_in, f_out, pid, argc, argv);
666
667         fflush(stdout);
668         fflush(stderr);
669
670         return ret;
671 }
672
673
674 static RETSIGTYPE sigusr1_handler(int val) {
675         exit_cleanup(RERR_SIGNAL);
676 }
677
678 static RETSIGTYPE sigusr2_handler(int val) {
679         _exit(0);
680 }
681
682 int main(int argc,char *argv[])
683 {       
684         extern int am_root;
685         extern int orig_umask;
686         extern int dry_run;
687         extern int am_daemon;
688         extern int am_server;
689
690         signal(SIGUSR1, sigusr1_handler);
691         signal(SIGUSR2, sigusr2_handler);
692
693         starttime = time(NULL);
694         am_root = (getuid() == 0);
695
696         memset(&stats, 0, sizeof(stats));
697
698         if (argc < 2) {
699                 usage(FERROR);
700                 exit_cleanup(RERR_SYNTAX);
701         }
702
703         /* we set a 0 umask so that correct file permissions can be
704            carried across */
705         orig_umask = (int)umask(0);
706
707         if (!parse_arguments(argc, argv, 1)) {
708                 exit_cleanup(RERR_SYNTAX);
709         }
710
711         argc -= optind;
712         argv += optind;
713         optind = 0;
714
715         signal(SIGCHLD,SIG_IGN);
716         signal(SIGINT,SIGNAL_CAST sig_int);
717         signal(SIGPIPE,SIGNAL_CAST sig_int);
718         signal(SIGHUP,SIGNAL_CAST sig_int);
719         signal(SIGTERM,SIGNAL_CAST sig_int);
720
721         /* Initialize push_dir here because on some old systems getcwd
722            (implemented by forking "pwd" and reading its output) doesn't
723            work when there are other child processes.  Also, on all systems
724            that implement getcwd that way "pwd" can't be found after chroot. */
725         push_dir(NULL,0);
726
727         if (am_daemon) {
728                 return daemon_main();
729         }
730
731         if (argc < 1) {
732                 usage(FERROR);
733                 exit_cleanup(RERR_SYNTAX);
734         }
735
736         if (dry_run)
737                 verbose = MAX(verbose,1);
738
739 #ifndef SUPPORT_LINKS
740         if (!am_server && preserve_links) {
741                 rprintf(FERROR,"ERROR: symbolic links not supported\n");
742                 exit_cleanup(RERR_UNSUPPORTED);
743         }
744 #endif
745
746         if (am_server) {
747                 set_nonblocking(STDIN_FILENO);
748                 set_nonblocking(STDOUT_FILENO);
749                 start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
750         }
751
752         return start_client(argc, argv);
753 }
754