Try to fix "infinite loop" warning on AIX and other compilers. (We
[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 (msleep(20))
364                         ;
365         }
366
367         close(recv_pipe[1]);
368         close(error_pipe[1]);
369         if (f_in != f_out) close(f_in);
370
371         io_start_buffering(f_out);
372
373         io_set_error_fd(error_pipe[0]);
374
375         generate_files(f_out,flist,local_name,recv_pipe[0]);
376
377         read_int(recv_pipe[0]);
378         close(recv_pipe[0]);
379         if (remote_version >= 24) {
380                 /* send a final goodbye message */
381                 write_int(f_out, -1);
382         }
383         io_flush();
384
385         kill(pid, SIGUSR2);
386         wait_process(pid, &status);
387         return status;
388 }
389
390
391 static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
392 {
393         int status;
394         struct file_list *flist;
395         char *local_name=NULL;
396         char *dir = NULL;
397         extern int delete_mode;
398         extern int delete_excluded;
399         extern int am_daemon;
400         extern int module_id;
401         extern int am_sender;
402
403         if (verbose > 2)
404                 rprintf(FINFO,"server_recv(%d) starting pid=%d\n",argc,(int)getpid());
405
406         if (am_daemon && lp_read_only(module_id) && !am_sender) {
407                 rprintf(FERROR,"ERROR: module is read only\n");
408                 exit_cleanup(RERR_SYNTAX);
409                 return;
410         }
411
412         
413         if (argc > 0) {
414                 dir = argv[0];
415                 argc--;
416                 argv++;
417                 if (!am_daemon && !push_dir(dir, 0)) {
418                         rprintf(FERROR,"push_dir %s : %s (4)\n",
419                                 dir,strerror(errno));
420                         exit_cleanup(RERR_FILESELECT);
421                 }    
422         }
423
424         if (delete_mode && !delete_excluded)
425                 recv_exclude_list(f_in);
426
427         flist = recv_file_list(f_in);
428         if (!flist) {
429                 rprintf(FERROR,"server_recv: recv_file_list error\n");
430                 exit_cleanup(RERR_FILESELECT);
431         }
432         
433         if (argc > 0) {    
434                 if (strcmp(dir,".")) {
435                         argv[0] += strlen(dir);
436                         if (argv[0][0] == '/') argv[0]++;
437                 }
438                 local_name = get_local_name(flist,argv[0]);
439         }
440
441         status = do_recv(f_in,f_out,flist,local_name);
442         exit_cleanup(status);
443 }
444
445
446 void start_server(int f_in, int f_out, int argc, char *argv[])
447 {
448         extern int cvs_exclude;
449         extern int am_sender;
450         extern int remote_version;
451
452         setup_protocol(f_out, f_in);
453
454         set_nonblocking(f_in);
455         set_nonblocking(f_out);
456
457         if (remote_version >= 23)
458                 io_start_multiplex_out(f_out);
459
460         if (am_sender) {
461                 recv_exclude_list(f_in);
462                 if (cvs_exclude)
463                         add_cvs_excludes();
464                 do_server_sender(f_in, f_out, argc, argv);
465         } else {
466                 do_server_recv(f_in, f_out, argc, argv);
467         }
468         exit_cleanup(0);
469 }
470
471
472 /*
473  * This is called once the connection has been negotiated.  It is used
474  * for rsyncd, remote-shell, and local connections.
475  */
476 int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[])
477 {
478         struct file_list *flist;
479         int status = 0, status2 = 0;
480         char *local_name = NULL;
481         extern int am_sender;
482         extern int remote_version;
483         extern pid_t cleanup_child_pid;
484
485         cleanup_child_pid = pid;
486
487         set_nonblocking(f_in);
488         set_nonblocking(f_out);
489
490         setup_protocol(f_out,f_in);
491
492         if (remote_version >= 23)
493                 io_start_multiplex_in(f_in);
494         
495         if (am_sender) {
496                 extern int cvs_exclude;
497                 extern int delete_mode;
498                 extern int delete_excluded;
499                 if (cvs_exclude)
500                         add_cvs_excludes();
501                 if (delete_mode && !delete_excluded) 
502                         send_exclude_list(f_out);
503                 flist = send_file_list(f_out,argc,argv);
504                 if (verbose > 3) 
505                         rprintf(FINFO,"file list sent\n");
506
507                 send_files(flist,f_out,f_in);
508                 if (remote_version >= 24) {
509                         /* final goodbye message */             
510                         read_int(f_in);
511                 }
512                 if (pid != -1) {
513                         if (verbose > 3)
514                                 rprintf(FINFO,"client_run waiting on %d\n",pid);
515                         io_flush();
516                         wait_process(pid, &status);
517                 }
518                 report(-1);
519                 exit_cleanup(status);
520         }
521
522         if (argc == 0) {
523                 extern int list_only;
524                 list_only = 1;
525         }
526         
527         send_exclude_list(f_out);
528         
529         flist = recv_file_list(f_in);
530         if (!flist || flist->count == 0) {
531                 rprintf(FINFO, "client: nothing to do: "
532                         "perhaps you need to specify some filenames or "
533                         "the --recursive option?\n");
534                 exit_cleanup(0);
535         }
536         
537         local_name = get_local_name(flist,argv[0]);
538         
539         status2 = do_recv(f_in,f_out,flist,local_name);
540         
541         if (pid != -1) {
542                 if (verbose > 3)
543                         rprintf(FINFO,"client_run2 waiting on %d\n",pid);
544                 io_flush();
545                 wait_process(pid, &status);
546         }
547         
548         return MAX(status, status2);
549 }
550
551 static char *find_colon(char *s)
552 {
553         char *p, *p2;
554
555         p = strchr(s,':');
556         if (!p) return NULL;
557         
558         /* now check to see if there is a / in the string before the : - if there is then
559            discard the colon on the assumption that the : is part of a filename */
560         p2 = strchr(s,'/');
561         if (p2 && p2 < p) return NULL;
562
563         return p;
564 }
565
566
567 /*
568  * Start a client for either type of remote connection.  Work out
569  * whether the arguments request a remote shell or rsyncd connection,
570  * and call the appropriate connection function, then run_client.
571  */
572 static int start_client(int argc, char *argv[])
573 {
574         char *p;
575         char *shell_machine = NULL;
576         char *shell_path = NULL;
577         char *shell_user = NULL;
578         int ret;
579         pid_t pid;
580         int f_in,f_out;
581         extern int local_server;
582         extern int am_sender;
583         extern char *shell_cmd;
584         extern int rsync_port;
585         extern int whole_file;
586         char *argv0 = strdup(argv[0]);
587
588         if (strncasecmp(URL_PREFIX, argv0, strlen(URL_PREFIX)) == 0) {
589                 char *host, *path;
590
591                 host = argv0 + strlen(URL_PREFIX);
592                 p = strchr(host,'/');
593                 if (p) {
594                         *p = 0;
595                         path = p+1;
596                 } else {
597                         path="";
598                 }
599                 p = strchr(host,':');
600                 if (p) {
601                         rsync_port = atoi(p+1);
602                         *p = 0;
603                 }
604                 return start_socket_client(host, path, argc-1, argv+1);
605         }
606
607         p = find_colon(argv0);
608
609         if (p) {
610                 if (p[1] == ':') {
611                         *p = 0;
612                         return start_socket_client(argv0, p+2, argc-1, argv+1);
613                 }
614
615                 if (argc < 1) {
616                         usage(FERROR);
617                         exit_cleanup(RERR_SYNTAX);
618                 }
619
620                 am_sender = 0;
621                 *p = 0;
622                 shell_machine = argv0;
623                 shell_path = p+1;
624                 argc--;
625                 argv++;
626         } else {
627                 am_sender = 1;
628
629                 p = find_colon(argv[argc-1]);
630                 if (!p) {
631                         local_server = 1;
632                         /* disable "rsync algorithm" when both sides local */
633                         whole_file = 1;
634                 } else if (p[1] == ':') {
635                         *p = 0;
636                         return start_socket_client(argv[argc-1], p+2, argc-1, argv);
637                 }
638
639                 if (argc < 2) {
640                         usage(FERROR);
641                         exit_cleanup(RERR_SYNTAX);
642                 }
643                 
644                 if (local_server) {
645                         shell_machine = NULL;
646                         shell_path = argv[argc-1];
647                 } else {
648                         *p = 0;
649                         shell_machine = argv[argc-1];
650                         shell_path = p+1;
651                 }
652                 argc--;
653         }
654         
655         if (shell_machine) {
656                 p = strchr(shell_machine,'@');
657                 if (p) {
658                         *p = 0;
659                         shell_user = shell_machine;
660                         shell_machine = p+1;
661                 }
662         }
663
664         if (verbose > 3) {
665                 rprintf(FINFO,"cmd=%s machine=%s user=%s path=%s\n",
666                         shell_cmd?shell_cmd:"",
667                         shell_machine?shell_machine:"",
668                         shell_user?shell_user:"",
669                         shell_path?shell_path:"");
670         }
671         
672         if (!am_sender && argc > 1) {
673                 usage(FERROR);
674                 exit_cleanup(RERR_SYNTAX);
675         }
676
677         if (argc == 0 && !am_sender) {
678                 extern int list_only;
679                 list_only = 1;
680         }
681         
682         pid = do_cmd(shell_cmd,shell_machine,shell_user,shell_path,&f_in,&f_out);
683         
684         ret = client_run(f_in, f_out, pid, argc, argv);
685
686         fflush(stdout);
687         fflush(stderr);
688
689         return ret;
690 }
691
692
693 static RETSIGTYPE sigusr1_handler(int val) {
694         exit_cleanup(RERR_SIGNAL);
695 }
696
697 static RETSIGTYPE sigusr2_handler(int val) {
698         extern int log_got_error;
699         if (log_got_error) _exit(RERR_PARTIAL);
700         _exit(0);
701 }
702
703 static RETSIGTYPE sigchld_handler(int val) {
704 #ifdef WNOHANG
705         while (waitpid(-1, NULL, WNOHANG) > 0) ;
706 #endif
707 }
708
709 int main(int argc,char *argv[])
710 {       
711         extern int am_root;
712         extern int orig_umask;
713         extern int dry_run;
714         extern int am_daemon;
715         extern int am_server;
716         int ret;
717
718         signal(SIGUSR1, sigusr1_handler);
719         signal(SIGUSR2, sigusr2_handler);
720         signal(SIGCHLD, sigchld_handler);
721
722         starttime = time(NULL);
723         am_root = (getuid() == 0);
724
725         memset(&stats, 0, sizeof(stats));
726
727         if (argc < 2) {
728                 usage(FERROR);
729                 exit_cleanup(RERR_SYNTAX);
730         }
731
732         /* we set a 0 umask so that correct file permissions can be
733            carried across */
734         orig_umask = (int)umask(0);
735
736         if (!parse_arguments(&argc, (const char ***) &argv, 1)) {
737                 /* FIXME: We ought to call the same error-handling
738                  * code here, rather than relying on getopt. */
739                 option_error();
740                 exit_cleanup(RERR_SYNTAX);
741         }
742
743         signal(SIGINT,SIGNAL_CAST sig_int);
744         signal(SIGPIPE,SIGNAL_CAST sig_int);
745         signal(SIGHUP,SIGNAL_CAST sig_int);
746         signal(SIGTERM,SIGNAL_CAST sig_int);
747
748         /* Initialize push_dir here because on some old systems getcwd
749            (implemented by forking "pwd" and reading its output) doesn't
750            work when there are other child processes.  Also, on all systems
751            that implement getcwd that way "pwd" can't be found after chroot. */
752         push_dir(NULL,0);
753
754         if (am_daemon) {
755                 return daemon_main();
756         }
757
758         if (argc < 1) {
759                 usage(FERROR);
760                 exit_cleanup(RERR_SYNTAX);
761         }
762
763         if (dry_run)
764                 verbose = MAX(verbose,1);
765
766 #ifndef SUPPORT_LINKS
767         if (!am_server && preserve_links) {
768                 rprintf(FERROR,"ERROR: symbolic links not supported\n");
769                 exit_cleanup(RERR_UNSUPPORTED);
770         }
771 #endif
772
773         if (am_server) {
774                 set_nonblocking(STDIN_FILENO);
775                 set_nonblocking(STDOUT_FILENO);
776                 start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
777         }
778
779         ret = start_client(argc, argv);
780         exit_cleanup(ret);
781         return ret;
782 }
783