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