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