Changeset View
Standalone View
usr.sbin/pkg/pkg.c
/*- | /*- | ||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD | * SPDX-License-Identifier: BSD-2-Clause-FreeBSD | ||||
* | * | ||||
* Copyright (c) 2012-2014 Baptiste Daroussin <bapt@FreeBSD.org> | * Copyright (c) 2012-2014 Baptiste Daroussin <bapt@FreeBSD.org> | ||||
* Copyright (c) 2013 Bryan Drewery <bdrewery@FreeBSD.org> | * Copyright (c) 2013 Bryan Drewery <bdrewery@FreeBSD.org> | ||||
* All rights reserved. | * All rights reserved. | ||||
* | * | ||||
* Redistribution and use in source and binary forms, with or without | * Redistribution and use in source and binary forms, with or without | ||||
* modification, are permitted provided that the following conditions | * modification, are permitted provided that the following conditions | ||||
* are met: | * are met: | ||||
* 1. Redistributions of source code must retain the above copyright | * 1. Redistributions of source code must retain the above copyright | ||||
* notice, this list of conditions and the following disclaimer. | * notice, this list of conditions and the following disclaimer. | ||||
* 2. Redistributions in binary form must reproduce the above copyright | * 2. Redistributions in binary form must reproduce the above copyright | ||||
* notice, this list of conditions and the following disclaimer in the | * notice, this list of conditions and the following disclaimer in the | ||||
* documentation and/or other materials provided with the distribution. | * documentation and/or other materials provided with the distribution. | ||||
* | * | ||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | ||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | ||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||||
* SUCH DAMAGE. | * SUCH DAMAGE. | ||||
*/ | */ | ||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | ||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
#include <sys/types.h> | |||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/queue.h> | #include <sys/queue.h> | ||||
#include <sys/types.h> | |||||
#include <sys/sbuf.h> | #include <sys/sbuf.h> | ||||
#include <sys/wait.h> | #include <sys/wait.h> | ||||
#include <archive.h> | #include <archive.h> | ||||
#include <archive_entry.h> | #include <archive_entry.h> | ||||
#include <dirent.h> | #include <dirent.h> | ||||
#include <err.h> | #include <err.h> | ||||
#include <errno.h> | #include <errno.h> | ||||
#include <fcntl.h> | #include <fcntl.h> | ||||
#include <fetch.h> | #include <fetch.h> | ||||
#include <openssl/err.h> | |||||
#include <openssl/ssl.h> | |||||
#include <paths.h> | #include <paths.h> | ||||
#include <stdbool.h> | #include <stdbool.h> | ||||
#include <stdlib.h> | |||||
#include <stdio.h> | #include <stdio.h> | ||||
#include <stdlib.h> | |||||
#include <string.h> | #include <string.h> | ||||
#include <unistd.h> | |||||
#include <ucl.h> | #include <ucl.h> | ||||
#include <unistd.h> | |||||
#include <openssl/err.h> | |||||
#include <openssl/ssl.h> | |||||
#include "dns_utils.h" | |||||
#include "config.h" | #include "config.h" | ||||
#include "dns_utils.h" | |||||
struct sig_cert { | struct sig_cert { | ||||
char *name; | char *name; | ||||
unsigned char *sig; | unsigned char *sig; | ||||
int siglen; | int siglen; | ||||
unsigned char *cert; | unsigned char *cert; | ||||
int certlen; | int certlen; | ||||
bool trusted; | bool trusted; | ||||
▲ Show 20 Lines • Show All 49 Lines • ▼ Show 20 Lines | extract_pkg_static(int fd, char *p, int sz) | ||||
while ((r = archive_read_next_header(a, &ae)) == ARCHIVE_OK) { | while ((r = archive_read_next_header(a, &ae)) == ARCHIVE_OK) { | ||||
end = strrchr(archive_entry_pathname(ae), '/'); | end = strrchr(archive_entry_pathname(ae), '/'); | ||||
if (end == NULL) | if (end == NULL) | ||||
continue; | continue; | ||||
if (strcmp(end, "/pkg-static") == 0) { | if (strcmp(end, "/pkg-static") == 0) { | ||||
r = archive_read_extract(a, ae, | r = archive_read_extract(a, ae, | ||||
ARCHIVE_EXTRACT_OWNER | ARCHIVE_EXTRACT_PERM | | ARCHIVE_EXTRACT_OWNER | ARCHIVE_EXTRACT_PERM | | ||||
ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_ACL | | ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_ACL | | ||||
ARCHIVE_EXTRACT_FFLAGS | ARCHIVE_EXTRACT_XATTR); | ARCHIVE_EXTRACT_FFLAGS | ARCHIVE_EXTRACT_XATTR); | ||||
strlcpy(p, archive_entry_pathname(ae), sz); | strlcpy(p, archive_entry_pathname(ae), sz); | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
if (r == ARCHIVE_OK) | if (r == ARCHIVE_OK) | ||||
ret = 0; | ret = 0; | ||||
else | else | ||||
warnx("failed to extract pkg-static: %s", | warnx("failed to extract pkg-static: %s", | ||||
archive_error_string(a)); | archive_error_string(a)); | ||||
cleanup: | cleanup: | ||||
archive_read_free(a); | archive_read_free(a); | ||||
return (ret); | return (ret); | ||||
} | } | ||||
static int | static int | ||||
install_pkg_static(const char *path, const char *pkgpath, bool force) | install_pkg_static(const char *path, const char *pkgpath, bool force) | ||||
{ | { | ||||
int pstat; | int pstat; | ||||
pid_t pid; | pid_t pid; | ||||
switch ((pid = fork())) { | switch ((pid = fork())) { | ||||
case -1: | case -1: | ||||
return (-1); | return (-1); | ||||
case 0: | case 0: | ||||
if (force) | if (force) | ||||
execl(path, "pkg-static", "add", "-f", pkgpath, | execl(path, "pkg-static", "add", "-f", pkgpath, | ||||
(char *)NULL); | (char *)NULL); | ||||
else | else | ||||
execl(path, "pkg-static", "add", pkgpath, | execl(path, "pkg-static", "add", pkgpath, (char *)NULL); | ||||
(char *)NULL); | |||||
_exit(1); | _exit(1); | ||||
default: | default: | ||||
break; | break; | ||||
} | } | ||||
while (waitpid(pid, &pstat, 0) == -1) | while (waitpid(pid, &pstat, 0) == -1) | ||||
if (errno != EINTR) | if (errno != EINTR) | ||||
return (-1); | return (-1); | ||||
Show All 19 Lines | fetch_to_fd(const char *url, char *path) | ||||
char buf[10240]; | char buf[10240]; | ||||
char zone[MAXHOSTNAMELEN + 13]; | char zone[MAXHOSTNAMELEN + 13]; | ||||
static const char *mirror_type = NULL; | static const char *mirror_type = NULL; | ||||
max_retry = 3; | max_retry = 3; | ||||
current = mirrors = NULL; | current = mirrors = NULL; | ||||
remote = NULL; | remote = NULL; | ||||
if (mirror_type == NULL && config_string(MIRROR_TYPE, &mirror_type) | if (mirror_type == NULL && | ||||
!= 0) { | config_string(MIRROR_TYPE, &mirror_type) != 0) { | ||||
warnx("No MIRROR_TYPE defined"); | warnx("No MIRROR_TYPE defined"); | ||||
return (-1); | return (-1); | ||||
} | } | ||||
if ((fd = mkstemp(path)) == -1) { | if ((fd = mkstemp(path)) == -1) { | ||||
warn("mkstemp()"); | warn("mkstemp()"); | ||||
return (-1); | return (-1); | ||||
} | } | ||||
retry = max_retry; | retry = max_retry; | ||||
if ((u = fetchParseURL(url)) == NULL) { | if ((u = fetchParseURL(url)) == NULL) { | ||||
warn("fetchParseURL('%s')", url); | warn("fetchParseURL('%s')", url); | ||||
return (-1); | return (-1); | ||||
} | } | ||||
while (remote == NULL) { | while (remote == NULL) { | ||||
if (retry == max_retry) { | if (retry == max_retry) { | ||||
if (strcmp(u->scheme, "file") != 0 && | if (strcmp(u->scheme, "file") != 0 && | ||||
strcasecmp(mirror_type, "srv") == 0) { | strcasecmp(mirror_type, "srv") == 0) { | ||||
snprintf(zone, sizeof(zone), | snprintf(zone, sizeof(zone), "_%s._tcp.%s", | ||||
"_%s._tcp.%s", u->scheme, u->host); | u->scheme, u->host); | ||||
mirrors = dns_getsrvinfo(zone); | mirrors = dns_getsrvinfo(zone); | ||||
current = mirrors; | current = mirrors; | ||||
} | } | ||||
} | } | ||||
if (mirrors != NULL) { | if (mirrors != NULL) { | ||||
strlcpy(u->host, current->host, sizeof(u->host)); | strlcpy(u->host, current->host, sizeof(u->host)); | ||||
u->port = current->port; | u->port = current->port; | ||||
▲ Show 20 Lines • Show All 84 Lines • ▼ Show 20 Lines | parse_fingerprint(ucl_object_t *obj) | ||||
f = calloc(1, sizeof(struct fingerprint)); | f = calloc(1, sizeof(struct fingerprint)); | ||||
f->type = fct; | f->type = fct; | ||||
strlcpy(f->hash, fp, sizeof(f->hash)); | strlcpy(f->hash, fp, sizeof(f->hash)); | ||||
return (f); | return (f); | ||||
} | } | ||||
static void | static void | ||||
free_fingerprint_list(struct fingerprint_list* list) | free_fingerprint_list(struct fingerprint_list *list) | ||||
{ | { | ||||
struct fingerprint *fingerprint, *tmp; | struct fingerprint *fingerprint, *tmp; | ||||
STAILQ_FOREACH_SAFE(fingerprint, list, next, tmp) { | STAILQ_FOREACH_SAFE (fingerprint, list, next, tmp) { | ||||
free(fingerprint->name); | free(fingerprint->name); | ||||
free(fingerprint); | free(fingerprint); | ||||
} | } | ||||
free(list); | free(list); | ||||
} | } | ||||
static struct fingerprint * | static struct fingerprint * | ||||
load_fingerprint(const char *dir, const char *filename) | load_fingerprint(const char *dir, const char *filename) | ||||
▲ Show 20 Lines • Show All 265 Lines • ▼ Show 20 Lines | read_pubkey(int fd) | ||||
if (lseek(fd, 0, 0) == -1) { | if (lseek(fd, 0, 0) == -1) { | ||||
warn("lseek"); | warn("lseek"); | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
sig = sbuf_new_auto(); | sig = sbuf_new_auto(); | ||||
while ((r = read(fd, buf, sizeof(buf))) >0) { | while ((r = read(fd, buf, sizeof(buf))) > 0) { | ||||
sbuf_bcat(sig, buf, r); | sbuf_bcat(sig, buf, r); | ||||
} | } | ||||
sbuf_finish(sig); | sbuf_finish(sig); | ||||
pk = calloc(1, sizeof(struct pubkey)); | pk = calloc(1, sizeof(struct pubkey)); | ||||
pk->siglen = sbuf_len(sig); | pk->siglen = sbuf_len(sig); | ||||
pk->sig = calloc(1, pk->siglen); | pk->sig = calloc(1, pk->siglen); | ||||
memcpy(pk->sig, sbuf_data(sig), pk->siglen); | memcpy(pk->sig, sbuf_data(sig), pk->siglen); | ||||
sbuf_delete(sig); | sbuf_delete(sig); | ||||
return (pk); | return (pk); | ||||
} | } | ||||
static struct sig_cert * | static struct sig_cert * | ||||
parse_cert(int fd) { | parse_cert(int fd) | ||||
{ | |||||
int my_fd; | int my_fd; | ||||
struct sig_cert *sc; | struct sig_cert *sc; | ||||
FILE *fp; | FILE *fp; | ||||
struct sbuf *buf, *sig, *cert; | struct sbuf *buf, *sig, *cert; | ||||
char *line; | char *line; | ||||
size_t linecap; | size_t linecap; | ||||
ssize_t linelen; | ssize_t linelen; | ||||
▲ Show 20 Lines • Show All 76 Lines • ▼ Show 20 Lines | verify_pubsignature(int fd_pkg, int fd_sig) | ||||
if ((pk = read_pubkey(fd_sig)) == NULL) { | if ((pk = read_pubkey(fd_sig)) == NULL) { | ||||
warnx("Error reading signature"); | warnx("Error reading signature"); | ||||
goto cleanup; | goto cleanup; | ||||
} | } | ||||
/* Verify the signature. */ | /* Verify the signature. */ | ||||
printf("Verifying signature with public key %s... ", pubkey); | printf("Verifying signature with public key %s... ", pubkey); | ||||
if (rsa_verify_cert(fd_pkg, pubkey, NULL, 0, pk->sig, | if (rsa_verify_cert(fd_pkg, pubkey, NULL, 0, pk->sig, pk->siglen) == | ||||
pk->siglen) == false) { | false) { | ||||
fprintf(stderr, "Signature is not valid\n"); | fprintf(stderr, "Signature is not valid\n"); | ||||
goto cleanup; | goto cleanup; | ||||
} | } | ||||
ret = true; | ret = true; | ||||
cleanup: | cleanup: | ||||
if (pk) { | if (pk) { | ||||
▲ Show 20 Lines • Show All 51 Lines • ▼ Show 20 Lines | verify_signature(int fd_pkg, int fd_sig) | ||||
/* Explicitly mark as non-trusted until proven otherwise. */ | /* Explicitly mark as non-trusted until proven otherwise. */ | ||||
sc->trusted = false; | sc->trusted = false; | ||||
/* Parse signature and pubkey out of the certificate */ | /* Parse signature and pubkey out of the certificate */ | ||||
sha256_buf(sc->cert, sc->certlen, hash); | sha256_buf(sc->cert, sc->certlen, hash); | ||||
/* Check if this hash is revoked */ | /* Check if this hash is revoked */ | ||||
if (revoked != NULL) { | if (revoked != NULL) { | ||||
STAILQ_FOREACH(fingerprint, revoked, next) { | STAILQ_FOREACH (fingerprint, revoked, next) { | ||||
if (strcasecmp(fingerprint->hash, hash) == 0) { | if (strcasecmp(fingerprint->hash, hash) == 0) { | ||||
fprintf(stderr, "The package was signed with " | fprintf(stderr, | ||||
"The package was signed with " | |||||
"revoked certificate %s\n", | "revoked certificate %s\n", | ||||
fingerprint->name); | fingerprint->name); | ||||
goto cleanup; | goto cleanup; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
STAILQ_FOREACH(fingerprint, trusted, next) { | STAILQ_FOREACH (fingerprint, trusted, next) { | ||||
if (strcasecmp(fingerprint->hash, hash) == 0) { | if (strcasecmp(fingerprint->hash, hash) == 0) { | ||||
sc->trusted = true; | sc->trusted = true; | ||||
sc->name = strdup(fingerprint->name); | sc->name = strdup(fingerprint->name); | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
if (sc->trusted == false) { | if (sc->trusted == false) { | ||||
fprintf(stderr, "No trusted fingerprint found matching " | fprintf(stderr, | ||||
"No trusted fingerprint found matching " | |||||
"package's certificate\n"); | "package's certificate\n"); | ||||
goto cleanup; | goto cleanup; | ||||
} | } | ||||
/* Verify the signature. */ | /* Verify the signature. */ | ||||
printf("Verifying signature with trusted certificate %s... ", sc->name); | printf("Verifying signature with trusted certificate %s... ", sc->name); | ||||
if (rsa_verify_cert(fd_pkg, NULL, sc->cert, sc->certlen, sc->sig, | if (rsa_verify_cert(fd_pkg, NULL, sc->cert, sc->certlen, sc->sig, | ||||
sc->siglen) == false) { | sc->siglen) == false) { | ||||
fprintf(stderr, "Signature is not valid\n"); | fprintf(stderr, "Signature is not valid\n"); | ||||
goto cleanup; | goto cleanup; | ||||
} | } | ||||
ret = true; | ret = true; | ||||
cleanup: | cleanup: | ||||
if (trusted) | if (trusted) | ||||
free_fingerprint_list(trusted); | free_fingerprint_list(trusted); | ||||
if (revoked) | if (revoked) | ||||
free_fingerprint_list(revoked); | free_fingerprint_list(revoked); | ||||
if (sc) { | if (sc) { | ||||
free(sc->cert); | free(sc->cert); | ||||
free(sc->sig); | free(sc->sig); | ||||
free(sc->name); | free(sc->name); | ||||
free(sc); | free(sc); | ||||
} | } | ||||
return (ret); | return (ret); | ||||
} | } | ||||
static int | static int | ||||
bootstrap_pkg(bool force) | bootstrap_pkg(bool force) | ||||
{ | { | ||||
const char *extensions[6] = { ".txz", ".tzst", ".tbz", ".tgz", ".tar", | |||||
kevans: I'd be tempted to move this out to the global scope, make it static, drop the NULL terminator… | |||||
Done Inline Actionsin discussion with @bapt we want to add also the .bsd extension, it's not used yet but he wants to use it as the generic extension for packages emaste: in discussion with @bapt we want to add also the `.bsd` extension, it's not used yet but he… | |||||
NULL }; | |||||
int fd_pkg, fd_sig; | int fd_pkg, fd_sig; | ||||
int ret; | int ret; | ||||
char url[MAXPATHLEN]; | char url[MAXPATHLEN]; | ||||
char tmppkg[MAXPATHLEN]; | char tmppkg[MAXPATHLEN]; | ||||
char tmpsig[MAXPATHLEN]; | char tmpsig[MAXPATHLEN]; | ||||
char packagename[MAXPATHLEN]; | |||||
const char *packagesite; | const char *packagesite; | ||||
const char *signature_type; | const char *signature_type; | ||||
char pkgstatic[MAXPATHLEN]; | char pkgstatic[MAXPATHLEN]; | ||||
fd_sig = -1; | fd_sig = -1; | ||||
ret = -1; | ret = -1; | ||||
if (config_string(PACKAGESITE, &packagesite) != 0) { | if (config_string(PACKAGESITE, &packagesite) != 0) { | ||||
warnx("No PACKAGESITE defined"); | warnx("No PACKAGESITE defined"); | ||||
return (-1); | return (-1); | ||||
} | } | ||||
if (config_string(SIGNATURE_TYPE, &signature_type) != 0) { | if (config_string(SIGNATURE_TYPE, &signature_type) != 0) { | ||||
warnx("Error looking up SIGNATURE_TYPE"); | warnx("Error looking up SIGNATURE_TYPE"); | ||||
return (-1); | return (-1); | ||||
} | } | ||||
printf("Bootstrapping pkg from %s, please wait...\n", packagesite); | printf("Bootstrapping pkg from %s, please wait...\n", packagesite); | ||||
/* Support pkg+http:// for PACKAGESITE which is the new format | /* Support pkg+http:// for PACKAGESITE which is the new format | ||||
in 1.2 to avoid confusion on why http://pkg.FreeBSD.org has | in 1.2 to avoid confusion on why http://pkg.FreeBSD.org has | ||||
no A record. */ | no A record. */ | ||||
if (strncmp(URL_SCHEME_PREFIX, packagesite, | if (strncmp( | ||||
strlen(URL_SCHEME_PREFIX)) == 0) | URL_SCHEME_PREFIX, packagesite, strlen(URL_SCHEME_PREFIX)) == 0) | ||||
packagesite += strlen(URL_SCHEME_PREFIX); | packagesite += strlen(URL_SCHEME_PREFIX); | ||||
snprintf(url, MAXPATHLEN, "%s/Latest/pkg.txz", packagesite); | |||||
snprintf(tmppkg, MAXPATHLEN, "%s/pkg.txz.XXXXXX", | for (const char **n = extensions; *n != NULL; n++) { | ||||
getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP); | snprintf(packagename, MAXPATHLEN, "pkg%s", *n); | ||||
snprintf( | |||||
url, MAXPATHLEN, "%s/Latest/%s", packagesite, packagename); | |||||
Done Inline Actions... loop here from 0 to nitems(extension) (macro provided by sys/param.h) kevans: ... loop here from 0 to `nitems(extension)` (macro provided by `sys/param.h`) | |||||
snprintf(tmppkg, MAXPATHLEN, "%s/%s.XXXXXX", | |||||
getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP, | |||||
packagename); | |||||
if ((fd_pkg = fetch_to_fd(url, tmppkg)) == -1) | if ((fd_pkg = fetch_to_fd(url, tmppkg)) == -1) | ||||
goto fetchfail; | continue; | ||||
Done Inline ActionsFreeBSD style is a 4 spaces for 2nd-level indents. clang-format should be able to help here, have a look at the instructions for clang-formatting a git patch at https://clang.llvm.org/docs/ClangFormat.html and see how it works, and then put those instructions on https://wiki.freebsd.org/Phabricator emaste: FreeBSD style is a 4 spaces for 2nd-level indents.
clang-format should be able to help here… | |||||
Not Done Inline ActionsAll paths through the oop after this either goto fetchfail or cleanup, so you could invert this condition and break out of the loop, dropping the rest of the loop's body out of it. Do we suspect that we could hit a failure mode where, e.g., pkg.txz exists but the rest of this won't line up and we need to try a different archive type? kevans: All paths through the oop after this either goto fetchfail or cleanup, so you could invert this… | |||||
Not Done Inline ActionsI believe that the desired behavior for when pkg.txz is fetched but reaches a failure state for whatever reason to attempt to fetch the next file from the extensions array to attempt recovery. zac_freebsdfoundation.org: I believe that the desired behavior for when pkg.txz is fetched but reaches a failure state for… | |||||
if (signature_type != NULL && | if (signature_type != NULL && | ||||
strcasecmp(signature_type, "NONE") != 0) { | strcasecmp(signature_type, "NONE") != 0) { | ||||
if (strcasecmp(signature_type, "FINGERPRINTS") == 0) { | if (strcasecmp(signature_type, "FINGERPRINTS") == 0) { | ||||
snprintf(tmpsig, MAXPATHLEN, "%s/pkg.txz.sig.XXXXXX", | snprintf(tmpsig, MAXPATHLEN, "%s/%s.sig.XXXXXX", | ||||
getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP); | getenv("TMPDIR") ? getenv("TMPDIR") : | ||||
snprintf(url, MAXPATHLEN, "%s/Latest/pkg.txz.sig", | _PATH_TMP, | ||||
packagesite); | packagename); | ||||
snprintf(url, MAXPATHLEN, "%s/Latest/%s.sig", | |||||
packagesite, packagename); | |||||
if ((fd_sig = fetch_to_fd(url, tmpsig)) == -1) { | if ((fd_sig = fetch_to_fd(url, tmpsig)) == -1) { | ||||
fprintf(stderr, "Signature for pkg not " | fprintf(stderr, | ||||
"Signature for pkg not " | |||||
"available.\n"); | "available.\n"); | ||||
goto fetchfail; | goto fetchfail; | ||||
} | } | ||||
if (verify_signature(fd_pkg, fd_sig) == false) | if (verify_signature(fd_pkg, fd_sig) == false) | ||||
goto cleanup; | goto cleanup; | ||||
} else if (strcasecmp(signature_type, "PUBKEY") == 0) { | } else if (strcasecmp(signature_type, "PUBKEY") == 0) { | ||||
snprintf(tmpsig, MAXPATHLEN, | snprintf(tmpsig, MAXPATHLEN, | ||||
"%s/pkg.txz.pubkeysig.XXXXXX", | "%s/%s.pubkeysig.XXXXXX", | ||||
getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP); | getenv("TMPDIR") ? getenv("TMPDIR") : | ||||
snprintf(url, MAXPATHLEN, "%s/Latest/pkg.txz.pubkeysig", | _PATH_TMP, | ||||
packagesite); | packagename); | ||||
snprintf(url, MAXPATHLEN, | |||||
"%s/Latest/%s.pubkeysig", packagesite, | |||||
packagename); | |||||
if ((fd_sig = fetch_to_fd(url, tmpsig)) == -1) { | if ((fd_sig = fetch_to_fd(url, tmpsig)) == -1) { | ||||
fprintf(stderr, "Signature for pkg not " | fprintf(stderr, | ||||
"Signature for pkg not " | |||||
"available.\n"); | "available.\n"); | ||||
goto fetchfail; | goto fetchfail; | ||||
} | } | ||||
if (verify_pubsignature(fd_pkg, fd_sig) == false) | if (verify_pubsignature(fd_pkg, fd_sig) == | ||||
false) | |||||
goto cleanup; | goto cleanup; | ||||
} else { | } else { | ||||
warnx("Signature type %s is not supported for " | warnx("Signature type %s is not supported for " | ||||
"bootstrapping.", signature_type); | "bootstrapping.", | ||||
signature_type); | |||||
goto cleanup; | goto cleanup; | ||||
} | } | ||||
} | } | ||||
if ((ret = extract_pkg_static(fd_pkg, pkgstatic, MAXPATHLEN)) == 0) | if ((ret = extract_pkg_static(fd_pkg, pkgstatic, MAXPATHLEN)) == | ||||
0) | |||||
ret = install_pkg_static(pkgstatic, tmppkg, force); | ret = install_pkg_static(pkgstatic, tmppkg, force); | ||||
goto cleanup; | goto cleanup; | ||||
} | |||||
fetchfail: | fetchfail: | ||||
warnx("Error fetching %s: %s", url, fetchLastErrString); | warnx("Error fetching %s: %s", url, fetchLastErrString); | ||||
if (fetchLastErrCode == FETCH_RESOLV) { | if (fetchLastErrCode == FETCH_RESOLV) { | ||||
fprintf(stderr, "Address resolution failed for %s.\n", packagesite); | fprintf( | ||||
stderr, "Address resolution failed for %s.\n", packagesite); | |||||
fprintf(stderr, "Consider changing PACKAGESITE.\n"); | fprintf(stderr, "Consider changing PACKAGESITE.\n"); | ||||
} else { | } else { | ||||
fprintf(stderr, "A pre-built version of pkg could not be found for " | fprintf(stderr, | ||||
"A pre-built version of pkg could not be found for " | |||||
"your system.\n"); | "your system.\n"); | ||||
fprintf(stderr, "Consider changing PACKAGESITE or installing it from " | fprintf(stderr, | ||||
"Consider changing PACKAGESITE or installing it from " | |||||
"ports: 'ports-mgmt/pkg'.\n"); | "ports: 'ports-mgmt/pkg'.\n"); | ||||
} | } | ||||
cleanup: | cleanup: | ||||
if (fd_sig != -1) { | if (fd_sig != -1) { | ||||
close(fd_sig); | close(fd_sig); | ||||
unlink(tmpsig); | unlink(tmpsig); | ||||
} | } | ||||
if (fd_pkg != -1) { | if (fd_pkg != -1) { | ||||
close(fd_pkg); | close(fd_pkg); | ||||
unlink(tmppkg); | unlink(tmppkg); | ||||
} | } | ||||
return (ret); | return (ret); | ||||
} | } | ||||
static const char confirmation_message[] = | static const char confirmation_message[] = | ||||
"The package management tool is not yet installed on your system.\n" | "The package management tool is not yet installed on your system.\n" | ||||
"Do you want to fetch and install it now? [y/N]: "; | "Do you want to fetch and install it now? [y/N]: "; | ||||
static const char non_interactive_message[] = | static const char non_interactive_message[] = | ||||
"The package management tool is not yet installed on your system.\n" | "The package management tool is not yet installed on your system.\n" | ||||
"Please set ASSUME_ALWAYS_YES=yes environment variable to be able to bootstrap " | "Please set ASSUME_ALWAYS_YES=yes environment variable to be able to bootstrap " | ||||
"in non-interactive (stdin not being a tty)\n"; | "in non-interactive (stdin not being a tty)\n"; | ||||
static int | static int | ||||
pkg_query_yes_no(void) | pkg_query_yes_no(void) | ||||
{ | { | ||||
int ret, c; | int ret, c; | ||||
fflush(stdout); | fflush(stdout); | ||||
c = getchar(); | c = getchar(); | ||||
Show All 23 Lines | bootstrap_pkg_local(const char *pkgpath, bool force) | ||||
fd_pkg = open(pkgpath, O_RDONLY); | fd_pkg = open(pkgpath, O_RDONLY); | ||||
if (fd_pkg == -1) | if (fd_pkg == -1) | ||||
err(EXIT_FAILURE, "Unable to open %s", pkgpath); | err(EXIT_FAILURE, "Unable to open %s", pkgpath); | ||||
if (config_string(SIGNATURE_TYPE, &signature_type) != 0) { | if (config_string(SIGNATURE_TYPE, &signature_type) != 0) { | ||||
warnx("Error looking up SIGNATURE_TYPE"); | warnx("Error looking up SIGNATURE_TYPE"); | ||||
goto cleanup; | goto cleanup; | ||||
} | } | ||||
if (signature_type != NULL && | if (signature_type != NULL && strcasecmp(signature_type, "NONE") != 0) { | ||||
strcasecmp(signature_type, "NONE") != 0) { | |||||
if (strcasecmp(signature_type, "FINGERPRINTS") == 0) { | if (strcasecmp(signature_type, "FINGERPRINTS") == 0) { | ||||
snprintf(path, sizeof(path), "%s.sig", pkgpath); | snprintf(path, sizeof(path), "%s.sig", pkgpath); | ||||
if ((fd_sig = open(path, O_RDONLY)) == -1) { | if ((fd_sig = open(path, O_RDONLY)) == -1) { | ||||
fprintf(stderr, "Signature for pkg not " | fprintf(stderr, | ||||
"Signature for pkg not " | |||||
"available.\n"); | "available.\n"); | ||||
goto cleanup; | goto cleanup; | ||||
} | } | ||||
if (verify_signature(fd_pkg, fd_sig) == false) | if (verify_signature(fd_pkg, fd_sig) == false) | ||||
goto cleanup; | goto cleanup; | ||||
} else if (strcasecmp(signature_type, "PUBKEY") == 0) { | } else if (strcasecmp(signature_type, "PUBKEY") == 0) { | ||||
snprintf(path, sizeof(path), "%s.pubkeysig", pkgpath); | snprintf(path, sizeof(path), "%s.pubkeysig", pkgpath); | ||||
if ((fd_sig = open(path, O_RDONLY)) == -1) { | if ((fd_sig = open(path, O_RDONLY)) == -1) { | ||||
fprintf(stderr, "Signature for pkg not " | fprintf(stderr, | ||||
"Signature for pkg not " | |||||
"available.\n"); | "available.\n"); | ||||
goto cleanup; | goto cleanup; | ||||
} | } | ||||
if (verify_pubsignature(fd_pkg, fd_sig) == false) | if (verify_pubsignature(fd_pkg, fd_sig) == false) | ||||
goto cleanup; | goto cleanup; | ||||
} else { | } else { | ||||
warnx("Signature type %s is not supported for " | warnx("Signature type %s is not supported for " | ||||
"bootstrapping.", signature_type); | "bootstrapping.", | ||||
signature_type); | |||||
goto cleanup; | goto cleanup; | ||||
} | } | ||||
} | } | ||||
if ((ret = extract_pkg_static(fd_pkg, pkgstatic, MAXPATHLEN)) == 0) | if ((ret = extract_pkg_static(fd_pkg, pkgstatic, MAXPATHLEN)) == 0) | ||||
ret = install_pkg_static(pkgstatic, pkgpath, force); | ret = install_pkg_static(pkgstatic, pkgpath, force); | ||||
cleanup: | cleanup: | ||||
Show All 18 Lines | main(int argc, char *argv[]) | ||||
yes = false; | yes = false; | ||||
snprintf(pkgpath, MAXPATHLEN, "%s/sbin/pkg", | snprintf(pkgpath, MAXPATHLEN, "%s/sbin/pkg", | ||||
getenv("LOCALBASE") ? getenv("LOCALBASE") : _LOCALBASE); | getenv("LOCALBASE") ? getenv("LOCALBASE") : _LOCALBASE); | ||||
if (argc > 1 && strcmp(argv[1], "bootstrap") == 0) { | if (argc > 1 && strcmp(argv[1], "bootstrap") == 0) { | ||||
bootstrap_only = true; | bootstrap_only = true; | ||||
if (argc > 3) { | if (argc > 3) { | ||||
fprintf(stderr, "Too many arguments\nUsage: pkg bootstrap [-f]\n"); | fprintf(stderr, | ||||
"Too many arguments\nUsage: pkg bootstrap [-f]\n"); | |||||
exit(EXIT_FAILURE); | exit(EXIT_FAILURE); | ||||
} | } | ||||
if (argc == 3 && strcmp(argv[2], "-f") == 0) { | if (argc == 3 && strcmp(argv[2], "-f") == 0) { | ||||
force = true; | force = true; | ||||
} else if (argc == 3) { | } else if (argc == 3) { | ||||
fprintf(stderr, "Invalid argument specified\nUsage: pkg bootstrap [-f]\n"); | fprintf(stderr, | ||||
"Invalid argument specified\nUsage: pkg bootstrap [-f]\n"); | |||||
exit(EXIT_FAILURE); | exit(EXIT_FAILURE); | ||||
} | } | ||||
} | } | ||||
if ((bootstrap_only && force) || access(pkgpath, X_OK) == -1) { | if ((bootstrap_only && force) || access(pkgpath, X_OK) == -1) { | ||||
/* | /* | ||||
* To allow 'pkg -N' to be used as a reliable test for whether | * To allow 'pkg -N' to be used as a reliable test for whether | ||||
* a system is configured to use pkg, don't bootstrap pkg | * a system is configured to use pkg, don't bootstrap pkg | ||||
* when that argument is given as argv[1]. | * when that argument is given as argv[1]. | ||||
*/ | */ | ||||
if (argv[1] != NULL && strcmp(argv[1], "-N") == 0) | if (argv[1] != NULL && strcmp(argv[1], "-N") == 0) | ||||
errx(EXIT_FAILURE, "pkg is not installed"); | errx(EXIT_FAILURE, "pkg is not installed"); | ||||
config_init(); | config_init(); | ||||
▲ Show 20 Lines • Show All 60 Lines • Show Last 20 Lines |
I'd be tempted to move this out to the global scope, make it static, drop the NULL terminator, then...