diff --git a/bin/xbps-bin/Makefile b/bin/xbps-bin/Makefile index 2fa3ffad..7df5d0a2 100644 --- a/bin/xbps-bin/Makefile +++ b/bin/xbps-bin/Makefile @@ -2,9 +2,11 @@ TOPDIR = ../.. -include $(TOPDIR)/config.mk BIN = xbps-bin -OBJS = check.o install.o main.o remove.o show-deps.o +OBJS = install.o main.o remove.o show-deps.o 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 MAN = $(BIN).8 include $(TOPDIR)/prog.mk diff --git a/bin/xbps-bin/check.c b/bin/xbps-bin/check.c index be545e57..ea94bece 100644 --- a/bin/xbps-bin/check.c +++ b/bin/xbps-bin/check.c @@ -35,30 +35,17 @@ #include #include "defs.h" -/* - * Checks package integrity of an installed package. - * The following tasks are processed in that order: - * - * o Check if package was installed manually, but currently - * other packages are depending on it. This package shall be - * changed to automatic mode, i.e installed as dependency of - * those packages. - * - * o Check for metadata files (files.plist and props.plist), - * we only check if the file exists and its dictionary can - * be externalized and is not empty. - * - * o Check for missing installed files. - * - * o Check for target file in symlinks, so that we can check that - * they have not been modified. - * - * o Check the hash for all installed files, except - * configuration files (which is expected if they are modified). - * - * o Check for missing run time dependencies. - * - */ +#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) @@ -94,77 +81,20 @@ check_pkg_integrity_all(void) int check_pkg_integrity(const char *pkgname) { - struct xbps_handle *xhp; - prop_dictionary_t pkgd, dict, propsd = NULL, filesd = NULL; - prop_array_t array, reqby; - prop_object_t obj; - prop_object_iterator_t iter; - const char *file, *sha256, *reqpkg, *tgt = NULL; - char *path, buf[PATH_MAX]; + prop_dictionary_t pkgd, propsd, filesd; int rv = 0; - bool broken = false, test_broken = false, autoinst = false; - - assert(pkgname != NULL); - xhp = xbps_handle_get(); + bool broken = false; + /* find real pkg by name */ pkgd = xbps_find_pkg_dict_installed(pkgname, false); if (pkgd == NULL) { - /* try looking for a virtual pkg */ + /* find virtual pkg by name */ pkgd = xbps_find_virtualpkg_dict_installed(pkgname, false); } if (pkgd == NULL) { printf("Package %s is not installed.\n", pkgname); return 0; } - /* - * Check if package has been installed manually but any other - * package is currently depending on it; in that case the package - * must be in automatic mode. - */ - if (prop_dictionary_get_bool(pkgd, "automatic-install", &autoinst)) { - reqby = prop_dictionary_get(pkgd, "requiredby"); - if (((prop_object_type(reqby) == PROP_TYPE_ARRAY)) && - ((prop_array_count(reqby) > 0) && !autoinst)) { - path = xbps_xasprintf("%s/%s/%s", - prop_string_cstring_nocopy(xhp->rootdir), - XBPS_META_PATH, XBPS_REGPKGDB); - assert(path != NULL); - - /* pkg has reversedeps and was installed manually */ - prop_dictionary_set_bool(pkgd, - "automatic-install", true); - - dict = prop_dictionary_internalize_from_zfile(path); - if (dict == NULL) { - xbps_error_printf("%s: [0] failed to set " - "automatic mode (%s)\n", pkgname, strerror(errno)); - return rv; - } - array = prop_dictionary_get(dict, "packages"); - rv = xbps_array_replace_dict_by_name(array, pkgd, pkgname); - if (rv != 0) { - xbps_error_printf("%s: [1] failed to set " - "automatic mode (%s)\n", pkgname, strerror(rv)); - return rv; - } - if (!prop_dictionary_set(dict, "packages", array)) { - xbps_error_printf("%s: [2] failed to set " - "automatic mode (%s)\n", pkgname, strerror(rv)); - return rv; - } - if (!prop_dictionary_externalize_to_zfile(dict, path)) { - xbps_error_printf("%s: [3] failed to set " - "automatic mode (%s)\n", pkgname, strerror(errno)); - return rv; - } - free(path); - path = NULL; - xbps_warn_printf("%s: was installed manually and has " - "reverse dependencies (FIXED)\n", pkgname); - } - } - prop_object_release(pkgd); - /* * Check for props.plist metadata file. */ @@ -180,7 +110,6 @@ check_pkg_integrity(const char *pkgname) broken = true; goto out; } - /* * Check for files.plist metadata file. */ @@ -197,186 +126,21 @@ check_pkg_integrity(const char *pkgname) goto out; } - /* - * Check for target files in symlinks. - */ - array = prop_dictionary_get(filesd, "links"); - if ((prop_object_type(array) == PROP_TYPE_ARRAY) && - prop_array_count(array) > 0) { - iter = xbps_array_iter_from_dict(filesd, "links"); - if (iter == NULL) - abort(); - - while ((obj = prop_object_iterator_next(iter))) { - if (!prop_dictionary_get_cstring_nocopy(obj, "target", &tgt)) - continue; - prop_dictionary_get_cstring_nocopy(obj, "file", &file); - if (strcmp(tgt, "") == 0) { - xbps_warn_printf("%s: `%s' symlink with " - "empty target object!\n", pkgname, file); - continue; - } - path = xbps_xasprintf("%s/%s", - prop_string_cstring_nocopy(xhp->rootdir), file); - if (path == NULL) - abort(); - - memset(&buf, 0, sizeof(buf)); - if (realpath(path, buf) == NULL) { - xbps_error_printf("%s: broken symlink `%s': " - "%s\n", pkgname, file, strerror(errno)); - test_broken = true; - continue; - } - - free(path); - if (!prop_string_equals_cstring(xhp->rootdir, "/") && - strstr(buf, prop_string_cstring_nocopy(xhp->rootdir))) - path = buf + prop_string_size(xhp->rootdir); - else - path = buf; - - if (strcmp(path, tgt)) { - xbps_error_printf("%s: modified symlink `%s', " - "target: `%s' (shall be: `%s')\n", - pkgname, file, tgt, path); - test_broken = true; - } - path = NULL; - } - prop_object_iterator_release(iter); - } - if (test_broken) { - test_broken = false; - xbps_error_printf("%s: links check FAILED.\n", pkgname); - broken = true; - } - - /* - * Check for missing files and its hash. - */ - array = prop_dictionary_get(filesd, "files"); - if ((prop_object_type(array) == PROP_TYPE_ARRAY) && - prop_array_count(array) > 0) { - iter = xbps_array_iter_from_dict(filesd, "files"); - if (iter == NULL) - abort(); - - while ((obj = prop_object_iterator_next(iter))) { - prop_dictionary_get_cstring_nocopy(obj, "file", &file); - path = xbps_xasprintf("%s/%s", - prop_string_cstring_nocopy(xhp->rootdir), file); - if (path == NULL) { - prop_object_iterator_release(iter); - abort(); - } - prop_dictionary_get_cstring_nocopy(obj, - "sha256", &sha256); - rv = xbps_file_hash_check(path, sha256); - switch (rv) { - case 0: - break; - case ENOENT: - xbps_error_printf("%s: unexistent file %s.\n", - pkgname, file); - test_broken = true; - break; - case ERANGE: - xbps_error_printf("%s: hash mismatch for %s.\n", - pkgname, file); - test_broken = true; - break; - default: - xbps_error_printf( - "%s: can't check `%s' (%s)\n", - pkgname, file, strerror(rv)); - break; - } - free(path); - } - prop_object_iterator_release(iter); - } - if (test_broken) { - test_broken = false; - broken = true; - xbps_error_printf("%s: files check FAILED.\n", pkgname); - } - - /* - * Check for missing configuration files. - */ - array = prop_dictionary_get(filesd, "conf_files"); - if (array && prop_object_type(array) == PROP_TYPE_ARRAY && - prop_array_count(array) > 0) { - iter = xbps_array_iter_from_dict(filesd, "conf_files"); - if (iter == NULL) - abort(); - - while ((obj = prop_object_iterator_next(iter))) { - prop_dictionary_get_cstring_nocopy(obj, "file", &file); - path = xbps_xasprintf("%s/%s", - prop_string_cstring_nocopy(xhp->rootdir), file); - if (path == NULL) { - prop_object_iterator_release(iter); - abort(); - } - if ((rv = access(path, R_OK)) == -1) { - if (errno == ENOENT) { - xbps_error_printf( - "%s: unexistent file %s\n", - pkgname, file); - test_broken = true; - } else - xbps_error_printf( - "%s: can't check `%s' (%s)\n", - pkgname, file, - strerror(errno)); - } - free(path); - } - prop_object_iterator_release(iter); - } - if (test_broken) { - test_broken = false; - xbps_error_printf("%s: conf files check FAILED.\n", pkgname); - broken = true; - } - - /* - * Check for missing run time dependencies. - */ - if (!xbps_pkg_has_rundeps(propsd)) - goto out; - - iter = xbps_array_iter_from_dict(propsd, "run_depends"); - if (iter == NULL) - abort(); - - while ((obj = prop_object_iterator_next(iter))) { - reqpkg = prop_string_cstring_nocopy(obj); - if (reqpkg == NULL) { - prop_object_iterator_release(iter); - abort(); - } - if (xbps_check_is_installed_pkg_by_pattern(reqpkg) <= 0) { - xbps_error_printf("%s: dependency not satisfied: %s\n", - pkgname, reqpkg); - test_broken = true; - } - } - prop_object_iterator_release(iter); - if (test_broken) { - xbps_error_printf("%s: rundeps check FAILED.\n", pkgname); - broken = true; - } + /* Execute pkg checks */ + RUN_PKG_CHECK(autoinstall); + RUN_PKG_CHECK(files); + RUN_PKG_CHECK(symlinks); + RUN_PKG_CHECK(rundeps); out: - if (filesd) + if (prop_object_type(filesd) == PROP_TYPE_DICTIONARY) prop_object_release(filesd); - if (propsd) + if (prop_object_type(propsd) == PROP_TYPE_DICTIONARY) prop_object_release(propsd); + if (prop_object_type(pkgd) == PROP_TYPE_DICTIONARY) + prop_object_release(pkgd); if (broken) - return -1; + return 1; return 0; } diff --git a/bin/xbps-bin/check_pkg_automatic.c b/bin/xbps-bin/check_pkg_automatic.c new file mode 100644 index 00000000..c10bd94e --- /dev/null +++ b/bin/xbps-bin/check_pkg_automatic.c @@ -0,0 +1,121 @@ +/*- + * 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" + +/* + * Checks package integrity of an installed package. + * The following task is accomplished in this file: + * + * o Check if package was installed manually, but currently + * other packages are depending on it. This package shall be + * changed to automatic mode, i.e installed as dependency of + * those packages. + * + * Returns 0 if test ran successfully, 1 otherwise and -1 on error. + */ +int +check_pkg_autoinstall(prop_dictionary_t pkgd_regpkgdb, + prop_dictionary_t pkg_propsd, + prop_dictionary_t pkg_filesd) +{ + const struct xbps_handle *xhp = xbps_handle_get(); + prop_dictionary_t dict; + prop_array_t array, reqby; + const char *pkgname; + char *path; + int rv = 0; + bool autoinst = false; + + (void)pkg_propsd; + (void)pkg_filesd; + + prop_dictionary_get_cstring_nocopy(pkgd_regpkgdb, "pkgname", &pkgname); + /* + * Check if package has been installed manually but any other + * package is currently depending on it; in that case the package + * must be in automatic mode. + */ + if (prop_dictionary_get_bool(pkgd_regpkgdb, + "automatic-install", &autoinst)) { + reqby = prop_dictionary_get(pkgd_regpkgdb, "requiredby"); + if (((prop_object_type(reqby) == PROP_TYPE_ARRAY)) && + ((prop_array_count(reqby) > 0) && !autoinst)) { + path = xbps_xasprintf("%s/%s/%s", + prop_string_cstring_nocopy(xhp->rootdir), + XBPS_META_PATH, XBPS_REGPKGDB); + assert(path != NULL); + + /* pkg has reversedeps and was installed manually */ + prop_dictionary_set_bool(pkgd_regpkgdb, + "automatic-install", true); + + dict = prop_dictionary_internalize_from_zfile(path); + if (dict == NULL) { + xbps_error_printf("%s: [0] failed to set " + "automatic mode (%s)\n", pkgname, + strerror(errno)); + return -1; + } + array = prop_dictionary_get(dict, "packages"); + rv = xbps_array_replace_dict_by_name(array, + pkgd_regpkgdb, pkgname); + if (rv != 0) { + xbps_error_printf("%s: [1] failed to set " + "automatic mode (%s)\n", pkgname, + strerror(rv)); + return -1; + } + if (!prop_dictionary_set(dict, "packages", array)) { + xbps_error_printf("%s: [2] failed to set " + "automatic mode (%s)\n", pkgname, + strerror(rv)); + return -1; + } + if (!prop_dictionary_externalize_to_zfile(dict, path)) { + xbps_error_printf("%s: [3] failed to set " + "automatic mode (%s)\n", pkgname, + strerror(errno)); + return -1; + } + free(path); + path = NULL; + xbps_warn_printf("%s: was installed manually and has " + "reverse dependencies (FIXED)\n", pkgname); + } + } + + return 0; +} diff --git a/bin/xbps-bin/check_pkg_files.c b/bin/xbps-bin/check_pkg_files.c new file mode 100644 index 00000000..d1a7c578 --- /dev/null +++ b/bin/xbps-bin/check_pkg_files.c @@ -0,0 +1,153 @@ +/*- + * 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" + +/* + * Checks package integrity of an installed package. + * The following tasks are processed in that order: + * + * o Check for missing installed files. + * + * o Check the hash for all installed files, except + * configuration files (which is expected if they are modified). + * + * Return 0 if test ran successfully, 1 otherwise and -1 on error. + */ +int +check_pkg_files(prop_dictionary_t pkgd_regpkgdb, + prop_dictionary_t pkg_propsd, + prop_dictionary_t pkg_filesd) +{ + struct xbps_handle *xhp = xbps_handle_get(); + prop_array_t array; + prop_object_t obj; + prop_object_iterator_t iter; + const char *pkgname, *file, *sha256; + char *path; + int rv = 0; + bool broken = false, test_broken = false; + + (void)pkg_propsd; + prop_dictionary_get_cstring_nocopy(pkgd_regpkgdb, "pkgname", &pkgname); + + array = prop_dictionary_get(pkg_filesd, "files"); + if ((prop_object_type(array) == PROP_TYPE_ARRAY) && + prop_array_count(array) > 0) { + iter = xbps_array_iter_from_dict(pkg_filesd, "files"); + if (iter == NULL) + return -1; + + while ((obj = prop_object_iterator_next(iter))) { + prop_dictionary_get_cstring_nocopy(obj, "file", &file); + path = xbps_xasprintf("%s/%s", + prop_string_cstring_nocopy(xhp->rootdir), file); + if (path == NULL) { + prop_object_iterator_release(iter); + return -1; + } + prop_dictionary_get_cstring_nocopy(obj, + "sha256", &sha256); + rv = xbps_file_hash_check(path, sha256); + switch (rv) { + case 0: + break; + case ENOENT: + xbps_error_printf("%s: unexistent file %s.\n", + pkgname, file); + test_broken = true; + break; + case ERANGE: + xbps_error_printf("%s: hash mismatch for %s.\n", + pkgname, file); + test_broken = true; + break; + default: + xbps_error_printf( + "%s: can't check `%s' (%s)\n", + pkgname, file, strerror(rv)); + break; + } + free(path); + } + prop_object_iterator_release(iter); + } + if (test_broken) { + xbps_error_printf("%s: files check FAILED.\n", pkgname); + test_broken = false; + broken = true; + } + + /* + * Check for missing configuration files. + */ + array = prop_dictionary_get(pkg_filesd, "conf_files"); + if (array && prop_object_type(array) == PROP_TYPE_ARRAY && + prop_array_count(array) > 0) { + iter = xbps_array_iter_from_dict(pkg_filesd, "conf_files"); + if (iter == NULL) + return -1; + + while ((obj = prop_object_iterator_next(iter))) { + prop_dictionary_get_cstring_nocopy(obj, "file", &file); + path = xbps_xasprintf("%s/%s", + prop_string_cstring_nocopy(xhp->rootdir), file); + if (path == NULL) { + prop_object_iterator_release(iter); + return -1; + } + if ((rv = access(path, R_OK)) == -1) { + if (errno == ENOENT) { + xbps_error_printf( + "%s: unexistent file %s\n", + pkgname, file); + test_broken = true; + } else + xbps_error_printf( + "%s: can't check `%s' (%s)\n", + pkgname, file, + strerror(errno)); + } + free(path); + } + prop_object_iterator_release(iter); + } + if (test_broken) { + xbps_error_printf("%s: conf files check FAILED.\n", pkgname); + broken = true; + } + + return broken; +} diff --git a/bin/xbps-bin/check_pkg_rundeps.c b/bin/xbps-bin/check_pkg_rundeps.c new file mode 100644 index 00000000..a1da69a6 --- /dev/null +++ b/bin/xbps-bin/check_pkg_rundeps.c @@ -0,0 +1,81 @@ +/*- + * 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" + +/* + * Checks package integrity of an installed package. + * The following task is accomplished in this file: + * + * o Check for missing run time dependencies. + * + * Returns 0 if test ran successfully, 1 otherwise and -1 on error. + */ + +int +check_pkg_rundeps(prop_dictionary_t pkgd_regpkgdb, + prop_dictionary_t pkg_propsd, + prop_dictionary_t pkg_filesd) +{ + prop_object_t obj; + prop_object_iterator_t iter; + const char *reqpkg, *pkgname; + bool test_broken = false; + + (void)pkg_filesd; + prop_dictionary_get_cstring_nocopy(pkgd_regpkgdb, "pkgname", &pkgname); + + if (!xbps_pkg_has_rundeps(pkg_propsd)) + return 0; + + iter = xbps_array_iter_from_dict(pkg_propsd, "run_depends"); + if (iter == NULL) + return -1; + + while ((obj = prop_object_iterator_next(iter))) { + reqpkg = prop_string_cstring_nocopy(obj); + if (reqpkg == NULL) { + prop_object_iterator_release(iter); + return -1; + } + if (xbps_check_is_installed_pkg_by_pattern(reqpkg) <= 0) { + xbps_error_printf("%s: dependency not satisfied: %s\n", + pkgname, reqpkg); + test_broken = true; + } + } + prop_object_iterator_release(iter); + return test_broken; +} diff --git a/bin/xbps-bin/check_pkg_symlinks.c b/bin/xbps-bin/check_pkg_symlinks.c new file mode 100644 index 00000000..09a467cf --- /dev/null +++ b/bin/xbps-bin/check_pkg_symlinks.c @@ -0,0 +1,110 @@ +/*- + * 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" + +/* + * Checks package integrity of an installed package. + * The following task is accomplished in this file: + * + * o Check for target file in symlinks, so that we can check that + * they have not been modified. + * + * returns 0 if test ran successfully, 1 otherwise and -1 on error. + */ +int +check_pkg_symlinks(prop_dictionary_t pkgd_regpkgdb, + prop_dictionary_t pkg_propsd, + prop_dictionary_t pkg_filesd) +{ + const struct xbps_handle *xhp = xbps_handle_get(); + prop_array_t array; + prop_object_t obj; + prop_object_iterator_t iter; + const char *pkgname, *file, *tgt = NULL; + char *path, buf[PATH_MAX]; + bool test_broken = false; + + (void)pkg_propsd; + prop_dictionary_get_cstring_nocopy(pkgd_regpkgdb, "pkgname", &pkgname); + + array = prop_dictionary_get(pkg_filesd, "links"); + if ((prop_object_type(array) == PROP_TYPE_ARRAY) && + prop_array_count(array) > 0) { + iter = xbps_array_iter_from_dict(pkg_filesd, "links"); + if (iter == NULL) + return -1; + + while ((obj = prop_object_iterator_next(iter))) { + if (!prop_dictionary_get_cstring_nocopy(obj, "target", &tgt)) + continue; + prop_dictionary_get_cstring_nocopy(obj, "file", &file); + if (strcmp(tgt, "") == 0) { + xbps_warn_printf("%s: `%s' symlink with " + "empty target object!\n", pkgname, file); + continue; + } + path = xbps_xasprintf("%s/%s", + prop_string_cstring_nocopy(xhp->rootdir), file); + if (path == NULL) + return -1; + + memset(&buf, 0, sizeof(buf)); + if (realpath(path, buf) == NULL) { + xbps_error_printf("%s: broken symlink `%s': " + "%s\n", pkgname, file, strerror(errno)); + test_broken = true; + continue; + } + + free(path); + if (!prop_string_equals_cstring(xhp->rootdir, "/") && + strstr(buf, prop_string_cstring_nocopy(xhp->rootdir))) + path = buf + prop_string_size(xhp->rootdir); + else + path = buf; + + if (strcmp(path, tgt)) { + xbps_error_printf("%s: modified symlink `%s', " + "target: `%s' (shall be: `%s')\n", + pkgname, file, tgt, path); + test_broken = true; + } + path = NULL; + } + prop_object_iterator_release(iter); + } + return test_broken; +} diff --git a/bin/xbps-bin/defs.h b/bin/xbps-bin/defs.h index a8829df4..28d4ae29 100644 --- a/bin/xbps-bin/defs.h +++ b/bin/xbps-bin/defs.h @@ -45,12 +45,21 @@ int autoupdate_pkgs(bool, bool); int autoremove_pkgs(bool, bool); int exec_transaction(bool, bool); +/* from remove.c */ int remove_installed_pkgs(int, char **, bool, bool, bool, bool); /* from check.c */ int check_pkg_integrity(const char *); int check_pkg_integrity_all(void); +#define CHECK_PKG_DECL(type) \ +int check_pkg_##type (prop_dictionary_t, prop_dictionary_t, prop_dictionary_t) + +CHECK_PKG_DECL(autoinstall); +CHECK_PKG_DECL(files); +CHECK_PKG_DECL(rundeps); +CHECK_PKG_DECL(symlinks); + /* from show-deps.c */ int show_pkg_deps(const char *); int show_pkg_reverse_deps(const char *);