1/* 2 * FreeBSD install - a package for the installation and maintenance 3 * of non-core utilities. 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 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * Jordan K. Hubbard 15 * 18 July 1993 16 * 17 * URL file access utilities. 18 * 19 */ 20 21#include <sys/cdefs.h> 22__FBSDID("$FreeBSD$"); 23 24#include "lib.h" 25#include <err.h> 26#include <fetch.h> 27#include <libgen.h> 28#include <sys/wait.h> 29#include <stdio.h> 30 31/* 32 * Try and fetch a file by URL, returning the directory name for where 33 * it's unpacked, if successful. 34 */ 35const char * 36fileGetURL(const char *base, const char *spec, int keep_package) 37{ 38 const char *rp; 39 char *cp, *tmp; 40 char fname[FILENAME_MAX]; 41 char pen[FILENAME_MAX]; 42 char pkg[FILENAME_MAX]; 43 char buf[8192]; 44 FILE *ftp; 45 pid_t tpid; 46 int pfd[2], pstat, r, w = 0; 47 char *hint; 48 int fd, pkgfd = 0; 49 50 rp = NULL; 51 /* Special tip that sysinstall left for us */ 52 hint = getenv("PKG_ADD_BASE"); 53 if (!isURL(spec)) { 54 if (!base && !hint) 55 return NULL; 56 /* 57 * We've been given an existing URL (that's known-good) and now we need 58 * to construct a composite one out of that and the basename we were 59 * handed as a dependency. 60 */ 61 if (base) { 62 strcpy(fname, base); 63 /* 64 * Advance back two slashes to get to the root of the package 65 * hierarchy 66 */ 67 cp = strrchr(fname, '/'); 68 if (cp) { 69 *cp = '\0'; /* chop name */ 70 cp = strrchr(fname, '/'); 71 } 72 if (cp) { 73 *(cp + 1) = '\0'; 74 strcat(cp, "All/"); 75 strcat(cp, spec); 76 if (getenv("PACKAGESUFFIX")) 77 strcat(cp, getenv("PACKAGESUFFIX")); 78 else 79 strcat(cp, ".tbz"); 80 } 81 else 82 return NULL; 83 } 84 else { 85 /* 86 * Otherwise, we've been given an environment variable hinting 87 * at the right location from sysinstall 88 */ 89 strcpy(fname, hint); 90 strcat(fname, spec); 91 if (getenv("PACKAGESUFFIX")) 92 strcat(fname, getenv("PACKAGESUFFIX")); 93 else 94 strcat(fname, ".tbz"); 95 } 96 } 97 else 98 strcpy(fname, spec); 99 100 if (keep_package) { 101 tmp = getenv("PKGDIR"); 102 strlcpy(pkg, tmp ? tmp : ".", sizeof(pkg)); 103 tmp = basename(fname); 104 strlcat(pkg, "/", sizeof(pkg)); 105 strlcat(pkg, tmp, sizeof(pkg)); 106 if ((pkgfd = open(pkg, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1) { 107 printf("Error: Unable to open %s\n", pkg); 108 perror("open"); 109 return NULL; 110 } 111 } 112 113 fetchDebug = (Verbose > 0); 114 if ((ftp = fetchGetURL(fname, Verbose ? "v" : NULL)) == NULL) { 115 printf("Error: Unable to get %s: %s\n", 116 fname, fetchLastErrString); 117 /* If the fetch fails, yank the package. */ 118 if (keep_package && unlink(pkg) < 0 && Verbose) { 119 warnx("failed to remove partially fetched package: %s", pkg); 120 } 121 return NULL; 122 } 123 124 if (isatty(0) || Verbose) 125 printf("Fetching %s...", fname), fflush(stdout); 126 pen[0] = '\0'; 127 if ((rp = make_playpen(pen, 0)) == NULL) { 128 printf("Error: Unable to construct a new playpen for FTP!\n"); 129 fclose(ftp); 130 return NULL; 131 } 132 if (pipe(pfd) == -1) { 133 warn("pipe()"); 134 cleanup(0); 135 exit(2); 136 } 137 if ((tpid = fork()) == -1) { 138 warn("pipe()"); 139 cleanup(0); 140 exit(2); 141 } 142 if (!tpid) { 143 dup2(pfd[0], 0); 144 for (fd = getdtablesize() - 1; fd >= 3; --fd) 145 close(fd); 146 execl("/usr/bin/tar", "tar", 147 Verbose ? "-xpjvf" : "-xpjf", 148 "-", (char *)0); 149 _exit(2); 150 } 151 close(pfd[0]); 152 for (;;) { 153 if ((r = fread(buf, 1, sizeof buf, ftp)) < 1) 154 break; 155 if ((w = write(pfd[1], buf, r)) != r) 156 break; 157 if (keep_package) { 158 if ((w = write(pkgfd, buf, r)) != r) 159 break; 160 } 161 } 162 if (ferror(ftp)) 163 warn("warning: error reading from server"); 164 fclose(ftp); 165 if (keep_package) { 166 close(pkgfd); 167 } 168 close(pfd[1]); 169 if (w == -1) 170 warn("warning: error writing to tar"); 171 tpid = waitpid(tpid, &pstat, 0); 172 if (Verbose) 173 printf("tar command returns %d status\n", WEXITSTATUS(pstat)); 174 if (rp && (isatty(0) || Verbose)) 175 printf(" Done.\n"); 176 return rp; 177} 178