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