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