/* vi: set expandtab sw=4 sts=4: */ /* release.c - the opkg package management system Copyright (C) 2010,2011 Javier Palacios SPDX-License-Identifier: GPL-2.0-or-later This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. */ #include "config.h" #include #include #include #include #include "opkg_message.h" #include "release.h" #include "opkg_utils.h" #include "xfuncs.h" #include "opkg_archive.h" #include "opkg_download.h" #include "sprintf_alloc.h" #include "release_parse.h" #include "parse_util.h" #include "file_util.h" static void release_init(release_t * release) { release->name = NULL; release->datestring = NULL; release->architectures = NULL; release->architectures_count = 0; release->components = NULL; release->components_count = 0; release->complist = NULL; release->complist_count = 0; } static const char *item_in_list(const char *comp, char **complist, unsigned int count) { unsigned int i; if (!complist) return comp; for (i = 0; i < count; i++) { if (strcmp(comp, complist[i]) == 0) return complist[i]; } return NULL; } static int release_arch_supported(release_t * release) { nv_pair_list_elt_t *l; list_for_each_entry(l, &opkg_config->arch_list.head, node) { nv_pair_t *nv = (nv_pair_t *) l->data; const char *arch = item_in_list(nv->name, release->architectures, release->architectures_count); if (arch) { opkg_msg(DEBUG, "Arch %s (priority %s) supported for dist %s.\n", nv->name, nv->value, release->name); return 1; } } return 0; } static int release_get_size(release_t * release, const char *pathname) { const cksum_t *cksum; if (release->md5sums) { cksum = cksum_list_find(release->md5sums, pathname); return cksum->size; } #ifdef HAVE_SHA256 if (release->sha256sums) { cksum = cksum_list_find(release->sha256sums, pathname); return cksum->size; } #endif return -1; } static const char *release_get_md5(release_t * release, const char *pathname) { const cksum_t *cksum; if (release->md5sums) { cksum = cksum_list_find(release->md5sums, pathname); return cksum->value; } return '\0'; } #ifdef HAVE_SHA256 static const char *release_get_sha256(release_t * release, const char *pathname) { const cksum_t *cksum; if (release->sha256sums) { cksum = cksum_list_find(release->sha256sums, pathname); return cksum->value; } return '\0'; } #endif int release_verify_file(release_t * release, const char *file_name, const char *pathname) { struct stat f_info; char *f_md5 = NULL; const char *md5 = release_get_md5(release, pathname); #ifdef HAVE_SHA256 char *f_sha256 = NULL; const char *sha256 = release_get_sha256(release, pathname); #endif int ret = 0; int r; r = stat(file_name, &f_info); if ((r != 0) || (f_info.st_size != release_get_size(release, pathname))) { opkg_msg(ERROR, "Size verification failed for %s - %s.\n", release->name, pathname); ret = 1; } else { f_md5 = file_md5sum_alloc(file_name); #ifdef HAVE_SHA256 f_sha256 = file_sha256sum_alloc(file_name); #endif if (md5 && strcmp(md5, f_md5)) { opkg_msg(ERROR, "MD5 verification failed for %s - %s.\n", release->name, pathname); ret = 1; #ifdef HAVE_SHA256 } else if (sha256 && strcmp(sha256, f_sha256)) { opkg_msg(ERROR, "SHA256 verification failed for %s - %s.\n", release->name, pathname); ret = 1; #endif } } free(f_md5); #ifdef HAVE_SHA256 free(f_sha256); #endif return ret; } release_t *release_new(void) { release_t *release; release = xcalloc(1, sizeof(release_t)); release_init(release); return release; } void release_deinit(release_t * release) { unsigned int i; free(release->name); free(release->datestring); for (i = 0; i < release->architectures_count; i++) { free(release->architectures[i]); } free(release->architectures); for (i = 0; i < release->components_count; i++) { free(release->components[i]); } free(release->components); for (i = 0; i < release->complist_count; i++) { free(release->complist[i]); } free(release->complist); } int release_init_from_file(release_t * release, const char *filename) { int err = 0; FILE *release_file = NULL; char *bp = NULL; if (opkg_config->compress_list_files) { struct opkg_ar *ar; size_t size; ar = ar_open_compressed_file(filename); if (!ar) return -1; FILE *mfp = open_memstream(&bp, &size); if (ar_copy_to_stream(ar, mfp) < 0) { opkg_perror(ERROR, "Failed to open %s", filename); err = -1; goto cleanup; } fclose(mfp); release_file = fmemopen(bp, size, "r"); if (release_file == NULL) { opkg_perror(ERROR, "Failed to open memory buffer: %s\n", strerror(errno)); err = -1; goto cleanup; } } else { release_file = fopen(filename, "r"); if (release_file == NULL) { opkg_perror(ERROR, "Failed to open %s", filename); return -1; } } err = release_parse_from_stream(release, release_file); if (!err) { if (!release_arch_supported(release)) { opkg_msg(ERROR, "No valid architecture found on Release file.\n"); err = -1; } } cleanup: fclose(release_file); free(bp); return err; } int release_comps_supported(release_t * release, const char *complist) { int ret = 1; unsigned int i; if (complist) { release->complist = parse_list(complist, &release->complist_count, ' ', 1); for (i = 0; i < release->complist_count; i++) { const char *arch = item_in_list (release->complist[i], release->components, release->components_count); if (!arch) { opkg_msg(ERROR, "Component %s not supported for dist %s.\n", release->complist[i], release->name); ret = 0; } } } return ret; } const char **release_comps(release_t * release, unsigned int *count) { char **comps = release->complist; if (!comps) { comps = release->components; *count = release->components_count; } else { *count = release->complist_count; } return (const char **)comps; } int release_download(release_t * release, pkg_src_t * dist, char *lists_dir, char *tmpdir) { int ret = 0; unsigned int ncomp; const char **comps = release_comps(release, &ncomp); nv_pair_list_elt_t *l; unsigned int i; for (i = 0; i < ncomp; i++) { int err = 0; char *prefix; sprintf_alloc(&prefix, "%s/dists/%s/%s/binary", dist->value, dist->name, comps[i]); list_for_each_entry(l, &opkg_config->arch_list.head, node) { char *url; char *list_file_name; char *subpath = NULL; nv_pair_t *nv = (nv_pair_t *) l->data; sprintf_alloc(&list_file_name, "%s/%s-%s-%s", lists_dir, dist->name, comps[i], nv->name); sprintf_alloc(&subpath, "%s/binary-%s/%s", comps[i], nv->name, dist->gzip ? "Packages.gz" : "Packages"); if (dist->gzip) { char *cache_location; sprintf_alloc(&url, "%s-%s/Packages.gz", prefix, nv->name); cache_location = opkg_download_cache(url, NULL, NULL); if (cache_location) { err = release_verify_file(release, cache_location, subpath); if (err) { unlink(list_file_name); } else { if (opkg_config->compress_list_files) { strcat(list_file_name, ".gz"); err = file_copy(cache_location, list_file_name); } else { err = file_decompress(cache_location, list_file_name); } if (err) { opkg_msg(ERROR, "Couldn't %s %s", (opkg_config->compress_list_files) ? "copy" : "decompress", url); } } } free(url); free(cache_location); } if (!dist->gzip || err) { sprintf_alloc(&url, "%s-%s/Packages", prefix, nv->name); err = opkg_download(url, list_file_name, NULL, NULL); if (!err) { if (opkg_config->compress_list_files) err = file_gz_compress(list_file_name); err = release_verify_file(release, list_file_name, subpath); if (err) unlink(list_file_name); } free(url); } free(list_file_name); } if (err) ret = 1; free(prefix); } return ret; }