diff --git a/bin/xbps-bin/Makefile b/bin/xbps-bin/Makefile index b1cf168624b..546853bbe6a 100644 --- a/bin/xbps-bin/Makefile +++ b/bin/xbps-bin/Makefile @@ -1,5 +1,5 @@ BIN = xbps-bin -OBJS = install.o main.o remove.o ../xbps-repo/util.o +OBJS = check.o install.o main.o remove.o ../xbps-repo/util.o TOPDIR = ../.. include $(TOPDIR)/prog.mk diff --git a/bin/xbps-bin/check.c b/bin/xbps-bin/check.c new file mode 100644 index 00000000000..95e5d520160 --- /dev/null +++ b/bin/xbps-bin/check.c @@ -0,0 +1,289 @@ +/*- + * Copyright (c) 2009 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 +#include "defs.h" + +/* + * Checks package integrity of an installed package. This + * consists in four tasks: + * + * 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 the hash for all installed files, except + * configuration files (which is expected if they are modified). + * o Check for missing run time dependencies. + * + * If any of these checks fail, the package will change its + * state to 'broken'. + */ + +int +xbps_check_pkg_integrity(const char *pkgname) +{ + prop_dictionary_t pkgd, propsd, filesd; + prop_array_t array; + prop_object_t obj; + prop_object_iterator_t iter; + const char *rootdir, *file, *sha256, *reqpkg; + char *path; + int rv = 0; + bool files_broken = false, broken = false; + + assert(pkgname != NULL); + + rootdir = xbps_get_rootdir(); + pkgd = xbps_find_pkg_installed_from_plist(pkgname); + if (pkgd == NULL) { + printf("Package %s is not installed.\n", pkgname); + return 0; + } + + /* + * Check for props.plist metadata file. + */ + path = xbps_xasprintf("%s/%s/metadata/%s/%s", rootdir, + XBPS_META_PATH, pkgname, XBPS_PKGPROPS); + if (path == NULL) { + rv = errno; + goto out; + } + + propsd = prop_dictionary_internalize_from_file(path); + free(path); + if (propsd == NULL) { + printf("%s: unexistent %s metadata file.\n", pkgname, + XBPS_PKGPROPS); + rv = errno; + broken = true; + goto out; + } else if (prop_object_type(propsd) != PROP_TYPE_DICTIONARY) { + printf("%s: invalid %s metadata file.\n", pkgname, + XBPS_PKGPROPS); + rv = EINVAL; + broken = true; + goto out1; + } else if (prop_dictionary_count(propsd) == 0) { + printf("%s: incomplete %s metadata file.\n", pkgname, + XBPS_PKGPROPS); + rv = EINVAL; + broken = true; + goto out1; + } + + /* + * Check for files.plist metadata file. + */ + path = xbps_xasprintf("%s/%s/metadata/%s/%s", rootdir, + XBPS_META_PATH, pkgname, XBPS_PKGFILES); + if (path == NULL) { + rv = errno; + goto out1; + } + + filesd = prop_dictionary_internalize_from_file(path); + free(path); + if (filesd == NULL) { + printf("%s: unexistent %s metadata file.\n", pkgname, + XBPS_PKGPROPS); + rv = ENOENT; + broken = true; + goto out1; + } else if (prop_object_type(filesd) != PROP_TYPE_DICTIONARY) { + printf("%s: invalid %s metadata file.\n", pkgname, + XBPS_PKGFILES); + rv = EINVAL; + broken = true; + goto out2; + } else if (prop_dictionary_count(filesd) == 0) { + printf("%s: incomplete %s metadata file.\n", pkgname, + XBPS_PKGFILES); + rv = EINVAL; + broken = true; + goto out2; + } else if (((array = prop_dictionary_get(filesd, "files")) == NULL) || + ((array = prop_dictionary_get(filesd, "links")) == NULL) || + ((array = prop_dictionary_get(filesd, "dirs")) == NULL)) { + printf("%s: incomplete %s metadata file.\n", pkgname, + XBPS_PKGFILES); + rv = EINVAL; + broken = true; + goto out2; + } + + printf("%s: metadata check PASSED.\n", pkgname); + + /* + * 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_get_array_iter_from_dict(filesd, "files"); + if (iter == NULL) { + rv = ENOMEM; + goto out2; + } + while ((obj = prop_object_iterator_next(iter))) { + prop_dictionary_get_cstring_nocopy(obj, "file", &file); + path = xbps_xasprintf("%s/%s", rootdir, file); + if (path == NULL) { + prop_object_iterator_release(iter); + rv = errno; + goto out2; + } + prop_dictionary_get_cstring_nocopy(obj, + "sha256", &sha256); + rv = xbps_check_file_hash(path, sha256); + switch (rv) { + case 0: + break; + case ENOENT: + printf("%s: unexistent file %s.\n", + pkgname, file); + files_broken = true; + broken = true; + break; + case ERANGE: + printf("%s: hash mismatch for %s.\n", + pkgname, file); + files_broken = true; + broken = true; + break; + default: + printf("%s: unexpected error for %s (%s)\n", + pkgname, file, strerror(rv)); + break; + } + free(path); + } + prop_object_iterator_release(iter); + if (files_broken) + printf("%s: files check FAILED.\n", pkgname); + else + printf("%s: files check PASSED.\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_get_array_iter_from_dict(filesd, "conf_files"); + if (iter == NULL) { + rv = ENOMEM; + goto out2; + } + while ((obj = prop_object_iterator_next(iter))) { + prop_dictionary_get_cstring_nocopy(obj, "file", &file); + path = xbps_xasprintf("%s/%s", rootdir, file); + if (path == NULL) { + prop_object_iterator_release(iter); + rv = ENOMEM; + goto out2; + } + if ((rv = access(path, R_OK)) == -1) { + if (errno == ENOENT) { + printf("%s: unexistent file %s\n", + pkgname, file); + broken = true; + } else + printf("%s: unexpected error for " + "%s (%s)\n", pkgname, file, + strerror(errno)); + } + free(path); + } + prop_object_iterator_release(iter); + if (rv == 0) + printf("%s: configuration files check PASSED.\n", + pkgname); + else + printf("%s: configuration files check FAILED.\n", + pkgname); + } + + /* + * Check for missing run time dependencies. + */ + if (xbps_pkg_has_rundeps(propsd)) { + iter = xbps_get_array_iter_from_dict(propsd, "run_depends"); + if (iter == NULL) { + rv = ENOMEM; + goto out2; + } + while ((obj = prop_object_iterator_next(iter))) { + reqpkg = prop_string_cstring_nocopy(obj); + if (xbps_check_is_installed_pkg(reqpkg) < 0) { + rv = ENOENT; + printf("%s: dependency not satisfied: %s\n", + pkgname, reqpkg); + broken = true; + } + } + prop_object_iterator_release(iter); + if (rv == ENOENT) + printf("%s: run-time dependency check FAILED.\n", + pkgname); + else + printf("%s: run-time dependency check PASSED.\n", + pkgname); + } + +out2: + prop_object_release(filesd); +out1: + prop_object_release(propsd); +out: + prop_object_release(pkgd); + + if (broken) { + rv = xbps_set_pkg_state_installed(pkgname, + XBPS_PKG_STATE_BROKEN); + if (rv == 0) + printf("%s: changed package state to broken.\n", + pkgname); + else + printf("%s: can't change package state (%s).\n", + pkgname, strerror(rv)); + } + + xbps_release_regpkgdb_dict(); + + return rv; +} diff --git a/bin/xbps-bin/defs.h b/bin/xbps-bin/defs.h index 578ab688ffe..e5664073500 100644 --- a/bin/xbps-bin/defs.h +++ b/bin/xbps-bin/defs.h @@ -28,7 +28,8 @@ void xbps_install_pkg(const char *, bool, bool); void xbps_autoremove_pkgs(void); -void xbps_remove_pkg(const char *, bool); +void xbps_remove_installed_pkg(const char *, bool); void xbps_autoupdate_pkgs(bool); +int xbps_check_pkg_integrity(const char *); #endif /* !_XBPS_BIN_DEFS_H_ */ diff --git a/bin/xbps-bin/install.c b/bin/xbps-bin/install.c index 55a79a3bc5b..db417880aba 100644 --- a/bin/xbps-bin/install.c +++ b/bin/xbps-bin/install.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -34,8 +35,25 @@ #include #include "defs.h" +enum { + TRANS_ONE, + TRANS_ALL +}; + +struct transaction { + prop_dictionary_t dict; + prop_object_iterator_t iter; + const char *originpkgname; + const char *curpkgname; + int type; + bool force; + bool update; +}; + static void show_missing_deps(prop_dictionary_t, const char *); static int show_missing_dep_cb(prop_object_t, void *, bool *); +static int exec_transaction(struct transaction *); +static void cleanup(int); static void show_missing_deps(prop_dictionary_t d, const char *pkgname) @@ -65,36 +83,44 @@ show_missing_dep_cb(prop_object_t obj, void *arg, bool *loop_done) return EINVAL; } -static void -check_pkg_hashes(prop_dictionary_t props, prop_object_iterator_t iter) +static int +check_pkg_hashes(prop_object_iterator_t iter) { prop_object_t obj; - const char *repoloc, *filename; + const char *pkgname, *repoloc, *filename; int rv = 0; + pkg_state_t state = 0; printf("Checking binary package file(s) integrity...\n"); while ((obj = prop_object_iterator_next(iter)) != NULL) { + prop_dictionary_get_cstring_nocopy(obj, "pkgname", &pkgname); + state = 0; + if (xbps_get_pkg_state_dictionary(obj, &state) != 0) + return EINVAL; + + if (state == XBPS_PKG_STATE_UNPACKED) + continue; + prop_dictionary_get_cstring_nocopy(obj, "repository", &repoloc); prop_dictionary_get_cstring_nocopy(obj, "filename", &filename); rv = xbps_check_pkg_file_hash(obj, repoloc); if (rv != 0 && rv != ERANGE) { - printf("error: checking hash for %s (%s)\n", - filename, strerror(rv)); - prop_object_release(props); - exit(EXIT_FAILURE); + printf("Unexpected error while checking hash for " + "%s (%s)\n", filename, strerror(rv)); + return -1; } else if (rv != 0 && rv == ERANGE) { - printf("Hash doesn't match for %s!\n", filename); - prop_object_release(props); - exit(EXIT_FAILURE); + printf("Hash mismatch for %s, exiting.\n", + filename); + return -1; } } prop_object_iterator_reset(iter); - printf("\n"); + + return 0; } -static void -show_transaction_sizes(prop_dictionary_t props, prop_object_iterator_t iter, - const char *descr) +static int +show_transaction_sizes(prop_object_iterator_t iter, const char *descr) { prop_object_t obj; uint64_t tsize = 0, dlsize = 0, instsize = 0; @@ -145,301 +171,344 @@ show_transaction_sizes(prop_dictionary_t props, prop_object_iterator_t iter, */ if (xbps_humanize_number(size, 5, (int64_t)dlsize, "", HN_AUTOSCALE, HN_NOSPACE) == -1) { - printf("error: humanize_number %s\n", strerror(errno)); - prop_object_release(props); - exit(EXIT_FAILURE); + printf("error: humanize_number returns %s\n", + strerror(errno)); + return -1; } printf("Total download size: %s\n", size); if (xbps_humanize_number(size, 5, (int64_t)instsize, "", HN_AUTOSCALE, HN_NOSPACE) == -1) { - printf("error: humanize_number2 %s\n", strerror(errno)); - prop_object_release(props); - exit(EXIT_FAILURE); + printf("error: humanize_number2 returns %s\n", + strerror(errno)); + return -1; } printf("Total installed size: %s\n\n", size); + + return 0; } void xbps_install_pkg(const char *pkg, bool force, bool update) { - prop_dictionary_t props, instpkg; + struct transaction *trans; + prop_dictionary_t pkgd; prop_array_t array; - prop_object_t obj; - prop_object_iterator_t iter; - const char *instver, *origin, *pkgname, *version; int rv = 0; - bool pkg_is_dep = false, doup = false; /* - * Find and sort all required package dictionaries. + * Find all required pkgs and sort the package transaction. */ - printf("Finding/sorting required binary packages...\n"); - - rv = xbps_prepare_pkg(pkg); - if (rv != 0 && rv == EAGAIN) { - printf("Unable to locate %s in repository pool.\n", pkg); - exit(EXIT_FAILURE); - } else if (rv != 0 && rv != ENOENT) { - printf("Unexpected error: %s\n", strerror(rv)); - exit(EXIT_FAILURE); + pkgd = xbps_find_pkg_installed_from_plist(pkg); + if (update) { + if (pkgd) { + if ((rv = xbps_find_new_pkg(pkg, pkgd)) == 0) { + printf("Package '%s' is up to date.\n", pkg); + prop_object_release(pkgd); + cleanup(rv); + } + prop_object_release(pkgd); + } else { + printf("Package '%s' not installed.\n", pkg); + cleanup(rv); + } + } else { + if (pkgd) { + printf("Package '%s' is already installed.\n", pkg); + prop_object_release(pkgd); + cleanup(rv); + } + rv = xbps_prepare_pkg(pkg); + if (rv != 0 && rv == EAGAIN) { + printf("unable to locate %s in repository pool.", pkg); + cleanup(rv); + } else if (rv != 0 && rv != ENOENT) { + printf("unexpected error: %s", strerror(rv)); + cleanup(rv); + } } - props = xbps_get_pkg_props(); - if (props == NULL) { + trans = calloc(1, sizeof(struct transaction)); + if (trans == NULL) + goto out; + + trans->dict = xbps_get_pkg_props(); + if (trans->dict == NULL) { printf("error: unexistent props dictionary!\n"); - exit(EXIT_FAILURE); + goto out1; } /* * Bail out if there are unresolved deps. */ - array = prop_dictionary_get(props, "missing_deps"); + array = prop_dictionary_get(trans->dict, "missing_deps"); if (prop_array_count(array) > 0) { - show_missing_deps(props, pkg); - goto out; + show_missing_deps(trans->dict, pkg); + goto out2; } - prop_dictionary_get_cstring_nocopy(props, "origin", &origin); + prop_dictionary_get_cstring_nocopy(trans->dict, + "origin", &trans->originpkgname); - array = prop_dictionary_get(props, "packages"); - if (array == NULL || prop_array_count(array) == 0) { - printf("error: empty packages array!\n"); - goto out; - } - iter = prop_array_iterator(array); - if (iter == NULL) { - printf("error: allocating array mem! (%s)\n", strerror(errno)); - goto out; + /* + * It's time to run the transaction! + */ + trans->iter = xbps_get_array_iter_from_dict(trans->dict, "packages"); + if (trans->iter == NULL) { + printf("error: allocating array mem! (%s)", + strerror(errno)); + goto out2; } + + trans->force = force; + trans->update = update; + trans->type = TRANS_ONE; + rv = exec_transaction(trans); + + prop_object_iterator_release(trans->iter); +out2: + prop_object_release(trans->dict); +out1: + free(trans); +out: + cleanup(rv); +} + +static int +exec_transaction(struct transaction *trans) +{ + prop_dictionary_t instpkgd; + prop_object_t obj; + const char *pkgname, *version, *instver, *filename; + int rv = 0; + bool essential, isdep; + pkg_state_t state = 0; + + assert(trans != NULL); + assert(trans->dict != NULL); + assert(trans->iter != NULL); + + essential = isdep = false; /* * Show download/installed size for the transaction. */ - show_transaction_sizes(props, iter, "installed"); + rv = show_transaction_sizes(trans->iter, + trans->type == TRANS_ALL ? "updated" : "installed"); + if (rv != 0) + return rv; /* * Ask interactively (if -f not set). */ - if (force == false) { + if (trans->force == false) { if (xbps_noyes("Do you want to continue?") == false) { printf("Aborting!\n"); - goto out2; + return 0; } } /* * Check the SHA256 hash for all required packages. */ - check_pkg_hashes(props, iter); + if ((rv = check_pkg_hashes(trans->iter)) != 0) + return rv; /* - * Install all packages, the list is already sorted. + * Iterate over the transaction dictionary. */ - while ((obj = prop_object_iterator_next(iter)) != NULL) { + while ((obj = prop_object_iterator_next(trans->iter)) != NULL) { prop_dictionary_get_cstring_nocopy(obj, "pkgname", &pkgname); prop_dictionary_get_cstring_nocopy(obj, "version", &version); - if (strcmp(origin, pkgname)) - pkg_is_dep = true; + prop_dictionary_get_bool(obj, "essential", &essential); + prop_dictionary_get_cstring_nocopy(obj, "filename", &filename); - if (update && strcmp(pkg, pkgname) == 0) { - /* - * Update a package, firstly removing current package. - */ - instpkg = xbps_find_pkg_installed_from_plist(pkgname); - if (instpkg == NULL) { + if ((trans->type == TRANS_ONE) && + strcmp(trans->originpkgname, pkgname)) + isdep = true; + + /* + * If dependency is already unpacked skip this phase. + */ + state = 0; + if (xbps_get_pkg_state_dictionary(obj, &state) != 0) + return EINVAL; + + if (state == XBPS_PKG_STATE_UNPACKED) + continue; + + if ((trans->type == TRANS_ALL) || + (trans->update && + strcmp(trans->curpkgname, pkgname) == 0)) { + instpkgd = xbps_find_pkg_installed_from_plist(pkgname); + if (instpkgd == NULL) { printf("error: unable to find %s installed " "dict!\n", pkgname); - goto out2; + return EINVAL; } - prop_dictionary_get_cstring_nocopy(instpkg, + prop_dictionary_get_cstring_nocopy(instpkgd, "version", &instver); - printf("Updating package %s-%s to %s...\n", pkgname, - instver, version); - prop_object_release(instpkg); - rv = xbps_remove_binary_pkg(pkgname, update); - if (rv != 0) { - printf("error: removing %s-%s (%s)\n", - pkgname, instver, strerror(rv)); - goto out2; - } + prop_object_release(instpkgd); - } else { - printf("Installing %s%s-%s ...\n", - pkg_is_dep ? "dependency " : "", pkgname, version); + /* + * If this package is not 'essential', just remove + * the old package and install the new one. Otherwise + * we just overwrite the files. + */ + if (essential == false) { + rv = xbps_remove_pkg(pkgname, version, true); + if (rv != 0) { + printf("error: removing %s-%s (%s)\n", + pkgname, instver, strerror(rv)); + return rv; + } + } } /* * Unpack binary package. */ - if ((rv = xbps_unpack_binary_pkg(obj)) != 0) { + printf("Unpacking %s-%s (from .../%s) ...\n", pkgname, version, + filename); + if ((rv = xbps_unpack_binary_pkg(obj, essential)) != 0) { printf("error: unpacking %s-%s (%s)\n", pkgname, version, strerror(rv)); - goto out2; + return rv; } /* * Register binary package. */ - if (update && !pkg_is_dep) - doup = true; - - if ((rv = xbps_register_pkg(obj, doup, pkg_is_dep)) != 0) { + if ((rv = xbps_register_pkg(obj, isdep)) != 0) { printf("error: registering %s-%s! (%s)\n", pkgname, version, strerror(rv)); - goto out2; + return rv; } - pkg_is_dep = false; + isdep = false; + /* + * Set package state to unpacked in the transaction + * dictionary. + */ + if ((rv = xbps_set_pkg_state_dictionary(obj, + XBPS_PKG_STATE_UNPACKED)) != 0) + return rv; } -out2: - prop_object_iterator_release(iter); -out: - prop_object_release(props); - xbps_release_repolist_data(); - xbps_release_regpkgdb_dict(); - if (rv != 0) - exit(EXIT_FAILURE); + prop_object_iterator_reset(trans->iter); + /* + * Configure all unpacked packages. + */ + while ((obj = prop_object_iterator_next(trans->iter)) != NULL) { + prop_dictionary_get_cstring_nocopy(obj, "pkgname", &pkgname); + prop_dictionary_get_cstring_nocopy(obj, "version", &version); + printf("Configuring package %s-%s ...\n", pkgname, version); - exit(EXIT_SUCCESS); + if ((rv = xbps_configure_pkg(pkgname, version)) != 0) { + printf("Error configuring package %s-%s\n", + pkgname, version); + return rv; + } + } + + return 0; } void xbps_autoupdate_pkgs(bool force) { - prop_dictionary_t dict, props, instpkg; - prop_array_t array; + struct transaction *trans; + prop_dictionary_t dict; prop_object_t obj; - prop_object_iterator_t iter; - const char *pkgname, *version, *instver; + const char *pkgname; int rv = 0; + /* + * Prepare dictionary with all registered packages. + */ dict = xbps_prepare_regpkgdb_dict(); if (dict == NULL) { printf("No packages currently installed (%s).\n", strerror(errno)); - exit(EXIT_SUCCESS); + cleanup(rv); } - - iter = xbps_get_array_iter_from_dict(dict, "packages"); - if (iter == NULL) { - rv = EINVAL; - goto out; - } - + /* + * Prepare dictionary with all registered repositories. + */ if ((rv = xbps_prepare_repolist_data()) != 0) goto out; - while ((obj = prop_object_iterator_next(iter)) != NULL) { + /* + * Prepare transaction data. + */ + trans = calloc(1, sizeof(struct transaction)); + if (trans == NULL) + goto out; + + trans->iter = xbps_get_array_iter_from_dict(dict, "packages"); + if (trans->iter == NULL) { + rv = EINVAL; + goto out1; + } + + /* + * Find out if there is a newer version for all currently + * installed packages. + */ + while ((obj = prop_object_iterator_next(trans->iter)) != NULL) { prop_dictionary_get_cstring_nocopy(obj, "pkgname", &pkgname); rv = xbps_find_new_pkg(pkgname, obj); - if (rv != 0) - break; + if (rv != 0) { + prop_object_iterator_release(trans->iter); + goto out1; + } } - prop_object_iterator_release(iter); + prop_object_iterator_release(trans->iter); - /* Sort the list of packages */ - props = xbps_get_pkg_props(); - if (props == NULL) { + /* + * Get package transaction dictionary. + */ + trans->dict = xbps_get_pkg_props(); + if (trans->dict == NULL) { if (errno == 0) { printf("All packages are up-to-date.\n"); - exit(EXIT_SUCCESS); + goto out; } printf("Error while checking for new pkgs: %s\n", strerror(errno)); - goto out; + goto out1; } - if ((rv = xbps_sort_pkg_deps(props)) != 0) { + /* + * Sort the package transaction dictionary. + */ + if ((rv = xbps_sort_pkg_deps(trans->dict)) != 0) { printf("Error while sorting packages: %s\n", strerror(rv)); - goto out; + goto out2; } - /* Update all packages now */ - array = prop_dictionary_get(props, "packages"); - if (array == NULL || prop_array_count(array) == 0) { - printf("error: empty packages array!\n"); - prop_object_release(props); - goto out; - } - iter = prop_array_iterator(array); - if (iter == NULL) { + + /* + * It's time to run the transaction! + */ + trans->iter = xbps_get_array_iter_from_dict(trans->dict, "packages"); + if (trans->iter == NULL) { printf("error: allocating array mem! (%s)\n", strerror(errno)); - prop_object_release(props); - goto out; + goto out2; } - /* - * Show download/installed size for the transaction. - */ - show_transaction_sizes(props, iter, "upgraded"); - - /* - * Ask interactively (if -f not set). - */ - if (force == false) { - if (xbps_noyes("Do you want to continue?") == false) { - printf("Aborting!\n"); - prop_object_release(props); - goto out2; - } - } - - /* - * Check the SHA256 hash for all required packages. - */ - check_pkg_hashes(props, iter); - - while ((obj = prop_object_iterator_next(iter)) != NULL) { - prop_dictionary_get_cstring_nocopy(obj, "pkgname", &pkgname); - prop_dictionary_get_cstring_nocopy(obj, "version", &version); - - /* - * Update a package, firstly removing current package. - */ - instpkg = xbps_find_pkg_installed_from_plist(pkgname); - if (instpkg == NULL) { - printf("error: unable to find %s installed " - "dict!\n", pkgname); - prop_object_release(props); - goto out2; - } - - prop_dictionary_get_cstring_nocopy(instpkg, - "version", &instver); - printf("Updating package %s-%s to %s...\n", pkgname, - instver, version); - prop_object_release(instpkg); - rv = xbps_remove_binary_pkg(pkgname, true); - if (rv != 0) { - printf("error: removing %s-%s (%s)\n", - pkgname, instver, strerror(rv)); - prop_object_release(props); - goto out2; - } - - /* - * Unpack binary package. - */ - if ((rv = xbps_unpack_binary_pkg(obj)) != 0) { - printf("error: unpacking %s-%s (%s)\n", pkgname, - version, strerror(rv)); - prop_object_release(props); - goto out2; - } - /* - * Register binary package. - */ - if ((rv = xbps_register_pkg(obj, true, false)) != 0) { - printf("error: registering %s-%s! (%s)\n", - pkgname, version, strerror(rv)); - prop_object_release(props); - goto out2; - } - } + trans->force = force; + trans->update = true; + trans->type = TRANS_ALL; + rv = exec_transaction(trans); + prop_object_iterator_release(trans->iter); out2: - prop_object_iterator_release(iter); + prop_object_release(trans->dict); +out1: + free(trans); out: + cleanup(rv); +} + +static void +cleanup(int rv) +{ xbps_release_repolist_data(); xbps_release_regpkgdb_dict(); - if (rv != 0) - exit(EXIT_FAILURE); - - exit(EXIT_SUCCESS); + exit(rv == 0 ? EXIT_SUCCESS : EXIT_FAILURE); } diff --git a/bin/xbps-bin/main.c b/bin/xbps-bin/main.c index 0db1329dc20..0feee5e6c0f 100644 --- a/bin/xbps-bin/main.c +++ b/bin/xbps-bin/main.c @@ -45,9 +45,10 @@ usage(void) { printf("Usage: xbps-bin [options] [target] [arguments]\n\n" " Available targets:\n" - " autoremove, autoupdate, files, install, list, remove\n" - " show, update\n" + " autoremove, autoupdate, check, files, install, list\n" + " remove, show, update\n" " Targets with arguments:\n" + " check\t\n" " files\t\n" " install\t\n" " remove\t\n" @@ -56,8 +57,6 @@ usage(void) " Options shared by all targets:\n" " -r\t\t\n" " -v\t\t\n" - " Options used by the files target:\n" - " -C\t\tTo check the SHA256 hash for any listed file.\n" " Options used by the (auto)remove target:\n" " -f\t\tForce installation or removal of packages.\n" " \t\tBeware with this option if you use autoremove!\n" @@ -65,7 +64,7 @@ usage(void) " Examples:\n" " $ xbps-bin autoremove\n" " $ xbps-bin autoupdate\n" - " $ xbps-bin -C files klibc\n" + " $ xbps-bin files klibc\n" " $ xbps-bin install klibc\n" " $ xbps-bin -r /path/to/root install klibc\n" " $ xbps-bin list\n" @@ -101,13 +100,10 @@ main(int argc, char **argv) { prop_dictionary_t dict; int c, flags = 0, rv = 0; - bool chkhash = false, force = false, verbose = false; + bool force = false, verbose = false; while ((c = getopt(argc, argv, "Cfr:v")) != -1) { switch (c) { - case 'C': - chkhash = true; - break; case 'f': force = true; break; @@ -178,7 +174,7 @@ main(int argc, char **argv) if (argc != 2) usage(); - xbps_remove_pkg(argv[1], force); + xbps_remove_installed_pkg(argv[1], force); } else if (strcasecmp(argv[0], "show") == 0) { /* Shows info about an installed binary package. */ @@ -196,12 +192,19 @@ main(int argc, char **argv) if (argc != 2) usage(); - rv = show_pkg_files_from_metadir(argv[1], chkhash); + rv = show_pkg_files_from_metadir(argv[1]); if (rv != 0) { printf("Package %s not installed.\n", argv[1]); exit(EXIT_FAILURE); } + } else if (strcasecmp(argv[0], "check") == 0) { + /* Checks the integrity of an installed package. */ + if (argc != 2) + usage(); + + rv = xbps_check_pkg_integrity(argv[1]); + } else if (strcasecmp(argv[0], "autoupdate") == 0) { /* * To update all packages currently installed. diff --git a/bin/xbps-bin/remove.c b/bin/xbps-bin/remove.c index 5237b661bda..2a990e7eef4 100644 --- a/bin/xbps-bin/remove.c +++ b/bin/xbps-bin/remove.c @@ -96,7 +96,7 @@ xbps_autoremove_pkgs(void) prop_dictionary_get_cstring_nocopy(obj, "version", &version); printf("Removing package %s-%s ...\n", pkgname, version); - if ((rv = xbps_remove_binary_pkg(pkgname, false)) != 0) + if ((rv = xbps_remove_pkg(pkgname, version, false)) != 0) goto out2; } out2: @@ -110,7 +110,7 @@ out: } void -xbps_remove_pkg(const char *pkgname, bool force) +xbps_remove_installed_pkg(const char *pkgname, bool force) { prop_array_t reqby; prop_dictionary_t dict; @@ -151,7 +151,7 @@ xbps_remove_pkg(const char *pkgname, bool force) } printf("Removing package %s-%s ...\n", pkgname, version); - if ((rv = xbps_remove_binary_pkg(pkgname, false)) != 0) { + if ((rv = xbps_remove_pkg(pkgname, version, false)) != 0) { printf("Unable to remove %s-%s (%s).\n", pkgname, version, strerror(errno)); goto out; diff --git a/bin/xbps-pkgdb/main.c b/bin/xbps-pkgdb/main.c index dbae941cf88..012dd33a41a 100644 --- a/bin/xbps-pkgdb/main.c +++ b/bin/xbps-pkgdb/main.c @@ -139,7 +139,12 @@ main(int argc, char **argv) prop_dictionary_set_cstring_nocopy(dict, "version", argv[2]); prop_dictionary_set_cstring_nocopy(dict, "short_desc", argv[3]); - rv = xbps_register_pkg(dict, false, automatic); + rv = xbps_set_pkg_state_installed(argv[1], + XBPS_PKG_STATE_INSTALLED); + if (rv != 0) + exit(EXIT_FAILURE); + + rv = xbps_register_pkg(dict, automatic); if (rv == EEXIST) { printf("%s=> %s-%s already registered.\n", in_chroot ? "[chroot] " : "", argv[1], argv[2]); diff --git a/bin/xbps-repo/index.c b/bin/xbps-repo/index.c index 1f93749fbdc..6bbe929789a 100644 --- a/bin/xbps-repo/index.c +++ b/bin/xbps-repo/index.c @@ -36,7 +36,7 @@ #include "index.h" /* Array of valid architectures */ -const char *archdirs[] = { "i686", "x86_64", "noarch", NULL }; +static const char *archdirs[] = { "i686", "x86_64", "noarch", NULL }; static prop_dictionary_t repoidx_getdict(const char *pkgdir) @@ -52,16 +52,13 @@ repoidx_getdict(const char *pkgdir) dict = prop_dictionary_internalize_from_file(plist); if (dict == NULL) { dict = prop_dictionary_create(); - if (dict == NULL) { - free(plist); - return NULL; - } + if (dict == NULL) + goto out; array = prop_array_create(); if (array == NULL) { - free(plist); prop_object_release(dict); - return NULL; + goto out; } prop_dictionary_set(dict, "packages", array); @@ -71,6 +68,7 @@ repoidx_getdict(const char *pkgdir) prop_dictionary_set_cstring_nocopy(dict, "pkgindex-version", XBPS_PKGINDEX_VERSION); } +out: free(plist); return dict; @@ -84,38 +82,36 @@ repoidx_addpkg(const char *file, const char *filename, const char *pkgdir) struct archive *ar; struct archive_entry *entry; struct stat st; - ssize_t nbytes = -1; const char *pkgname, *version, *regver; - char *props, *sha256, *plist; - size_t propslen = 0; + char *sha256, *plist; int rv = 0; ar = archive_read_new(); - if (ar == NULL) - return errno; - + if (ar == NULL) { + rv = errno; + goto out; + } /* Enable support for tar format and all compression methods */ archive_read_support_compression_all(ar); archive_read_support_format_tar(ar); if ((rv = archive_read_open_filename(ar, file, ARCHIVE_READ_BLOCKSIZE)) == -1) { - archive_read_finish(ar); - return errno; + rv = errno; + goto out1; } /* Get existing or create repo index dictionary */ idxdict = repoidx_getdict(pkgdir); if (idxdict == NULL) { - archive_read_finish(ar); - return errno; + rv = errno; + goto out1; } plist = xbps_get_pkg_index_plist(pkgdir); if (plist == NULL) { prop_dictionary_remove(idxdict, "packages"); - prop_object_release(idxdict); - archive_read_finish(ar); - return ENOMEM; + rv = ENOMEM; + goto out2; } /* @@ -123,32 +119,15 @@ repoidx_addpkg(const char *file, const char *filename, const char *pkgdir) * into a buffer. */ while (archive_read_next_header(ar, &entry) == ARCHIVE_OK) { - if (strstr(archive_entry_pathname(entry), "props.plist") == 0) { + if (strstr(archive_entry_pathname(entry), XBPS_PKGPROPS) == 0) { archive_read_data_skip(ar); continue; } - - propslen = (size_t)archive_entry_size(entry); - props = malloc(propslen); - if (props == NULL) { - rv = errno; - break; - } - nbytes = archive_read_data(ar, props, propslen); - if ((size_t)nbytes != propslen) { - rv = EINVAL; - break; - } - newpkgd = prop_dictionary_internalize(props); - free(props); - propslen = 0; + newpkgd = xbps_read_dict_from_archive_entry(ar, entry); if (newpkgd == NULL) { - archive_read_data_skip(ar); - continue; - } else if (prop_object_type(newpkgd) != PROP_TYPE_DICTIONARY) { - prop_object_release(newpkgd); - archive_read_data_skip(ar); - continue; + printf("%s: can't read %s metadata file, skipping!\n", + file, XBPS_PKGPROPS); + break; } prop_dictionary_get_cstring_nocopy(newpkgd, "pkgname", @@ -233,10 +212,13 @@ repoidx_addpkg(const char *file, const char *filename, const char *pkgdir) pkgname, version); break; } - archive_read_finish(ar); - free(plist); - prop_object_release(idxdict); + free(plist); +out2: + prop_object_release(idxdict); +out1: + archive_read_finish(ar); +out: return rv; } @@ -253,7 +235,6 @@ xbps_repo_genindex(const char *pkgdir) if (uname(&un) == -1) return errno; - /* * Iterate over the known architecture directories to find * binary packages. @@ -296,7 +277,6 @@ xbps_repo_genindex(const char *pkgdir) free(path); return rv; } - } (void)closedir(dirp); free(path); diff --git a/bin/xbps-repo/util.c b/bin/xbps-repo/util.c index 1a720d39e5c..50ddd2cf8b6 100644 --- a/bin/xbps-repo/util.c +++ b/bin/xbps-repo/util.c @@ -197,14 +197,14 @@ show_pkg_info_from_metadir(const char *pkgname) } int -show_pkg_files_from_metadir(const char *pkgname, bool hash) +show_pkg_files_from_metadir(const char *pkgname) { prop_dictionary_t pkgd; prop_array_t array; prop_object_iterator_t iter = NULL; prop_object_t obj; - const char *destdir, *file, *sha256; - char *plist, *path = NULL, *array_str = "files"; + const char *destdir, *file; + char *plist, *array_str = "files"; int i, rv = 0; destdir = xbps_get_rootdir(); @@ -233,7 +233,6 @@ show_pkg_files_from_metadir(const char *pkgname, bool hash) printf("%s\n", file); } prop_object_iterator_release(iter); - iter = NULL; } /* Files and configuration files. */ @@ -254,41 +253,10 @@ show_pkg_files_from_metadir(const char *pkgname, bool hash) } while ((obj = prop_object_iterator_next(iter))) { prop_dictionary_get_cstring_nocopy(obj, "file", &file); - if (hash == false) { - printf("%s\n", file); - continue; - } - - printf("%s", file); - if (destdir) { - path = xbps_xasprintf("%s/%s", destdir, file); - if (path == NULL) { - rv = EINVAL; - goto out2; - } - } - prop_dictionary_get_cstring_nocopy(obj, - "sha256", &sha256); - if (destdir) - rv = xbps_check_file_hash(path, sha256); - else - rv = xbps_check_file_hash(file, sha256); - - if (rv != 0 && rv != ERANGE) - printf(" (can't check: %s)", strerror(rv)); - else if (rv == ERANGE) - printf(" WARNING! SHA256 HASH MISMATCH!"); - - printf("\n"); - if (destdir) - free(path); + printf("%s\n", file); } prop_object_iterator_release(iter); - iter = NULL; } -out2: - if (iter != NULL) - prop_object_iterator_release(iter); out: prop_object_release(pkgd); diff --git a/bin/xbps-repo/util.h b/bin/xbps-repo/util.h index a4d4ce61533..92f5db2c110 100644 --- a/bin/xbps-repo/util.h +++ b/bin/xbps-repo/util.h @@ -28,7 +28,7 @@ int search_string_in_pkgs(prop_object_t, void *, bool *); int show_pkg_info_from_metadir(const char *); -int show_pkg_files_from_metadir(const char *, bool); +int show_pkg_files_from_metadir(const char *); int show_pkg_info_from_repolist(prop_object_t, void *, bool *); int list_strings_in_array(prop_object_t, void *, bool *); int list_strings_sep_in_array(prop_object_t, void *, bool *); diff --git a/doc/BINPKG_INFO b/doc/BINPKG_INFO index 22932598329..0c23d55f02c 100644 --- a/doc/BINPKG_INFO +++ b/doc/BINPKG_INFO @@ -5,22 +5,27 @@ A binary package built with xbps is a normal tar(1) archive, compressed with bzip2 and has the following structure: - / - /usr ------| - /var ------| => Package structure that will be installed. - /etc ------| + Package metadata + ----------------- + /INSTALL + /REMOVE + /files.plist + /props.plist + + Package data + ----------------- + /usr + /var + /etc ... - /var/db/xbps/metadata/$pkgname - /var/db/xbps/metadata/$pkgname/files.plist - /var/db/xbps/metadata/$pkgname/props.plist - /var/db/xbps/metadata/$pkgname/INSTALL - /var/db/xbps/metadata/$pkgname/REMOVE Metadata info is stored in the "/var/db/xbps/metadata/$pkgname" -directory and two files will be always be present: flist and props.plist. +directory and two files will be always be present: files.plist +and props.plist. The files.plist file contains the list of files/links/dirs that package will install, as well as SHA256 hashes for files. + The props.plist file contains package metadata properties and has the following structure: diff --git a/doc/TODO b/doc/TODO index 557e6d8ba16..86b00837cec 100644 --- a/doc/TODO +++ b/doc/TODO @@ -29,13 +29,9 @@ xbps-bin: * Implement shell style match patterns with fnmatch(). * Make -f flag to overwrite files when installing, and to ignore files with wrong checksum or unexistent when removing. - * Add a target to check pkg integrity: normal files, metadata - and its dependencies. libxbps: * Fix glibc updates: removing libc is bad. - * Create xbps_upgrade_pkg() to replace or remove/unpack and register. - Remove duplicate code from xbps-bin/install.c. [IN PROGRESS] * Add support to upgrade packages but overwritting current files; this will fix libc, sh and others. An "essential" boolean obj seems to be a good way to find such packages, like dpkg. [IN PROGRESS] diff --git a/lib/Makefile b/lib/Makefile index 24fc4b73167..787f482555d 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -9,9 +9,10 @@ LIBXBPS = libxbps.so LIBXBPS_STATIC = libxbps.a LIBXBPS_LDFLAGS = -larchive -lprop -shared -Wl,-soname,$(LIBXBPS).$(MAJOR) -OBJECTS = cmpver.o depends.o fexec.o findpkg.o humanize_number.o -OBJECTS += orphans.o plist.o register.o remove.o repository.o requiredby.o -OBJECTS += sha256.o sortdeps.o unpack.o util.o +OBJECTS = configure.o cmpver.o depends.o fexec.o findpkg.o +OBJECTS += humanize_number.o orphans.o plist.o register.o remove.o +OBJECTS += repository.o requiredby.o sha256.o sortdeps.o state.o +OBJECTS += unpack.o util.o all: $(LIBXBPS) $(LIBXBPS_STATIC) .PHONY: all diff --git a/lib/configure.c b/lib/configure.c new file mode 100644 index 00000000000..7b301aaba96 --- /dev/null +++ b/lib/configure.c @@ -0,0 +1,92 @@ +/*- + * Copyright (c) 2009 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 + +/* + * Configure a package that is currently unpacked. This + * runs the post INSTALL action if required and updates the + * package state to installed. + */ +int +xbps_configure_pkg(const char *pkgname, const char *version) +{ + const char *rootdir; + char *buf; + int rv = 0; + pkg_state_t state = 0; + + assert(pkgname != NULL); + assert(version != NULL); + rootdir = xbps_get_rootdir(); + + if ((rv = xbps_get_pkg_state_installed(pkgname, &state)) != 0) + return rv; + + /* + * If package is already installed do nothing, and only + * continue if it's unpacked. + */ + if (state == XBPS_PKG_STATE_INSTALLED) + return 0; + else if (state != XBPS_PKG_STATE_UNPACKED) + return EINVAL; + + buf = xbps_xasprintf(".%s/metadata/%s/INSTALL", + XBPS_META_PATH, pkgname); + if (buf == NULL) + return errno; + + if (access(buf, R_OK) == 0) { + if (chdir(rootdir) == -1) + return errno; + + if ((rv = xbps_file_chdir_exec(rootdir, buf, "post", + pkgname, version, NULL)) != 0) { + free(buf); + printf("%s: post INSTALL action returned: %s\n", + pkgname, strerror(errno)); + return rv; + } + } else { + if (errno != ENOENT) { + free(buf); + return errno; + } + } + free(buf); + + return xbps_set_pkg_state_installed(pkgname, XBPS_PKG_STATE_INSTALLED); +} diff --git a/lib/depends.c b/lib/depends.c index 7fb4d04c4b7..023711e5d39 100644 --- a/lib/depends.c +++ b/lib/depends.c @@ -32,29 +32,27 @@ #include -static int add_missing_reqdep(prop_dictionary_t, const char *, - const char *); -static int find_repo_deps(prop_dictionary_t, prop_dictionary_t, - prop_dictionary_t, prop_array_t); -static int find_repo_missing_deps(prop_dictionary_t, prop_dictionary_t, - prop_dictionary_t); +static int add_missing_reqdep(prop_dictionary_t, const char *, const char *); +static int find_repo_deps(prop_dictionary_t, prop_dictionary_t, prop_array_t); +static int find_repo_missing_deps(prop_dictionary_t, prop_dictionary_t); static int -store_dependency(prop_dictionary_t master, prop_dictionary_t origind, - prop_dictionary_t depd, prop_dictionary_t repod) +store_dependency(prop_dictionary_t master, prop_dictionary_t depd, + prop_dictionary_t repod) { prop_dictionary_t dict; prop_array_t array; - const char *reqbyname, *repoloc; + const char *repoloc, *pkgname; + int rv = 0; + pkg_state_t state = 0; - assert(origind != NULL); + assert(master != NULL); assert(depd != NULL); assert(repod != NULL); - /* * Get some info about dependencies and current repository. */ - prop_dictionary_get_cstring_nocopy(origind, "pkgname", &reqbyname); + prop_dictionary_get_cstring_nocopy(depd, "pkgname", &pkgname); prop_dictionary_get_cstring_nocopy(repod, "location-local", &repoloc); dict = prop_dictionary_copy(depd); @@ -66,6 +64,26 @@ store_dependency(prop_dictionary_t master, prop_dictionary_t origind, prop_object_release(dict); return errno; } + /* + * Always set "not-installed" package state. Will be overwritten + * to its correct state later. + */ + rv = xbps_set_pkg_state_dictionary(dict, XBPS_PKG_STATE_NOT_INSTALLED); + if (rv != 0) { + prop_object_release(dict); + return rv; + } + /* + * Overwrite package state in dictionary if it was unpacked + * previously. + */ + rv = xbps_get_pkg_state_installed(pkgname, &state); + if (rv == 0) { + if ((rv = xbps_set_pkg_state_dictionary(dict, state)) != 0) { + prop_object_release(dict); + return rv; + } + } /* * Add required objects into package dep's dictionary. */ @@ -132,8 +150,7 @@ xbps_find_deps_in_pkg(prop_dictionary_t master, prop_dictionary_t pkg) assert(iter != NULL); pkg_rdeps = prop_dictionary_get(pkg, "run_depends"); - if (pkg_rdeps == NULL) - return 0; + assert(pkg_rdeps != NULL); /* * Iterate over the repository pool and find out if we have @@ -145,7 +162,7 @@ xbps_find_deps_in_pkg(prop_dictionary_t master, prop_dictionary_t pkg) * if any of them is not there it will be added * into the missing_deps array. */ - rv = find_repo_deps(master, rdata->rd_repod, pkg, pkg_rdeps); + rv = find_repo_deps(master, rdata->rd_repod, pkg_rdeps); if (rv != 0) { if (rv == ENOENT) { rv = 0; @@ -164,7 +181,7 @@ xbps_find_deps_in_pkg(prop_dictionary_t master, prop_dictionary_t pkg) * just in case that indirect deps weren't found. */ SIMPLEQ_FOREACH(rdata, &repodata_queue, chain) { - rv = find_repo_missing_deps(master, rdata->rd_repod, pkg); + rv = find_repo_missing_deps(master, rdata->rd_repod); if (rv != 0 && rv != ENOENT) return rv; } @@ -173,8 +190,7 @@ xbps_find_deps_in_pkg(prop_dictionary_t master, prop_dictionary_t pkg) } static int -find_repo_missing_deps(prop_dictionary_t master, prop_dictionary_t repo, - prop_dictionary_t pkg) +find_repo_missing_deps(prop_dictionary_t master, prop_dictionary_t repo) { prop_array_t array; prop_dictionary_t curpkgd; @@ -214,7 +230,7 @@ find_repo_missing_deps(prop_dictionary_t master, prop_dictionary_t repo, /* * Package is on repo, add it into the dictionary. */ - if ((rv = store_dependency(master, pkg, curpkgd, repo)) != 0) + if ((rv = store_dependency(master, curpkgd, repo)) != 0) break; /* * Remove package from missing_deps array now. @@ -233,9 +249,9 @@ find_repo_missing_deps(prop_dictionary_t master, prop_dictionary_t repo, static int find_repo_deps(prop_dictionary_t master, prop_dictionary_t repo, - prop_dictionary_t pkg, prop_array_t pkg_rdeps) + prop_array_t pkg_rdeps) { - prop_dictionary_t curpkgd; + prop_dictionary_t curpkgd, tmpd = NULL; prop_array_t curpkg_rdeps; prop_object_t obj; prop_object_iterator_t iter; @@ -285,10 +301,24 @@ find_repo_deps(prop_dictionary_t master, prop_dictionary_t repo, continue; } } + /* + * If package is installed but version doesn't satisfy + * the dependency mark it as an update, otherwise as + * an install. + */ + tmpd = xbps_find_pkg_installed_from_plist(pkgname); + if (tmpd != NULL) { + prop_dictionary_set_cstring_nocopy(curpkgd, + "trans-action", "update"); + prop_object_release(tmpd); + } else { + prop_dictionary_set_cstring_nocopy(curpkgd, + "trans-action", "install"); + } /* * Package is on repo, add it into the dictionary. */ - if ((rv = store_dependency(master, pkg, curpkgd, repo)) != 0) { + if ((rv = store_dependency(master, curpkgd, repo)) != 0) { free(pkgname); break; } @@ -311,7 +341,7 @@ find_repo_deps(prop_dictionary_t master, prop_dictionary_t repo, /* * Iterate on required pkg to find more deps. */ - if (!find_repo_deps(master, repo, curpkgd, curpkg_rdeps)) + if (!find_repo_deps(master, repo, curpkg_rdeps)) continue; } prop_object_iterator_release(iter); diff --git a/lib/findpkg.c b/lib/findpkg.c index d7015027c99..f9598233e29 100644 --- a/lib/findpkg.c +++ b/lib/findpkg.c @@ -91,7 +91,7 @@ xbps_get_pkg_props(void) if (pkg_props_initialized == false) return NULL; - return prop_dictionary_copy(pkg_props); + return pkg_props; } int @@ -134,13 +134,13 @@ xbps_prepare_repolist_data(void) array = prop_dictionary_get(dict, "repository-list"); if (array == NULL) { rv = EINVAL; - goto out; + goto out1; } iter = prop_array_iterator(array); if (iter == NULL) { rv = ENOMEM; - goto out; + goto out1; } while ((obj = prop_object_iterator_next(iter)) != NULL) { @@ -175,8 +175,9 @@ xbps_prepare_repolist_data(void) out2: prop_object_iterator_release(iter); -out: +out1: prop_object_release(dict); +out: if (rv != 0) xbps_release_repolist_data(); @@ -283,6 +284,7 @@ xbps_prepare_pkg(const char *pkgname) struct repository_data *rdata; const char *repoloc; int rv = 0; + pkg_state_t state = 0; assert(pkgname != NULL); @@ -364,6 +366,24 @@ xbps_prepare_pkg(const char *pkgname) goto out; } + /* + * Always set "not-installed" package state. Will be overwritten + * to its correct state later. + */ + rv = xbps_set_pkg_state_dictionary(pkgrd, XBPS_PKG_STATE_NOT_INSTALLED); + if (rv != 0) + goto out; + + /* + * Overwrite package state in dictionary if it was unpacked + * previously. + */ + rv = xbps_get_pkg_state_installed(pkgname, &state); + if (rv == 0) { + if ((rv = xbps_set_pkg_state_dictionary(pkgrd, state)) != 0) + goto out; + } + if (!prop_array_add(pkgs_array, pkgrd)) rv = errno; diff --git a/lib/register.c b/lib/register.c index 534ee99e192..8b778ecc866 100644 --- a/lib/register.c +++ b/lib/register.c @@ -34,25 +34,10 @@ #include -static prop_dictionary_t -make_dict_from_pkg(const char *name, const char *ver, const char *desc) -{ - prop_dictionary_t dict; - - dict = prop_dictionary_create(); - assert(dict != NULL); - - prop_dictionary_set_cstring_nocopy(dict, "pkgname", name); - prop_dictionary_set_cstring_nocopy(dict, "version", ver); - prop_dictionary_set_cstring_nocopy(dict, "short_desc", desc); - - return dict; -} - int -xbps_register_pkg(prop_dictionary_t pkgrd, bool update, bool automatic) +xbps_register_pkg(prop_dictionary_t pkgrd, bool automatic) { - prop_dictionary_t dict, pkgd, newpkgd; + prop_dictionary_t dict, pkgd; prop_array_t array; const char *pkgname, *version, *desc, *rootdir; char *plist; @@ -69,93 +54,41 @@ xbps_register_pkg(prop_dictionary_t pkgrd, bool update, bool automatic) prop_dictionary_get_cstring_nocopy(pkgrd, "short_desc", &desc); dict = prop_dictionary_internalize_from_file(plist); - if (dict == NULL) { - /* - * No packages registered yet. Register package into - * the dictionary. - */ - dict = prop_dictionary_create(); - if (dict == NULL) { - free(plist); - return ENOMEM; - } - - array = prop_array_create(); - if (array == NULL) { - rv = ENOMEM; - goto out; - } - - pkgd = make_dict_from_pkg(pkgname, version, desc); - if (!xbps_add_obj_to_array(array, pkgd)) { - prop_object_release(array); - rv = EINVAL; - goto out; - } - - prop_dictionary_set_bool(pkgd, "automatic-install", - automatic); - - if (!xbps_add_obj_to_dict(dict, array, "packages")) { - prop_object_release(array); - rv = EINVAL; - goto out; - } - - } else { - /* - * Check if package is already registered and return - * an error if not updating. - */ + if (dict != NULL) { pkgd = xbps_find_pkg_in_dict(dict, "packages", pkgname); - if (pkgd != NULL && update == false) { - rv = EEXIST; - goto out; - } - array = prop_dictionary_get(dict, "packages"); - if (array == NULL) { + if (pkgd == NULL) { rv = ENOENT; goto out; } - - newpkgd = make_dict_from_pkg(pkgname, version, desc); - prop_dictionary_set_bool(newpkgd, "automatic-install", - automatic); + prop_dictionary_set_cstring_nocopy(pkgd, "version", version); + prop_dictionary_set_cstring_nocopy(pkgd, "short_desc", desc); + prop_dictionary_set_bool(pkgd, "automatic-install", automatic); /* * Add the requiredby objects for dependent packages. */ if (pkgrd && xbps_pkg_has_rundeps(pkgrd)) { + array = prop_dictionary_get(dict, "packages"); + if (array == NULL) { + prop_object_release(pkgd); + rv = ENOENT; + goto out; + } rv = xbps_requiredby_pkg_add(array, pkgrd); if (rv != 0) { - prop_object_release(newpkgd); - goto out; - } - } - - if (update) { - /* - * If updating a package, set new version in - * pkg dictionary. - */ - prop_dictionary_set_cstring_nocopy(pkgd, - "version", version); - } else { - /* - * If installing a package, add new pkg - * dictionary into the packages array. - */ - if (!xbps_add_obj_to_array(array, newpkgd)) { - prop_object_release(newpkgd); - rv = EINVAL; + prop_object_release(pkgd); goto out; } } + /* + * Write plist file to storage. + */ + if (!prop_dictionary_externalize_to_file(dict, plist)) + rv = errno; + } else { + free(plist); + return ENOENT; } - - if (!prop_dictionary_externalize_to_file(dict, plist)) - rv = errno; - out: prop_object_release(dict); free(plist); diff --git a/lib/remove.c b/lib/remove.c index efa1d7b1ba6..25413662403 100644 --- a/lib/remove.c +++ b/lib/remove.c @@ -60,7 +60,7 @@ xbps_unregister_pkg(const char *pkgname) } static int -xbps_remove_binary_pkg_meta(const char *pkgname) +remove_pkg_metadir(const char *pkgname) { struct dirent *dp; DIR *dirp; @@ -271,7 +271,7 @@ dirs: } int -xbps_remove_binary_pkg(const char *pkgname, bool update) +xbps_remove_pkg(const char *pkgname, const char *version, bool update) { prop_dictionary_t dict; const char *rootdir = xbps_get_rootdir(); @@ -280,6 +280,7 @@ xbps_remove_binary_pkg(const char *pkgname, bool update) bool prepostf = false; assert(pkgname != NULL); + assert(version != NULL); /* * Check if pkg is installed before anything else. @@ -287,9 +288,6 @@ xbps_remove_binary_pkg(const char *pkgname, bool update) if (xbps_check_is_installed_pkgname(pkgname) == false) return ENOENT; - if (strcmp(rootdir, "") == 0) - rootdir = "/"; - if (chdir(rootdir) == -1) return errno; @@ -306,7 +304,8 @@ xbps_remove_binary_pkg(const char *pkgname, bool update) * Run the pre remove action. */ prepostf = true; - rv = xbps_file_chdir_exec(rootdir, buf, "pre", pkgname, NULL); + rv = xbps_file_chdir_exec(rootdir, buf, "pre", pkgname, + version, NULL); if (rv != 0) { printf("%s: prerm action target error (%s)\n", pkgname, strerror(errno)); @@ -317,10 +316,10 @@ xbps_remove_binary_pkg(const char *pkgname, bool update) /* * Iterate over the pkg file list dictionary and remove all - * files/dirs associated. + * files, configuration files, links and dirs. */ - path = xbps_xasprintf("%s/%s/metadata/%s/files.plist", - rootdir, XBPS_META_PATH, pkgname); + path = xbps_xasprintf("%s/%s/metadata/%s/%s", + rootdir, XBPS_META_PATH, pkgname, XBPS_PKGFILES); if (path == NULL) { free(buf); return errno; @@ -343,11 +342,12 @@ xbps_remove_binary_pkg(const char *pkgname, bool update) prop_object_release(dict); /* - * Run the post remove action if REMOVE file is there. + * Run the post remove action if REMOVE file is there + * and we aren't updating a package. */ - if (prepostf) { + if (update == false && prepostf) { if ((rv = xbps_file_chdir_exec(rootdir, buf, "post", - pkgname, NULL)) != 0) { + pkgname, version, NULL)) != 0) { printf("%s: postrm action target error (%s)\n", pkgname, strerror(errno)); free(buf); @@ -365,16 +365,17 @@ xbps_remove_binary_pkg(const char *pkgname, bool update) if (update == false) { /* - * Unregister pkg from database only if it's a removal - * and not an update. + * Unregister pkg from database. */ rv = xbps_unregister_pkg(pkgname); if (rv != 0) return rv; + + /* + * Remove pkg metadata directory. + */ + return remove_pkg_metadir(pkgname); } - /* - * Remove pkg metadata directory. - */ - return xbps_remove_binary_pkg_meta(pkgname); + return 0; } diff --git a/lib/state.c b/lib/state.c new file mode 100644 index 00000000000..18b544be942 --- /dev/null +++ b/lib/state.c @@ -0,0 +1,235 @@ +/*- + * Copyright (c) 2009 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 + +static int +set_new_state(prop_dictionary_t dict, pkg_state_t state) +{ + const char *state_str; + + assert(dict != NULL); + + switch (state) { + case XBPS_PKG_STATE_UNPACKED: + state_str = "unpacked"; + break; + case XBPS_PKG_STATE_INSTALLED: + state_str = "installed"; + break; + case XBPS_PKG_STATE_BROKEN: + state_str = "broken"; + break; + case XBPS_PKG_STATE_CONFIG_FILES: + state_str = "config-files"; + break; + case XBPS_PKG_STATE_NOT_INSTALLED: + state_str = "not-installed"; + break; + default: + return -1; + } + + if (!prop_dictionary_set_cstring_nocopy(dict, "state", state_str)) + return -1; + + return 0; +} + +static pkg_state_t +get_state(prop_dictionary_t dict) +{ + const char *state_str; + pkg_state_t state = 0; + + assert(dict != NULL); + + prop_dictionary_get_cstring_nocopy(dict, "state", &state_str); + if (state_str == NULL) + return 0; + + if (strcmp(state_str, "unpacked") == 0) + state = XBPS_PKG_STATE_UNPACKED; + else if (strcmp(state_str, "installed") == 0) + state = XBPS_PKG_STATE_INSTALLED; + else if (strcmp(state_str, "broken") == 0) + state = XBPS_PKG_STATE_BROKEN; + else if (strcmp(state_str, "config-files") == 0) + state = XBPS_PKG_STATE_CONFIG_FILES; + else if (strcmp(state_str, "not-installed") == 0) + state = XBPS_PKG_STATE_NOT_INSTALLED; + else + return 0; + + return state; +} + +int +xbps_get_pkg_state_installed(const char *pkgname, pkg_state_t *state) +{ + prop_dictionary_t dict, pkgd; + const char *rootdir; + char *plist; + + assert(pkgname != NULL); + rootdir = xbps_get_rootdir(); + plist = xbps_xasprintf("%s/%s/%s", rootdir, + XBPS_META_PATH, XBPS_REGPKGDB); + if (plist == NULL) + return errno; + + dict = prop_dictionary_internalize_from_file(plist); + if (dict == NULL) { + free(plist); + return errno; + } + free(plist); + + pkgd = xbps_find_pkg_in_dict(dict, "packages", pkgname); + if (pkgd == NULL) { + prop_object_release(dict); + return ENOENT; + } + *state = get_state(pkgd); + if (*state == 0) { + prop_object_release(dict); + return EINVAL; + } + prop_object_release(dict); + + return 0; +} + +int +xbps_get_pkg_state_dictionary(prop_dictionary_t dict, pkg_state_t *state) +{ + assert(dict != NULL); + + if ((*state = get_state(dict)) == 0) + return EINVAL; + + return 0; +} + +int +xbps_set_pkg_state_dictionary(prop_dictionary_t dict, pkg_state_t state) +{ + assert(dict != NULL); + + return set_new_state(dict, state); +} + +int +xbps_set_pkg_state_installed(const char *pkgname, pkg_state_t state) +{ + prop_dictionary_t dict, pkgd; + prop_array_t array; + const char *rootdir; + char *plist; + int rv = 0; + bool newpkg = false; + + rootdir = xbps_get_rootdir(); + plist = xbps_xasprintf("%s/%s/%s", rootdir, + XBPS_META_PATH, XBPS_REGPKGDB); + if (plist == NULL) + return EINVAL; + + dict = prop_dictionary_internalize_from_file(plist); + if (dict == NULL) { + dict = prop_dictionary_create(); + if (dict == NULL) { + free(plist); + return ENOMEM; + } + array = prop_array_create(); + if (array == NULL) { + rv = ENOMEM; + goto out; + } + pkgd = prop_dictionary_create(); + if (pkgd == NULL) { + prop_object_release(array); + rv = errno; + goto out; + } + prop_dictionary_set_cstring_nocopy(pkgd, "pkgname", pkgname); + if ((rv = set_new_state(pkgd, state)) != 0) { + prop_object_release(array); + goto out; + } + if (!xbps_add_obj_to_array(array, pkgd)) { + prop_object_release(array); + rv = EINVAL; + goto out; + } + if (!xbps_add_obj_to_dict(dict, array, "packages")) { + prop_object_release(array); + rv = EINVAL; + goto out; + } + + } else { + pkgd = xbps_find_pkg_in_dict(dict, "packages", pkgname); + if (pkgd == NULL) { + newpkg = true; + pkgd = prop_dictionary_create(); + prop_dictionary_set_cstring_nocopy(pkgd, "pkgname", + pkgname); + } + array = prop_dictionary_get(dict, "packages"); + if (array == NULL) { + rv = ENOENT; + goto out; + } + if ((rv = set_new_state(pkgd, state)) != 0) { + prop_object_release(pkgd); + goto out; + } + if (newpkg && !xbps_add_obj_to_array(array, pkgd)) { + prop_object_release(pkgd); + rv = EINVAL; + goto out; + } + } + + if (!prop_dictionary_externalize_to_file(dict, plist)) + rv = errno; + +out: + prop_object_release(dict); + free(plist); + + return rv; +} diff --git a/lib/unpack.c b/lib/unpack.c index d6ead40558d..b33d7e08eb5 100644 --- a/lib/unpack.c +++ b/lib/unpack.c @@ -35,13 +35,14 @@ #include -static int unpack_archive_fini(struct archive *, prop_dictionary_t); +static int unpack_archive_fini(struct archive *, prop_dictionary_t, bool); int -xbps_unpack_binary_pkg(prop_dictionary_t pkg) +xbps_unpack_binary_pkg(prop_dictionary_t pkg, bool essential) { prop_string_t filename, repoloc, arch; struct archive *ar; + const char *pkgname; char *binfile; int pkg_fd, rv = 0; @@ -50,6 +51,7 @@ xbps_unpack_binary_pkg(prop_dictionary_t pkg) /* * Append filename to the full path for binary pkg. */ + prop_dictionary_get_cstring_nocopy(pkg, "pkgname", &pkgname); filename = prop_dictionary_get(pkg, "filename"); arch = prop_dictionary_get(pkg, "architecture"); repoloc = prop_dictionary_get(pkg, "repository"); @@ -74,7 +76,9 @@ xbps_unpack_binary_pkg(prop_dictionary_t pkg) goto out2; } - /* Enable support for tar format and all compression methods */ + /* + * Enable support for tar format and all compression methods. + */ archive_read_support_compression_all(ar); archive_read_support_format_tar(ar); @@ -82,15 +86,14 @@ xbps_unpack_binary_pkg(prop_dictionary_t pkg) ARCHIVE_READ_BLOCKSIZE)) != 0) goto out3; - rv = unpack_archive_fini(ar, pkg); + rv = unpack_archive_fini(ar, pkg, essential); /* * If installation of package was successful, make sure the package * is really on storage (if possible). */ if (rv == 0) - if (fsync(pkg_fd) == -1) + if (fdatasync(pkg_fd) == -1) rv = errno; - out3: archive_read_finish(ar); out2: @@ -98,31 +101,39 @@ out2: out: free(binfile); + if (rv == 0) { + /* + * Set package state to unpacked. + */ + rv = xbps_set_pkg_state_installed(pkgname, + XBPS_PKG_STATE_UNPACKED); + } + return rv; } /* - * Flags for extracting files in binary packages. + * Flags for extracting files in binary packages. If a package + * is marked as "essential", its files will be overwritten and then + * the old and new dictionaries are compared to find out if there + * are some files that were in the old package that should be removed. */ #define EXTRACT_FLAGS ARCHIVE_EXTRACT_SECURE_NODOTDOT | \ - ARCHIVE_EXTRACT_SECURE_SYMLINKS | \ - ARCHIVE_EXTRACT_NO_OVERWRITE | \ - ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER + ARCHIVE_EXTRACT_SECURE_SYMLINKS #define FEXTRACT_FLAGS ARCHIVE_EXTRACT_OWNER | ARCHIVE_EXTRACT_PERM | \ ARCHIVE_EXTRACT_TIME | EXTRACT_FLAGS - /* * TODO: remove printfs and return appropiate errors to be interpreted by * the consumer. */ static int -unpack_archive_fini(struct archive *ar, prop_dictionary_t pkg) +unpack_archive_fini(struct archive *ar, prop_dictionary_t pkg, + bool essential) { struct archive_entry *entry; - const char *prepost = "./INSTALL"; const char *pkgname, *version, *rootdir; - char *buf; - int rv = 0, flags = 0, lflags = 0; + char *buf, *buf2; + int rv = 0, flags, lflags; bool actgt = false; assert(ar != NULL); @@ -130,6 +141,10 @@ unpack_archive_fini(struct archive *ar, prop_dictionary_t pkg) rootdir = xbps_get_rootdir(); flags = xbps_get_flags(); + /* + * First we change to the destination directory or / if + * not specified. + */ if (strcmp(rootdir, "") == 0) rootdir = "/"; @@ -144,38 +159,72 @@ unpack_archive_fini(struct archive *ar, prop_dictionary_t pkg) else lflags = EXTRACT_FLAGS; - buf = xbps_xasprintf(".%s/metadata/%s/INSTALL", - XBPS_META_PATH, pkgname); - if (buf == NULL) - return errno; + if (essential == false) { + lflags |= ARCHIVE_EXTRACT_NO_OVERWRITE; + lflags |= ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER; + } while (archive_read_next_header(ar, &entry) == ARCHIVE_OK) { /* - * Run the pre installation action target if there's a script - * before writing data to disk. + * Run the pre INSTALL action if the file is there. */ - if (strcmp(prepost, archive_entry_pathname(entry)) == 0) { - actgt = true; - printf("\n"); - (void)fflush(stdout); + if (strcmp("./INSTALL", archive_entry_pathname(entry)) == 0) { + buf = xbps_xasprintf(".%s/metadata/%s/INSTALL", + XBPS_META_PATH, pkgname); + if (buf == NULL) + return errno; + actgt = true; archive_entry_set_pathname(entry, buf); if (archive_read_extract(ar, entry, lflags) != 0) { - if ((rv = archive_errno(ar)) != EEXIST) - break; + if ((rv = archive_errno(ar)) != EEXIST) { + free(buf); + return rv; + } } if ((rv = xbps_file_chdir_exec(rootdir, buf, "pre", pkgname, version, NULL)) != 0) { + free(buf); printf("%s: preinst action target error %s\n", pkgname, strerror(errno)); - (void)fflush(stdout); - break; + return rv; } - /* pass to the next entry if successful */ + free(buf); continue; + + /* + * Unpack metadata files (REMOVE, files.plist and props.plist) + * into the proper path. + */ + } else if (strcmp("./REMOVE", + archive_entry_pathname(entry)) == 0) { + buf2 = xbps_xasprintf(".%s/metadata/%s/REMOVE", + XBPS_META_PATH, pkgname); + if (buf2 == NULL) + return errno; + archive_entry_set_pathname(entry, buf2); + free(buf2); + buf2 = NULL; + } else if (strcmp("./files.plist", + archive_entry_pathname(entry)) == 0) { + buf2 = xbps_xasprintf(".%s/metadata/%s/files.plist", + XBPS_META_PATH, pkgname); + if (buf2 == NULL) + return errno; + archive_entry_set_pathname(entry, buf2); + free(buf2); + buf2 = NULL; + } else if (strcmp("./props.plist", + archive_entry_pathname(entry)) == 0) { + buf2 = xbps_xasprintf(".%s/metadata/%s/props.plist", + XBPS_META_PATH, pkgname); + if (buf2 == NULL) + return errno; + archive_entry_set_pathname(entry, buf2); + free(buf2); } /* * Extract all data from the archive now. @@ -185,14 +234,12 @@ unpack_archive_fini(struct archive *ar, prop_dictionary_t pkg) if (rv != EEXIST) { printf("ERROR: %s...exiting!\n", archive_error_string(ar)); - (void)fflush(stdout); - break; + return rv;; } else if (rv == EEXIST) { if (flags & XBPS_VERBOSE) { printf("WARNING: ignoring existent " "path: %s\n", archive_entry_pathname(entry)); - (void)fflush(stdout); } rv = 0; continue; @@ -204,20 +251,5 @@ unpack_archive_fini(struct archive *ar, prop_dictionary_t pkg) } } - if (rv == 0 && actgt) { - /* - * Run the post installaction action target, if package - * contains the script. - */ - if ((rv = xbps_file_chdir_exec(rootdir, buf, "post", - pkgname, version, NULL)) != 0) { - printf("%s: postinst action target error %s\n", - pkgname, strerror(errno)); - (void)fflush(stdout); - } - } - - free(buf); - return rv; } diff --git a/lib/util.c b/lib/util.c index 03f64859af3..c85e4706da2 100644 --- a/lib/util.c +++ b/lib/util.c @@ -116,6 +116,7 @@ xbps_check_is_installed_pkg(const char *pkg) const char *reqver, *instver; char *pkgname; int rv = 0; + pkg_state_t state = 0; assert(pkg != NULL); @@ -125,16 +126,28 @@ xbps_check_is_installed_pkg(const char *pkg) dict = xbps_find_pkg_installed_from_plist(pkgname); if (dict == NULL) { free(pkgname); - return -2; /* not installed */ + return -1; /* not installed */ } + /* + * Check that package state is fully installed, not + * unpacked or something else. + */ + if (xbps_get_pkg_state_installed(pkgname, &state) != 0) { + free(pkgname); + return -1; + } + free(pkgname); + + if (state != XBPS_PKG_STATE_INSTALLED) + return -1; + /* Get version from installed package */ prop_dictionary_get_cstring_nocopy(dict, "version", &instver); /* Compare installed and required version. */ rv = xbps_cmpver(instver, reqver); - free(pkgname); prop_object_release(dict); return rv; diff --git a/shutils/make-binpkg.sh b/shutils/make-binpkg.sh index 1cf1bbf8192..bcd983e5d99 100644 --- a/shutils/make-binpkg.sh +++ b/shutils/make-binpkg.sh @@ -51,6 +51,7 @@ xbps_make_binpkg() xbps_make_binpkg_real() { local binpkg pkgdir arch use_sudo lver + local tar_flags="cfp" if [ ! -d ${DESTDIR} ]; then echo "$pkgname: unexistent destdir... skipping!" @@ -79,25 +80,39 @@ xbps_make_binpkg_real() binpkg=$pkgname-$lver.$arch.xbps pkgdir=$XBPS_PACKAGESDIR/$arch + # + # Make sure that INSTALL is the first file on the archive, + # this is to ensure that it's run before any other file is + # unpacked. + # if [ -x ./INSTALL ]; then - # - # Make sure that INSTALL is the first file on the archive, - # this is to ensure that it's run before any other file is - # unpacked. - # - run_rootcmd $use_sudo tar cfp \ - $XBPS_BUILDDIR/$binpkg ./INSTALL && \ - run_rootcmd $use_sudo tar rfp $XBPS_BUILDDIR/$binpkg . \ - --exclude "./INSTALL" \ - --exclude "./var/db/xbps/metadata/*/flist" && \ - bzip2 -9 $XBPS_BUILDDIR/$binpkg && \ - mv $XBPS_BUILDDIR/$binpkg.bz2 $XBPS_BUILDDIR/$binpkg - else - run_rootcmd $use_sudo tar cfp $XBPS_BUILDDIR/$binpkg . \ - --exclude "./var/db/xbps/metadata/*/flist" && \ - bzip2 -9 $XBPS_BUILDDIR/$binpkg && \ - mv $XBPS_BUILDDIR/$binpkg.bz2 $XBPS_BUILDDIR/$binpkg + run_rootcmd $use_sudo tar $tar_flags \ + $XBPS_BUILDDIR/$binpkg ./INSTALL + [ $? -ne 0 ] && msg_error "Failed to add INSTALL script." fi + if [ -x ./REMOVE ]; then + if [ -x ./INSTALL ]; then + tar_flags="rfp" + fi + run_rootcmd $use_sudo tar $tar_flags \ + $XBPS_BUILDDIR/$binpkg ./REMOVE + [ $? -ne 0 ] && msg_error "Failed to add REMOVE script." + fi + if [ -x ./INSTALL -o -x ./REMOVE ]; then + tar_flags="rfp" + elif [ ! -x ./INSTALL -o ! -x ./REMOVE ]; then + tar_flags="cfp" + fi + run_rootcmd $use_sudo tar $tar_flags $XBPS_BUILDDIR/$binpkg \ + ./files.plist ./props.plist + [ $? -ne 0 ] && msg_error "Failed to add metadata files." + + run_rootcmd $use_sudo tar rfp $XBPS_BUILDDIR/$binpkg . \ + --exclude "./INSTALL" --exclude "./REMOVE" \ + --exclude "./files.plist" --exclude "./props.plist" \ + --exclude "./var/db/xbps/metadata/*/flist" && \ + bzip2 -9 $XBPS_BUILDDIR/$binpkg && \ + mv $XBPS_BUILDDIR/$binpkg.bz2 $XBPS_BUILDDIR/$binpkg if [ $? -eq 0 ]; then [ ! -d $pkgdir ] && mkdir -p $pkgdir mv -f $XBPS_BUILDDIR/$binpkg $pkgdir diff --git a/shutils/metadata.sh b/shutils/metadata.sh index 7158074fb1e..e778e63bf94 100644 --- a/shutils/metadata.sh +++ b/shutils/metadata.sh @@ -346,12 +346,12 @@ _EOF else rm -f $TMPFLIST fi - mv -f $TMPFPLIST $metadir/files.plist - mv -f $TMPFPROPS $metadir/props.plist + mv -f $TMPFPLIST ${DESTDIR}/files.plist + mv -f $TMPFPROPS ${DESTDIR}/props.plist - $XBPS_REGPKGDB_CMD sanitize-plist $metadir/files.plist - $XBPS_REGPKGDB_CMD sanitize-plist $metadir/props.plist - chmod 644 $metadir/* + $XBPS_REGPKGDB_CMD sanitize-plist ${DESTDIR}/files.plist + $XBPS_REGPKGDB_CMD sanitize-plist ${DESTDIR}/props.plist + chmod 644 ${DESTDIR}/files.plist ${DESTDIR}/props.plist # # Update desktop-file-utils database if package contains diff --git a/shutils/metadata_scripts.sh b/shutils/metadata_scripts.sh index 85d7a8c1e10..126c4d65b2c 100644 --- a/shutils/metadata_scripts.sh +++ b/shutils/metadata_scripts.sh @@ -26,7 +26,6 @@ xbps_write_metadata_scripts_pkg() { local action="$1" - local metadir="${DESTDIR}/var/db/xbps/metadata/$pkgname" local tmpf=$(mktemp -t xbps-install.XXXXXXXXXX) || exit 1 local fpattern="s|${DESTDIR}||g;s|^\./$||g;/^$/d" local targets found info_files @@ -217,7 +216,7 @@ _EOF rm -f $tmpf return 0 fi - mv $tmpf ${metadir}/REMOVE && chmod 755 ${metadir}/REMOVE + mv $tmpf ${DESTDIR}/REMOVE && chmod 755 ${DESTDIR}/REMOVE ;; esac }