Beispiel #1
0
static xbps_dictionary_t
get_pkg_in_array(xbps_array_t array, const char *str, bool virtual)
{
	xbps_object_t obj = NULL;
	xbps_object_iterator_t iter;
	const char *pkgver;
	char *dpkgn;
	bool found = false;

	iter = xbps_array_iterator(array);
	assert(iter);

	while ((obj = xbps_object_iterator_next(iter))) {
		if (virtual) {
			/*
			 * Check if package pattern matches
			 * any virtual package version in dictionary.
			 */
			if (xbps_pkgpattern_version(str))
				found = xbps_match_virtual_pkg_in_dict(obj, str, true);
			else
				found = xbps_match_virtual_pkg_in_dict(obj, str, false);

			if (found)
				break;
		} else if (xbps_pkgpattern_version(str)) {
			/* match by pattern against pkgver */
			if (!xbps_dictionary_get_cstring_nocopy(obj,
			    "pkgver", &pkgver))
				continue;
			if (xbps_pkgpattern_match(pkgver, str)) {
				found = true;
				break;
			}
		} else if (xbps_pkg_version(str)) {
			/* match by exact pkgver */
			if (!xbps_dictionary_get_cstring_nocopy(obj,
			    "pkgver", &pkgver))
				continue;
			if (strcmp(str, pkgver) == 0) {
				found = true;
				break;
			}
		} else {
			/* match by pkgname */
			if (!xbps_dictionary_get_cstring_nocopy(obj,
			    "pkgver", &pkgver))
				continue;
			dpkgn = xbps_pkg_name(pkgver);
			assert(dpkgn);
			if (strcmp(dpkgn, str) == 0) {
				free(dpkgn);
				found = true;
				break;
			}
			free(dpkgn);
		}
	}
Beispiel #2
0
/*
 * Verify reverse dependencies for packages in transaction.
 * This will catch cases where a package update would break its reverse dependencies:
 *
 * 	- foo-1.0 is being updated to 2.0.
 * 	- baz-1.1 depends on foo<2.0.
 * 	- foo is updated to 2.0, hence baz-1.1 is currently broken.
 *
 * Abort transaction if such case is found.
 */
static bool
check_virtual_pkgs(xbps_array_t mdeps,
		   xbps_dictionary_t trans_pkgd,
		   xbps_dictionary_t rev_pkgd)
{
	xbps_array_t provides;
	bool matched = false;

	provides = xbps_dictionary_get(trans_pkgd, "provides");
	for (unsigned int i = 0; i < xbps_array_count(provides); i++) {
		xbps_array_t rundeps;
		const char *pkgver, *revpkgver, *pkgpattern;
		char *pkgname, *vpkgname, *vpkgver, *str;

		pkgver = revpkgver = pkgpattern = NULL;
		pkgname = vpkgname = vpkgver = str = NULL;

		xbps_dictionary_get_cstring_nocopy(trans_pkgd, "pkgver", &pkgver);
		xbps_dictionary_get_cstring_nocopy(rev_pkgd, "pkgver", &revpkgver);
		xbps_array_get_cstring(provides, i, &vpkgver);
		vpkgname = xbps_pkg_name(vpkgver);
		assert(vpkgname);
		rundeps = xbps_dictionary_get(rev_pkgd, "run_depends");
		for (unsigned int x = 0; x < xbps_array_count(rundeps); x++) {
			xbps_array_get_cstring_nocopy(rundeps, x, &pkgpattern);
			if (((pkgname = xbps_pkgpattern_name(pkgpattern)) == NULL) &&
			    ((pkgname = xbps_pkg_name(pkgpattern)) == NULL))
				continue;

			if (strcmp(vpkgname, pkgname)) {
				free(pkgname);
				continue;
			}
			free(pkgname);
			if (!strcmp(vpkgver, pkgpattern) ||
			    xbps_pkgpattern_match(vpkgver, pkgpattern)) {
				continue;
			}

			str = xbps_xasprintf("%s broken, needs '%s' virtual pkg (got `%s')",
			    revpkgver, pkgpattern, vpkgver);
			xbps_array_add_cstring(mdeps, str);
			free(str);
			matched = true;
		}
		free(vpkgname);
		free(vpkgver);
	}
	return matched;
}
Beispiel #3
0
/*
 * Verify reverse dependencies for packages in transaction.
 * This will catch cases where a package update would break its reverse dependencies:
 *
 * 	- foo-1.0 is being updated to 2.0.
 * 	- baz-1.1 depends on foo<2.0.
 * 	- foo is updated to 2.0, hence baz-1.1 is currently broken.
 *
 * Abort transaction if such case is found.
 */
static bool
check_virtual_pkgs(struct xbps_handle *xhp,
		   xbps_dictionary_t trans_pkgd,
		   xbps_dictionary_t rev_pkgd)
{
	xbps_array_t unsorted, provides, rundeps, mdeps;
	const char *pkgver, *revpkgver, *pkgpattern;
	char *pkgname, *pkgdepname, *vpkgname, *vpkgver, *str;
	unsigned int i, x;
	bool matched = false;

	unsorted = xbps_dictionary_get(xhp->transd, "unsorted_deps");
	provides = xbps_dictionary_get(trans_pkgd, "provides");
	for (i = 0; i < xbps_array_count(provides); i++) {
		char *tmp = NULL;

		xbps_array_get_cstring(provides, i, &vpkgver);
		if (strchr(vpkgver, '_') == NULL) {
			tmp = xbps_xasprintf("%s_1", vpkgver);
			vpkgver = strdup(tmp);
		}
		vpkgname = xbps_pkg_name(vpkgver);
		assert(vpkgname);
		rundeps = xbps_dictionary_get(rev_pkgd, "run_depends");
		for (x = 0; x < xbps_array_count(rundeps); x++) {
			xbps_array_get_cstring_nocopy(rundeps, x, &pkgpattern);
			if (((pkgname = xbps_pkgpattern_name(pkgpattern)) == NULL) &&
			    ((pkgname = xbps_pkg_name(pkgpattern)) == NULL))
				continue;

			if (strcmp(vpkgname, pkgname)) {
				free(pkgname);
				continue;
			}
			free(pkgname);
			if (xbps_pkgpattern_match(vpkgver, pkgpattern))
				continue;

			/*
			 * Installed package conflicts with package
			 * in transaction being updated, check
			 * if a new version of this conflicting package
			 * is in the transaction.
			 */
			xbps_dictionary_get_cstring_nocopy(trans_pkgd, "pkgver", &pkgver);
			pkgdepname = xbps_pkg_name(pkgver);
			assert(pkgdepname);
			if (xbps_find_pkg_in_array(unsorted, pkgdepname)) {
				free(pkgdepname);
				continue;
			}
			free(pkgdepname);

			mdeps = xbps_dictionary_get(xhp->transd, "missing_deps");
			xbps_dictionary_get_cstring_nocopy(trans_pkgd, "pkgver", &pkgver);
			xbps_dictionary_get_cstring_nocopy(rev_pkgd, "pkgver", &revpkgver);
			str = xbps_xasprintf("CONFLICT: `%s' update "
			    "breaks `%s', needs `%s' virtual pkg (got `%s`)",
			    pkgver, revpkgver, pkgpattern, vpkgver);
			xbps_array_add_cstring(mdeps, str);
			free(str);
			matched = true;
		}
		free(vpkgname);
		free(vpkgver);
	}
	return matched;
}
Beispiel #4
0
int
main(int argc, char **argv)
{
	xbps_dictionary_t dict;
	struct xbps_handle xh;
	struct xferstat xfer;
	const char *version, *rootdir = NULL, *confdir = NULL;
	char *pkgname, *hash, *filename;
	int flags = 0, c, rv = 0;

	while ((c = getopt(argc, argv, "C:dr:V")) != -1) {
		switch (c) {
		case 'C':
			confdir = optarg;
			break;
		case 'r':
			/* To specify the root directory */
			rootdir = optarg;
			break;
		case 'd':
			flags |= XBPS_FLAG_DEBUG;
			break;
		case 'V':
			printf("%s\n", XBPS_RELVER);
			exit(EXIT_SUCCESS);
		case '?':
		default:
			usage();
		}
	}

	argc -= optind;
	argv += optind;

	if (argc < 1)
		usage();

	memset(&xh, 0, sizeof(xh));

	if ((strcmp(argv[0], "version") == 0) ||
	    (strcmp(argv[0], "real-version") == 0) ||
	    (strcmp(argv[0], "arch") == 0) ||
	    (strcmp(argv[0], "getsystemdir") == 0) ||
	    (strcmp(argv[0], "fetch") == 0)) {
		/*
		* Initialize libxbps.
		*/
		xh.flags = flags;
		xh.fetch_cb = fetch_file_progress_cb;
		xh.fetch_cb_data = &xfer;
		if (rootdir)
			xbps_strlcpy(xh.rootdir, rootdir, sizeof(xh.rootdir));
		if (confdir)
			xbps_strlcpy(xh.confdir, confdir, sizeof(xh.confdir));
		if ((rv = xbps_init(&xh)) != 0) {
			xbps_error_printf("xbps-uhelper: failed to "
			    "initialize libxbps: %s.\n", strerror(rv));
			exit(EXIT_FAILURE);
		}
	}

	if (strcmp(argv[0], "version") == 0) {
		/* Prints version of an installed package */
		if (argc != 2)
			usage();

		if ((((dict = xbps_pkgdb_get_pkg(&xh, argv[1])) == NULL)) &&
		    (((dict = xbps_pkgdb_get_virtualpkg(&xh, argv[1])) == NULL)))
			exit(EXIT_FAILURE);

		xbps_dictionary_get_cstring_nocopy(dict, "pkgver", &version);
		printf("%s\n", xbps_pkg_version(version));
	} else if (strcmp(argv[0], "real-version") == 0) {
		/* Prints version of an installed real package, not virtual */
		if (argc != 2)
			usage();

		if ((dict = xbps_pkgdb_get_pkg(&xh, argv[1])) == NULL)
			exit(EXIT_FAILURE);

		xbps_dictionary_get_cstring_nocopy(dict, "pkgver", &version);
		printf("%s\n", xbps_pkg_version(version));
	} else if (strcmp(argv[0], "getpkgversion") == 0) {
		/* Returns the version of a pkg string */
		if (argc != 2)
			usage();

		version = xbps_pkg_version(argv[1]);
		if (version == NULL) {
			fprintf(stderr,
			    "Invalid string, expected <string>-<version>_<revision>\n");
			exit(EXIT_FAILURE);
		}
		printf("%s\n", version);
	} else if (strcmp(argv[0], "getpkgname") == 0) {
		/* Returns the name of a pkg string */
		if (argc != 2)
			usage();

		pkgname = xbps_pkg_name(argv[1]);
		if (pkgname == NULL) {
			fprintf(stderr,
			    "Invalid string, expected <string>-<version>_<revision>\n");
			exit(EXIT_FAILURE);
		}
		printf("%s\n", pkgname);
		free(pkgname);
	} else if (strcmp(argv[0], "getpkgrevision") == 0) {
		/* Returns the revision of a pkg string */
		if (argc != 2)
			usage();

		version = xbps_pkg_revision(argv[1]);
		if (version == NULL)
			exit(EXIT_SUCCESS);

		printf("%s\n", version);
	} else if (strcmp(argv[0], "getpkgdepname") == 0) {
		/* Returns the pkgname of a dependency */
		if (argc != 2)
			usage();

		pkgname = xbps_pkgpattern_name(argv[1]);
		if (pkgname == NULL)
			exit(EXIT_FAILURE);

		printf("%s\n", pkgname);
		free(pkgname);
	} else if (strcmp(argv[0], "getpkgdepversion") == 0) {
		/* returns the version of a package pattern dependency */
		if (argc != 2)
			usage();

		version = xbps_pkgpattern_version(argv[1]);
		if (version == NULL)
			exit(EXIT_FAILURE);

		printf("%s\n", version);
	} else if (strcmp(argv[0], "binpkgver") == 0) {
		/* Returns the pkgver of a binpkg string */
		if (argc != 2)
			usage();

		version = xbps_binpkg_pkgver(argv[1]);
		if (version == NULL) {
			fprintf(stderr,
			    "Invalid string, expected <pkgname>-<version>_<revision>.<arch>.xbps\n");
			exit(EXIT_FAILURE);
		}
		printf("%s\n", version);
	} else if (strcmp(argv[0], "binpkgarch") == 0) {
		/* Returns the arch of a binpkg string */
		if (argc != 2)
			usage();

		version = xbps_binpkg_arch(argv[1]);
		if (version == NULL) {
			fprintf(stderr,
			    "Invalid string, expected <pkgname>-<version>_<revision>.<arch>.xbps\n");
			exit(EXIT_FAILURE);
		}
		printf("%s\n", version);
	} else if (strcmp(argv[0], "pkgmatch") == 0) {
		/* Matches a pkg with a pattern */
		if (argc != 3)
			usage();

		exit(xbps_pkgpattern_match(argv[1], argv[2]));
	} else if (strcmp(argv[0], "cmpver") == 0) {
		/* Compare two version strings, installed vs required */
		if (argc != 3)
			usage();

		exit(xbps_cmpver(argv[1], argv[2]));
	} else if (strcmp(argv[0], "arch") == 0) {
		/* returns the xbps native arch */
		if (argc != 1)
			usage();

		printf("%s\n", xh.native_arch);
	} else if (strcmp(argv[0], "getsystemdir") == 0) {
		/* returns the xbps system directory (<sharedir>/xbps.d) */
		if (argc != 1)
			usage();

		printf("%s\n", XBPS_SYSDEFCONF_PATH);
	} else if (strcmp(argv[0], "digest") == 0) {
		/* Prints SHA256 hashes for specified files */
		if (argc < 2)
			usage();

		for (int i = 1; i < argc; i++) {
			hash = xbps_file_hash(argv[i]);
			if (hash == NULL) {
				fprintf(stderr,
				    "E: couldn't get hash for %s (%s)\n",
				    argv[i], strerror(errno));
				exit(EXIT_FAILURE);
			}
			printf("%s\n", hash);
		}
	} else if (strcmp(argv[0], "fetch") == 0) {
		/* Fetch a file from specified URL */
		if (argc < 2)
			usage();

		for (int i = 1; i < argc; i++) {
			filename = fname(argv[i]);
			rv = xbps_fetch_file_dest(&xh, argv[i], filename, "v");

			if (rv == -1) {
				printf("%s: %s\n", argv[i],
				    xbps_fetch_error_string());
			} else if (rv == 0) {
				printf("%s: file is identical with remote.\n",
				    argv[i]);
			} else
				rv = 0;
		}
	} else {
		usage();
	}

	exit(rv ? EXIT_FAILURE : EXIT_SUCCESS);
}
Beispiel #5
0
static int
find_repo_deps(struct xbps_handle *xhp,
	       xbps_array_t unsorted,		/* array of unsorted deps */
	       xbps_array_t pkg_rdeps_array,	/* current pkg rundeps array  */
	       xbps_array_t pkg_provides,	/* current pkg provides array */
	       const char *curpkg,		/* current pkgver */
	       unsigned short *depth)		/* max recursion depth */
{
	xbps_dictionary_t curpkgd = NULL;
	xbps_object_t obj;
	xbps_object_iterator_t iter;
	xbps_array_t curpkgrdeps = NULL, curpkgprovides = NULL;
	pkg_state_t state;
	const char *reqpkg, *pkgver_q, *reason = NULL;
	char *pkgname, *reqpkgname;
	int rv = 0;
	bool foundvpkg;

	if (*depth >= MAX_DEPTH)
		return ELOOP;

	/*
	 * Iterate over the list of required run dependencies for
	 * current package.
	 */
	iter = xbps_array_iterator(pkg_rdeps_array);
	assert(iter);

	while ((obj = xbps_object_iterator_next(iter))) {
		foundvpkg = false;
		reqpkg = xbps_string_cstring_nocopy(obj);
		if (xhp->flags & XBPS_FLAG_DEBUG) {
			xbps_dbg_printf(xhp, "%s", "");
			for (unsigned short x = 0; x < *depth; x++) {
				xbps_dbg_printf_append(xhp, " ");
			}
			xbps_dbg_printf_append(xhp, "%s: requires dependency '%s': ", curpkg ? curpkg : " ", reqpkg);
		}
		if (((pkgname = xbps_pkgpattern_name(reqpkg)) == NULL) &&
		    ((pkgname = xbps_pkg_name(reqpkg)) == NULL)) {
			xbps_dbg_printf(xhp, "%s: can't guess pkgname for dependency: %s\n", curpkg, reqpkg);
			xbps_set_cb_state(xhp, XBPS_STATE_INVALID_DEP, ENXIO, NULL,
			    "%s: can't guess pkgname for dependency '%s'", curpkg, reqpkg);
			rv = ENXIO;
			break;
		}
		/*
		 * Pass 1: check if required dependency is provided as virtual
		 * package via "provides", if true ignore dependency.
		 */
		if (pkg_provides && xbps_match_virtual_pkg_in_array(pkg_provides, reqpkg)) {
			xbps_dbg_printf_append(xhp, "%s is a vpkg provided by %s, ignored.\n", pkgname, curpkg);
			free(pkgname);
			continue;
		}
		/*
		 * Pass 2: check if required dependency has been already
		 * added in the transaction dictionary.
		 */
		if ((curpkgd = xbps_find_pkg_in_array(unsorted, reqpkg, NULL)) ||
		    (curpkgd = xbps_find_virtualpkg_in_array(xhp, unsorted, reqpkg, NULL))) {
			xbps_dictionary_get_cstring_nocopy(curpkgd, "pkgver", &pkgver_q);
			xbps_dbg_printf_append(xhp, " (%s queued)\n", pkgver_q);
			free(pkgname);
			continue;
		}
		/*
		 * Pass 3: check if required dependency is already installed
		 * and its version is fully matched.
		 */
		if ((curpkgd = xbps_pkgdb_get_pkg(xhp, pkgname)) == NULL) {
			if ((curpkgd = xbps_pkgdb_get_virtualpkg(xhp, pkgname))) {
				foundvpkg = true;
			}
		}
		if (curpkgd == NULL) {
			if (errno && errno != ENOENT) {
				/* error */
				rv = errno;
				xbps_dbg_printf(xhp, "failed to find installed pkg for `%s': %s\n", reqpkg, strerror(rv));
				free(pkgname);
				break;
			}
			free(pkgname);
			/* Required dependency not installed */
			xbps_dbg_printf_append(xhp, "not installed.\n");
			reason = "install";
			state = XBPS_PKG_STATE_NOT_INSTALLED;
		} else {
			/*
			 * Required dependency is installed, check if its version can
			 * satisfy the requirements.
			 */
			xbps_dictionary_get_cstring_nocopy(curpkgd, "pkgver", &pkgver_q);

			/* Check its state */
			if ((rv = xbps_pkg_state_dictionary(curpkgd, &state)) != 0) {
				free(pkgname);
				break;
			}

			if (foundvpkg && xbps_match_virtual_pkg_in_dict(curpkgd, reqpkg)) {
				/*
				 * Check if required dependency is a virtual package and is satisfied
				 * by an installed package.
				 */
				xbps_dbg_printf_append(xhp, "[virtual] satisfied by `%s'.\n", pkgver_q);
				free(pkgname);
				continue;
			}
			rv = xbps_pkgpattern_match(pkgver_q, reqpkg);
			if (rv == 0) {
				char *curpkgname;
				/*
				 * The version requirement is not satisfied.
				 */
				curpkgname = xbps_pkg_name(pkgver_q);
				assert(curpkgname);
				if (strcmp(pkgname, curpkgname)) {
					xbps_dbg_printf_append(xhp, "not installed `%s (vpkg)'", pkgver_q);
					if (xbps_dictionary_get(curpkgd, "hold")) {
						xbps_dbg_printf_append(xhp, " on hold state! ignoring package.\n");
					} else {
						xbps_dbg_printf_append(xhp, "\n");
						reason = "install";
					}
				} else {
					xbps_dbg_printf_append(xhp, "installed `%s', must be updated", pkgver_q);
					if (xbps_dictionary_get(curpkgd, "hold")) {
						xbps_dbg_printf_append(xhp, " on hold state! ignoring package.\n");
					} else {
						xbps_dbg_printf_append(xhp, "\n");
						reason = "update";
					}
				}
				free(curpkgname);
				free(pkgname);
			} else if (rv == 1) {
				/*
				 * The version requirement is satisfied.
				 */
				free(pkgname);
				rv = 0;
				if (state == XBPS_PKG_STATE_UNPACKED) {
					/*
					 * Package matches the dependency pattern but was only unpacked,
					 * configure pkg.
					 */
					xbps_dbg_printf_append(xhp, "installed `%s', must be configured.\n", pkgver_q);
					reason = "configure";
				} else if (state == XBPS_PKG_STATE_INSTALLED) {
					/*
					 * Package matches the dependency pattern and is fully installed,
					 * skip to next one.
					 */
					xbps_dbg_printf_append(xhp, "installed `%s'.\n", pkgver_q);
					continue;
				}
			} else {
				/* error matching pkgpattern */
				xbps_dbg_printf(xhp, "failed to match pattern %s with %s\n", reqpkg, pkgver_q);
				free(pkgname);
				break;
			}
		}
		if (xbps_dictionary_get(curpkgd, "hold")) {
			xbps_dbg_printf(xhp, "%s on hold state! ignoring package.\n", curpkg);
			continue;
		}
		/*
		 * Pass 4: find required dependency in repository pool.
		 * If dependency does not match add pkg into the missing
		 * deps array and pass to next one.
		 */
		if (((curpkgd = xbps_rpool_get_pkg(xhp, reqpkg)) == NULL) &&
		    ((curpkgd = xbps_rpool_get_virtualpkg(xhp, reqpkg)) == NULL)) {
			/* pkg not found, there was some error */
			if (errno && errno != ENOENT) {
				xbps_dbg_printf(xhp, "failed to find pkg for `%s' in rpool: %s\n", reqpkg, strerror(errno));
				rv = errno;
				break;
			}
			rv = add_missing_reqdep(xhp, reqpkg);
			if (rv != 0 && rv != EEXIST) {
				xbps_dbg_printf(xhp, "`%s': add_missing_reqdep failed\n", reqpkg);
				break;
			} else if (rv == EEXIST) {
				xbps_dbg_printf(xhp, "`%s' missing dep already added.\n", reqpkg);
				rv = 0;
				continue;
			} else {
				xbps_dbg_printf(xhp, "`%s' added into the missing deps array.\n", reqpkg);
				continue;
			}
		}
		xbps_dictionary_get_cstring_nocopy(curpkgd, "pkgver", &pkgver_q);
		reqpkgname = xbps_pkg_name(pkgver_q);
		assert(reqpkgname);
		/*
		 * Check dependency validity.
		 */
		pkgname = xbps_pkg_name(curpkg);
		assert(pkgname);
		if (strcmp(pkgname, reqpkgname) == 0) {
			xbps_dbg_printf_append(xhp, "[ignoring wrong dependency %s (depends on itself)]\n", reqpkg);
			xbps_remove_string_from_array(pkg_rdeps_array, reqpkg);
			free(pkgname);
			free(reqpkgname);
			continue;
		}
		free(pkgname);
		free(reqpkgname);
		/*
		 * If package doesn't have rundeps, pass to the next one.
		 */
		curpkgrdeps = xbps_dictionary_get(curpkgd, "run_depends");
		if (curpkgrdeps == NULL) {
			/*
			 * Package is on repo, add it into the transaction dictionary.
			 */
			xbps_dictionary_set_cstring_nocopy(curpkgd, "transaction", reason);
			rv = xbps_transaction_store(xhp, unsorted, curpkgd, reason, true);
			if (rv != 0) {
				xbps_dbg_printf(xhp, "xbps_transaction_store failed for `%s': %s\n", reqpkg, strerror(rv));
				break;
			}
			continue;
		}

		if (xhp->flags & XBPS_FLAG_DEBUG) {
			xbps_dbg_printf(xhp, "%s", "");
			for (unsigned short x = 0; x < *depth; x++) {
				xbps_dbg_printf_append(xhp, " ");
			}
			xbps_dbg_printf_append(xhp, "%s: finding dependencies:\n", pkgver_q);
		}
		/*
		 * Recursively find rundeps for current pkg dictionary.
		 */
		(*depth)++;
		curpkgprovides = xbps_dictionary_get(curpkgd, "provides");
		rv = find_repo_deps(xhp, unsorted, curpkgrdeps, curpkgprovides, pkgver_q, depth);
		if (rv != 0) {
			xbps_dbg_printf(xhp, "Error checking %s for rundeps: %s\n", reqpkg, strerror(rv));
			break;
		}
		/*
		 * Package is on repo, add it into the transaction dictionary.
		 */
		xbps_dictionary_set_cstring_nocopy(curpkgd, "transaction", reason);
		rv = xbps_transaction_store(xhp, unsorted, curpkgd, reason, true);
		if (rv != 0) {
			xbps_dbg_printf(xhp, "xbps_transaction_store failed for `%s': %s\n", reqpkg, strerror(rv));
			break;
		}
	}
	xbps_object_iterator_release(iter);
	(*depth)--;

	return rv;
}