1 /*- 2 * Copyright (c) 2000-2004 Dag-Erling Co�dan Sm�rgrav 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer 10 * in this position and unchanged. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #if HAVE_CONFIG_H 30 #include "config.h" 31 #endif 32 #if !defined(NETBSD) && !defined(__minix) 33 #include <nbcompat.h> 34 #endif 35 36 #if HAVE_SYS_PARAM_H 37 #include <sys/param.h> 38 #endif 39 #if HAVE_SYS_IOCTL_H 40 #include <sys/ioctl.h> 41 #endif 42 #if HAVE_SYS_SOCKET_H 43 #include <sys/socket.h> 44 #endif 45 #if HAVE_SYS_STAT_H 46 #include <sys/stat.h> 47 #endif 48 #if HAVE_SYS_TIME_H 49 #include <sys/time.h> 50 #endif 51 #if HAVE_UTIME_H 52 #include <utime.h> 53 #endif 54 #include <ctype.h> 55 #if HAVE_ERR_H 56 #include <err.h> 57 #endif 58 #include <errno.h> 59 #include <signal.h> 60 #if HAVE_STDINT_H 61 #include <stdint.h> 62 #endif 63 #include <stdio.h> 64 #include <stdlib.h> 65 #include <string.h> 66 #if HAVE_TERMIOS_H 67 #include <termios.h> 68 #endif 69 #include <unistd.h> 70 71 #include <fetch.h> 72 73 #if HAVE_SYSEXITS_H 74 #include <sysexits.h> 75 #endif 76 77 #ifndef EX_USAGE 78 #define EX_USAGE 64 79 #endif 80 81 #ifndef EX_IOERR 82 #define EX_IOERR 74 83 #endif 84 85 #define MINBUFSIZE 4096 86 87 /* Option flags */ 88 int A_flag; /* -A: do not follow 302 redirects */ 89 int a_flag; /* -a: auto retry */ 90 off_t B_size; /* -B: buffer size */ 91 int d_flag; /* -d: direct connection */ 92 int F_flag; /* -F: restart without checking mtime */ 93 int i_flag; /* -i: fetch file if modified */ 94 int l_flag; /* -l: link rather than copy file: URLs */ 95 int m_flag; /* -[Mm]: mirror mode */ 96 char *N_filename; /* -N: netrc file name */ 97 int n_flag; /* -n: do not preserve modification time */ 98 int o_flag; /* -o: specify output file */ 99 int o_directory; /* output file is a directory */ 100 char *o_filename; /* name of output file */ 101 int o_stdout; /* output file is stdout */ 102 int once_flag; /* -1: stop at first successful file */ 103 int R_flag; /* -R: don't delete partially transferred files */ 104 int r_flag; /* -r: restart previously interrupted transfer */ 105 off_t S_size; /* -S: require size to match */ 106 int s_flag; /* -s: show size, don't fetch */ 107 long T_secs = 120; /* -T: transfer timeout in seconds */ 108 int U_flag; /* -U: do not use high ports */ 109 int v_level = 1; /* -v: verbosity level */ 110 int v_tty; /* stdout is a tty */ 111 pid_t pgrp; /* our process group */ 112 long w_secs; /* -w: retry delay */ 113 int family = PF_UNSPEC; /* -[46]: address family to use */ 114 115 volatile int sigalrm; /* SIGALRM received */ 116 #ifdef SIGINFO 117 volatile int siginfo; /* SIGINFO received */ 118 #endif 119 volatile int sigint; /* SIGINT received */ 120 121 long ftp_timeout; /* default timeout for FTP transfers */ 122 long http_timeout; /* default timeout for HTTP transfers */ 123 char *buf; /* transfer buffer */ 124 125 126 /* 127 * Signal handler 128 */ 129 static void 130 sig_handler(int sig) 131 { 132 switch (sig) { 133 case SIGALRM: 134 fetchRestartCalls = 0; 135 sigalrm = 1; 136 break; 137 #ifdef SIGINFO 138 case SIGINFO: 139 siginfo = 1; 140 break; 141 #endif 142 case SIGINT: 143 fetchRestartCalls = 0; 144 sigint = 1; 145 break; 146 } 147 } 148 149 struct xferstat { 150 char name[64]; 151 struct timeval start; 152 struct timeval last; 153 off_t size; 154 off_t offset; 155 off_t rcvd; 156 }; 157 158 /* 159 * Compute and display ETA 160 */ 161 static const char * 162 stat_eta(struct xferstat *xs) 163 { 164 static char str[16]; 165 long elapsed, eta; 166 off_t received, expected; 167 168 elapsed = xs->last.tv_sec - xs->start.tv_sec; 169 received = xs->rcvd - xs->offset; 170 expected = xs->size - xs->rcvd; 171 eta = (long)((double)elapsed * expected / received); 172 if (eta > 3600) 173 snprintf(str, sizeof str, "%02ldh%02ldm", 174 eta / 3600, (eta % 3600) / 60); 175 else 176 snprintf(str, sizeof str, "%02ldm%02lds", 177 eta / 60, eta % 60); 178 return (str); 179 } 180 181 /* 182 * Format a number as "xxxx YB" where Y is ' ', 'k', 'M'... 183 */ 184 static const char *prefixes = " kMGTP"; 185 static const char * 186 stat_bytes(off_t bytes) 187 { 188 static char str[16]; 189 const char *prefix = prefixes; 190 191 while (bytes > 9999 && prefix[1] != '\0') { 192 bytes /= 1024; 193 prefix++; 194 } 195 snprintf(str, sizeof str, "%4jd %cB", (intmax_t)bytes, *prefix); 196 return (str); 197 } 198 199 /* 200 * Compute and display transfer rate 201 */ 202 static const char * 203 stat_bps(struct xferstat *xs) 204 { 205 static char str[16]; 206 double delta, bps; 207 208 delta = (xs->last.tv_sec + (xs->last.tv_usec / 1.e6)) 209 - (xs->start.tv_sec + (xs->start.tv_usec / 1.e6)); 210 if (delta == 0.0) { 211 snprintf(str, sizeof str, "?? Bps"); 212 } else { 213 bps = (xs->rcvd - xs->offset) / delta; 214 snprintf(str, sizeof str, "%sps", stat_bytes((off_t)bps)); 215 } 216 return (str); 217 } 218 219 /* 220 * Update the stats display 221 */ 222 static void 223 stat_display(struct xferstat *xs, int force) 224 { 225 struct timeval now; 226 #if !defined(__minix) 227 int ctty_pgrp; 228 #endif /* !defined(__minix) */ 229 230 /* Minix returns "Not a typewriter error" */ 231 #if defined(TIOCGPGRP) && !defined(__minix) 232 /* check if we're the foreground process */ 233 if (ioctl(STDERR_FILENO, TIOCGPGRP, &ctty_pgrp) == -1 || 234 (pid_t)ctty_pgrp != pgrp) 235 return; 236 #endif 237 238 gettimeofday(&now, NULL); 239 if (!force && now.tv_sec <= xs->last.tv_sec) 240 return; 241 xs->last = now; 242 243 fprintf(stderr, "\r%-46.46s", xs->name); 244 if (xs->size <= 0) { 245 #if HAVE_SETPROCTITLE 246 setproctitle("%s [%s]", xs->name, stat_bytes(xs->rcvd)); 247 #endif 248 fprintf(stderr, " %s", stat_bytes(xs->rcvd)); 249 } else { 250 #if HAVE_SETPROCTITLE 251 setproctitle("%s [%d%% of %s]", xs->name, 252 (int)((100.0 * xs->rcvd) / xs->size), 253 stat_bytes(xs->size)); 254 #endif 255 fprintf(stderr, "%3d%% of %s", 256 (int)((100.0 * xs->rcvd) / xs->size), 257 stat_bytes(xs->size)); 258 } 259 fprintf(stderr, " %s", stat_bps(xs)); 260 if (xs->size > 0 && xs->rcvd > 0 && 261 xs->last.tv_sec >= xs->start.tv_sec + 10) 262 fprintf(stderr, " %s", stat_eta(xs)); 263 fflush(stderr); 264 } 265 266 /* 267 * Initialize the transfer statistics 268 */ 269 static void 270 stat_start(struct xferstat *xs, const char *name, off_t size, off_t offset) 271 { 272 snprintf(xs->name, sizeof xs->name, "%s", name); 273 gettimeofday(&xs->start, NULL); 274 xs->last.tv_sec = xs->last.tv_usec = 0; 275 xs->size = size; 276 xs->offset = offset; 277 xs->rcvd = offset; 278 if (v_tty && v_level > 0) 279 stat_display(xs, 1); 280 else if (v_level > 0) 281 fprintf(stderr, "%-46s", xs->name); 282 } 283 284 /* 285 * Update the transfer statistics 286 */ 287 static void 288 stat_update(struct xferstat *xs, off_t rcvd) 289 { 290 xs->rcvd = rcvd; 291 if (v_tty && v_level > 0) 292 stat_display(xs, 0); 293 } 294 295 /* 296 * Finalize the transfer statistics 297 */ 298 static void 299 stat_end(struct xferstat *xs) 300 { 301 gettimeofday(&xs->last, NULL); 302 if (v_tty && v_level > 0) { 303 stat_display(xs, 1); 304 putc('\n', stderr); 305 } else if (v_level > 0) { 306 fprintf(stderr, " %s %s\n", 307 stat_bytes(xs->size), stat_bps(xs)); 308 } 309 } 310 311 #if HAVE_TERMIOS_H && !defined(PREFER_GETPASS) 312 static int 313 read_password(const char *prompt, char *pwbuf, size_t pwbuf_len) 314 { 315 struct termios tios; 316 tcflag_t saved_flags; 317 int nopwd; 318 319 fprintf(stderr, "%s", prompt); 320 if (tcgetattr(STDIN_FILENO, &tios) != 0) 321 return (fgets(pwbuf, pwbuf_len, stdin) == NULL); 322 323 saved_flags = tios.c_lflag; 324 tios.c_lflag &= ~ECHO; 325 tios.c_lflag |= ECHONL|ICANON; 326 #ifndef __minix 327 tcsetattr(STDIN_FILENO, TCSAFLUSH|TCSASOFT, &tios); 328 #else 329 tcsetattr(STDIN_FILENO, TCSAFLUSH, &tios); 330 #endif 331 nopwd = (fgets(pwbuf, pwbuf_len, stdin) == NULL); 332 tios.c_lflag = saved_flags; 333 #ifndef __minix 334 tcsetattr(STDIN_FILENO, TCSANOW|TCSASOFT, &tios); 335 #else 336 tcsetattr(STDIN_FILENO, TCSANOW, &tios); 337 #endif 338 339 return nopwd; 340 } 341 #elif HAVE_GETPASSPHRASE || HAVE_GETPASS 342 static int 343 read_password(const char *prompt, char *pwbuf, size_t pwbuf_len) 344 { 345 char *pass; 346 347 #if HAVE_GETPASSPHRASE && !defined(PREFER_GETPASS) 348 pass = getpassphrase(prompt); 349 #else 350 pass = getpass(prompt); 351 #endif 352 if (pass == NULL || strlen(pass) >= pwbuf_len) 353 return 1; 354 strcpy(pwbuf, pass); 355 return 0; 356 } 357 #else 358 static int 359 read_password(const char *prompt, char *pwbuf, size_t pwbuf_len) 360 { 361 362 fprintf(stderr, prompt); 363 return (fgets(pwbuf, pwbuf_len, stdin) == NULL); 364 } 365 #endif 366 367 /* 368 * Ask the user for authentication details 369 */ 370 static int 371 query_auth(struct url *URL) 372 { 373 int i, nopwd; 374 375 fprintf(stderr, "Authentication required for <%s://%s:%d/>!\n", 376 URL->scheme, URL->host, URL->port); 377 378 fprintf(stderr, "Login: "); 379 if (fgets(URL->user, sizeof URL->user, stdin) == NULL) 380 return (-1); 381 for (i = strlen(URL->user); i >= 0; --i) 382 if (URL->user[i] == '\r' || URL->user[i] == '\n') 383 URL->user[i] = '\0'; 384 385 nopwd = read_password("Password: ", URL->pwd, sizeof(URL->pwd)); 386 387 if (nopwd) 388 return (-1); 389 for (i = strlen(URL->pwd); i >= 0; --i) 390 if (URL->pwd[i] == '\r' || URL->pwd[i] == '\n') 391 URL->pwd[i] = '\0'; 392 393 return (0); 394 } 395 396 /* 397 * Fetch a file 398 */ 399 static int 400 fetch(char *URL, const char *path) 401 { 402 struct url *url; 403 struct url_stat us; 404 struct stat sb, nsb; 405 struct xferstat xs; 406 FILE *of; 407 fetchIO *f; 408 size_t size, wr; 409 ssize_t ssize; 410 off_t count; 411 char flags[8]; 412 char *tmppath; 413 int r; 414 unsigned timeout; 415 char *ptr; 416 417 f = NULL; 418 of = NULL; 419 tmppath = NULL; 420 421 timeout = 0; 422 *flags = 0; 423 count = 0; 424 425 /* set verbosity level */ 426 if (v_level > 1) 427 strcat(flags, "v"); 428 if (v_level > 2) 429 fetchDebug = 1; 430 431 /* parse URL */ 432 if ((url = fetchParseURL(URL)) == NULL) { 433 warnx("%s: parse error", URL); 434 goto failure; 435 } 436 437 /* if no scheme was specified, take a guess */ 438 if (!*url->scheme) { 439 if (!*url->host) 440 strcpy(url->scheme, SCHEME_FILE); 441 else if (strncasecmp(url->host, "ftp.", 4) == 0) 442 strcpy(url->scheme, SCHEME_FTP); 443 else if (strncasecmp(url->host, "www.", 4) == 0) 444 strcpy(url->scheme, SCHEME_HTTP); 445 } 446 447 /* common flags */ 448 switch (family) { 449 case PF_INET: 450 strcat(flags, "4"); 451 break; 452 #ifndef __minix 453 case PF_INET6: 454 strcat(flags, "6"); 455 break; 456 #endif 457 } 458 459 /* Protocol independent flags */ 460 if (i_flag) { 461 if (stat(path, &sb) == 0) { 462 url->last_modified = sb.st_mtime; 463 strcat(flags, "i"); 464 } else if (errno != ENOENT) { 465 warn("%s: stat()", path); 466 goto failure; 467 } 468 } 469 470 /* FTP specific flags */ 471 if (strcmp(url->scheme, SCHEME_FTP) == 0) { 472 if (d_flag) 473 strcat(flags, "d"); 474 if (U_flag) 475 strcat(flags, "l"); 476 timeout = T_secs ? T_secs : ftp_timeout; 477 } 478 479 /* HTTP specific flags */ 480 if (strcmp(url->scheme, SCHEME_HTTP) == 0) { 481 if (d_flag) 482 strcat(flags, "d"); 483 if (A_flag) 484 strcat(flags, "A"); 485 timeout = T_secs ? T_secs : http_timeout; 486 } 487 488 /* set the protocol timeout. */ 489 fetchTimeout = timeout; 490 491 /* just print size */ 492 if (s_flag) { 493 if (timeout) 494 alarm(timeout); 495 r = fetchStat(url, &us, flags); 496 if (timeout) 497 alarm(0); 498 if (sigalrm || sigint) 499 goto signal; 500 if (r == -1) { 501 warnx("%s", fetchLastErrString); 502 goto failure; 503 } 504 if (us.size == -1) 505 printf("Unknown\n"); 506 else 507 printf("%jd\n", (intmax_t)us.size); 508 goto success; 509 } 510 511 /* 512 * If the -r flag was specified, we have to compare the local 513 * and remote files, so we should really do a fetchStat() 514 * first, but I know of at least one HTTP server that only 515 * sends the content size in response to GET requests, and 516 * leaves it out of replies to HEAD requests. Also, in the 517 * (frequent) case that the local and remote files match but 518 * the local file is truncated, we have sufficient information 519 * before the compare to issue a correct request. Therefore, 520 * we always issue a GET request as if we were sure the local 521 * file was a truncated copy of the remote file; we can drop 522 * the connection later if we change our minds. 523 */ 524 sb.st_size = -1; 525 if (!o_stdout) { 526 r = stat(path, &sb); 527 if (r == 0 && r_flag && S_ISREG(sb.st_mode)) { 528 url->offset = sb.st_size; 529 } else if (r == -1 || !S_ISREG(sb.st_mode)) { 530 /* 531 * Whatever value sb.st_size has now is either 532 * wrong (if stat(2) failed) or irrelevant (if the 533 * path does not refer to a regular file) 534 */ 535 sb.st_size = -1; 536 } 537 if (r == -1 && errno != ENOENT) { 538 warnx("%s: stat()", path); 539 goto failure; 540 } 541 } 542 543 /* start the transfer */ 544 if (timeout) 545 alarm(timeout); 546 f = fetchXGet(url, &us, flags); 547 if (timeout) 548 alarm(0); 549 if (sigalrm || sigint) 550 goto signal; 551 if (f == NULL && i_flag && fetchLastErrCode == FETCH_UNCHANGED) { 552 /* URL was not modified, return OK. */ 553 printf("%s: not modified\n", URL); 554 r = 0; 555 goto done; 556 } 557 if (f == NULL) { 558 warnx("%s: %s", URL, fetchLastErrString); 559 goto failure; 560 } 561 if (sigint) 562 goto signal; 563 564 /* check that size is as expected */ 565 if (S_size) { 566 if (us.size == -1) { 567 warnx("%s: size unknown", URL); 568 } else if (us.size != S_size) { 569 warnx("%s: size mismatch: expected %jd, actual %jd", 570 URL, (intmax_t)S_size, (intmax_t)us.size); 571 goto failure; 572 } 573 } 574 575 /* symlink instead of copy */ 576 if (l_flag && strcmp(url->scheme, "file") == 0 && !o_stdout) { 577 char *name = fetchUnquotePath(url); 578 if (name == NULL) { 579 warnx("Can't unquote URL"); 580 goto failure; 581 } 582 if (symlink(name, path) == -1) { 583 warn("%s: symlink()", path); 584 free(name); 585 goto failure; 586 } 587 free(name); 588 goto success; 589 } 590 591 if (us.size == -1 && !o_stdout && v_level > 0) 592 warnx("%s: size of remote file is not known", URL); 593 if (v_level > 1) { 594 if (sb.st_size != -1) 595 fprintf(stderr, "local size / mtime: %jd / %ld\n", 596 (intmax_t)sb.st_size, (long)sb.st_mtime); 597 if (us.size != -1) 598 fprintf(stderr, "remote size / mtime: %jd / %ld\n", 599 (intmax_t)us.size, (long)us.mtime); 600 } 601 602 /* open output file */ 603 if (o_stdout) { 604 /* output to stdout */ 605 of = stdout; 606 } else if (r_flag && sb.st_size != -1) { 607 /* resume mode, local file exists */ 608 if (!F_flag && us.mtime && sb.st_mtime != us.mtime) { 609 /* no match! have to refetch */ 610 fetchIO_close(f); 611 /* if precious, warn the user and give up */ 612 if (R_flag) { 613 warnx("%s: local modification time " 614 "does not match remote", path); 615 goto failure_keep; 616 } 617 } else if (us.size != -1) { 618 if (us.size == sb.st_size) 619 /* nothing to do */ 620 goto success; 621 if (sb.st_size > us.size) { 622 /* local file too long! */ 623 warnx("%s: local file (%jd bytes) is longer " 624 "than remote file (%jd bytes)", path, 625 (intmax_t)sb.st_size, (intmax_t)us.size); 626 goto failure; 627 } 628 /* we got it, open local file */ 629 if ((of = fopen(path, "a")) == NULL) { 630 warn("%s: fopen()", path); 631 goto failure; 632 } 633 /* check that it didn't move under our feet */ 634 if (fstat(fileno(of), &nsb) == -1) { 635 /* can't happen! */ 636 warn("%s: fstat()", path); 637 goto failure; 638 } 639 if (nsb.st_dev != sb.st_dev || 640 nsb.st_ino != nsb.st_ino || 641 nsb.st_size != sb.st_size) { 642 warnx("%s: file has changed", URL); 643 fclose(of); 644 of = NULL; 645 sb = nsb; 646 } 647 } 648 } else if (m_flag && sb.st_size != -1) { 649 /* mirror mode, local file exists */ 650 if (sb.st_size == us.size && sb.st_mtime == us.mtime) 651 goto success; 652 } 653 654 if (of == NULL) { 655 /* 656 * We don't yet have an output file; either this is a 657 * vanilla run with no special flags, or the local and 658 * remote files didn't match. 659 */ 660 661 if (url->offset > 0) { 662 /* 663 * We tried to restart a transfer, but for 664 * some reason gave up - so we have to restart 665 * from scratch if we want the whole file 666 */ 667 url->offset = 0; 668 if ((f = fetchXGet(url, &us, flags)) == NULL) { 669 warnx("%s: %s", URL, fetchLastErrString); 670 goto failure; 671 } 672 if (sigint) 673 goto signal; 674 } 675 676 /* construct a temp file name */ 677 if (sb.st_size != -1 && S_ISREG(sb.st_mode)) { 678 #ifndef __minix 679 asprintf(&tmppath, "%s.fetch.XXXXXX", path); 680 #else 681 { 682 int len; 683 if((tmppath = malloc(sizeof(char)*MINBUFSIZE)) != NULL) { 684 len = snprintf(tmppath, MINBUFSIZE, "%s.fetch.XXXXXX", path); 685 if(len >= MINBUFSIZE) { 686 free(tmppath); 687 tmppath = NULL; 688 } 689 } 690 } 691 #endif 692 693 if (tmppath != NULL) { 694 int fd; 695 696 fd = mkstemp(tmppath); 697 if (fd == -1) { 698 warn("%s: mkstemp failed", tmppath); 699 goto failure; 700 } 701 fchown(fd, sb.st_uid, sb.st_gid); 702 fchmod(fd, sb.st_mode & ALLPERMS); 703 of = fdopen(fd, "w"); 704 if (of == NULL) { 705 close(fd); 706 unlink(tmppath); 707 free(tmppath); 708 tmppath = NULL; 709 } 710 } 711 } 712 if (of == NULL) 713 of = fopen(path, "w"); 714 if (of == NULL) { 715 warn("%s: open()", path); 716 goto failure; 717 } 718 } 719 count = url->offset; 720 721 /* start the counter */ 722 stat_start(&xs, path, us.size, count); 723 724 sigalrm = sigint = 0; 725 726 /* suck in the data */ 727 #ifdef SIGINFO 728 siginfo = 0; 729 signal(SIGINFO, sig_handler); 730 #endif 731 while (!sigint) { 732 if (us.size != -1 && us.size - count < B_size && 733 us.size - count >= 0) 734 size = us.size - count; 735 else 736 size = B_size; 737 #ifdef SIGINFO 738 if (siginfo) { 739 stat_display(&xs, 1); 740 siginfo = 0; 741 } 742 #else 743 /* Constant info is better than none. */ 744 if (v_level) { 745 stat_display(&xs, 1); 746 } 747 #endif 748 if ((ssize = fetchIO_read(f, buf, B_size)) == 0) 749 break; 750 if (ssize == -1 && errno == EINTR) 751 continue; 752 if (ssize == -1) 753 break; 754 size = ssize; 755 stat_update(&xs, count += size); 756 for (ptr = buf; size > 0; ptr += wr, size -= wr) { 757 if ((wr = fwrite(ptr, 1, size, of)) < size) { 758 if (ferror(of) && errno == EINTR && !sigint) 759 clearerr(of); 760 else 761 break; 762 } 763 } 764 if (size != 0) 765 break; 766 } 767 if (!sigalrm) 768 sigalrm = 0; 769 #ifdef SIGINFO 770 signal(SIGINFO, SIG_DFL); 771 #endif 772 773 stat_end(&xs); 774 775 /* 776 * If the transfer timed out or was interrupted, we still want to 777 * set the mtime in case the file is not removed (-r or -R) and 778 * the user later restarts the transfer. 779 */ 780 signal: 781 /* set mtime of local file */ 782 if (!n_flag && us.mtime && !o_stdout && of != NULL && 783 (stat(path, &sb) != -1) && sb.st_mode & S_IFREG) { 784 struct timeval tv[2]; 785 786 fflush(of); 787 tv[0].tv_sec = (long)(us.atime ? us.atime : us.mtime); 788 tv[1].tv_sec = (long)us.mtime; 789 tv[0].tv_usec = tv[1].tv_usec = 0; 790 if (utimes(tmppath ? tmppath : path, tv)) 791 warn("%s: utimes()", tmppath ? tmppath : path); 792 } 793 794 /* timed out or interrupted? */ 795 if (fetchLastErrCode == FETCH_TIMEOUT) 796 sigalrm = 1; 797 if (sigalrm) 798 warnx("transfer timed out"); 799 if (sigint) { 800 warnx("transfer interrupted"); 801 goto failure; 802 } 803 804 /* timeout / interrupt before connection completley established? */ 805 if (f == NULL) 806 goto failure; 807 808 if (!sigalrm && ferror(of)) { 809 /* check the status of our files */ 810 warn("writing to %s failed", path); 811 goto failure; 812 } 813 814 /* did the transfer complete normally? */ 815 if (us.size != -1 && count < us.size) { 816 warnx("%s appears to be truncated: %jd/%jd bytes", 817 path, (intmax_t)count, (intmax_t)us.size); 818 goto failure_keep; 819 } 820 821 /* 822 * If the transfer timed out and we didn't know how much to 823 * expect, assume the worst (i.e. we didn't get all of it) 824 */ 825 if (sigalrm && us.size == -1) { 826 warnx("%s may be truncated", path); 827 goto failure_keep; 828 } 829 830 success: 831 r = 0; 832 if (tmppath != NULL && rename(tmppath, path) == -1) { 833 warn("%s: rename()", path); 834 goto failure_keep; 835 } 836 goto done; 837 failure: 838 if (of && of != stdout && !R_flag && !r_flag) 839 if (stat(path, &sb) != -1 && (sb.st_mode & S_IFREG)) 840 unlink(tmppath ? tmppath : path); 841 if (R_flag && tmppath != NULL && sb.st_size == -1) 842 rename(tmppath, path); /* ignore errors here */ 843 failure_keep: 844 r = -1; 845 goto done; 846 done: 847 if (f) 848 fetchIO_close(f); 849 if (of && of != stdout) 850 fclose(of); 851 if (url) 852 fetchFreeURL(url); 853 if (tmppath != NULL) 854 free(tmppath); 855 return (r); 856 } 857 858 static void 859 usage(void) 860 { 861 #ifndef __minix 862 fprintf(stderr, "%s\n%s\n%s\n", 863 "usage: fetch [-146AFMPRUadilmnpqrsv] [-N netrc] [-o outputfile]", 864 " [-S bytes] [-B bytes] [-T seconds] [-w seconds]", 865 " [-h host -f file [-c dir] | URL ...]"); 866 #else 867 fprintf(stderr, "%s\n%s\n%s\n", 868 "usage: fetch [-146AFMPRUadilmnpqrsv] [-N netrc] [-o outputfile]", 869 " [-S bytes] [-B bytes] [-T seconds] [-w seconds]", 870 " [-h host -f file [-c dir] | URL ...]"); 871 #endif 872 } 873 874 875 /* 876 * Entry point 877 */ 878 int 879 main(int argc, char *argv[]) 880 { 881 struct stat sb; 882 struct sigaction sa; 883 const char *p, *s; 884 char *end, *q; 885 int c, e, r; 886 #ifndef __minix 887 while ((c = getopt(argc, argv, 888 "14AaB:dFilMmN:no:qRrS:sT:Uvw:")) != -1) 889 #else 890 while ((c = getopt(argc, argv, 891 "146AaB:dFilMmN:no:qRrS:sT:Uvw:")) != -1) 892 #endif 893 switch (c) { 894 case '1': 895 once_flag = 1; 896 break; 897 case '4': 898 family = PF_INET; 899 break; 900 #ifndef __minix 901 case '6': 902 family = PF_INET6; 903 break; 904 #endif 905 case 'A': 906 A_flag = 1; 907 break; 908 case 'a': 909 a_flag = 1; 910 break; 911 case 'B': 912 B_size = (off_t)strtol(optarg, &end, 10); 913 if (*optarg == '\0' || *end != '\0') 914 errx(1, "invalid buffer size (%s)", optarg); 915 break; 916 case 'd': 917 d_flag = 1; 918 break; 919 case 'F': 920 F_flag = 1; 921 break; 922 case 'i': 923 i_flag = 1; 924 break; 925 case 'l': 926 l_flag = 1; 927 break; 928 case 'o': 929 o_flag = 1; 930 o_filename = optarg; 931 break; 932 case 'M': 933 case 'm': 934 if (r_flag) 935 errx(1, "the -m and -r flags " 936 "are mutually exclusive"); 937 m_flag = 1; 938 break; 939 case 'N': 940 N_filename = optarg; 941 break; 942 case 'n': 943 n_flag = 1; 944 break; 945 case 'q': 946 v_level = 0; 947 break; 948 case 'R': 949 R_flag = 1; 950 break; 951 case 'r': 952 if (m_flag) 953 errx(1, "the -m and -r flags " 954 "are mutually exclusive"); 955 r_flag = 1; 956 break; 957 case 'S': 958 S_size = (off_t)strtol(optarg, &end, 10); 959 if (*optarg == '\0' || *end != '\0') 960 errx(1, "invalid size (%s)", optarg); 961 break; 962 case 's': 963 s_flag = 1; 964 break; 965 case 'T': 966 T_secs = strtol(optarg, &end, 10); 967 if (*optarg == '\0' || *end != '\0') 968 errx(1, "invalid timeout (%s)", optarg); 969 break; 970 case 'U': 971 U_flag = 1; 972 break; 973 case 'v': 974 v_level++; 975 break; 976 case 'w': 977 a_flag = 1; 978 w_secs = strtol(optarg, &end, 10); 979 if (*optarg == '\0' || *end != '\0') 980 errx(1, "invalid delay (%s)", optarg); 981 break; 982 default: 983 usage(); 984 exit(EX_USAGE); 985 } 986 987 argc -= optind; 988 argv += optind; 989 990 if (!argc) { 991 usage(); 992 exit(EX_USAGE); 993 } 994 995 fetchConnectionCacheInit(10, 1); 996 997 /* allocate buffer */ 998 if (B_size < MINBUFSIZE) 999 B_size = MINBUFSIZE; 1000 if ((buf = malloc(B_size)) == NULL) 1001 errx(1, "%s", strerror(ENOMEM)); 1002 1003 /* timeouts */ 1004 if ((s = getenv("FTP_TIMEOUT")) != NULL) { 1005 ftp_timeout = strtol(s, &end, 10); 1006 if (*s == '\0' || *end != '\0' || ftp_timeout < 0) { 1007 warnx("FTP_TIMEOUT (%s) is not a positive integer", s); 1008 ftp_timeout = 0; 1009 } 1010 } 1011 if ((s = getenv("HTTP_TIMEOUT")) != NULL) { 1012 http_timeout = strtol(s, &end, 10); 1013 if (*s == '\0' || *end != '\0' || http_timeout < 0) { 1014 warnx("HTTP_TIMEOUT (%s) is not a positive integer", s); 1015 http_timeout = 0; 1016 } 1017 } 1018 1019 /* signal handling */ 1020 sa.sa_flags = 0; 1021 sa.sa_handler = sig_handler; 1022 sigemptyset(&sa.sa_mask); 1023 sigaction(SIGALRM, &sa, NULL); 1024 sa.sa_flags = SA_RESETHAND; 1025 sigaction(SIGINT, &sa, NULL); 1026 1027 /* output file */ 1028 if (o_flag) { 1029 if (strcmp(o_filename, "-") == 0) { 1030 o_stdout = 1; 1031 if (i_flag) { 1032 warnx("-i and -o - are incompatible, dropping -i"); 1033 i_flag = 0; 1034 } 1035 } else if (stat(o_filename, &sb) == -1) { 1036 if (errno == ENOENT) { 1037 if (argc > 1) 1038 errx(EX_USAGE, "%s is not a directory", 1039 o_filename); 1040 } else { 1041 err(EX_IOERR, "%s", o_filename); 1042 } 1043 } else { 1044 if (sb.st_mode & S_IFDIR) 1045 o_directory = 1; 1046 } 1047 } 1048 1049 /* check if output is to a tty (for progress report) */ 1050 v_tty = isatty(STDERR_FILENO); 1051 if (v_tty) 1052 pgrp = getpgrp(); 1053 1054 r = 0; 1055 1056 /* authentication */ 1057 if (v_tty) 1058 fetchAuthMethod = query_auth; 1059 if (N_filename != NULL) 1060 setenv("NETRC", N_filename, 1); 1061 1062 while (argc) { 1063 if ((p = strrchr(*argv, '/')) == NULL) 1064 p = *argv; 1065 else 1066 p++; 1067 1068 if (!*p) 1069 p = "fetch.out"; 1070 1071 fetchLastErrCode = 0; 1072 1073 if (o_flag) { 1074 if (o_stdout) { 1075 e = fetch(*argv, "-"); 1076 } else if (o_directory) { 1077 #ifndef __minix 1078 asprintf(&q, "%s/%s", o_filename, p); 1079 #else 1080 { 1081 int len; 1082 1083 if ((q = malloc(sizeof(char)*MINBUFSIZE)) != NULL) { 1084 len = snprintf(q, MINBUFSIZE, "%s/%s", o_filename, p); 1085 if (len >= MINBUFSIZE) { 1086 free(q); 1087 q = NULL; 1088 } 1089 }else{ 1090 err(1, "Unable to allocate memory"); 1091 } 1092 } 1093 #endif 1094 e = fetch(*argv, q); 1095 free(q); 1096 } else { 1097 e = fetch(*argv, o_filename); 1098 } 1099 } else { 1100 e = fetch(*argv, p); 1101 } 1102 1103 if (sigint) 1104 kill(getpid(), SIGINT); 1105 1106 if (e == 0 && once_flag) 1107 exit(0); 1108 1109 if (e) { 1110 r = 1; 1111 if ((fetchLastErrCode 1112 && fetchLastErrCode != FETCH_UNAVAIL 1113 && fetchLastErrCode != FETCH_MOVED 1114 && fetchLastErrCode != FETCH_URL 1115 && fetchLastErrCode != FETCH_RESOLV 1116 && fetchLastErrCode != FETCH_UNKNOWN)) { 1117 if (w_secs && v_level) 1118 fprintf(stderr, "Waiting %ld seconds " 1119 "before retrying\n", w_secs); 1120 if (w_secs) 1121 sleep(w_secs); 1122 if (a_flag) 1123 continue; 1124 } 1125 } 1126 1127 argc--, argv++; 1128 } 1129 1130 exit(r); 1131 } 1132