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