split the options parsing code into options.c
[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                 in = read_longint(f);
52                 out = 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 (am_daemon) {
208                 extern int module_id;
209                 char *name = lp_name(module_id);
210                 int l = strlen(name);
211                 for (i=0;i<argc;i++) {
212                         if (strncmp(argv[i], name, l) == 0) {
213                                 argv[i] += l;
214                                 if (!*argv[i]) argv[i] = ".";
215                         }
216                 }
217         }
218         
219         if (argc == 0 && recurse) {
220                 argc=1;
221                 argv--;
222                 argv[0] = ".";
223         }
224         
225         rprintf(FINFO,"sending file list\n");
226         
227         flist = send_file_list(f_out,argc,argv);
228         send_files(flist,f_out,f_in);
229         report(f_out);
230         exit_cleanup(0);
231 }
232
233
234 static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
235 {
236   int pid;
237   int status=0;
238   int recv_pipe[2];
239   extern int preserve_hard_links;
240
241   if (preserve_hard_links)
242     init_hard_links(flist);
243
244   if (pipe(recv_pipe) < 0) {
245     rprintf(FERROR,"pipe failed in do_recv\n");
246     exit(1);
247   }
248   
249
250   if ((pid=do_fork()) == 0) {
251     recv_files(f_in,flist,local_name,recv_pipe[1]);
252     if (verbose > 2)
253       rprintf(FINFO,"receiver read %ld\n",(long)read_total());
254     exit_cleanup(0);
255   }
256
257   generate_files(f_out,flist,local_name,recv_pipe[0]);
258
259   waitpid(pid, &status, 0);
260
261   return status;
262 }
263
264
265 static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
266 {
267         int status;
268         struct file_list *flist;
269         char *local_name=NULL;
270         char *dir = NULL;
271         extern int delete_mode;
272         extern int am_daemon;
273
274         if (verbose > 2)
275                 rprintf(FINFO,"server_recv(%d) starting pid=%d\n",argc,(int)getpid());
276         
277         if (am_daemon) {
278                 extern int module_id;
279                 char *name = lp_name(module_id);
280                 int i, l = strlen(name);
281                 for (i=0;i<argc;i++) {
282                         if (strncmp(argv[i], name, l) == 0) {
283                                 argv[i] += l;
284                                 if (!*argv[i]) argv[i] = ".";
285                         }
286                 }
287         }
288
289         if (argc > 0) {
290                 dir = argv[0];
291                 argc--;
292                 argv++;
293                 if (!am_daemon && chdir(dir) != 0) {
294                         rprintf(FERROR,"chdir %s : %s (4)\n",
295                                 dir,strerror(errno));
296                         exit_cleanup(1);
297                 }    
298         }
299
300         if (delete_mode)
301                 recv_exclude_list(f_in);
302
303         flist = recv_file_list(f_in);
304         if (!flist || flist->count == 0) {
305                 rprintf(FERROR,"nothing to do\n");
306                 exit_cleanup(1);
307         }
308         
309         if (argc > 0) {    
310                 if (strcmp(dir,".")) {
311                         argv[0] += strlen(dir);
312                         if (argv[0][0] == '/') argv[0]++;
313                 }
314                 local_name = get_local_name(flist,argv[0]);
315         }
316
317         status = do_recv(f_in,f_out,flist,local_name);
318         exit_cleanup(status);
319 }
320
321
322 void start_server(int f_in, int f_out, int argc, char *argv[])
323 {
324         extern int cvs_exclude;
325         extern int am_sender;
326
327         setup_protocol(f_out, f_in);
328         
329         if (am_sender) {
330                 recv_exclude_list(f_in);
331                 if (cvs_exclude)
332                         add_cvs_excludes();
333                 do_server_sender(f_in, f_out, argc, argv);
334         } else {
335                 do_server_recv(f_in, f_out, argc, argv);
336         }
337         exit_cleanup(0);
338 }
339
340 int client_run(int f_in, int f_out, int pid, int argc, char *argv[])
341 {
342         struct file_list *flist;
343         int status = 0, status2 = 0;
344         char *local_name = NULL;
345         extern int am_sender;
346
347         setup_protocol(f_out,f_in);
348         
349         if (am_sender) {
350                 extern int cvs_exclude;
351                 extern int delete_mode;
352                 if (cvs_exclude)
353                         add_cvs_excludes();
354                 if (delete_mode) 
355                         send_exclude_list(f_out);
356                 flist = send_file_list(f_out,argc,argv);
357                 if (verbose > 3) 
358                         rprintf(FINFO,"file list sent\n");
359                 send_files(flist,f_out,f_in);
360                 if (pid != -1) {
361                         if (verbose > 3)
362                                 rprintf(FINFO,"waiting on %d\n",pid);
363                         waitpid(pid, &status, 0);
364                 }
365                 report(-1);
366                 exit_cleanup(status);
367         }
368         
369         send_exclude_list(f_out);
370         
371         flist = recv_file_list(f_in);
372         if (!flist || flist->count == 0) {
373                 rprintf(FINFO,"nothing to do\n");
374                 exit_cleanup(0);
375         }
376         
377         local_name = get_local_name(flist,argv[0]);
378         
379         status2 = do_recv(f_in,f_out,flist,local_name);
380         
381         report(f_in);
382         
383         if (pid != -1) {
384                 waitpid(pid, &status, 0);
385         }
386         
387         return status | status2;
388 }
389
390
391 int start_client(int argc, char *argv[])
392 {
393         char *p;
394         char *shell_machine = NULL;
395         char *shell_path = NULL;
396         char *shell_user = NULL;
397         int pid;
398         int f_in,f_out;
399         extern int local_server;
400         extern int am_sender;
401         extern char *shell_cmd;
402
403         p = strchr(argv[0],':');
404
405         if (p) {
406                 if (p[1] == ':') {
407                         *p = 0;
408                         return start_socket_client(argv[0], p+2, argc-1, argv+1);
409                 }
410
411                 if (argc < 2) {
412                         usage(FERROR);
413                         exit_cleanup(1);
414                 }
415
416                 am_sender = 0;
417                 *p = 0;
418                 shell_machine = argv[0];
419                 shell_path = p+1;
420                 argc--;
421                 argv++;
422         } else {
423                 am_sender = 1;
424
425                 p = strchr(argv[argc-1],':');
426                 if (!p) {
427                         local_server = 1;
428                 } else if (p[1] == ':') {
429                         *p = 0;
430                         return start_socket_client(argv[argc-1], p+2, argc-1, argv);
431                 }
432
433                 if (argc < 2) {
434                         usage(FERROR);
435                         exit_cleanup(1);
436                 }
437                 
438                 if (local_server) {
439                         shell_machine = NULL;
440                         shell_path = argv[argc-1];
441                 } else {
442                         *p = 0;
443                         shell_machine = argv[argc-1];
444                         shell_path = p+1;
445                 }
446                 argc--;
447         }
448         
449         if (shell_machine) {
450                 p = strchr(shell_machine,'@');
451                 if (p) {
452                         *p = 0;
453                         shell_user = shell_machine;
454                         shell_machine = p+1;
455                 }
456         }
457
458         if (verbose > 3) {
459                 rprintf(FINFO,"cmd=%s machine=%s user=%s path=%s\n",
460                         shell_cmd?shell_cmd:"",
461                         shell_machine?shell_machine:"",
462                         shell_user?shell_user:"",
463                         shell_path?shell_path:"");
464         }
465         
466         if (!am_sender && argc != 1) {
467                 usage(FERROR);
468                 exit_cleanup(1);
469         }
470         
471         pid = do_cmd(shell_cmd,shell_machine,shell_user,shell_path,&f_in,&f_out);
472         
473 #if HAVE_SETLINEBUF
474         setlinebuf(stdout);
475         setlinebuf(stderr);
476 #endif
477
478         return client_run(f_in, f_out, pid, argc, argv);
479 }
480
481
482 RETSIGTYPE sigusr1_handler(int val) {
483         exit_cleanup(1);
484 }
485
486 int main(int argc,char *argv[])
487 {       
488         extern int am_root;
489         extern int orig_umask;
490         extern int dry_run;
491         extern int am_daemon;
492         extern int am_server;
493
494         signal(SIGUSR1, sigusr1_handler);
495
496         starttime = time(NULL);
497         am_root = (getuid() == 0);
498
499         /* we set a 0 umask so that correct file permissions can be
500            carried across */
501         orig_umask = (int)umask(0);
502
503         parse_arguments(argc, argv);
504
505         argc -= optind;
506         argv += optind;
507         optind = 0;
508
509         signal(SIGCHLD,SIG_IGN);
510         signal(SIGINT,SIGNAL_CAST sig_int);
511         signal(SIGPIPE,SIGNAL_CAST sig_int);
512         signal(SIGHUP,SIGNAL_CAST sig_int);
513
514         if (am_daemon) {
515                 return daemon_main();
516         }
517
518         if (dry_run)
519                 verbose = MAX(verbose,1);
520
521 #ifndef SUPPORT_LINKS
522         if (!am_server && preserve_links) {
523                 rprintf(FERROR,"ERROR: symbolic links not supported\n");
524                 exit_cleanup(1);
525         }
526 #endif
527
528         if (am_server) {
529                 start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
530         }
531
532         return start_client(argc, argv);
533 }
534