char HIDDEN * xbps_get_remote_repo_string(const char *uri) { struct url *url; size_t i; char *p; if ((url = fetchParseURL(uri)) == NULL) return NULL; /* * Replace '.' ':' and '/' characters with underscores, so that * provided URL: * * http://nocturno.local:8080/repo/x86_64 * * becomes: * * http___nocturno_local_8080_repo_x86_64 */ if (url->port != 0) p = xbps_xasprintf("%s://%s:%u%s", url->scheme, url->host, url->port, url->doc); else p = xbps_xasprintf("%s://%s%s", url->scheme, url->host, url->doc); fetchFreeURL(url); for (i = 0; i < strlen(p); i++) { if (p[i] == '.' || p[i] == '/' || p[i] == ':') p[i] = '_'; } return p; }
static void gethttpmirrors(struct pkg_repo *repo, const char *url) { FILE *f; char *line = NULL; size_t linecap = 0; ssize_t linelen; struct http_mirror *m; struct url *u; if ((f = fetchGetURL(url, "")) == NULL) return; while ((linelen = getline(&line, &linecap, f)) > 0) { if (strncmp(line, "URL:", 4) == 0) { /* trim '\n' */ if (line[linelen - 1] == '\n') line[linelen - 1 ] = '\0'; line += 4; while (isspace(*line)) { line++; } if (*line == '\0') continue; if ((u = fetchParseURL(line)) != NULL) { m = malloc(sizeof(struct http_mirror)); m->url = u; LL_APPEND(repo->http, m); } } } fclose(f); return; }
/* * Attempt to parse the given URL; if successful, call fetchStat(). */ int fetchStatURL(const char *URL, struct url_stat *us, const char *flags) { struct url *u; int s; if ((u = fetchParseURL(URL)) == NULL) return (-1); s = fetchStat(u, us, flags); fetchFreeURL(u); return (s); }
/* * Attempt to parse the given URL; if successful, call fetchPut(). */ fetchIO * fetchPutURL(const char *URL, const char *flags) { struct url *u; fetchIO *f; if ((u = fetchParseURL(URL)) == NULL) return (NULL); f = fetchPut(u, flags); fetchFreeURL(u); return (f); }
/* * Attempt to parse the given URL; if successful, call fetchXGet(). */ fetchIO * fetchXGetURL(const char *URL, struct url_stat *us, const char *flags) { struct url *u; fetchIO *f; if ((u = fetchParseURL(URL)) == NULL) return (NULL); f = fetchXGet(u, us, flags); fetchFreeURL(u); return (f); }
/* * Attempt to parse the given URL; if successful, call fetchList(). */ struct url_ent * fetchListURL(const char *URL, const char *flags) { struct url *u; struct url_ent *ue; if ((u = fetchParseURL(URL)) == NULL) return (NULL); ue = fetchList(u, flags); fetchFreeURL(u); return (ue); }
/* * Open a pkg_summary and if newer than local return an open libfetch * connection to it. */ Sumfile * sum_open(char *str_url, time_t *db_mtime) { Sumfile *sum = NULL; fetchIO *f = NULL; struct url *url; struct url_stat st; url = fetchParseURL(str_url); if (url == NULL || (f = fetchXGet(url, &st, "")) == NULL) goto nofetch; if (st.size == -1) { /* could not obtain file size */ *db_mtime = 0; /* not -1, don't force update */ goto nofetch; } if (st.mtime <= *db_mtime) { /* * -1 used to identify return type, * local summary up-to-date */ *db_mtime = -1; goto nofetch; } *db_mtime = st.mtime; #ifndef _MINIX /* XXX: SSIZE_MAX fails under MINIX */ /* st.size is an off_t, it will be > SSIZE_MAX on 32 bits systems */ if (sizeof(st.size) == sizeof(SSIZE_MAX) && st.size > SSIZE_MAX - 1) err(EXIT_FAILURE, "file is too large"); #endif XMALLOC(sum, sizeof(Sumfile)); sum->fd = f; sum->url = url; sum->size = st.size; goto out; nofetch: if (url) fetchFreeURL(url); if (f) fetchIO_close(f); out: return sum; }
/* * Attempt to parse the given URL; if successful, call fetchList(). */ int fetchListURL(struct url_list *ue, const char *URL, const char *pattern, const char *flags) { struct url *u; int rv; if ((u = fetchParseURL(URL)) == NULL) return -1; rv = fetchList(ue, u, pattern, flags); fetchFreeURL(u); return rv; }
int main(int argc, char **argv) { struct db_connection dbc; struct utsname u; struct url *uo; char *url; if (dbc_open_fetchlist(&dbc)) exit(EXIT_FAILURE); if (uname(&u)) { perror("uname"); dbc_abort(&dbc); exit(EXIT_FAILURE); } /* Build patch directory URL. */ if (asprintf(&url, "%s%s/%s/%s", PATCHSITE_URL, u.machine, u.release, PATCHLIST_NAME) < 0) { perror("asprintf"); dbc_abort(&dbc); exit(EXIT_FAILURE); } /* Fetch the directory list. */ uo = fetchParseURL(url); if (!uo) { fprintf(stderr, "Invalid URL: %s", url); free(url); dbc_abort(&dbc); exit(EXIT_FAILURE); } fio = fetchGet(uo, ""); /* Reading fio is done by yacc. */ yyparse(); fetchIO_close(fio); fetchFreeURL(uo); free(url); dbc_done(&dbc); exit(EXIT_SUCCESS); }
static int bootstrap_pkg(void) { struct url *u; FILE *remote; FILE *config; char *site; struct dns_srvinfo *mirrors, *current; /* To store _https._tcp. + hostname + \0 */ char zone[MAXHOSTNAMELEN + 13]; char url[MAXPATHLEN]; char conf[MAXPATHLEN]; char tmppkg[MAXPATHLEN]; const char *packagesite, *mirror_type; char buf[10240]; char pkgstatic[MAXPATHLEN]; int fd, retry, ret, max_retry; struct url_stat st; off_t done, r; time_t now; time_t last; done = 0; last = 0; max_retry = 3; ret = -1; remote = NULL; config = NULL; current = mirrors = NULL; printf("Bootstrapping pkg please wait\n"); if (config_string(PACKAGESITE, &packagesite) != 0) { warnx("No PACKAGESITE defined"); return (-1); } if (config_string(MIRROR_TYPE, &mirror_type) != 0) { warnx("No MIRROR_TYPE defined"); return (-1); } snprintf(url, MAXPATHLEN, "%s/Latest/pkg.txz", packagesite); snprintf(tmppkg, MAXPATHLEN, "%s/pkg.txz.XXXXXX", getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP); if ((fd = mkstemp(tmppkg)) == -1) { warn("mkstemp()"); return (-1); } retry = max_retry; u = fetchParseURL(url); while (remote == NULL) { if (retry == max_retry) { if (strcmp(u->scheme, "file") != 0 && strcasecmp(mirror_type, "srv") == 0) { snprintf(zone, sizeof(zone), "_%s._tcp.%s", u->scheme, u->host); mirrors = dns_getsrvinfo(zone); current = mirrors; } } if (mirrors != NULL) strlcpy(u->host, current->host, sizeof(u->host)); remote = fetchXGet(u, &st, ""); if (remote == NULL) { --retry; if (retry <= 0) goto fetchfail; if (mirrors == NULL) { sleep(1); } else { current = current->next; if (current == NULL) current = mirrors; } } } if (remote == NULL) goto fetchfail; while (done < st.size) { if ((r = fread(buf, 1, sizeof(buf), remote)) < 1) break; if (write(fd, buf, r) != r) { warn("write()"); goto cleanup; } done += r; now = time(NULL); if (now > last || done == st.size) last = now; } if (ferror(remote)) goto fetchfail; if ((ret = extract_pkg_static(fd, pkgstatic, MAXPATHLEN)) == 0) ret = install_pkg_static(pkgstatic, tmppkg); snprintf(conf, MAXPATHLEN, "%s/etc/pkg.conf", getenv("LOCALBASE") ? getenv("LOCALBASE") : _LOCALBASE); if (access(conf, R_OK) == -1) { site = strrchr(url, '/'); if (site == NULL) goto cleanup; site[0] = '\0'; site = strrchr(url, '/'); if (site == NULL) goto cleanup; site[0] = '\0'; config = fopen(conf, "w+"); if (config == NULL) goto cleanup; fprintf(config, "packagesite: %s\n", url); fclose(config); } goto cleanup; fetchfail: warnx("Error fetching %s: %s", url, fetchLastErrString); fprintf(stderr, "A pre-built version of pkg could not be found for your system.\n"); fprintf(stderr, "Consider changing PACKAGESITE or installing it from ports: 'ports-mgmt/pkg'.\n"); cleanup: if (remote != NULL) fclose(remote); close(fd); unlink(tmppkg); return (ret); }
void fetch_pkg_vulnerabilities(int argc, char **argv) { struct pkg_vulnerabilities *pv_check; char *buf; size_t buf_len, buf_fetched; ssize_t cur_fetched; struct url *url; struct url_stat st; fetchIO *f; int fd; struct stat sb; char my_flags[20]; const char *flags; parse_options(argc, argv, "su"); if (argc != optind) usage(); if (verbose >= 2) fprintf(stderr, "Fetching %s\n", pkg_vulnerabilities_url); url = fetchParseURL(pkg_vulnerabilities_url); if (url == NULL) errx(EXIT_FAILURE, "Could not parse location of pkg_vulnerabilities: %s", fetchLastErrString); flags = fetch_flags; if (update_pkg_vuln) { fd = open(pkg_vulnerabilities_file, O_RDONLY); if (fd != -1 && fstat(fd, &sb) != -1) { url->last_modified = sb.st_mtime; snprintf(my_flags, sizeof(my_flags), "%si", fetch_flags); flags = my_flags; } else update_pkg_vuln = 0; if (fd != -1) close(fd); } f = fetchXGet(url, &st, flags); if (f == NULL && update_pkg_vuln && fetchLastErrCode == FETCH_UNCHANGED) { if (verbose >= 1) fprintf(stderr, "%s is not newer\n", pkg_vulnerabilities_url); exit(EXIT_SUCCESS); } if (f == NULL) errx(EXIT_FAILURE, "Could not fetch vulnerability file: %s", fetchLastErrString); if (st.size > SSIZE_MAX - 1) errx(EXIT_FAILURE, "pkg-vulnerabilities is too large"); buf_len = st.size; buf = xmalloc(buf_len + 1); buf_fetched = 0; while (buf_fetched < buf_len) { cur_fetched = fetchIO_read(f, buf + buf_fetched, buf_len - buf_fetched); if (cur_fetched == 0) errx(EXIT_FAILURE, "Truncated pkg-vulnerabilities received"); else if (cur_fetched == -1) errx(EXIT_FAILURE, "IO error while fetching pkg-vulnerabilities: %s", fetchLastErrString); buf_fetched += cur_fetched; } buf[buf_len] = '\0'; pv_check = read_pkg_vulnerabilities_memory(buf, buf_len, check_signature); free_pkg_vulnerabilities(pv_check); fd = open(pkg_vulnerabilities_file, O_WRONLY | O_CREAT | O_TRUNC, 0644); if (fd == -1) err(EXIT_FAILURE, "Cannot create pkg-vulnerability file %s", pkg_vulnerabilities_file); if (write(fd, buf, buf_len) != (ssize_t)buf_len) err(EXIT_FAILURE, "Cannot write pkg-vulnerability file"); if (close(fd) == -1) err(EXIT_FAILURE, "Cannot close pkg-vulnerability file after write"); free(buf); exit(EXIT_SUCCESS); }
/* * Fetch a file */ static int fetch(char *URL, const char *path) { struct url *url; struct url_stat us; struct stat sb, nsb; struct xferstat xs; FILE *f, *of; size_t size, readcnt, wr; off_t count; char flags[8]; const char *slash; char *tmppath; int r; unsigned timeout; char *ptr; f = of = NULL; tmppath = NULL; timeout = 0; *flags = 0; count = 0; /* set verbosity level */ if (v_level > 1) strcat(flags, "v"); if (v_level > 2) fetchDebug = 1; /* parse URL */ if ((url = fetchParseURL(URL)) == NULL) { warnx("%s: parse error", URL); goto failure; } /* if no scheme was specified, take a guess */ if (*url->scheme == 0) { if (*url->host == 0) strcpy(url->scheme, SCHEME_FILE); else if (strncasecmp(url->host, "ftp.", 4) == 0) strcpy(url->scheme, SCHEME_FTP); else if (strncasecmp(url->host, "www.", 4) == 0) strcpy(url->scheme, SCHEME_HTTP); } /* common flags */ switch (family) { case PF_INET: strcat(flags, "4"); break; case PF_INET6: strcat(flags, "6"); break; } /* FTP specific flags */ if (strcmp(url->scheme, SCHEME_FTP) == 0) { if (p_flag) strcat(flags, "p"); if (d_flag) strcat(flags, "d"); if (U_flag) strcat(flags, "l"); timeout = T_secs ? T_secs : ftp_timeout; } /* HTTP specific flags */ if (strcmp(url->scheme, SCHEME_HTTP) == 0 || strcmp(url->scheme, SCHEME_HTTPS) == 0) { if (d_flag) strcat(flags, "d"); if (A_flag) strcat(flags, "A"); timeout = T_secs ? T_secs : http_timeout; if (i_flag) { if (stat(i_filename, &sb)) { warn("%s: stat()", i_filename); goto failure; } url->ims_time = sb.st_mtime; strcat(flags, "i"); } } /* set the protocol timeout. */ fetchTimeout = timeout; /* just print size */ if (s_flag) { if (timeout) alarm(timeout); r = fetchStat(url, &us, flags); if (timeout) alarm(0); if (sigalrm || sigint) goto signal; if (r == -1) { warnx("%s", fetchLastErrString); goto failure; } if (us.size == -1) printf("Unknown\n"); else printf("%jd\n", (intmax_t)us.size); goto success; } /* * If the -r flag was specified, we have to compare the local * and remote files, so we should really do a fetchStat() * first, but I know of at least one HTTP server that only * sends the content size in response to GET requests, and * leaves it out of replies to HEAD requests. Also, in the * (frequent) case that the local and remote files match but * the local file is truncated, we have sufficient information * before the compare to issue a correct request. Therefore, * we always issue a GET request as if we were sure the local * file was a truncated copy of the remote file; we can drop * the connection later if we change our minds. */ sb.st_size = -1; if (!o_stdout) { r = stat(path, &sb); if (r == 0 && r_flag && S_ISREG(sb.st_mode)) { url->offset = sb.st_size; } else if (r == -1 || !S_ISREG(sb.st_mode)) { /* * Whatever value sb.st_size has now is either * wrong (if stat(2) failed) or irrelevant (if the * path does not refer to a regular file) */ sb.st_size = -1; } if (r == -1 && errno != ENOENT) { warnx("%s: stat()", path); goto failure; } } /* start the transfer */ if (timeout) alarm(timeout); f = fetchXGet(url, &us, flags); if (timeout) alarm(0); if (sigalrm || sigint) goto signal; if (f == NULL) { warnx("%s: %s", URL, fetchLastErrString); if (i_flag && strcmp(url->scheme, SCHEME_HTTP) == 0 && fetchLastErrCode == FETCH_OK && strcmp(fetchLastErrString, "Not Modified") == 0) { /* HTTP Not Modified Response, return OK. */ r = 0; goto done; } else goto failure; } if (sigint) goto signal; /* check that size is as expected */ if (S_size) { if (us.size == -1) { warnx("%s: size unknown", URL); } else if (us.size != S_size) { warnx("%s: size mismatch: expected %jd, actual %jd", URL, (intmax_t)S_size, (intmax_t)us.size); goto failure; } } /* symlink instead of copy */ if (l_flag && strcmp(url->scheme, "file") == 0 && !o_stdout) { if (symlink(url->doc, path) == -1) { warn("%s: symlink()", path); goto failure; } goto success; } if (us.size == -1 && !o_stdout && v_level > 0) warnx("%s: size of remote file is not known", URL); if (v_level > 1) { if (sb.st_size != -1) fprintf(stderr, "local size / mtime: %jd / %ld\n", (intmax_t)sb.st_size, (long)sb.st_mtime); if (us.size != -1) fprintf(stderr, "remote size / mtime: %jd / %ld\n", (intmax_t)us.size, (long)us.mtime); } /* open output file */ if (o_stdout) { /* output to stdout */ of = stdout; } else if (r_flag && sb.st_size != -1) { /* resume mode, local file exists */ if (!F_flag && us.mtime && sb.st_mtime != us.mtime) { /* no match! have to refetch */ fclose(f); /* if precious, warn the user and give up */ if (R_flag) { warnx("%s: local modification time " "does not match remote", path); goto failure_keep; } } else if (us.size != -1) { if (us.size == sb.st_size) /* nothing to do */ goto success; if (sb.st_size > us.size) { /* local file too long! */ warnx("%s: local file (%jd bytes) is longer " "than remote file (%jd bytes)", path, (intmax_t)sb.st_size, (intmax_t)us.size); goto failure; } /* we got it, open local file */ if ((of = fopen(path, "a")) == NULL) { warn("%s: fopen()", path); goto failure; } /* check that it didn't move under our feet */ if (fstat(fileno(of), &nsb) == -1) { /* can't happen! */ warn("%s: fstat()", path); goto failure; } if (nsb.st_dev != sb.st_dev || nsb.st_ino != nsb.st_ino || nsb.st_size != sb.st_size) { warnx("%s: file has changed", URL); fclose(of); of = NULL; sb = nsb; } } } else if (m_flag && sb.st_size != -1) { /* mirror mode, local file exists */ if (sb.st_size == us.size && sb.st_mtime == us.mtime) goto success; } if (of == NULL) { /* * We don't yet have an output file; either this is a * vanilla run with no special flags, or the local and * remote files didn't match. */ if (url->offset > 0) { /* * We tried to restart a transfer, but for * some reason gave up - so we have to restart * from scratch if we want the whole file */ url->offset = 0; if ((f = fetchXGet(url, &us, flags)) == NULL) { warnx("%s: %s", URL, fetchLastErrString); goto failure; } if (sigint) goto signal; } /* construct a temporary file name */ if (sb.st_size != -1 && S_ISREG(sb.st_mode)) { if ((slash = strrchr(path, '/')) == NULL) slash = path; else ++slash; asprintf(&tmppath, "%.*s.fetch.XXXXXX.%s", (int)(slash - path), path, slash); if (tmppath != NULL) { if (mkstemps(tmppath, strlen(slash)+1) == -1) { warn("%s: mkstemps()", path); goto failure; } of = fopen(tmppath, "w"); chown(tmppath, sb.st_uid, sb.st_gid); chmod(tmppath, sb.st_mode & ALLPERMS); } } if (of == NULL) if ((of = fopen(path, "w")) == NULL) { warn("%s: fopen()", path); goto failure; } } count = url->offset; /* start the counter */ stat_start(&xs, path, us.size, count); sigalrm = siginfo = sigint = 0; /* suck in the data */ signal(SIGINFO, sig_handler); while (!sigint) { if (us.size != -1 && us.size - count < B_size && us.size - count >= 0) size = us.size - count; else size = B_size; if (siginfo) { stat_end(&xs); siginfo = 0; } if (size == 0) break; if ((readcnt = fread(buf, 1, size, f)) < size) { if (ferror(f) && errno == EINTR && !sigint) clearerr(f); else if (readcnt == 0) break; } stat_update(&xs, count += readcnt); for (ptr = buf; readcnt > 0; ptr += wr, readcnt -= wr) if ((wr = fwrite(ptr, 1, readcnt, of)) < readcnt) { if (ferror(of) && errno == EINTR && !sigint) clearerr(of); else break; } if (readcnt != 0) break; } if (!sigalrm) sigalrm = ferror(f) && errno == ETIMEDOUT; signal(SIGINFO, SIG_DFL); stat_end(&xs); /* * If the transfer timed out or was interrupted, we still want to * set the mtime in case the file is not removed (-r or -R) and * the user later restarts the transfer. */ signal: /* set mtime of local file */ if (!n_flag && us.mtime && !o_stdout && of != NULL && (stat(path, &sb) != -1) && sb.st_mode & S_IFREG) { struct timeval tv[2]; fflush(of); tv[0].tv_sec = (long)(us.atime ? us.atime : us.mtime); tv[1].tv_sec = (long)us.mtime; tv[0].tv_usec = tv[1].tv_usec = 0; if (utimes(tmppath ? tmppath : path, tv)) warn("%s: utimes()", tmppath ? tmppath : path); } /* timed out or interrupted? */ if (sigalrm) warnx("transfer timed out"); if (sigint) { warnx("transfer interrupted"); goto failure; } /* timeout / interrupt before connection completley established? */ if (f == NULL) goto failure; if (!sigalrm) { /* check the status of our files */ if (ferror(f)) warn("%s", URL); if (ferror(of)) warn("%s", path); if (ferror(f) || ferror(of)) goto failure; } /* did the transfer complete normally? */ if (us.size != -1 && count < us.size) { warnx("%s appears to be truncated: %jd/%jd bytes", path, (intmax_t)count, (intmax_t)us.size); goto failure_keep; } /* * If the transfer timed out and we didn't know how much to * expect, assume the worst (i.e. we didn't get all of it) */ if (sigalrm && us.size == -1) { warnx("%s may be truncated", path); goto failure_keep; } success: r = 0; if (tmppath != NULL && rename(tmppath, path) == -1) { warn("%s: rename()", path); goto failure_keep; } goto done; failure: if (of && of != stdout && !R_flag && !r_flag) if (stat(path, &sb) != -1 && (sb.st_mode & S_IFREG)) unlink(tmppath ? tmppath : path); if (R_flag && tmppath != NULL && sb.st_size == -1) rename(tmppath, path); /* ignore errors here */ failure_keep: r = -1; goto done; done: if (f) fclose(f); if (of && of != stdout) fclose(of); if (url) fetchFreeURL(url); if (tmppath != NULL) free(tmppath); return (r); }
int pkg_fetch_file_to_fd(const char *url, int dest, time_t t) { FILE *remote = NULL; struct url *u; struct url_stat st; off_t done = 0; off_t r; int64_t max_retry, retry; time_t begin_dl; time_t now; time_t last = 0; char buf[10240]; char *doc; char docpath[MAXPATHLEN]; int retcode = EPKG_OK; bool srv = false; bool http = false; char zone[MAXHOSTNAMELEN + 13]; struct dns_srvinfo *srv_current = NULL; struct http_mirror *http_current = NULL; const char *mt; fetchTimeout = 30; if (pkg_config_int64(PKG_CONFIG_FETCH_RETRY, &max_retry) == EPKG_FATAL) max_retry = 3; retry = max_retry; u = fetchParseURL(url); doc = u->doc; while (remote == NULL) { if (retry == max_retry) { pkg_config_string(PKG_CONFIG_MIRRORS, &mt); if (mt != NULL && strncasecmp(mt, "srv", 3) == 0 && \ strcmp(u->scheme, "file") != 0) { srv = true; snprintf(zone, sizeof(zone), "_%s._tcp.%s", u->scheme, u->host); pthread_mutex_lock(&mirror_mtx); if (srv_mirrors != NULL) srv_mirrors = dns_getsrvinfo(zone); pthread_mutex_unlock(&mirror_mtx); srv_current = srv_mirrors; } else if (mt != NULL && strncasecmp(mt, "http", 4) == 0 && \ strcmp(u->scheme, "file") != 0 && \ strcmp(u->scheme, "ftp") != 0) { http = true; snprintf(zone, sizeof(zone), "%s://%s", u->scheme, u->host); pthread_mutex_lock(&mirror_mtx); if (STAILQ_EMPTY(&http_mirrors)) gethttpmirrors(zone); pthread_mutex_unlock(&mirror_mtx); http_current = STAILQ_FIRST(&http_mirrors); } } if (srv && srv_mirrors != NULL) strlcpy(u->host, srv_current->host, sizeof(u->host)); else if (http && !STAILQ_EMPTY(&http_mirrors)) { strlcpy(u->scheme, http_current->url->scheme, sizeof(u->scheme)); strlcpy(u->host, http_current->url->host, sizeof(u->host)); snprintf(docpath, MAXPATHLEN, "%s%s", http_current->url->doc, doc); u->doc = docpath; u->port = http_current->url->port; } remote = fetchXGet(u, &st, ""); if (remote == NULL) { --retry; if (retry <= 0) { pkg_emit_error("%s: %s", url, fetchLastErrString); retcode = EPKG_FATAL; goto cleanup; } if (srv && srv_mirrors != NULL) { srv_current = srv_current->next; if (srv_current == NULL) srv_current = srv_mirrors; } else if (http && !STAILQ_EMPTY(&http_mirrors)) { http_current = STAILQ_NEXT(http_current, next); if (http_current == NULL) http_current = STAILQ_FIRST(&http_mirrors); } else { sleep(1); } } } if (t != 0) { if (st.mtime <= t) { retcode = EPKG_UPTODATE; goto cleanup; } } begin_dl = time(NULL); while (done < st.size) { if ((r = fread(buf, 1, sizeof(buf), remote)) < 1) break; if (write(dest, buf, r) != r) { pkg_emit_errno("write", ""); retcode = EPKG_FATAL; goto cleanup; } done += r; now = time(NULL); /* Only call the callback every second */ if (now > last || done == st.size) { pkg_emit_fetching(url, st.size, done, (now - begin_dl)); last = now; } } if (ferror(remote)) { pkg_emit_error("%s: %s", url, fetchLastErrString); retcode = EPKG_FATAL; goto cleanup; } cleanup: if (remote != NULL) fclose(remote); /* restore original doc */ u->doc = doc; fetchFreeURL(u); return (retcode); }
int pkg_fetch_file_to_fd(const char *url, int dest, time_t t) { FILE *remote = NULL; struct url *u; struct url_stat st; off_t done = 0; off_t r; int64_t max_retry, retry; time_t begin_dl; time_t now; time_t last = 0; char buf[10240]; int retcode = EPKG_OK; bool srv = false; char zone[MAXHOSTNAMELEN + 12]; struct dns_srvinfo *mirrors, *current; current = mirrors = NULL; fetchTimeout = 30; if (pkg_config_int64(PKG_CONFIG_FETCH_RETRY, &max_retry) == EPKG_FATAL) max_retry = 3; retry = max_retry; u = fetchParseURL(url); while (remote == NULL) { if (retry == max_retry) { pkg_config_bool(PKG_CONFIG_SRV_MIRROR, &srv); if (srv) { if (strcmp(u->scheme, "file") != 0) { snprintf(zone, sizeof(zone), "_%s._tcp.%s", u->scheme, u->host); mirrors = dns_getsrvinfo(zone); current = mirrors; } } } if (mirrors != NULL) strlcpy(u->host, current->host, sizeof(u->host)); remote = fetchXGet(u, &st, ""); if (remote == NULL) { --retry; if (retry <= 0) { pkg_emit_error("%s: %s", url, fetchLastErrString); retcode = EPKG_FATAL; goto cleanup; } if (mirrors == NULL) { sleep(1); } else { current = current->next; if (current == NULL) current = mirrors; } } } if (t != 0) { if (st.mtime <= t) { retcode = EPKG_UPTODATE; goto cleanup; } } begin_dl = time(NULL); while (done < st.size) { if ((r = fread(buf, 1, sizeof(buf), remote)) < 1) break; if (write(dest, buf, r) != r) { pkg_emit_errno("write", ""); retcode = EPKG_FATAL; goto cleanup; } done += r; now = time(NULL); /* Only call the callback every second */ if (now > last || done == st.size) { pkg_emit_fetching(url, st.size, done, (now - begin_dl)); last = now; } } if (ferror(remote)) { pkg_emit_error("%s: %s", url, fetchLastErrString); retcode = EPKG_FATAL; goto cleanup; } cleanup: if (remote != NULL) fclose(remote); fetchFreeURL(u); return (retcode); }
/* if db_mtime == NULL, we're downloading a package, pkg_summary otherwise */ Dlfile * download_file(char *str_url, time_t *db_mtime) { /* from pkg_install/files/admin/audit.c */ Dlfile *file; char *p; size_t buf_len, buf_fetched; ssize_t cur_fetched; off_t statsize; time_t begin_dl, now; struct url_stat st; struct url *url; fetchIO *f = NULL; url = fetchParseURL(str_url); if (url == NULL || (f = fetchXGet(url, &st, "")) == NULL) return NULL; if (st.size == -1) { /* could not obtain file size */ if (db_mtime != NULL) /* we're downloading pkg_summary */ *db_mtime = 0; /* not -1, don't force update */ return NULL; } if (db_mtime != NULL) { if (st.mtime <= *db_mtime) { /* -1 used to identify return type, local summary up-to-date */ *db_mtime = -1; fetchIO_close(f); return NULL; } *db_mtime = st.mtime; } if ((p = strrchr(str_url, '/')) != NULL) p++; else p = (char *)str_url; /* should not happen */ #ifndef _MINIX /* XXX: SSIZE_MAX fails under MINIX */ /* st.size is an off_t, it will be > SSIZE_MAX on 32 bits systems */ if (sizeof(st.size) == sizeof(SSIZE_MAX) && st.size > SSIZE_MAX - 1) err(EXIT_FAILURE, "file is too large"); #endif buf_len = st.size; XMALLOC(file, sizeof(Dlfile)); XMALLOC(file->buf, buf_len + 1); printf(MSG_DOWNLOADING, p); fflush(stdout); buf_fetched = 0; begin_dl = time(NULL); statsize = 0; start_progress_meter(p, buf_len, &statsize); while (buf_fetched < buf_len) { cur_fetched = fetchIO_read(f, file->buf + buf_fetched, fetch_buffer); if (cur_fetched == 0) errx(EXIT_FAILURE, "truncated file"); else if (cur_fetched == -1) errx(EXIT_FAILURE, "failure during fetch of file: %s", fetchLastErrString); buf_fetched += cur_fetched; statsize += cur_fetched; now = time(NULL); } stop_progress_meter(); file->buf[buf_len] = '\0'; file->size = buf_len; if (file->buf[0] == '\0') errx(EXIT_FAILURE, "empty download, exiting.\n"); fetchIO_close(f); return file; }
/* * Download a package to the local cache. */ ssize_t download_pkg(char *pkg_url, FILE *fp) { struct url_stat st; size_t size, wrote; ssize_t fetched, written = 0; off_t statsize = 0; struct url *url; fetchIO *f = NULL; char buf[4096]; char *pkg, *ptr; if ((url = fetchParseURL(pkg_url)) == NULL) errx(EXIT_FAILURE, "%s: parse failure", pkg_url); if ((f = fetchXGet(url, &st, "")) == NULL) errx(EXIT_FAILURE, "%s: %s", pkg_url, fetchLastErrString); /* Package not available */ if (st.size == -1) return st.size; if ((pkg = strrchr(pkg_url, '/')) != NULL) pkg++; else pkg = (char *)pkg_url; /* should not happen */ if (parsable) { printf(MSG_DOWNLOAD_START); } else { printf(MSG_DOWNLOADING, pkg); fflush(stdout); start_progress_meter(pkg, st.size, &statsize); } while (written < st.size) { if ((fetched = fetchIO_read(f, buf, sizeof(buf))) == 0) break; if (fetched == -1 && errno == EINTR) continue; if (fetched == -1) errx(EXIT_FAILURE, "fetch failure: %s", fetchLastErrString); statsize += fetched; size = fetched; for (ptr = buf; size > 0; ptr += wrote, size -= wrote) { if ((wrote = fwrite(ptr, 1, size, fp)) < size) { if (ferror(fp) && errno == EINTR) clearerr(fp); else break; } written += wrote; } } if (parsable) printf(MSG_DOWNLOAD_END); else stop_progress_meter(); fetchIO_close(f); fetchFreeURL(url); if (written != st.size) return -1; return written; }
int main(int argc, char **argv) { struct termios tios; tcflag_t saved; struct url *url; FILE *in, *out; const size_t bufsize = 1024; char buf[bufsize], *fullpath, *base; char *passwd = NULL, *p, *user = NULL, *u; size_t n; int c; if (argc != 3) usage(1); while ((c = getopt(argc, argv, "hp:u:")) != -1) switch (c) { case 'h': usage(0); break; case 'p': passwd = optarg; break; case 'u': user = optarg; break; default: usage(1); break; } argc -= optind; argv += optind; in = inputfile(argv[0]); fullpath = malloc(strlen(argv[0]) + strlen(argv[1]) + 2); if (fullpath == NULL) err(1, "malloc"); strcpy(fullpath, argv[1]); base = fullpath + strlen(argv[1]); *base++ = '/'; strcpy(base, argv[0]); fetchTimeout = 0; url = fetchParseURL(fullpath); if (url == NULL) errx(1, "parsing URL: %s", fetchLastErrString); if (user == NULL) { fprintf(stderr, "Username: "******"reading username"); u = (char *)url->user; strsep(&u, "\n\r"); } else { strlcpy(url->user, user, sizeof(url->user)); } if (passwd == NULL) { fprintf(stderr, "Password: "******"reading password"); tios.c_lflag = saved; tcsetattr(STDIN_FILENO, TCSAFLUSH | TCSASOFT, &tios); } else { if (fgets(url->pwd, sizeof(url->pwd), stdin) == NULL) err(1, "reading password"); } p = (char *)url->pwd; strsep(&p, "\n\r"); } else { strlcpy(url->pwd, passwd, sizeof(url->pwd)); } out = fetchPutFTP(url, ""); if (out == NULL) { printf("user: %s, pwd: %s\n", url->user, url->pwd); errx(1, "couldn't open a connection to %s: %s", fullpath, fetchLastErrString); } while ((n = fread(buf, 1, bufsize, in)) > 0) { if (fwrite(buf, n, 1, out) != 1) err(1, "writing to %s", fullpath); } fclose(in); fclose(out); fetchFreeURL(url); return (0); }