diff --git a/bin/xbps-bin/Makefile b/bin/xbps-bin/Makefile index aa1a060fc2c..5a5231716a0 100644 --- a/bin/xbps-bin/Makefile +++ b/bin/xbps-bin/Makefile @@ -8,7 +8,7 @@ all: $(BIN) .PHONY: all $(BIN): $(OBJS) - $(CC) $(LDFLAGS) $^ -o $@ + $(CC) -g $(LDFLAGS) $^ -o $@ .PHONY: clean clean: clean-bins clean-objs diff --git a/bin/xbps-pkgdb/main.c b/bin/xbps-pkgdb/main.c index 15ebc461c59..0fdc7033ea3 100644 --- a/bin/xbps-pkgdb/main.c +++ b/bin/xbps-pkgdb/main.c @@ -154,7 +154,7 @@ main(int argc, char **argv) if (dbdict == NULL) exit(EXIT_FAILURE); - pkgdict = xbps_find_pkg_in_dict(dbdict, argv[1]); + pkgdict = xbps_find_pkg_in_dict(dbdict, "packages", argv[1]); if (pkgdict == NULL) exit(EXIT_FAILURE); diff --git a/bin/xbps-repo/util.c b/bin/xbps-repo/util.c index 1a6f38e0ad4..f10b451dfd0 100644 --- a/bin/xbps-repo/util.c +++ b/bin/xbps-repo/util.c @@ -176,7 +176,7 @@ show_pkg_info_from_repolist(prop_object_t obj, void *arg, bool *loop_done) return EINVAL; } - pkgdict = xbps_find_pkg_in_dict(dict, arg); + pkgdict = xbps_find_pkg_in_dict(dict, "packages", arg); if (pkgdict == NULL) { prop_object_release(dict); free(plist); diff --git a/include/install.h b/include/install.h index 21ef5ded05d..eebec35c8d9 100644 --- a/include/install.h +++ b/include/install.h @@ -26,13 +26,15 @@ #ifndef _XBPS_INSTALL_H_ #define _XBPS_INSTALL_H_ -/* From lib/install.c and lib/depends.c */ -int xbps_install_pkg_deps(prop_dictionary_t); -int xbps_install_binary_pkg(const char *, const char *); -int xbps_install_binary_pkg_from_repolist(prop_object_t, void *, bool *); -int xbps_register_pkg(const char *, const char *, const char *); -int xbps_unpack_binary_pkg(prop_dictionary_t, prop_dictionary_t, - int (*cb)(struct archive *, prop_dictionary_t)); -int xbps_unpack_archive_cb(struct archive *, prop_dictionary_t); +/* From lib/install.c, lib/depends.c and lib/unpack.c */ +int xbps_install_pkg_deps(prop_dictionary_t); +int xbps_install_binary_pkg(const char *, const char *); +int xbps_install_binary_pkg_fini(prop_dictionary_t, prop_dictionary_t, + const char *); +int xbps_register_pkg(const char *, const char *, const char *); +int xbps_unpack_binary_pkg(prop_dictionary_t, prop_dictionary_t, + const char *, + void (*cb_print)(prop_dictionary_t)); +int xbps_find_deps_in_pkg(prop_dictionary_t, prop_dictionary_t); #endif /* !_XBPS_INSTALL_H_ */ diff --git a/include/plist.h b/include/plist.h index af672ef18ec..bfebe88a08e 100644 --- a/include/plist.h +++ b/include/plist.h @@ -57,7 +57,7 @@ xbps_callback_array_iter_in_dict(prop_dictionary_t, const char *, * Returns the package's dictionary object, otherwise NULL. */ prop_dictionary_t -xbps_find_pkg_in_dict(prop_dictionary_t, const char *); +xbps_find_pkg_in_dict(prop_dictionary_t, const char *, const char *); prop_dictionary_t xbps_find_pkg_from_plist(const char *, const char *); diff --git a/lib/Makefile b/lib/Makefile index edf506d2168..8705e5eea85 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -9,7 +9,7 @@ LIBXBPS = libxbps.so LIBXBPS_LDFLAGS = -larchive -lprop -shared -Wl,-soname,$(LIBXBPS).$(MAJOR) OBJECTS = cmpver.o depends.o humanize_number.o install.o plist.o -OBJECTS += sha256.o util.o repository.o fexec.o remove.o +OBJECTS += sha256.o util.o repository.o fexec.o remove.o unpack.o all: $(LIBXBPS) .PHONY: all diff --git a/lib/depends.c b/lib/depends.c index 1f6f9e7be68..86e2a6fc778 100644 --- a/lib/depends.c +++ b/lib/depends.c @@ -32,137 +32,301 @@ #include -struct pkg_dependency { - SIMPLEQ_ENTRY(pkg_dependency) deps; - prop_dictionary_t repo; - uint64_t priority; - uint64_t reqcount; - const char *namever; - char *name; -}; +static int add_missing_reqdep(const char *, const char *); +static int check_missing_reqdep(const char *, const char *, size_t *); +static void remove_missing_reqdep(size_t *); -static SIMPLEQ_HEAD(, pkg_dependency) pkg_deps = - SIMPLEQ_HEAD_INITIALIZER(pkg_deps); +static prop_dictionary_t chaindeps; -static void xbps_destroy_dependency(struct pkg_dependency *); - -void -xbps_clean_pkg_depslist(void) +/* + * Creates the dictionary to store the dependency chain. + */ +static int +create_deps_dictionary(void) { - struct pkg_dependency *dep; + prop_array_t installed, direct, indirect, missing; + int rv = 0; - while (!SIMPLEQ_EMPTY(&pkg_deps)) { - dep = SIMPLEQ_FIRST(&pkg_deps); - SIMPLEQ_REMOVE_HEAD(&pkg_deps, deps); - xbps_destroy_dependency(dep); - } -} + chaindeps = prop_dictionary_create(); + if (chaindeps == NULL) + return ENOMEM; -static struct pkg_dependency * -xbps_get_dependency(void) -{ - struct pkg_dependency *dep = NULL; - uint64_t reqcount = 0 , priority = 0; - - /* Set max reqcount and priority found */ - SIMPLEQ_FOREACH(dep, &pkg_deps, deps) { - if (dep->reqcount > reqcount) - reqcount = dep->reqcount; - if (dep->priority > priority) - priority = dep->priority; + missing = prop_array_create(); + if (missing == NULL) { + rv = ENOMEM; + goto fail; } - /* Pass 1: return pkgs with highest reqcount and priority */ - SIMPLEQ_FOREACH(dep, &pkg_deps, deps) - if (dep->reqcount == reqcount && dep->priority == priority) - goto out; - - /* Pass 2: return pkgs with highest priority */ - SIMPLEQ_FOREACH(dep, &pkg_deps, deps) - if (dep->priority == priority) - goto out; - - /* Pass 3: return pkgs with highest reqcount */ - SIMPLEQ_FOREACH(dep, &pkg_deps, deps) - if (dep->reqcount == reqcount) - goto out; - - /* Last pass: return pkgs with default reqcount/priority */ - dep = SIMPLEQ_FIRST(&pkg_deps); - -out: - if (dep != NULL) { - /* - * Remove dep from queue, it will be freed later with - * xbps_destroy_dependency(). - */ - SIMPLEQ_REMOVE(&pkg_deps, dep, pkg_dependency, deps); + installed = prop_array_create(); + if (installed == NULL) { + rv = ENOMEM; + goto fail2; } - return dep; -} - -static void -xbps_destroy_dependency(struct pkg_dependency *dep) -{ - assert(dep != NULL); - - free(dep->name); - prop_object_release(dep->repo); - free(dep); -} - -void -xbps_add_pkg_dependency(const char *pkg, uint64_t prio, prop_dictionary_t repo) -{ - struct pkg_dependency *dep; - size_t len = 0; - char *pkgname; - - assert(repo != NULL); - assert(pkg != NULL); - assert(pkgd != NULL); - - pkgname = xbps_get_pkg_name(pkg); - - SIMPLEQ_FOREACH(dep, &pkg_deps, deps) { - if (strcmp(dep->name, pkgname) == 0) { - dep->reqcount++; - free(pkgname); - return; - } + direct = prop_array_create(); + if (direct == NULL) { + rv = ENOMEM; + goto fail3; } - dep = NULL; - dep = malloc(sizeof(*dep)); - assert(dep != NULL); + indirect = prop_array_create(); + if (indirect == NULL) { + rv = ENOMEM; + goto fail4; + } - len = strlen(pkgname) + 1; - dep->name = malloc(len); - assert(dep->name != NULL); + if (!xbps_add_obj_to_dict(chaindeps, missing, "missing_deps")) { + rv = EINVAL; + goto fail5; + } + if (!xbps_add_obj_to_dict(chaindeps, installed, "installed_deps")) { + rv = EINVAL; + goto fail5; + } + if (!xbps_add_obj_to_dict(chaindeps, direct, "direct_deps")) { + rv = EINVAL; + goto fail5; + } + if (!xbps_add_obj_to_dict(chaindeps, indirect, "indirect_deps")) { + rv = EINVAL; + goto fail5; + } + return rv; - memcpy(dep->name, pkgname, len - 1); - dep->name[len - 1] = '\0'; - free(pkgname); - dep->repo = prop_dictionary_copy(repo); - dep->namever = pkg; - dep->priority = prio; - dep->reqcount = 0; +fail5: + prop_object_release(indirect); +fail4: + prop_object_release(direct); +fail3: + prop_object_release(installed); +fail2: + prop_object_release(missing); +fail: + prop_object_release(chaindeps); - SIMPLEQ_INSERT_TAIL(&pkg_deps, dep, deps); + return rv; } static int -find_deps_in_pkg(prop_dictionary_t repo, prop_dictionary_t pkg) +store_dependency(prop_dictionary_t origind, prop_dictionary_t depd, + prop_dictionary_t repod) +{ + prop_dictionary_t dict, curpkgdir, curpkgindir; + prop_array_t array; + uint32_t prio = 0; + size_t len = 0; + const char *pkgname, *version, *reqbyname, *reqbyver; + const char *repoloc, *binfile, *array_key = NULL, *originpkg; + char *reqby; + int rv = 0; + + assert(origind != NULL); + assert(depd != NULL); + assert(repod != NULL); + + /* + * Get some info about dependencies and current repository. + */ + prop_dictionary_get_cstring_nocopy(depd, "pkgname", &pkgname); + prop_dictionary_get_cstring_nocopy(depd, "version", &version); + prop_dictionary_get_cstring_nocopy(depd, "filename", &binfile); + prop_dictionary_get_uint32(depd, "priority", &prio); + prop_dictionary_get_cstring_nocopy(origind, "pkgname", &reqbyname); + prop_dictionary_get_cstring_nocopy(origind, "version", &reqbyver); + prop_dictionary_get_cstring_nocopy(repod, "location-local", &repoloc); + + len = strlen(reqbyname) + strlen(reqbyver) + 2; + reqby = malloc(len + 1); + if (reqby == NULL) + return ENOMEM; + + (void)snprintf(reqby, len, "%s-%s", reqbyname, reqbyver); + + /* + * Check if dependency is already installed to select the + * correct array object. + */ + if (xbps_check_is_installed_pkgname(pkgname)) { + /* + * Dependency is already installed. + */ + array_key = "installed_deps"; + dict = xbps_find_pkg_in_dict(chaindeps, array_key, pkgname); + if (dict) + goto out; + } else { + /* + * Required dependency is not installed. Check if it's + * already registered in the chain, and update priority + * or add the object into array otherwise. + */ + prop_dictionary_get_cstring_nocopy(chaindeps, "origin", + &originpkg); + curpkgdir = xbps_find_pkg_in_dict(chaindeps, + "direct_deps", pkgname); + curpkgindir = xbps_find_pkg_in_dict(chaindeps, + "indirect_deps", pkgname); + + if (strcmp(originpkg, reqbyname) == 0) + array_key = "direct_deps"; + else + array_key = "indirect_deps"; + + if (curpkgdir && curpkgindir) { + goto out; + + } else if (curpkgdir) { + /* + * Update the priority. + */ + prop_dictionary_get_uint32(curpkgdir, + "priority", &prio); + prop_dictionary_set_uint32(curpkgdir, + "priority", ++prio); + goto out; + } else if (curpkgindir) { + prop_dictionary_get_uint32(curpkgindir, + "priority", &prio); + prop_dictionary_set_uint32(curpkgindir, + "priority", ++prio); + goto out; + } + } + + /* + * Create package dep's dictionary and array. + */ + dict = prop_dictionary_create(); + if (dict == NULL) { + rv = ENOMEM; + goto out; + } + + array = prop_dictionary_get(chaindeps, array_key); + if (array == NULL) { + prop_object_release(dict); + rv = ENOENT; + goto out; + } + + /* + * Add required objects into package dep's dictionary. + */ + prop_dictionary_set_cstring(dict, "pkgname", pkgname); + prop_dictionary_set_cstring(dict, "version", version); + prop_dictionary_set_cstring(dict, "requiredby", reqby); + + if ((strcmp(array_key, "direct_deps") == 0) || + (strcmp(array_key, "indirect_deps") == 0)) { + prop_dictionary_set_cstring(dict, "repository", repoloc); + prop_dictionary_set_cstring(dict, "filename", binfile); + prop_dictionary_set_uint32(dict, "priority", prio); + } + /* + * Add the dictionary into the array. + */ + if (!xbps_add_obj_to_array(array, dict)) { + prop_object_release(dict); + rv = EINVAL; + goto out; + } + +out: + free(reqby); + + return rv; +} + +static int +add_missing_reqdep(const char *pkgname, const char *version) +{ + prop_array_t array; + prop_dictionary_t depd; + size_t idx = 0; + + assert(pkgname != NULL); + assert(version != NULL); + + if (check_missing_reqdep(pkgname, version, &idx) == 0) + return EEXIST; + + array = prop_dictionary_get(chaindeps, "missing_deps"); + depd = prop_dictionary_create(); + if (depd == NULL) + return ENOMEM; + + prop_dictionary_set_cstring_nocopy(depd, "pkgname", pkgname); + prop_dictionary_set_cstring_nocopy(depd, "version", version); + if (!xbps_add_obj_to_array(array, depd)) { + prop_object_release(depd); + return EINVAL; + } + + return 0; +} + +static int +check_missing_reqdep(const char *pkgname, const char *version, + size_t *idx) +{ + prop_array_t array; + prop_object_t obj; + prop_object_iterator_t iter; + const char *missname, *missver; + size_t lidx = 0; + int rv = 0; + + assert(pkgname != NULL); + assert(version != NULL); + assert(idx != NULL); + + array = prop_dictionary_get(chaindeps, "missing_deps"); + assert(array != NULL); + + iter = prop_array_iterator(array); + if (iter == NULL) + return ENOMEM; + + while ((obj = prop_object_iterator_next(iter)) != NULL) { + prop_dictionary_get_cstring_nocopy(obj, "pkgname", &missname); + prop_dictionary_get_cstring_nocopy(obj, "version", &missver); + if ((strcmp(pkgname, missname) == 0) && + (strcmp(version, missver) == 0)) { + *idx = lidx; + goto out; + } + idx++; + } + + rv = ENOENT; + +out: + prop_object_iterator_release(iter); + return rv; +} + +static void +remove_missing_reqdep(size_t *idx) +{ + prop_array_t array; + + array = prop_dictionary_get(chaindeps, "missing_deps"); + assert(array != NULL); + prop_array_remove(array, *idx); +} + +int +xbps_find_deps_in_pkg(prop_dictionary_t repo, prop_dictionary_t pkg) { prop_dictionary_t pkgdict; prop_array_t array; - prop_number_t prio_num; prop_object_t obj; - prop_object_iterator_t iter = NULL; - uint64_t prio = 0; - const char *reqpkg; + prop_object_iterator_t iter; + size_t idx = 0; + const char *reqpkg, *reqvers; char *pkgname; + int rv = 0; + static bool deps_dict; array = prop_dictionary_get(pkg, "run_depends"); if (array == NULL || prop_array_count(array) == 0) @@ -170,7 +334,18 @@ find_deps_in_pkg(prop_dictionary_t repo, prop_dictionary_t pkg) iter = prop_array_iterator(array); if (iter == NULL) - return -1; + return ENOMEM; + + if (deps_dict == false) { + deps_dict = true; + rv = create_deps_dictionary(); + if (rv != 0) + goto out; + + prop_dictionary_get_cstring_nocopy(pkg, "pkgname", &reqpkg); + prop_dictionary_set_cstring_nocopy(chaindeps, + "origin", reqpkg); + } /* * Iterate over the list of required run dependencies for @@ -178,114 +353,105 @@ find_deps_in_pkg(prop_dictionary_t repo, prop_dictionary_t pkg) */ while ((obj = prop_object_iterator_next(iter))) { /* - * If required package is not in repo, just pass to the - * next one. + * If required package is not in repo, add it into the + * missing deps array and pass to the next one. */ reqpkg = prop_string_cstring_nocopy(obj); pkgname = xbps_get_pkg_name(reqpkg); - pkgdict = xbps_find_pkg_in_dict(repo, pkgname); + reqvers = xbps_get_pkg_version(reqpkg); + pkgdict = xbps_find_pkg_in_dict(repo, "packages", pkgname); if (pkgdict == NULL) { + rv = add_missing_reqdep(pkgname, reqvers); free(pkgname); - continue; + if (rv != 0 && rv != EEXIST) + break; + else if (rv == EEXIST) + continue; + else { + rv = XBPS_PKG_ENOTINREPO; + continue; + } } /* - * Package is on repo, add it into the list. + * Check if dependency wasn't found before. */ - prio_num = prop_dictionary_get(pkgdict, "priority"); - prio = prop_number_unsigned_integer_value(prio_num); - xbps_add_pkg_dependency(reqpkg, prio, repo); + rv = check_missing_reqdep(pkgname, reqvers, &idx); free(pkgname); + if (rv == 0) { + /* + * Found in current repository, remove it. + */ + remove_missing_reqdep(&idx); - /* Iterate on required pkg to find more deps */ - if (xbps_pkg_has_rundeps(pkgdict)) { - /* more deps? */ - if (!find_deps_in_pkg(repo, pkgdict)) - continue; - } + } else if (rv != 0 && rv != ENOENT) + break; + + /* + * Package is on repo, add it into the dictionary. + */ + if ((rv = store_dependency(pkg, pkgdict, repo)) != 0) + break; + /* + * Iterate on required pkg to find more deps. + */ + if (!xbps_find_deps_in_pkg(repo, pkgdict)) + continue; } +out: prop_object_iterator_release(iter); - return 0; + return rv; } int xbps_install_pkg_deps(prop_dictionary_t pkg) { - prop_dictionary_t repolistd, repod, pkgd; - prop_array_t array; - prop_object_iterator_t iter; + prop_array_t array, installed, direct, indirect; + prop_dictionary_t dict; prop_object_t obj; - struct pkg_dependency *dep; - size_t required_deps = 0, deps_found = 0; - const char *reqpkg, *version, *pkgname, *desc; - char *plist, *namestr; + prop_object_iterator_t iter; + uint32_t maxprio = 0, prio = 0; + size_t curidx = 0, idx = 0; + const char *array_key, *reqby, *curname; int rv = 0; - bool dep_found = false; assert(pkg != NULL); - plist = xbps_append_full_path(true, NULL, XBPS_REPOLIST); - if (plist == NULL) - return EINVAL; - - repolistd = prop_dictionary_internalize_from_file(plist); - if (repolistd == NULL) { - free(plist); - return EINVAL; - } - - free(plist); - array = prop_dictionary_get(repolistd, "repository-list"); - assert(array != NULL); - - iter = prop_array_iterator(array); - if (iter == NULL) { - free(plist); - prop_object_release(repolistd); - return ENOMEM; - } + /* + * Install required dependencies of a package. + * The order for installation will be: + * + * - Indirect deps with high->low prio. + * - Direct deps with high->low prio. + */ /* - * Iterate over the repository list and find out if we have - * all required dependencies. + * First case: all deps are satisfied. */ - while ((obj = prop_object_iterator_next(iter)) != NULL) { - plist = xbps_append_full_path(false, - prop_string_cstring_nocopy(obj), XBPS_PKGINDEX); - if (plist == NULL) { - xbps_clean_pkg_depslist(); - prop_object_iterator_release(iter); - rv = EINVAL; - goto out; - } - - repod = prop_dictionary_internalize_from_file(plist); - if (repod == NULL) { - free(plist); - prop_object_iterator_release(iter); - rv = errno; - goto out; - } - - free(plist); - rv = find_deps_in_pkg(repod, pkg); - if (rv == -1) { - prop_object_release(repod); - prop_object_iterator_release(iter); - goto out; - } - - prop_object_release(repod); - } - prop_object_iterator_release(iter); + installed = prop_dictionary_get(chaindeps, "installed_deps"); + direct = prop_dictionary_get(chaindeps, "direct_deps"); + indirect = prop_dictionary_get(chaindeps, "indirect_deps"); + if (prop_array_count(direct) == 0 && prop_array_count(indirect) == 0 && + prop_array_count(installed) > 0) + return 0; /* - * Find out if all required dependencies and binary packages - * from repositories are there. + * Second case: only direct deps are required. */ - array = prop_dictionary_get(pkg, "run_depends"); + if (prop_array_count(indirect) == 0 && prop_array_count(direct) > 0) + array_key = "direct_deps"; + else + array_key = "indirect_deps"; + +again: + array = prop_dictionary_get(chaindeps, array_key); + if (array == NULL || prop_array_count(array) == 0) { + rv = EINVAL; + goto out; + } + iter = prop_array_iterator(array); if (iter == NULL) { rv = ENOMEM; @@ -293,81 +459,42 @@ xbps_install_pkg_deps(prop_dictionary_t pkg) } while ((obj = prop_object_iterator_next(iter)) != NULL) { - dep_found = false; - required_deps++; - reqpkg = prop_string_cstring_nocopy(obj); - namestr = xbps_get_pkg_name(reqpkg); - version = xbps_get_pkg_version(reqpkg); - - SIMPLEQ_FOREACH(dep, &pkg_deps, deps) { - if (strcmp(dep->name, namestr) == 0) { - deps_found++; - dep_found = true; - break; - } + prop_dictionary_get_uint32(obj, "priority", &prio); + if (maxprio < prio) { + curidx = idx; + maxprio = prio; } - if (dep_found == false) { - printf("Cannot find %s >= %s in repository list.\n", - namestr, version); - (void)fflush(stdout); - } - free(namestr); + idx++; } prop_object_iterator_release(iter); - if (required_deps != deps_found) { - rv = XBPS_PKG_ENOTINREPO; + dict = prop_array_get(array, curidx); + if (dict == NULL) { + rv = ENOENT; goto out; } -#ifdef XBPS_DEBUG_DEPS - while ((dep = xbps_get_dependency()) != NULL) { - printf("%s reqcount %ju priority %ju\n", dep->name, - dep->reqcount, dep->priority); - xbps_destroy_dependency(dep); - } - exit(0); -#endif + prop_dictionary_get_cstring_nocopy(dict, "pkgname", &curname); + prop_dictionary_get_cstring_nocopy(dict, "requiredby", &reqby); + printf("[%s] %s requiredby %s prio %u\n", + strcmp(array_key, "indirect_deps") == 0 ? "INDIRECT" : "DIRECT", + curname, reqby, maxprio); - /* - * Iterate over the list of dependencies and install them. - * The list is sorted by three rules, see xbps_get_dependency(). - */ - while ((dep = xbps_get_dependency()) != NULL) { - pkgd = xbps_find_pkg_in_dict(dep->repo, dep->name); - if (pkgd == NULL) { - rv = EINVAL; - break; - } - - rv = xbps_check_is_installed_pkg(dep->namever); - if (rv == -1) { - rv = EINVAL; - break; - } else if (rv == 0) { - /* Dependency is already installed. */ - continue; - } - - prop_dictionary_get_cstring_nocopy(pkgd, "pkgname", &pkgname); - prop_dictionary_get_cstring_nocopy(pkgd, "version", &version); - prop_dictionary_get_cstring_nocopy(pkgd, "short_desc", &desc); - - rv = xbps_unpack_binary_pkg(dep->repo, pkgd, - xbps_unpack_archive_cb); - if (rv != 0) - break; - - rv = xbps_register_pkg(pkgname, version, desc); - if (rv != 0) - break; - - xbps_destroy_dependency(dep); + prop_array_remove(array, curidx); + if (prop_array_count(array) > 0) { + prio = maxprio = 0; + curidx = idx = 0; + goto again; + } else { + prio = maxprio = 0; + curidx = idx = 0; + array_key = "direct_deps"; + goto again; } out: - prop_object_release(repolistd); - xbps_clean_pkg_depslist(); + prop_object_release(chaindeps); + exit(0); return rv; } diff --git a/lib/install.c b/lib/install.c index 6ece76d7c75..d9373efa37e 100644 --- a/lib/install.c +++ b/lib/install.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2008 Juan Romero Pardines. + * Copyright (c) 2008-2009 Juan Romero Pardines. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -34,78 +34,27 @@ #include -static const char *chroot_dir; - int -xbps_install_binary_pkg_from_repolist(prop_object_t obj, void *arg, - bool *loop_done) +xbps_install_binary_pkg_fini(prop_dictionary_t repo, prop_dictionary_t pkg, + const char *destdir) { - prop_dictionary_t repod, pkgrd; - const char *pkgname = arg, *version, *desc; - char *plist; + const char *pkgname, *version, *desc; int rv = 0; - /* - * Get the dictionary from a repository's index file. - */ - plist = xbps_append_full_path(false, - prop_string_cstring_nocopy(obj), XBPS_PKGINDEX); - if (plist == NULL) - return EINVAL; - - repod = prop_dictionary_internalize_from_file(plist); - if (repod == NULL) { - free(plist); - return EINVAL; - } - - /* - * Get the package dictionary from current repository. - */ - pkgrd = xbps_find_pkg_in_dict(repod, pkgname); - if (pkgrd == NULL) { - free(plist); - prop_object_release(repod); - return XBPS_PKG_ENOTINREPO; - } - - prop_dictionary_get_cstring_nocopy(pkgrd, "version", &version); - prop_dictionary_get_cstring_nocopy(pkgrd, "short_desc", &desc); + assert(pkg != NULL); + prop_dictionary_get_cstring_nocopy(pkg, "pkgname", &pkgname); + prop_dictionary_get_cstring_nocopy(pkg, "version", &version); + prop_dictionary_get_cstring_nocopy(pkg, "short_desc", &desc); + assert(pkgname != NULL); assert(version != NULL); assert(desc != NULL); - /* - * Check if this package needs dependencies. - */ - if (!xbps_pkg_has_rundeps(pkgrd)) { - /* pkg has no deps, just install it. */ - goto install; - } - - /* - * Install all required dependencies. - */ - rv = xbps_install_pkg_deps(pkgrd); - if (rv != 0) { - free(plist); - prop_object_release(repod); - return rv; - } - -install: - /* - * Finally install the package, now that all - * required dependencies were installed. - */ - rv = xbps_unpack_binary_pkg(repod, pkgrd, xbps_unpack_archive_cb); + rv = xbps_unpack_binary_pkg(repo, pkg, destdir, NULL); if (rv == 0) { rv = xbps_register_pkg(pkgname, version, desc); if (rv == EEXIST) rv = 0; } - free(plist); - prop_object_release(repod); - *loop_done = true; return rv; } @@ -113,7 +62,10 @@ install: int xbps_install_binary_pkg(const char *pkgname, const char *destdir) { - prop_dictionary_t repolistd; + prop_array_t array; + prop_dictionary_t repolistd, repod, pkgrd = NULL; + prop_object_t obj; + prop_object_iterator_t iter; char *plist; int rv = 0; @@ -121,13 +73,11 @@ xbps_install_binary_pkg(const char *pkgname, const char *destdir) if (destdir) { if ((rv = chdir(destdir)) != 0) return errno; - chroot_dir = destdir; } else - chroot_dir = "NOTSET"; + destdir = "NOTSET"; /* - * Get the dictionary with the list of registered - * repositories. + * Get the dictionary with the list of registered repositories. */ plist = xbps_append_full_path(true, NULL, XBPS_REPOLIST); if (plist == NULL) @@ -138,16 +88,87 @@ xbps_install_binary_pkg(const char *pkgname, const char *destdir) free(plist); return EINVAL; } + free(plist); /* - * Iterate over the repositories to find the binary packages - * required by this package. + * Iterate over the repository pool and find out if we have + * all available binary packages. */ - rv = xbps_callback_array_iter_in_dict(repolistd, "repository-list", - xbps_install_binary_pkg_from_repolist, (void *)pkgname); + array = prop_dictionary_get(repolistd, "repository-list"); + assert(array != NULL); - free(plist); + iter = prop_array_iterator(array); + if (iter == NULL) { + prop_object_release(repolistd); + return ENOMEM; + } + + while ((obj = prop_object_iterator_next(iter)) != NULL) { + plist = xbps_append_full_path(false, + prop_string_cstring_nocopy(obj), XBPS_PKGINDEX); + if (plist == NULL) { + rv = EINVAL; + goto out; + } + + repod = prop_dictionary_internalize_from_file(plist); + if (repod == NULL) { + free(plist); + rv = errno; + goto out; + } + free(plist); + + /* + * Get the package dictionary from current repository. + * If it's not there, pass to the next repository. + */ + pkgrd = xbps_find_pkg_in_dict(repod, "packages", pkgname); + if (pkgrd == NULL) { + prop_object_release(repod); + rv = XBPS_PKG_ENOTINREPO; + continue; + } + + /* + * Check if this package needs dependencies. + */ + if (!xbps_pkg_has_rundeps(pkgrd)) { + /* pkg has no deps, just install it. */ + rv = xbps_install_binary_pkg_fini(repod, pkgrd, + destdir); + prop_object_release(repod); + goto out; + } + + /* + * Construct the dependency chain for this package. If any + * dependency is not available, pass to the next repository. + */ + rv = xbps_find_deps_in_pkg(repod, pkgrd); + if (rv != 0) { + prop_object_release(repod); + if (rv == XBPS_PKG_ENOTINREPO) + continue; + + goto out; + } + + /* + * Install all required dependencies and the package itself. + */ + rv = xbps_install_pkg_deps(pkgrd); + if (rv == 0) { + rv = xbps_install_binary_pkg_fini(repod, pkgrd, + destdir); + } + prop_object_release(repod); + break; + } + +out: prop_object_release(repolistd); + prop_object_iterator_release(iter); return rv; } @@ -218,7 +239,7 @@ xbps_register_pkg(const char *pkgname, const char *version, const char *desc) } else { /* Check if package is already registered. */ - pkgd = xbps_find_pkg_in_dict(dict, pkgname); + pkgd = xbps_find_pkg_in_dict(dict, "packages", pkgname); if (pkgd != NULL) { prop_object_release(dict); free(plist); @@ -237,7 +258,6 @@ xbps_register_pkg(const char *pkgname, const char *version, const char *desc) } } - if (!prop_dictionary_externalize_to_file(dict, plist)) rv = errno; @@ -246,171 +266,3 @@ xbps_register_pkg(const char *pkgname, const char *version, const char *desc) return rv; } - -/* - * Flags for extracting files in binary packages. - */ -#define EXTRACT_FLAGS ARCHIVE_EXTRACT_OWNER | ARCHIVE_EXTRACT_PERM | \ - ARCHIVE_EXTRACT_TIME | \ - ARCHIVE_EXTRACT_SECURE_NODOTDOT | \ - ARCHIVE_EXTRACT_SECURE_SYMLINKS | \ - ARCHIVE_EXTRACT_UNLINK - -int -xbps_unpack_archive_cb(struct archive *ar, prop_dictionary_t pkg) -{ - struct archive_entry *entry; - size_t len; - const char *prepost = "./XBPS_PREPOST_INSTALL"; - const char *pkgname, *version; - char *buf; - int rv = 0; - bool actgt = false; - - assert(ar != NULL); - assert(pkg != NULL); - - prop_dictionary_get_cstring_nocopy(pkg, "pkgname", &pkgname); - prop_dictionary_get_cstring_nocopy(pkg, "version", &version); - - /* - * This length is '.%s/metadata/%s/prepost-inst' not - * including nul. - */ - len = strlen(XBPS_META_PATH) + strlen(pkgname) + 24; - buf = malloc(len + 1); - if (buf == NULL) - return ENOMEM; - - if (snprintf(buf, len + 1, ".%s/metadata/%s/prepost-inst", - XBPS_META_PATH, pkgname) < 0) { - free(buf); - return -1; - } - - 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. - */ - if (strcmp(prepost, archive_entry_pathname(entry)) == 0) { - actgt = true; - - archive_entry_set_pathname(entry, buf); - - if ((rv = archive_read_extract(ar, entry, - EXTRACT_FLAGS)) != 0) - break; - - if ((rv = xbps_file_exec(buf, chroot_dir, "pre", - pkgname, version, NULL)) != 0) { - printf("%s: preinst action target error %s\n", - pkgname, strerror(errno)); - (void)fflush(stdout); - break; - } - - /* pass to the next entry if successful */ - continue; - } - /* - * Extract all data from the archive now. - */ - if ((rv = archive_read_extract(ar, entry, - EXTRACT_FLAGS)) != 0) { - printf("\ncouldn't unpack %s (%s), exiting!\n", - archive_entry_pathname(entry), strerror(errno)); - (void)fflush(stdout); - break; - } - } - - if (rv == 0 && actgt) { - /* - * Run the post installaction action target, if package - * contains the script. - */ - if ((rv = xbps_file_exec(buf, chroot_dir, "post", - pkgname, version, NULL)) != 0) { - printf("%s: postinst action target error %s\n", - pkgname, strerror(errno)); - (void)fflush(stdout); - } - } - - free(buf); - - return rv; -} - -int -xbps_unpack_binary_pkg(prop_dictionary_t repo, prop_dictionary_t pkg, - int (*cb)(struct archive *, prop_dictionary_t)) -{ - prop_string_t pkgname, version, filename, repoloc; - struct archive *ar; - char *binfile; - int pkg_fd, rv; - - assert(pkg != NULL); - assert(repo != NULL); - assert(cb != NULL); - - /* Append filename to the full path for binary pkg */ - filename = prop_dictionary_get(pkg, "filename"); - repoloc = prop_dictionary_get(repo, "location-local"); - - binfile= xbps_append_full_path(false, - prop_string_cstring_nocopy(repoloc), - prop_string_cstring_nocopy(filename)); - if (binfile == NULL) - return EINVAL; - - if ((pkg_fd = open(binfile, O_RDONLY)) == -1) { - free(binfile); - return errno; - } - - pkgname = prop_dictionary_get(pkg, "pkgname"); - version = prop_dictionary_get(pkg, "version"); - - printf("Installing %s-%s (%s) ...\n", - prop_string_cstring_nocopy(pkgname), - prop_string_cstring_nocopy(version), - prop_string_cstring_nocopy(filename)); - - (void)fflush(stdout); - - ar = archive_read_new(); - if (ar == NULL) { - free(binfile); - close(pkg_fd); - return ENOMEM; - } - - /* Enable support for all format and compression methods */ - archive_read_support_compression_all(ar); - archive_read_support_format_all(ar); - - if ((rv = archive_read_open_fd(ar, pkg_fd, 2048)) != 0) { - archive_read_finish(ar); - free(binfile); - close(pkg_fd); - return rv; - } - - rv = (*cb)(ar, pkg); - /* - * If installation of package was successful, make sure the package - * is really on storage (if possible). - */ - if (rv == 0) - if ((rv = fdatasync(pkg_fd)) == -1) - rv = errno; - - archive_read_finish(ar); - close(pkg_fd); - free(binfile); - - return rv; -} diff --git a/lib/plist.c b/lib/plist.c index eec13b8612c..33c7c1672ec 100644 --- a/lib/plist.c +++ b/lib/plist.c @@ -110,7 +110,7 @@ xbps_find_pkg_from_plist(const char *plist, const char *pkgname) return NULL; } - obj = xbps_find_pkg_in_dict(dict, pkgname); + obj = xbps_find_pkg_in_dict(dict, "packages", pkgname); if (obj == NULL) { prop_object_release(dict); errno = ENOENT; @@ -124,7 +124,8 @@ xbps_find_pkg_from_plist(const char *plist, const char *pkgname) } prop_dictionary_t -xbps_find_pkg_in_dict(prop_dictionary_t dict, const char *pkgname) +xbps_find_pkg_in_dict(prop_dictionary_t dict, const char *key, + const char *pkgname) { prop_object_iterator_t iter; prop_object_t obj; @@ -132,8 +133,9 @@ xbps_find_pkg_in_dict(prop_dictionary_t dict, const char *pkgname) assert(dict != NULL); assert(pkgname != NULL); + assert(key != NULL); - iter = xbps_get_array_iter_from_dict(dict, "packages"); + iter = xbps_get_array_iter_from_dict(dict, key); if (iter == NULL) return NULL; diff --git a/lib/unpack.c b/lib/unpack.c new file mode 100644 index 00000000000..d71a37b08eb --- /dev/null +++ b/lib/unpack.c @@ -0,0 +1,218 @@ +/*- + * Copyright (c) 2008-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 unpack_archive_init(prop_dictionary_t, const char *, const char *); +static int unpack_archive_fini(struct archive *, const char *, + prop_dictionary_t); + +int +xbps_unpack_binary_pkg(prop_dictionary_t repo, prop_dictionary_t pkg, + const char *destdir, + void (*cb_print)(prop_dictionary_t)) +{ + prop_string_t filename, repoloc; + char *binfile; + int rv = 0; + + assert(pkg != NULL); + + /* Append filename to the full path for binary pkg */ + filename = prop_dictionary_get(pkg, "filename"); + if (repo) + repoloc = prop_dictionary_get(repo, "location-local"); + else + repoloc = prop_dictionary_get(pkg, "location-local"); + + binfile = xbps_append_full_path(false, + prop_string_cstring_nocopy(repoloc), + prop_string_cstring_nocopy(filename)); + if (binfile == NULL) + return EINVAL; + + if (cb_print) + (*cb_print)(pkg); + + rv = unpack_archive_init(pkg, destdir, binfile); + free(binfile); + return rv; +} + + +static int +unpack_archive_init(prop_dictionary_t pkg, const char *destdir, + const char *binfile) +{ + struct archive *ar; + int pkg_fd, rv; + + assert(pkg != NULL); + assert(binfile != NULL); + + if ((pkg_fd = open(binfile, O_RDONLY)) == -1) + return errno; + + ar = archive_read_new(); + if (ar == NULL) { + (void)close(pkg_fd); + return ENOMEM; + } + + /* Enable support for all format and compression methods */ + archive_read_support_compression_all(ar); + archive_read_support_format_all(ar); + + /* 2048 is arbitrary... dunno what value is better. */ + if ((rv = archive_read_open_fd(ar, pkg_fd, 2048)) != 0) { + archive_read_finish(ar); + (void)close(pkg_fd); + return rv; + } + + rv = unpack_archive_fini(ar, destdir, pkg); + /* + * If installation of package was successful, make sure the package + * is really on storage (if possible). + */ + if (rv == 0) + if ((rv = fdatasync(pkg_fd)) == -1) + rv = errno; + + archive_read_finish(ar); + (void)close(pkg_fd); + + return rv; +} +/* + * Flags for extracting files in binary packages. + * TODO: change this for non root users. + */ +#define EXTRACT_FLAGS ARCHIVE_EXTRACT_OWNER | ARCHIVE_EXTRACT_PERM | \ + ARCHIVE_EXTRACT_TIME | \ + ARCHIVE_EXTRACT_SECURE_NODOTDOT | \ + ARCHIVE_EXTRACT_SECURE_SYMLINKS | \ + ARCHIVE_EXTRACT_UNLINK + +/* + * TODO: remove printfs and return appropiate errors to be interpreted by + * the consumer. + */ +static int +unpack_archive_fini(struct archive *ar, const char *destdir, + prop_dictionary_t pkg) +{ + struct archive_entry *entry; + size_t len; + const char *prepost = "./XBPS_PREPOST_INSTALL"; + const char *pkgname, *version; + char *buf; + int rv = 0; + bool actgt = false; + + assert(ar != NULL); + assert(pkg != NULL); + + prop_dictionary_get_cstring_nocopy(pkg, "pkgname", &pkgname); + prop_dictionary_get_cstring_nocopy(pkg, "version", &version); + + /* + * This length is '.%s/metadata/%s/prepost-inst' not + * including nul. + */ + len = strlen(XBPS_META_PATH) + strlen(pkgname) + 24; + buf = malloc(len + 1); + if (buf == NULL) + return ENOMEM; + + if (snprintf(buf, len + 1, ".%s/metadata/%s/prepost-inst", + XBPS_META_PATH, pkgname) < 0) { + free(buf); + return -1; + } + + 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. + */ + if (strcmp(prepost, archive_entry_pathname(entry)) == 0) { + actgt = true; + + archive_entry_set_pathname(entry, buf); + + if ((rv = archive_read_extract(ar, entry, + EXTRACT_FLAGS)) != 0) + break; + + if ((rv = xbps_file_exec(buf, destdir, "pre", + pkgname, version, NULL)) != 0) { + printf("%s: preinst action target error %s\n", + pkgname, strerror(errno)); + (void)fflush(stdout); + break; + } + + /* pass to the next entry if successful */ + continue; + } + /* + * Extract all data from the archive now. + */ + if ((rv = archive_read_extract(ar, entry, + EXTRACT_FLAGS)) != 0) { + printf("\ncouldn't unpack %s (%s), exiting!\n", + archive_entry_pathname(entry), strerror(errno)); + (void)fflush(stdout); + break; + } + } + + if (rv == 0 && actgt) { + /* + * Run the post installaction action target, if package + * contains the script. + */ + if ((rv = xbps_file_exec(buf, destdir, "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 7a8f5fca002..bc390b89dee 100644 --- a/lib/util.c +++ b/lib/util.c @@ -60,7 +60,7 @@ xbps_check_is_installed_pkg(const char *pkg) return 1; /* not installed */ } - pkgdict = xbps_find_pkg_in_dict(dict, pkgname); + pkgdict = xbps_find_pkg_in_dict(dict, "packages", pkgname); if (pkgdict == NULL) { prop_object_release(dict); free(pkgname); @@ -165,10 +165,9 @@ char * xbps_append_full_path(bool use_rootdir, const char *basedir, const char *plist) { const char *env; - char *buf; + char *buf = NULL; size_t len = 0; - assert(buf != NULL); assert(plist != NULL); if (basedir) diff --git a/vars.mk b/vars.mk index 9eb5ff598be..51e024b5458 100644 --- a/vars.mk +++ b/vars.mk @@ -6,7 +6,7 @@ LIBDIR ?= $(PREFIX)/lib ETCDIR ?= $(PREFIX)/etc TOPDIR ?= .. -LDFLAGS += -L$(TOPDIR)/lib -L$(PREFIX)/lib -lxbps +LDFLAGS += -L$(TOPDIR)/lib -L$(PREFIX) -lxbps CPPFLAGS += -I$(TOPDIR)/include CFLAGS += -Wstack-protector -fstack-protector-all CFLAGS += -O2 -Wall -Werror -fPIC -DPIC