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