added globbing support in the rsync daemon. This will allow you to
[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 int64 total_size = 0;
24
25 extern int csum_length;
26
27 extern int verbose;
28
29 static void report(int f)
30 {
31         int64 in,out,tsize;
32         time_t t = time(NULL);
33         extern int am_server;
34         extern int am_sender;
35
36         if (!verbose) return;
37
38         if (am_server && am_sender) {
39                 write_longint(f,read_total());
40                 write_longint(f,write_total());
41                 write_longint(f,total_size);
42                 write_flush(f);
43                 return;
44         }
45     
46         if (am_sender) {
47                 in = read_total();
48                 out = write_total();
49                 tsize = total_size;
50         } else {
51                 out = read_longint(f);
52                 in = read_longint(f);
53                 tsize = read_longint(f);
54         }
55         
56         printf("wrote %.0f bytes  read %.0f bytes  %.2f bytes/sec\n",
57                (double)out,(double)in,(in+out)/(0.5 + (t-starttime)));
58         printf("total size is %.0f  speedup is %.2f\n",
59                (double)tsize,(1.0*tsize)/(in+out));
60 }
61
62
63 static int do_cmd(char *cmd,char *machine,char *user,char *path,int *f_in,int *f_out)
64 {
65         char *args[100];
66         int i,argc=0, ret;
67         char *tok,*dir=NULL;
68         extern int local_server;
69         extern char *rsync_path;
70
71         if (!local_server) {
72                 if (!cmd)
73                         cmd = getenv(RSYNC_RSH_ENV);
74                 if (!cmd)
75                         cmd = RSYNC_RSH;
76                 cmd = strdup(cmd);
77                 if (!cmd) 
78                         goto oom;
79
80                 for (tok=strtok(cmd," ");tok;tok=strtok(NULL," ")) {
81                         args[argc++] = tok;
82                 }
83
84 #if HAVE_REMSH
85                 /* remsh (on HPUX) takes the arguments the other way around */
86                 args[argc++] = machine;
87                 if (user) {
88                         args[argc++] = "-l";
89                         args[argc++] = user;
90                 }
91 #else
92                 if (user) {
93                         args[argc++] = "-l";
94                         args[argc++] = user;
95                 }
96                 args[argc++] = machine;
97 #endif
98
99                 args[argc++] = rsync_path;
100
101                 server_options(args,&argc);
102         }
103
104         args[argc++] = ".";
105
106         if (path && *path) 
107                 args[argc++] = path;
108
109         args[argc] = NULL;
110
111         if (verbose > 3) {
112                 rprintf(FINFO,"cmd=");
113                 for (i=0;i<argc;i++)
114                         rprintf(FINFO,"%s ",args[i]);
115                 rprintf(FINFO,"\n");
116         }
117
118         if (local_server) {
119                 ret = local_child(argc, args, f_in, f_out);
120         } else {
121                 ret = piped_child(args,f_in,f_out);
122         }
123
124         if (dir) free(dir);
125
126         return ret;
127
128 oom:
129         out_of_memory("do_cmd");
130         return 0; /* not reached */
131 }
132
133
134
135
136 static char *get_local_name(struct file_list *flist,char *name)
137 {
138         STRUCT_STAT st;
139         extern int orig_umask;
140
141   if (do_stat(name,&st) == 0) {
142     if (S_ISDIR(st.st_mode)) {
143       if (chdir(name) != 0) {
144         rprintf(FERROR,"chdir %s : %s (1)\n",name,strerror(errno));
145         exit_cleanup(1);
146       }
147       return NULL;
148     }
149     if (flist->count > 1) {
150       rprintf(FERROR,"ERROR: destination must be a directory when copying more than 1 file\n");
151       exit_cleanup(1);
152     }
153     return name;
154   }
155
156   if (flist->count == 1)
157     return name;
158
159   if (!name) 
160     return NULL;
161
162   if (do_mkdir(name,0777 & ~orig_umask) != 0) {
163     rprintf(FERROR,"mkdir %s : %s (1)\n",name,strerror(errno));
164     exit_cleanup(1);
165   } else {
166     rprintf(FINFO,"created directory %s\n",name);
167   }
168
169   if (chdir(name) != 0) {
170     rprintf(FERROR,"chdir %s : %s (2)\n",name,strerror(errno));
171     exit_cleanup(1);
172   }
173
174   return NULL;
175 }
176
177
178
179
180 static void do_server_sender(int f_in, int f_out, int argc,char *argv[])
181 {
182         int i;
183         struct file_list *flist;
184         char *dir = argv[0];
185         extern int relative_paths;
186         extern int am_daemon;
187         extern int recurse;
188
189         if (verbose > 2)
190                 rprintf(FINFO,"server_sender starting pid=%d\n",(int)getpid());
191   
192         if (!relative_paths && chdir(dir) != 0) {
193                 rprintf(FERROR,"chdir %s: %s (3)\n",dir,strerror(errno));
194                 exit_cleanup(1);
195         }
196         argc--;
197         argv++;
198   
199         if (strcmp(dir,".")) {
200                 int l = strlen(dir);
201                 if (strcmp(dir,"/") == 0) 
202                         l = 0;
203                 for (i=0;i<argc;i++)
204                         argv[i] += l+1;
205         }
206
207         if (argc == 0 && recurse) {
208                 argc=1;
209                 argv--;
210                 argv[0] = ".";
211         }
212         
213         flist = send_file_list(f_out,argc,argv);
214         send_files(flist,f_out,f_in);
215         report(f_out);
216         exit_cleanup(0);
217 }
218
219
220 static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
221 {
222   int pid;
223   int status=0;
224   int recv_pipe[2];
225   extern int preserve_hard_links;
226
227   if (preserve_hard_links)
228     init_hard_links(flist);
229
230   if (pipe(recv_pipe) < 0) {
231     rprintf(FERROR,"pipe failed in do_recv\n");
232     exit(1);
233   }
234   
235
236   if ((pid=do_fork()) == 0) {
237     recv_files(f_in,flist,local_name,recv_pipe[1]);
238     if (verbose > 2)
239       rprintf(FINFO,"receiver read %ld\n",(long)read_total());
240     exit_cleanup(0);
241   }
242
243   generate_files(f_out,flist,local_name,recv_pipe[0]);
244
245   waitpid(pid, &status, 0);
246
247   return status;
248 }
249
250
251 static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
252 {
253         int status;
254         struct file_list *flist;
255         char *local_name=NULL;
256         char *dir = NULL;
257         extern int delete_mode;
258         extern int am_daemon;
259
260         if (verbose > 2)
261                 rprintf(FINFO,"server_recv(%d) starting pid=%d\n",argc,(int)getpid());
262         
263         if (argc > 0) {
264                 dir = argv[0];
265                 argc--;
266                 argv++;
267                 if (!am_daemon && chdir(dir) != 0) {
268                         rprintf(FERROR,"chdir %s : %s (4)\n",
269                                 dir,strerror(errno));
270                         exit_cleanup(1);
271                 }    
272         }
273
274         if (delete_mode)
275                 recv_exclude_list(f_in);
276
277         flist = recv_file_list(f_in);
278         if (!flist || flist->count == 0) {
279                 rprintf(FERROR,"nothing to do\n");
280                 exit_cleanup(1);
281         }
282         
283         if (argc > 0) {    
284                 if (strcmp(dir,".")) {
285                         argv[0] += strlen(dir);
286                         if (argv[0][0] == '/') argv[0]++;
287                 }
288                 local_name = get_local_name(flist,argv[0]);
289         }
290
291         status = do_recv(f_in,f_out,flist,local_name);
292         exit_cleanup(status);
293 }
294
295
296 void start_server(int f_in, int f_out, int argc, char *argv[])
297 {
298         extern int cvs_exclude;
299         extern int am_sender;
300
301         setup_protocol(f_out, f_in);
302         
303         if (am_sender) {
304                 recv_exclude_list(f_in);
305                 if (cvs_exclude)
306                         add_cvs_excludes();
307                 do_server_sender(f_in, f_out, argc, argv);
308         } else {
309                 do_server_recv(f_in, f_out, argc, argv);
310         }
311         exit_cleanup(0);
312 }
313
314 int client_run(int f_in, int f_out, int pid, int argc, char *argv[])
315 {
316         struct file_list *flist;
317         int status = 0, status2 = 0;
318         char *local_name = NULL;
319         extern int am_sender;
320
321         setup_protocol(f_out,f_in);
322         
323         if (am_sender) {
324                 extern int cvs_exclude;
325                 extern int delete_mode;
326                 if (cvs_exclude)
327                         add_cvs_excludes();
328                 if (delete_mode) 
329                         send_exclude_list(f_out);
330                 flist = send_file_list(f_out,argc,argv);
331                 if (verbose > 3) 
332                         rprintf(FINFO,"file list sent\n");
333                 send_files(flist,f_out,f_in);
334                 if (pid != -1) {
335                         if (verbose > 3)
336                                 rprintf(FINFO,"waiting on %d\n",pid);
337                         waitpid(pid, &status, 0);
338                 }
339                 report(-1);
340                 exit_cleanup(status);
341         }
342         
343         send_exclude_list(f_out);
344         
345         flist = recv_file_list(f_in);
346         if (!flist || flist->count == 0) {
347                 rprintf(FINFO,"nothing to do\n");
348                 exit_cleanup(0);
349         }
350         
351         local_name = get_local_name(flist,argv[0]);
352         
353         status2 = do_recv(f_in,f_out,flist,local_name);
354         
355         report(f_in);
356         
357         if (pid != -1) {
358                 waitpid(pid, &status, 0);
359         }
360         
361         return status | status2;
362 }
363
364
365 int start_client(int argc, char *argv[])
366 {
367         char *p;
368         char *shell_machine = NULL;
369         char *shell_path = NULL;
370         char *shell_user = NULL;
371         int pid;
372         int f_in,f_out;
373         extern int local_server;
374         extern int am_sender;
375         extern char *shell_cmd;
376
377         p = strchr(argv[0],':');
378
379         if (p) {
380                 if (p[1] == ':') {
381                         *p = 0;
382                         return start_socket_client(argv[0], p+2, argc-1, argv+1);
383                 }
384
385                 if (argc < 2) {
386                         usage(FERROR);
387                         exit_cleanup(1);
388                 }
389
390                 am_sender = 0;
391                 *p = 0;
392                 shell_machine = argv[0];
393                 shell_path = p+1;
394                 argc--;
395                 argv++;
396         } else {
397                 am_sender = 1;
398
399                 p = strchr(argv[argc-1],':');
400                 if (!p) {
401                         local_server = 1;
402                 } else if (p[1] == ':') {
403                         *p = 0;
404                         return start_socket_client(argv[argc-1], p+2, argc-1, argv);
405                 }
406
407                 if (argc < 2) {
408                         usage(FERROR);
409                         exit_cleanup(1);
410                 }
411                 
412                 if (local_server) {
413                         shell_machine = NULL;
414                         shell_path = argv[argc-1];
415                 } else {
416                         *p = 0;
417                         shell_machine = argv[argc-1];
418                         shell_path = p+1;
419                 }
420                 argc--;
421         }
422         
423         if (shell_machine) {
424                 p = strchr(shell_machine,'@');
425                 if (p) {
426                         *p = 0;
427                         shell_user = shell_machine;
428                         shell_machine = p+1;
429                 }
430         }
431
432         if (verbose > 3) {
433                 rprintf(FINFO,"cmd=%s machine=%s user=%s path=%s\n",
434                         shell_cmd?shell_cmd:"",
435                         shell_machine?shell_machine:"",
436                         shell_user?shell_user:"",
437                         shell_path?shell_path:"");
438         }
439         
440         if (!am_sender && argc != 1) {
441                 usage(FERROR);
442                 exit_cleanup(1);
443         }
444         
445         pid = do_cmd(shell_cmd,shell_machine,shell_user,shell_path,&f_in,&f_out);
446         
447 #if HAVE_SETLINEBUF
448         setlinebuf(stdout);
449         setlinebuf(stderr);
450 #endif
451
452         return client_run(f_in, f_out, pid, argc, argv);
453 }
454
455
456 RETSIGTYPE sigusr1_handler(int val) {
457         exit_cleanup(1);
458 }
459
460 int main(int argc,char *argv[])
461 {       
462         extern int am_root;
463         extern int orig_umask;
464         extern int dry_run;
465         extern int am_daemon;
466         extern int am_server;
467
468         signal(SIGUSR1, sigusr1_handler);
469
470         starttime = time(NULL);
471         am_root = (getuid() == 0);
472
473         if (argc < 2) {
474                 usage(FERROR);
475                 exit(1);
476         }
477
478         /* we set a 0 umask so that correct file permissions can be
479            carried across */
480         orig_umask = (int)umask(0);
481
482         parse_arguments(argc, argv);
483
484         argc -= optind;
485         argv += optind;
486         optind = 0;
487
488         signal(SIGCHLD,SIG_IGN);
489         signal(SIGINT,SIGNAL_CAST sig_int);
490         signal(SIGPIPE,SIGNAL_CAST sig_int);
491         signal(SIGHUP,SIGNAL_CAST sig_int);
492
493         if (am_daemon) {
494                 return daemon_main();
495         }
496
497         if (dry_run)
498                 verbose = MAX(verbose,1);
499
500 #ifndef SUPPORT_LINKS
501         if (!am_server && preserve_links) {
502                 rprintf(FERROR,"ERROR: symbolic links not supported\n");
503                 exit_cleanup(1);
504         }
505 #endif
506
507         if (am_server) {
508                 start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
509         }
510
511         return start_client(argc, argv);
512 }
513