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