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