diff --git a/bin/xbps-bin/install.c b/bin/xbps-bin/install.c index 291c9becaa..01450c69f9 100644 --- a/bin/xbps-bin/install.c +++ b/bin/xbps-bin/install.c @@ -415,10 +415,7 @@ exec_transaction(struct transaction *trans) */ 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); - - if ((rv = xbps_configure_pkg(pkgname, version)) != 0) { + if ((rv = xbps_configure_pkg(pkgname)) != 0) { printf("Error configuring package %s-%s\n", pkgname, version); return rv; diff --git a/bin/xbps-bin/main.c b/bin/xbps-bin/main.c index 93514348c2..1aa9f36cb8 100644 --- a/bin/xbps-bin/main.c +++ b/bin/xbps-bin/main.c @@ -42,31 +42,23 @@ usage(void) printf("Usage: xbps-bin [options] [target] [arguments]\n\n" " Available targets:\n" " autoremove, autoupdate, check, files, install, list\n" - " remove, show, update\n" + " purge, remove, show, update\n" " Targets with arguments:\n" " check\t\n" " files\t\n" " install\t\n" + " purge\t[|]\n" + " reconfigure\t[|]\n" " remove\t\n" " show\t\n" " update\t\n" " Options shared by all targets:\n" " -r\t\t\n" " -v\t\t\n" - " Options used by the (auto)remove target:\n" + " Options used by the (auto)remove and install target:\n" " -f\t\tForce installation or removal of packages.\n" " \t\tBeware with this option if you use autoremove!\n" - "\n" - " Examples:\n" - " $ xbps-bin autoremove\n" - " $ xbps-bin autoupdate\n" - " $ xbps-bin files klibc\n" - " $ xbps-bin install klibc\n" - " $ xbps-bin -r /path/to/root install klibc\n" - " $ xbps-bin list\n" - " $ xbps-bin -f remove klibc\n" - " $ xbps-bin show klibc\n" - " $ xbps-bin update klibc\n"); + "\n"); exit(EXIT_FAILURE); } @@ -95,12 +87,16 @@ int main(int argc, char **argv) { prop_dictionary_t dict; + prop_object_t obj; + prop_object_iterator_t iter; + const char *curpkgname; int c, flags = 0, rv = 0; bool force = false, verbose = false; while ((c = getopt(argc, argv, "Cfr:v")) != -1) { switch (c) { case 'f': + flags |= XBPS_FLAG_FORCE; force = true; break; case 'r': @@ -221,6 +217,52 @@ main(int argc, char **argv) xbps_autoremove_pkgs(); + } else if (strcasecmp(argv[0], "purge") == 0) { + /* + * Purge a package completely. + */ + if (argc != 2) + usage(); + + if (strcasecmp(argv[1], "all") == 0) { + iter = xbps_get_array_iter_from_dict(dict, "packages"); + if (iter == NULL) + goto out; + + while ((obj = prop_object_iterator_next(iter))) { + prop_dictionary_get_cstring_nocopy(obj, + "pkgname", &curpkgname); + if ((rv = xbps_purge_pkg(curpkgname)) != 0) + break; + } + prop_object_iterator_release(iter); + } else { + rv = xbps_purge_pkg(argv[1]); + } + + } else if (strcasecmp(argv[0], "reconfigure") == 0) { + /* + * Reconfigure a package. + */ + if (argc != 2) + usage(); + + if (strcasecmp(argv[1], "all") == 0) { + iter = xbps_get_array_iter_from_dict(dict, "packages"); + if (iter == NULL) + goto out; + + while ((obj = prop_object_iterator_next(iter))) { + prop_dictionary_get_cstring_nocopy(obj, + "pkgname", &curpkgname); + if ((rv = xbps_configure_pkg(curpkgname)) != 0) + break; + } + prop_object_iterator_release(iter); + } else { + rv = xbps_configure_pkg(argv[1]); + } + } else { usage(); } diff --git a/bin/xbps-bin/remove.c b/bin/xbps-bin/remove.c index 3dcc3d57de..6ea2e529ac 100644 --- a/bin/xbps-bin/remove.c +++ b/bin/xbps-bin/remove.c @@ -152,7 +152,6 @@ xbps_remove_installed_pkg(const char *pkgname, bool force) pkgname, version, strerror(errno)); goto out; } - printf("Package %s-%s removed successfully.\n", pkgname, version); out: xbps_release_regpkgdb_dict(); diff --git a/include/xbps_api.h b/include/xbps_api.h index 35c5ceafc1..62e362c69d 100644 --- a/include/xbps_api.h +++ b/include/xbps_api.h @@ -68,7 +68,7 @@ #endif /* From lib/configure.c */ -int xbps_configure_pkg(const char *, const char *); +int xbps_configure_pkg(const char *); /* from lib/cmpver.c */ int xbps_cmpver(const char *, const char *); @@ -103,19 +103,12 @@ int xbps_prepare_repolist_data(void); void xbps_release_repolist_data(void); prop_dictionary_t xbps_get_pkg_props(void); -/* From lib/register.c */ -int xbps_register_pkg(prop_dictionary_t, bool); - -/* From lib/requiredby.c */ -int xbps_requiredby_pkg_add(prop_array_t, prop_dictionary_t); -int xbps_requiredby_pkg_remove(const char *); - -/* From lib/unpack.c */ -int xbps_unpack_binary_pkg(prop_dictionary_t, bool); - /* From lib/depends.c */ int xbps_find_deps_in_pkg(prop_dictionary_t, prop_dictionary_t); +/* From lib/orphans.c */ +prop_array_t xbps_find_orphan_packages(void); + /* From lib/plist.c */ bool xbps_add_obj_to_dict(prop_dictionary_t, prop_object_t, const char *); @@ -151,14 +144,24 @@ int xbps_remove_pkg_from_dict(prop_dictionary_t, const char *, const char *); int xbps_remove_string_from_array(prop_array_t, const char *); +/* From lib/purge.c */ +int xbps_purge_pkg(const char *); + +/* From lib/register.c */ +int xbps_register_pkg(prop_dictionary_t, bool); +int xbps_unregister_pkg(const char *); + /* From lib/remove.c */ int xbps_remove_pkg(const char *, const char *, bool); -int xbps_unregister_pkg(const char *); /* From lib/repository.c */ int xbps_register_repository(const char *); int xbps_unregister_repository(const char *); +/* From lib/requiredby.c */ +int xbps_requiredby_pkg_add(prop_array_t, prop_dictionary_t); +int xbps_requiredby_pkg_remove(const char *); + /* From lib/sortdeps.c */ int xbps_sort_pkg_deps(prop_dictionary_t); @@ -175,6 +178,9 @@ int xbps_get_pkg_state_dictionary(prop_dictionary_t, pkg_state_t *); int xbps_set_pkg_state_installed(const char *, pkg_state_t); int xbps_set_pkg_state_dictionary(prop_dictionary_t, pkg_state_t); +/* From lib/unpack.c */ +int xbps_unpack_binary_pkg(prop_dictionary_t, bool); + /* From lib/util.c */ char * xbps_xasprintf(const char *, ...); char * xbps_get_file_hash(const char *); @@ -194,7 +200,4 @@ int xbps_get_flags(void); bool xbps_yesno(const char *, ...); bool xbps_noyes(const char *, ...); -/* From lib/orphans.c */ -prop_array_t xbps_find_orphan_packages(void); - #endif /* !_XBPS_API_H_ */ diff --git a/lib/Makefile b/lib/Makefile index d61706a4cf..e4cfda19cd 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -10,9 +10,9 @@ LIBXBPS_STATIC = libxbps.a LIBXBPS_LDFLAGS = -larchive -lprop -shared -Wl,-soname,$(LIBXBPS).$(MAJOR) 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 +OBJECTS += humanize_number.o orphans.o plist.o purge.o register.o remove.o +OBJECTS += repository.o requiredby.o sha256.o sortdeps.o state.o unpack.o +OBJECTS += util.o all: $(LIBXBPS) $(LIBXBPS_STATIC) .PHONY: all diff --git a/lib/configure.c b/lib/configure.c index ce700e85dd..8a695a3e72 100644 --- a/lib/configure.c +++ b/lib/configure.c @@ -36,29 +36,41 @@ * package state to installed. */ int -xbps_configure_pkg(const char *pkgname, const char *version) +xbps_configure_pkg(const char *pkgname) { - const char *rootdir; + prop_dictionary_t pkgd; + const char *rootdir, *version; char *buf; - int rv = 0; + int rv = 0, flags = 0; pkg_state_t state = 0; assert(pkgname != NULL); - assert(version != NULL); + rootdir = xbps_get_rootdir(); + flags = xbps_get_flags(); 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) + if (state == XBPS_PKG_STATE_INSTALLED) { + if ((flags & XBPS_FLAG_FORCE) == 0) + return 0; + } else if (state != XBPS_PKG_STATE_UNPACKED) return EINVAL; + pkgd = xbps_find_pkg_installed_from_plist(pkgname); + prop_dictionary_get_cstring_nocopy(pkgd, "version", &version); + prop_object_release(pkgd); + + printf("%sonfiguring package %s-%s...\n", + flags & XBPS_FLAG_FORCE ? "Rec" : "C", pkgname, version); + + if (strcmp(rootdir, "") == 0) + rootdir = "/"; + + if (chdir(rootdir) == -1) + return errno; + buf = xbps_xasprintf(".%s/metadata/%s/INSTALL", XBPS_META_PATH, pkgname); if (buf == NULL) diff --git a/lib/plist.c b/lib/plist.c index 637a6c046b..15f164ae7a 100644 --- a/lib/plist.c +++ b/lib/plist.c @@ -192,6 +192,7 @@ xbps_find_pkg_from_plist(const char *plist, const char *pkgname) prop_dictionary_t xbps_find_pkg_installed_from_plist(const char *pkgname) { + pkg_state_t state = 0; prop_dictionary_t pkgd; if (regpkgdb_initialized == false) @@ -201,7 +202,16 @@ xbps_find_pkg_installed_from_plist(const char *pkgname) if (pkgd == NULL) return NULL; - return prop_dictionary_copy(pkgd); + if (xbps_get_pkg_state_installed(pkgname, &state) != 0) + return NULL; + + switch (state) { + case XBPS_PKG_STATE_INSTALLED: + case XBPS_PKG_STATE_UNPACKED: + return prop_dictionary_copy(pkgd); + default: + return NULL; + } } prop_dictionary_t diff --git a/lib/purge.c b/lib/purge.c new file mode 100644 index 0000000000..8b307551b0 --- /dev/null +++ b/lib/purge.c @@ -0,0 +1,203 @@ +/*- + * 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 + +static int remove_pkg_metadata(const char *); + +/* + * Purge a package that is currently in "config-files" state. + * This removes configuration files if they weren't modified, + * removes metadata files and fully unregisters the package. + */ +int +xbps_purge_pkg(const char *pkgname) +{ + prop_dictionary_t dict; + prop_array_t array; + prop_object_t obj; + prop_object_iterator_t iter; + const char *rootdir, *file, *sha256; + char *path; + int rv = 0, flags; + pkg_state_t state = 0; + + assert(pkgname != NULL); + rootdir = xbps_get_rootdir(); + flags = xbps_get_flags(); + + /* + * Skip packages that aren't in "config-files" state. + */ + if ((rv = xbps_get_pkg_state_installed(pkgname, &state)) != 0) + return rv; + + if (state != XBPS_PKG_STATE_CONFIG_FILES) + return 0; + + /* + * Iterate over the pkg file list dictionary and remove all + * unmodified configuration files. + */ + path = xbps_xasprintf("%s/%s/metadata/%s/%s", + rootdir, XBPS_META_PATH, pkgname, XBPS_PKGFILES); + if (path == NULL) + return errno; + + dict = prop_dictionary_internalize_from_file(path); + if (dict == NULL) { + free(path); + return errno; + } + free(path); + + array = prop_dictionary_get(dict, "conf_files"); + if (array == NULL) { + goto out; + } else if (prop_object_type(array) != PROP_TYPE_ARRAY) { + prop_object_release(dict); + return EINVAL; + } else if (prop_array_count(array) == 0) { + goto out; + } + + iter = xbps_get_array_iter_from_dict(dict, "conf_files"); + if (iter == NULL) + return EINVAL; + + while ((obj = prop_object_iterator_next(iter))) { + if (!prop_dictionary_get_cstring_nocopy(obj, "file", &file)) { + prop_object_iterator_release(iter); + prop_object_release(dict); + return EINVAL; + } + path = xbps_xasprintf("%s/%s", rootdir, file); + if (path == NULL) { + prop_object_iterator_release(iter); + prop_object_release(dict); + return EINVAL; + } + prop_dictionary_get_cstring_nocopy(obj, "sha256", &sha256); + rv = xbps_check_file_hash(path, sha256); + if (rv == ENOENT) { + printf("Configuration file %s doesn't exist!\n", file); + free(path); + continue; + } else if (rv == ERANGE) { + if (flags & XBPS_FLAG_VERBOSE) + printf("Configuration file %s has been " + "modified, preserving...\n", file); + + free(path); + continue; + } else if (rv != 0 && rv != ERANGE) { + free(path); + prop_object_iterator_release(iter); + prop_object_release(dict); + return rv; + } + if ((rv = remove(path)) == -1) { + if (flags & XBPS_FLAG_VERBOSE) + printf("WARNING: can't remove %s (%s)\n", + file, strerror(errno)); + + free(path); + continue; + } + if (flags & XBPS_FLAG_VERBOSE) + printf("Removed configuration file %s\n", file); + + free(path); + } + + prop_object_iterator_release(iter); +out: + prop_object_release(dict); + + if ((rv = remove_pkg_metadata(pkgname)) == 0) { + if ((rv = xbps_unregister_pkg(pkgname)) == 0) + printf("Package %s has been purged successfully.\n", + pkgname); + } + + return rv; +} + +static int +remove_pkg_metadata(const char *pkgname) +{ + struct dirent *dp; + DIR *dirp; + const char *rootdir; + char *metadir, *path; + int flags = 0, rv = 0; + + assert(pkgname != NULL); + + rootdir = xbps_get_rootdir(); + flags = xbps_get_flags(); + + metadir = xbps_xasprintf("%s/%s/metadata/%s", rootdir, + XBPS_META_PATH, pkgname); + if (metadir == NULL) + return errno; + + dirp = opendir(metadir); + if (dirp == NULL) { + free(metadir); + return errno; + } + + while ((dp = readdir(dirp)) != NULL) { + if ((strcmp(dp->d_name, ".") == 0) || + (strcmp(dp->d_name, "..") == 0)) + continue; + + path = xbps_xasprintf("%s/%s", metadir, dp->d_name); + if (path == NULL) { + (void)closedir(dirp); + free(metadir); + return -1; + } + + if ((rv = unlink(path)) == -1) { + if (flags & XBPS_FLAG_VERBOSE) + printf("WARNING: can't remove %s (%s)\n", + pkgname, strerror(errno)); + } + free(path); + } + (void)closedir(dirp); + rv = rmdir(metadir); + free(metadir); + + return rv; +} diff --git a/lib/register.c b/lib/register.c index e8859c5482..43a0be0d34 100644 --- a/lib/register.c +++ b/lib/register.c @@ -91,3 +91,24 @@ out: return rv; } + +int +xbps_unregister_pkg(const char *pkgname) +{ + const char *rootdir; + char *plist; + int rv = 0; + + assert(pkgname != NULL); + + rootdir = xbps_get_rootdir(); + plist = xbps_xasprintf("%s/%s/%s", rootdir, + XBPS_META_PATH, XBPS_REGPKGDB); + if (plist == NULL) + return EINVAL; + + rv = xbps_remove_pkg_dict_from_file(pkgname, plist); + free(plist); + + return rv; +} diff --git a/lib/remove.c b/lib/remove.c index 329666c3db..ad3c8fb597 100644 --- a/lib/remove.c +++ b/lib/remove.c @@ -34,78 +34,6 @@ static int remove_pkg_files(prop_dictionary_t); -int -xbps_unregister_pkg(const char *pkgname) -{ - const char *rootdir; - char *plist; - int rv = 0; - - assert(pkgname != NULL); - - rootdir = xbps_get_rootdir(); - plist = xbps_xasprintf("%s/%s/%s", rootdir, - XBPS_META_PATH, XBPS_REGPKGDB); - if (plist == NULL) - return EINVAL; - - rv = xbps_remove_pkg_dict_from_file(pkgname, plist); - free(plist); - - return rv; -} - -static int -remove_pkg_metadir(const char *pkgname) -{ - struct dirent *dp; - DIR *dirp; - const char *rootdir; - char *metadir, *path; - int flags = 0, rv = 0; - - assert(pkgname != NULL); - - rootdir = xbps_get_rootdir(); - flags = xbps_get_flags(); - - metadir = xbps_xasprintf("%s/%s/metadata/%s", rootdir, - XBPS_META_PATH, pkgname); - if (metadir == NULL) - return errno; - - dirp = opendir(metadir); - if (dirp == NULL) { - free(metadir); - return errno; - } - - while ((dp = readdir(dirp)) != NULL) { - if ((strcmp(dp->d_name, ".") == 0) || - (strcmp(dp->d_name, "..") == 0)) - continue; - - path = xbps_xasprintf("%s/%s", metadir, dp->d_name); - if (path == NULL) { - (void)closedir(dirp); - free(metadir); - return -1; - } - - if ((rv = unlink(path)) == -1) { - if (flags & XBPS_FLAG_VERBOSE) - printf("WARNING: can't remove %s (%s)\n", - pkgname, strerror(errno)); - } - free(path); - } - (void)closedir(dirp); - rv = rmdir(metadir); - free(metadir); - - return rv; -} - static int remove_pkg_files(prop_dictionary_t dict) { @@ -113,9 +41,9 @@ remove_pkg_files(prop_dictionary_t dict) prop_object_iterator_t iter; prop_object_t obj; prop_bool_t bobj; - const char *file, *rootdir, *sha256, *array_str, *curftype; + const char *file, *rootdir, *sha256; char *path = NULL; - int i, flags = 0, rv = 0; + int flags = 0, rv = 0; rootdir = xbps_get_rootdir(); flags = xbps_get_flags(); @@ -155,73 +83,58 @@ remove_pkg_files(prop_dictionary_t dict) path = NULL; files: - /* Regular files and configuration files */ - for (i = 0; i < 2; i++) { - if (i == 0) { - array_str = "conf_files"; - curftype = "config file"; - } else { - array_str = "files"; - curftype = "file"; - } - array = prop_dictionary_get(dict, array_str); - if (array == NULL || prop_array_count(array) == 0) { - if (i == 0) - continue; - else - goto dirs; - } - iter = xbps_get_array_iter_from_dict(dict, array_str); - if (iter == NULL) - return EINVAL; + /* Regular files */ + array = prop_dictionary_get(dict, "files"); + if (array == NULL || prop_array_count(array) == 0) + goto dirs; - while ((obj = prop_object_iterator_next(iter))) { - if (!prop_dictionary_get_cstring_nocopy(obj, - "file", &file)) { - prop_object_iterator_release(iter); - return EINVAL; - } - path = xbps_xasprintf("%s/%s", rootdir, file); - if (path == NULL) { - prop_object_iterator_release(iter); - return EINVAL; - } - prop_dictionary_get_cstring_nocopy(obj, - "sha256", &sha256); - rv = xbps_check_file_hash(path, sha256); - if (rv == ENOENT) { - printf("WARNING: '%s' doesn't exist!\n", - file); - free(path); - continue; - } else if (rv == ERANGE) { - if (flags & XBPS_FLAG_VERBOSE) - printf("WARNING: SHA256 doesn't match " - "for %s %s, ignoring...\n", - curftype, file); - free(path); - continue; - } else if (rv != 0 && rv != ERANGE) { - free(path); - prop_object_iterator_release(iter); - return rv; - } - if ((rv = remove(path)) == -1) { - if (flags & XBPS_FLAG_VERBOSE) - printf("WARNING: can't remove " - "%s %s (%s)\n", curftype, file, - strerror(errno)); - free(path); - continue; - } + iter = xbps_get_array_iter_from_dict(dict, "files"); + if (iter == NULL) + return EINVAL; + + while ((obj = prop_object_iterator_next(iter))) { + if (!prop_dictionary_get_cstring_nocopy(obj, "file", &file)) { + prop_object_iterator_release(iter); + return EINVAL; + } + path = xbps_xasprintf("%s/%s", rootdir, file); + if (path == NULL) { + prop_object_iterator_release(iter); + return EINVAL; + } + prop_dictionary_get_cstring_nocopy(obj, "sha256", &sha256); + rv = xbps_check_file_hash(path, sha256); + if (rv == ENOENT) { + printf("WARNING: '%s' doesn't exist!\n", file); + free(path); + continue; + } else if (rv == ERANGE) { if (flags & XBPS_FLAG_VERBOSE) - printf("Removed %s: %s\n", curftype, file); + printf("WARNING: SHA256 doesn't match " + "for file %s, ignoring...\n", file); free(path); + continue; + } else if (rv != 0 && rv != ERANGE) { + free(path); + prop_object_iterator_release(iter); + return rv; } - prop_object_iterator_release(iter); - path = NULL; + if ((rv = remove(path)) == -1) { + if (flags & XBPS_FLAG_VERBOSE) + printf("WARNING: can't remove file %s (%s)\n", + file, strerror(errno)); + + free(path); + continue; + } + if (flags & XBPS_FLAG_VERBOSE) + printf("Removed file: %s\n", file); + + free(path); } + prop_object_iterator_release(iter); + path = NULL; dirs: /* Directories */ @@ -362,20 +275,14 @@ xbps_remove_pkg(const char *pkgname, const char *version, bool update) /* * Update the requiredby array of all required dependencies. */ - rv = xbps_requiredby_pkg_remove(pkgname); - if (rv != 0) + if ((rv = xbps_requiredby_pkg_remove(pkgname)) != 0) return rv; - if (update == false) { - /* - * Unregister pkg from database. - */ - if ((rv = xbps_unregister_pkg(pkgname)) != 0) - return rv; - } - /* - * Remove pkg metadata directory. + * Set package state to "config-files". */ - return remove_pkg_metadir(pkgname); + rv = xbps_set_pkg_state_installed(pkgname, + XBPS_PKG_STATE_CONFIG_FILES); + + return rv; }