diff --git a/lib/orphans.c b/lib/orphans.c index 13431fe29b4..311e09eed5f 100644 --- a/lib/orphans.c +++ b/lib/orphans.c @@ -32,43 +32,27 @@ #include <xbps_api.h> -struct orphan { - prop_array_t array; +struct orphan_pkg { + SIMPLEQ_ENTRY(orphan_pkg) chain; + prop_dictionary_t dict; const char *pkgname; - const char *version; }; +static SIMPLEQ_HEAD(orphan_head, orphan_pkg) orphan_list = + SIMPLEQ_HEAD_INITIALIZER(orphan_list); + static int find_orphan_pkg(prop_object_t obj, void *arg, bool *loop_done) { - struct orphan *orphan = arg; prop_array_t reqby; + prop_object_t obj2; + prop_object_iterator_t iter; + struct orphan_pkg *orphan; + char *pkgname; + unsigned int ndep = 0, cnt = 0; bool automatic = false; - (void)loop_done; - - reqby = prop_dictionary_get(obj, "requiredby"); - if (reqby != NULL && prop_array_count(reqby) > 0) - return 0; - - if (!prop_dictionary_get_bool(obj, "automatic-install", &automatic)) - return EINVAL; - - if (automatic) - if (!prop_array_add(orphan->array, obj)) - return EINVAL; - - return 0; -} - -static int -find_indirect_orphan_pkg(prop_object_t obj, void *arg, bool *loop_done) -{ - struct orphan *orphan = arg; - prop_array_t reqby; - char *pkg; - bool automatic = false; - + (void)arg; (void)loop_done; if (!prop_dictionary_get_bool(obj, "automatic-install", &automatic)) @@ -78,75 +62,93 @@ find_indirect_orphan_pkg(prop_object_t obj, void *arg, bool *loop_done) return 0; reqby = prop_dictionary_get(obj, "requiredby"); - if (reqby == NULL || prop_array_count(reqby) != 1) + if (reqby == NULL) + return 0; + else if (prop_object_type(reqby) != PROP_TYPE_ARRAY) + return EINVAL; + + if ((cnt = prop_array_count(reqby)) == 0) + goto add_orphan; + + iter = prop_array_iterator(reqby); + if (iter == NULL) + return errno; + + while ((obj2 = prop_object_iterator_next(iter)) != NULL) { + pkgname = xbps_get_pkg_name(prop_string_cstring_nocopy(obj2)); + SIMPLEQ_FOREACH(orphan, &orphan_list, chain) { + if (strcmp(orphan->pkgname, pkgname) == 0) { + ndep++; + break; + } + } + free(pkgname); + } + prop_object_iterator_release(iter); + if (ndep != cnt) return 0; - pkg = xbps_xasprintf("%s-%s", orphan->pkgname, orphan->version); - if (pkg == NULL) - return ENOMEM; +add_orphan: + orphan = NULL; + orphan = malloc(sizeof(struct orphan_pkg)); + if (orphan == NULL) + return errno; - if (xbps_find_string_in_array(reqby, pkg)) { - if (!prop_array_add(orphan->array, obj)) { - free(pkg); - return EINVAL; - } - } - free(pkg); + prop_dictionary_get_cstring_nocopy(obj, "pkgname", &orphan->pkgname); + orphan->dict = prop_dictionary_copy(obj); + SIMPLEQ_INSERT_TAIL(&orphan_list, orphan, chain); return 0; } +static void +cleanup(void) +{ + struct orphan_pkg *orphan; + + while ((orphan = SIMPLEQ_FIRST(&orphan_list)) != NULL) { + SIMPLEQ_REMOVE(&orphan_list, orphan, orphan_pkg, chain); + prop_object_release(orphan->dict); + free(orphan); + } +} + prop_array_t xbps_find_orphan_packages(void) { + prop_array_t array; prop_dictionary_t dict; - prop_object_t obj; - prop_object_iterator_t iter; - struct orphan orphan; + struct orphan_pkg *orphan; int rv = 0; if ((dict = xbps_prepare_regpkgdb_dict()) == NULL) return NULL; - - orphan.array = prop_array_create(); - if (orphan.array == NULL) - return NULL; - /* - * First look for direct orphan packages, i.e the ones - * that were required directly by a previous removed package. + * Find out all orphan packages by looking at the + * regpkgdb dictionary and we must do that in reverse order. */ - rv = xbps_callback_array_iter_in_dict(dict, "packages", - find_orphan_pkg, (void *)&orphan); + rv = xbps_callback_array_iter_reverse_in_dict(dict, "packages", + find_orphan_pkg, NULL); if (rv != 0) { - prop_object_release(orphan.array); + cleanup(); return NULL; } - /* - * Now look if any of these packages have dependencies that - * were installed indirectly by some removed package. + * Prepare an array with all packages previously found. We + * do this in that way to do a reverse order in which the + * packages were installed. */ - iter = prop_array_iterator(orphan.array); - if (iter == NULL) { - prop_object_release(orphan.array); + array = prop_array_create(); + if (array == NULL) { + cleanup(); return NULL; } - - while ((obj = prop_object_iterator_next(iter)) != NULL) { - prop_dictionary_get_cstring_nocopy(obj, "pkgname", - &orphan.pkgname); - prop_dictionary_get_cstring_nocopy(obj, "version", - &orphan.version); - rv = xbps_callback_array_iter_in_dict(dict, "packages", - find_indirect_orphan_pkg, (void *)&orphan); - if (rv != 0) { - prop_object_iterator_release(iter); - prop_object_release(orphan.array); - return NULL; - } + while ((orphan = SIMPLEQ_FIRST(&orphan_list)) != NULL) { + prop_array_add(array, orphan->dict); + SIMPLEQ_REMOVE(&orphan_list, orphan, orphan_pkg, chain); + prop_object_release(orphan->dict); + free(orphan); } - prop_object_iterator_release(iter); - return orphan.array; + return array; }