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