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