diff --git a/NEWS b/NEWS index 808b29a7..9ef0667d 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,9 @@ xbps-0.10.2 (???): + * xbps-bin(8): new test for the 'check' target to fix missing + entries in requiredby array, i.e reverse dependencies in + the package database plist. + * xbps-bin(8): the 'check' target now works virtual packages. * libxbps: failed to properly match installed virtualpkgs that were diff --git a/bin/xbps-bin/Makefile b/bin/xbps-bin/Makefile index 7df5d0a2..6d9c4af5 100644 --- a/bin/xbps-bin/Makefile +++ b/bin/xbps-bin/Makefile @@ -7,6 +7,7 @@ OBJS += show-info-files.o util.o find-files.o OBJS += question.o fetch_cb.o trans_cb.o OBJS += check.o check_pkg_automatic.o check_pkg_files.o OBJS += check_pkg_rundeps.o check_pkg_symlinks.o +OBJS += check_pkg_requiredby.o MAN = $(BIN).8 include $(TOPDIR)/prog.mk diff --git a/bin/xbps-bin/check.c b/bin/xbps-bin/check.c index ea94bece..04ccd255 100644 --- a/bin/xbps-bin/check.c +++ b/bin/xbps-bin/check.c @@ -35,33 +35,22 @@ #include #include "defs.h" -#define RUN_PKG_CHECK(name) \ -do { \ - rv = check_pkg_##name(pkgd, propsd, filesd); \ - if (rv) \ - broken = true; \ - else if (rv == -1) { \ - xbps_error_printf("%s: the %s test " \ - "returned error!\n", pkgname, #name); \ - goto out; \ - } \ -} while (0) - int check_pkg_integrity_all(void) { const struct xbps_handle *xhp; + prop_array_t regpkgs; prop_object_t obj; - prop_object_iterator_t iter = NULL; const char *pkgname, *version; - size_t npkgs = 0, nbrokenpkgs = 0; + size_t i, npkgs = 0, nbrokenpkgs = 0; xhp = xbps_handle_get(); - iter = xbps_array_iter_from_dict(xhp->regpkgdb_dictionary, "packages"); - if (iter == NULL) - return -1; + regpkgs = prop_dictionary_get(xhp->regpkgdb_dictionary, "packages"); + if (prop_object_type(regpkgs) != PROP_TYPE_ARRAY) + return 0; - while ((obj = prop_object_iterator_next(iter)) != NULL) { + for (i = 0; i < prop_array_count(regpkgs); i++) { + obj = prop_array_get(regpkgs, i); prop_dictionary_get_cstring_nocopy(obj, "pkgname", &pkgname); prop_dictionary_get_cstring_nocopy(obj, "version", &version); printf("Checking %s-%s ...\n", pkgname, version); @@ -70,8 +59,6 @@ check_pkg_integrity_all(void) npkgs++; } - prop_object_iterator_release(iter); - printf("%zu package%s processed: %zu broken.\n", npkgs, npkgs == 1 ? "" : "s", nbrokenpkgs); @@ -126,11 +113,26 @@ check_pkg_integrity(const char *pkgname) goto out; } +#define RUN_PKG_CHECK(name) \ +do { \ + rv = check_pkg_##name(pkgd, propsd, filesd); \ + if (rv) \ + broken = true; \ + else if (rv == -1) { \ + xbps_error_printf("%s: the %s test " \ + "returned error!\n", pkgname, #name); \ + goto out; \ + } \ +} while (0) + /* Execute pkg checks */ RUN_PKG_CHECK(autoinstall); RUN_PKG_CHECK(files); RUN_PKG_CHECK(symlinks); RUN_PKG_CHECK(rundeps); + RUN_PKG_CHECK(requiredby); + +#undef RUN_PKG_CHECK out: if (prop_object_type(filesd) == PROP_TYPE_DICTIONARY) diff --git a/bin/xbps-bin/check_pkg_requiredby.c b/bin/xbps-bin/check_pkg_requiredby.c new file mode 100644 index 00000000..ed7a6115 --- /dev/null +++ b/bin/xbps-bin/check_pkg_requiredby.c @@ -0,0 +1,194 @@ +/*- + * Copyright (c) 2011 Juan Romero Pardines. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 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 SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "defs.h" + +static int +write_pkgd_to_regpkgdb(prop_dictionary_t pkgd, + prop_array_t regpkgs, + const char *pkgn) +{ + struct xbps_handle *xhp = xbps_handle_get(); + char *path; + int rv; + + rv = xbps_array_replace_dict_by_name(regpkgs, pkgd, pkgn); + if (rv != 0) { + xbps_error_printf("%s: failed to replace pkgd: %s\n", + pkgn, strerror(rv)); + return -1; + } + if (!prop_dictionary_set(xhp->regpkgdb_dictionary, + "packages", regpkgs)) { + xbps_error_printf("%s: failed to set new regpkgdb " + "packages array: %s", pkgn, strerror(errno)); + return -1; + } + path = xbps_xasprintf("%s/%s/%s", + prop_string_cstring_nocopy(xhp->rootdir), + XBPS_META_PATH, XBPS_REGPKGDB); + if (path == NULL) + return -1; + + if (!prop_dictionary_externalize_to_zfile( + xhp->regpkgdb_dictionary, path)) { + xbps_error_printf("%s: failed to write regpkgdb plist:" + " %s\n", pkgn, strerror(errno)); + free(path); + return -1; + } + free(path); + + return 0; +} + +/* + * Checks package integrity of an installed package. + * The following task is accomplished in this file: + * + * o Check for missing reverse dependencies (aka requiredby) + * entries in pkg's regpkgdb dictionary. + * + * Returns 0 if test ran successfully, 1 otherwise and -1 on error. + */ +int +check_pkg_requiredby(prop_dictionary_t pkgd_regpkgdb, + prop_dictionary_t pkg_propsd, + prop_dictionary_t pkg_filesd) +{ + prop_array_t regpkgs, reqby, curpkg_rdeps, provides; + prop_dictionary_t curpkg_propsd; + prop_object_t obj; + prop_string_t curpkgver; + struct xbps_handle *xhp = xbps_handle_get(); + const char *curpkgn, *pkgname, *pkgver; + size_t i; + + (void)pkg_propsd; + (void)pkg_filesd; + + prop_dictionary_get_cstring_nocopy(pkgd_regpkgdb, "pkgname", &pkgname); + prop_dictionary_get_cstring_nocopy(pkgd_regpkgdb, "pkgver", &pkgver); + + regpkgs = prop_dictionary_get(xhp->regpkgdb_dictionary, "packages"); + + for (i = 0; i < prop_array_count(regpkgs); i++) { + obj = prop_array_get(regpkgs, i); + prop_dictionary_get_cstring_nocopy(obj, "pkgname", &curpkgn); + /* skip same pkg */ + if (strcmp(curpkgn, pkgname) == 0) + continue; + /* + * Internalize current pkg props dictionary from its + * installed metadata directory. + */ + curpkg_propsd = + xbps_dictionary_from_metadata_plist(curpkgn, XBPS_PKGPROPS); + if (curpkg_propsd == NULL) { + xbps_error_printf("%s: missing %s metadata file!\n", + curpkgn, XBPS_PKGPROPS); + return -1; + } + curpkg_rdeps = + prop_dictionary_get(curpkg_propsd, "run_depends"); + if (prop_object_type(curpkg_rdeps) != PROP_TYPE_ARRAY) { + /* package has no rundeps, skip */ + prop_object_release(curpkg_propsd); + continue; + } + /* + * Check for pkgpattern match with real packages... + */ + if (!xbps_match_pkgpattern_in_array(curpkg_rdeps, pkgver)) { + /* + * ... otherwise check if package provides any virtual + * package and is matched against any object in + * run_depends. + */ + provides = prop_dictionary_get(pkgd_regpkgdb, "provides"); + if (prop_object_type(provides) != PROP_TYPE_ARRAY) { + /* doesn't provide any virtual pkg */ + prop_object_release(curpkg_propsd); + continue; + } + if (!xbps_match_any_virtualpkg_in_rundeps(curpkg_rdeps, + provides)) { + /* doesn't match any virtual pkg */ + prop_object_release(curpkg_propsd); + continue; + } + } + reqby = prop_dictionary_get(pkgd_regpkgdb, "requiredby"); + curpkgver = prop_dictionary_get(curpkg_propsd, "pkgver"); + if (prop_object_type(reqby) == PROP_TYPE_ARRAY) { + /* + * Now check that current pkgver has been registered into + * its requiredby array. + */ + if (xbps_match_string_in_array(reqby, + prop_string_cstring_nocopy(curpkgver))) { + /* + * Current package already requires our package, + * this is good so skip it. + */ + prop_object_release(curpkg_propsd); + continue; + } + } else { + /* + * Missing requiredby array object, create it. + */ + reqby = prop_array_create(); + if (reqby == NULL) { + prop_object_release(curpkg_propsd); + return -1; + } + } + /* + * Replace current obj in regpkgdb and write new plist + * file to disk. + */ + prop_array_add(reqby, curpkgver); + prop_dictionary_set(pkgd_regpkgdb, "requiredby", reqby); + if (write_pkgd_to_regpkgdb(pkgd_regpkgdb, regpkgs, pkgname) != 0) + return -1; + + printf("%s: added requiredby entry for %s.\n", + pkgver, prop_string_cstring_nocopy(curpkgver)); + prop_object_release(curpkg_propsd); + } + + return 0; +} diff --git a/bin/xbps-bin/defs.h b/bin/xbps-bin/defs.h index 28d4ae29..9ad412cd 100644 --- a/bin/xbps-bin/defs.h +++ b/bin/xbps-bin/defs.h @@ -59,6 +59,7 @@ CHECK_PKG_DECL(autoinstall); CHECK_PKG_DECL(files); CHECK_PKG_DECL(rundeps); CHECK_PKG_DECL(symlinks); +CHECK_PKG_DECL(requiredby); /* from show-deps.c */ int show_pkg_deps(const char *);