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