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