ATF_TC_BODY(pkgdb_get_pkg_revdeps_test, tc) { struct xbps_handle xh; xbps_array_t res; xbps_string_t pstr; const char *tcsdir, *str; const char *eout = "four-0.1_1\ntwo-0.1_1\n"; unsigned int i; /* get test source dir */ tcsdir = atf_tc_get_config_var(tc, "srcdir"); memset(&xh, 0, sizeof(xh)); strncpy(xh.rootdir, tcsdir, sizeof(xh.rootdir)); strncpy(xh.metadir, tcsdir, sizeof(xh.metadir)); xh.flags = XBPS_FLAG_DEBUG; ATF_REQUIRE_EQ(xbps_init(&xh), 0); res = xbps_pkgdb_get_pkg_revdeps(&xh, "mixed"); ATF_REQUIRE_EQ(xbps_object_type(res), XBPS_TYPE_ARRAY); pstr = xbps_string_create(); for (i = 0; i < xbps_array_count(res); i++) { xbps_array_get_cstring_nocopy(res, i, &str); xbps_string_append_cstring(pstr, str); xbps_string_append_cstring(pstr, "\n"); } ATF_REQUIRE_STREQ(xbps_string_cstring_nocopy(pstr), eout); }
static void generate_full_revdeps_tree(struct xbps_handle *xhp) { xbps_object_t obj; xbps_object_iterator_t iter; if (xhp->pkgdb_revdeps) return; xhp->pkgdb_revdeps = xbps_dictionary_create(); assert(xhp->pkgdb_revdeps); iter = xbps_dictionary_iterator(xhp->pkgdb); assert(iter); while ((obj = xbps_object_iterator_next(iter))) { xbps_array_t rundeps; xbps_dictionary_t pkgd; const char *pkgver; pkgd = xbps_dictionary_get_keysym(xhp->pkgdb, obj); rundeps = xbps_dictionary_get(pkgd, "run_depends"); if (!xbps_array_count(rundeps)) continue; xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver); for (unsigned int i = 0; i < xbps_array_count(rundeps); i++) { xbps_array_t pkg; const char *pkgdep, *vpkgname; char *curpkgname; bool alloc = false; xbps_array_get_cstring_nocopy(rundeps, i, &pkgdep); curpkgname = xbps_pkgpattern_name(pkgdep); if (curpkgname == NULL) curpkgname = xbps_pkg_name(pkgdep); assert(curpkgname); vpkgname = vpkg_user_conf(xhp, curpkgname); if (vpkgname == NULL) vpkgname = curpkgname; pkg = xbps_dictionary_get(xhp->pkgdb_revdeps, vpkgname); if (pkg == NULL) { alloc = true; pkg = xbps_array_create(); } if (!xbps_match_string_in_array(pkg, pkgver)) { xbps_array_add_cstring_nocopy(pkg, pkgver); xbps_dictionary_set(xhp->pkgdb_revdeps, vpkgname, pkg); } free(curpkgname); if (alloc) xbps_object_release(pkg); } } xbps_object_iterator_release(iter); }
static void print_array(xbps_array_t a) { const char *str; for (unsigned int i = 0; i < xbps_array_count(a); i++) { xbps_array_get_cstring_nocopy(a, i, &str); fprintf(stderr, "%s\n", str); } }
static void show_conflicts(xbps_array_t a) { unsigned int i; const char *str; for (i = 0; i < xbps_array_count(a); i++) { xbps_array_get_cstring_nocopy(a, i, &str); fprintf(stderr, "%s\n", str); } }
static void print_results(struct xbps_handle *xhp, struct search_data *sd) { const char *pkgver, *desc, *inststr; char tmp[256], *out; unsigned int j, tlen = 0, len = 0; /* Iterate over results array and find out largest pkgver string */ for (unsigned int i = 0; i < xbps_array_count(sd->results); i+=2) { xbps_array_get_cstring_nocopy(sd->results, i, &pkgver); len = strlen(pkgver); if (tlen == 0 || len > tlen) tlen = len; } for (unsigned int i = 0; i < xbps_array_count(sd->results); i+=2) { xbps_array_get_cstring_nocopy(sd->results, i, &pkgver); xbps_array_get_cstring_nocopy(sd->results, i+1, &desc); xbps_strlcpy(tmp, pkgver, sizeof(tmp)); for (j = strlen(tmp); j < tlen; j++) tmp[j] = ' '; tmp[j] = '\0'; if (xbps_pkgdb_get_pkg(xhp, pkgver)) inststr = "[*]"; else inststr = "[-]"; len = strlen(inststr) + strlen(tmp) + strlen(desc) + 3; if (sd->maxcols && (int)len > sd->maxcols) { out = malloc(sd->maxcols+1); assert(out); snprintf(out, sd->maxcols-3, "%s %s %s", inststr, tmp, desc); xbps_strlcat(out, "...\n", sd->maxcols+1); printf("%s", out); free(out); } else { printf("%s %s %s\n", inststr, tmp, desc); } } }
static int pkgdb_map_vpkgs(struct xbps_handle *xhp) { xbps_object_iterator_t iter; xbps_object_t obj; int rv = 0; if (!xbps_dictionary_count(xhp->pkgdb)) return 0; if (xhp->vpkgd == NULL) { xhp->vpkgd = xbps_dictionary_create(); assert(xhp->vpkgd); } /* * This maps all pkgs that have virtualpkgs in pkgdb. */ iter = xbps_dictionary_iterator(xhp->pkgdb); assert(iter); while ((obj = xbps_object_iterator_next(iter))) { xbps_array_t provides; xbps_dictionary_t pkgd; const char *pkgver; char *pkgname; pkgd = xbps_dictionary_get_keysym(xhp->pkgdb, obj); provides = xbps_dictionary_get(pkgd, "provides"); if (provides == NULL) continue; xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver); pkgname = xbps_pkg_name(pkgver); assert(pkgname); for (unsigned int i = 0; i < xbps_array_count(provides); i++) { const char *vpkg; xbps_array_get_cstring_nocopy(provides, i, &vpkg); if (!xbps_dictionary_set_cstring(xhp->vpkgd, vpkg, pkgname)) { xbps_dbg_printf(xhp, "%s: set_cstring vpkg " "%s pkgname %s\n", __func__, vpkg, pkgname); rv = EINVAL; } else { xbps_dbg_printf(xhp, "[pkgdb] added vpkg %s for %s\n", vpkg, pkgname); } } free(pkgname); } xbps_object_iterator_release(iter); return rv; }
/* * 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; }
int show_pkg_revdeps(struct xbps_handle *xhp, const char *pkg) { xbps_array_t reqby; const char *pkgdep; unsigned int i; if ((reqby = xbps_pkgdb_get_pkg_revdeps(xhp, pkg)) != NULL) { for (i = 0; i < xbps_array_count(reqby); i++) { xbps_array_get_cstring_nocopy(reqby, i, &pkgdep); printf("%s\n", pkgdep); } } return 0; }
int repo_show_pkg_revdeps(struct xbps_handle *xhp, const char *pkg) { xbps_array_t revdeps; const char *pkgver; unsigned int i; int rv; revdeps = xbps_rpool_get_pkg_revdeps(xhp, pkg); rv = errno; for (i = 0; i < xbps_array_count(revdeps); i++) { xbps_array_get_cstring_nocopy(revdeps, i, &pkgver); printf("%s\n", pkgver); } return rv; }
bool HIDDEN xbps_transaction_shlibs(struct xbps_handle *xhp, xbps_array_t pkgs, xbps_array_t mshlibs) { xbps_object_t obj; xbps_object_iterator_t iter; xbps_dictionary_t shrequires, shprovides; bool unmatched = false; shrequires = collect_shlibs(xhp, pkgs, true); shprovides = collect_shlibs(xhp, pkgs, false); /* iterate over shlib-requires to find unmatched shlibs */ iter = xbps_dictionary_iterator(shrequires); assert(iter); while ((obj = xbps_object_iterator_next(iter))) { xbps_array_t array; const char *pkgver, *shlib; char *buf; shlib = xbps_dictionary_keysym_cstring_nocopy(obj); xbps_dbg_printf(xhp, "%s: checking for `%s': ", __func__, shlib); if (xbps_dictionary_get(shprovides, shlib)) { xbps_dbg_printf_append(xhp, "found\n"); continue; } xbps_dbg_printf_append(xhp, "not found\n"); unmatched = true; array = xbps_dictionary_get_keysym(shrequires, obj); for (unsigned int i = 0; i < xbps_array_count(array); i++) { xbps_array_get_cstring_nocopy(array, i, &pkgver); buf = xbps_xasprintf("%s: broken, unresolvable " "shlib `%s'", pkgver, shlib); xbps_array_add_cstring(mshlibs, buf); free(buf); } xbps_object_release(array); } xbps_object_iterator_release(iter); xbps_object_release(shprovides); return unmatched; }
xbps_array_t xbps_repo_get_pkg_revdeps(struct xbps_repo *repo, const char *pkg) { xbps_array_t revdeps = NULL, vdeps = NULL; xbps_dictionary_t pkgd; const char *vpkg; bool match = false; if (repo->idx == NULL) return NULL; if (((pkgd = xbps_repo_get_pkg(repo, pkg)) == NULL) && ((pkgd = xbps_repo_get_virtualpkg(repo, pkg)) == NULL)) { errno = ENOENT; return NULL; } /* * If pkg is a virtual pkg let's match it instead of the real pkgver. */ if ((vdeps = xbps_dictionary_get(pkgd, "provides"))) { for (unsigned int i = 0; i < xbps_array_count(vdeps); i++) { char *vpkgn; xbps_array_get_cstring_nocopy(vdeps, i, &vpkg); vpkgn = xbps_pkg_name(vpkg); assert(vpkgn); if (strcmp(vpkgn, pkg) == 0) { free(vpkgn); match = true; break; } free(vpkgn); vpkg = NULL; } if (match) revdeps = revdeps_match(repo, pkgd, vpkg); } if (!match) revdeps = revdeps_match(repo, pkgd, NULL); return revdeps; }
static bool entry_is_conf_file(const char *file) { xbps_array_t a; const char *curfile; unsigned int i; assert(file); a = xbps_dictionary_get(pkg_propsd, "conf_files"); if (a == NULL || xbps_array_count(a) == 0) return false; for (i = 0; i < xbps_array_count(a); i++) { xbps_array_get_cstring_nocopy(a, i, &curfile); if (strcmp(file, curfile) == 0) return true; } return false; }
/* * Check if pkg is explicitly marked to replace a specific installed version. */ bool xbps_pkg_reverts(xbps_dictionary_t pkg, const char *pkgver) { unsigned int i; xbps_array_t reverts; const char *version = xbps_pkg_version(pkgver); const char *revertver; if ((reverts = xbps_dictionary_get(pkg, "reverts")) == NULL) return false; for (i = 0; i < xbps_array_count(reverts); i++) { xbps_array_get_cstring_nocopy(reverts, i, &revertver); if (strcmp(version, revertver) == 0) { return true; } } return false; }
static void print_rdeps(struct xbps_handle *xhp, xbps_array_t rdeps, bool full, bool repo, bool origin, int *indent) { xbps_array_t currdeps; xbps_dictionary_t pkgd; const char *pkgdep; unsigned int i; int j; if (!origin) (*indent)++; for (i = 0; i < xbps_array_count(rdeps); i++) { xbps_array_get_cstring_nocopy(rdeps, i, &pkgdep); if (!origin || !full) for (j = 0; j < *indent; j++) putchar(' '); printf("%s\n", pkgdep); if (!full) continue; if (repo) { pkgd = xbps_rpool_get_pkg(xhp, pkgdep); if (pkgd == NULL) pkgd = xbps_rpool_get_virtualpkg(xhp, pkgdep); } else { pkgd = xbps_pkgdb_get_pkg(xhp, pkgdep); if (pkgd == NULL) pkgd = xbps_pkgdb_get_virtualpkg(xhp, pkgdep); } if (pkgd != NULL) { currdeps = xbps_dictionary_get(pkgd, "run_depends"); if (currdeps != NULL) print_rdeps(xhp, currdeps, full, repo, false, indent); } } (*indent)--; }
/* * Returns true if entry is a configuration file, false otherwise. */ int HIDDEN xbps_entry_is_a_conf_file(xbps_dictionary_t propsd, const char *entry_pname) { xbps_array_t array; const char *cffile; unsigned int i; assert(xbps_object_type(propsd) == XBPS_TYPE_DICTIONARY); assert(entry_pname != NULL); array = xbps_dictionary_get(propsd, "conf_files"); if (xbps_array_count(array) == 0) return false; for (i = 0; i < xbps_array_count(array); i++) { xbps_array_get_cstring_nocopy(array, i, &cffile); if (strcmp(cffile, entry_pname) == 0) return true; } return false; }
void HIDDEN xbps_transaction_revdeps(struct xbps_handle *xhp, xbps_array_t pkgs) { xbps_array_t mdeps; mdeps = xbps_dictionary_get(xhp->transd, "missing_deps"); for (unsigned int i = 0; i < xbps_array_count(pkgs); i++) { xbps_array_t pkgrdeps; xbps_object_t obj; const char *pkgver, *tract; char *pkgname; obj = xbps_array_get(pkgs, i); /* * if pkg in transaction is not installed, * pass to next one. */ xbps_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver); xbps_dictionary_get_cstring_nocopy(obj, "transaction", &tract); pkgname = xbps_pkg_name(pkgver); assert(pkgname); if (xbps_pkg_is_installed(xhp, pkgname) == 0) { free(pkgname); continue; } /* * If pkg is installed but does not have revdeps, * pass to next one. */ pkgrdeps = xbps_pkgdb_get_pkg_revdeps(xhp, pkgname); if (!xbps_array_count(pkgrdeps)) { free(pkgname); continue; } free(pkgname); /* * Time to validate revdeps for current pkg. */ for (unsigned int x = 0; x < xbps_array_count(pkgrdeps); x++) { xbps_array_t rundeps; xbps_dictionary_t revpkgd; const char *curpkgver, *revpkgver, *curdep, *curtract; char *curpkgname, *curdepname; bool found = false; xbps_array_get_cstring_nocopy(pkgrdeps, x, &curpkgver); pkgname = xbps_pkg_name(curpkgver); assert(pkgname); if ((revpkgd = xbps_find_pkg_in_array(pkgs, pkgname, NULL))) { xbps_dictionary_get_cstring_nocopy(revpkgd, "transaction", &curtract); if (strcmp(curtract, "remove") == 0) revpkgd = NULL; } if (revpkgd == NULL) revpkgd = xbps_pkgdb_get_pkg(xhp, curpkgver); xbps_dictionary_get_cstring_nocopy(revpkgd, "pkgver", &revpkgver); /* * If target pkg is being removed, all its revdeps * will be broken unless those revdeps are also in * the transaction. */ if (strcmp(tract, "remove") == 0) { if (xbps_dictionary_get(obj, "replaced")) { free(pkgname); continue; } if (xbps_find_pkg_in_array(pkgs, pkgname, "remove")) { free(pkgname); continue; } free(pkgname); broken_pkg(mdeps, curpkgver, pkgver, tract); continue; } /* * First try to match any supported virtual package. */ if (check_virtual_pkgs(mdeps, obj, revpkgd)) { free(pkgname); continue; } /* * Try to match real dependencies. */ rundeps = xbps_dictionary_get(revpkgd, "run_depends"); /* * Find out what dependency is it. */ curpkgname = xbps_pkg_name(pkgver); assert(curpkgname); for (unsigned int j = 0; j < xbps_array_count(rundeps); j++) { xbps_array_get_cstring_nocopy(rundeps, j, &curdep); if (((curdepname = xbps_pkg_name(curdep)) == NULL) && ((curdepname = xbps_pkgpattern_name(curdep)) == NULL)) abort(); if (strcmp(curdepname, curpkgname) == 0) { free(curdepname); found = true; break; } free(curdepname); } free(curpkgname); if (!found) { free(pkgname); continue; } if (xbps_match_pkgdep_in_array(rundeps, pkgver)) { free(pkgname); continue; } /* * Installed package conflicts with package * in transaction being updated, check * if a new version of this conflicting package * is in the transaction. */ if (xbps_find_pkg_in_array(pkgs, pkgname, "update")) { free(pkgname); continue; } free(pkgname); broken_pkg(mdeps, curpkgver, pkgver, tract); } } }
int xbps_transaction_prepare(struct xbps_handle *xhp) { xbps_array_t array, pkgs, edges; unsigned int i, cnt; int rv = 0; if (xhp->transd == NULL) return ENXIO; /* * Collect dependencies for pkgs in transaction. */ if ((edges = xbps_array_create()) == NULL) return ENOMEM; /* * The edges are also appended after its dependencies have been * collected; the edges at the original array are removed later. */ pkgs = xbps_dictionary_get(xhp->transd, "packages"); assert(xbps_object_type(pkgs) == XBPS_TYPE_ARRAY); cnt = xbps_array_count(pkgs); for (i = 0; i < cnt; i++) { xbps_dictionary_t pkgd; xbps_string_t str; const char *tract = NULL; pkgd = xbps_array_get(pkgs, i); str = xbps_dictionary_get(pkgd, "pkgver"); xbps_dictionary_get_cstring_nocopy(pkgd, "transaction", &tract); if ((strcmp(tract, "remove") == 0) || strcmp(tract, "hold") == 0) continue; assert(xbps_object_type(str) == XBPS_TYPE_STRING); if (!xbps_array_add(edges, str)) return ENOMEM; if ((rv = xbps_repository_find_deps(xhp, pkgs, pkgd)) != 0) return rv; if (!xbps_array_add(pkgs, pkgd)) return ENOMEM; } /* ... remove dup edges at head */ for (i = 0; i < xbps_array_count(edges); i++) { const char *pkgver; xbps_array_get_cstring_nocopy(edges, i, &pkgver); xbps_remove_pkg_from_array_by_pkgver(pkgs, pkgver); } xbps_object_release(edges); /* * Check for packages to be replaced. */ if ((rv = xbps_transaction_package_replace(xhp, pkgs)) != 0) { xbps_object_release(xhp->transd); xhp->transd = NULL; return rv; } /* * If there are missing deps or revdeps bail out. */ xbps_transaction_revdeps(xhp, pkgs); array = xbps_dictionary_get(xhp->transd, "missing_deps"); if (xbps_array_count(array)) { if (xhp->flags & XBPS_FLAG_FORCE_REMOVE_REVDEPS) { xbps_dbg_printf(xhp, "[trans] continuing with broken reverse dependencies!"); } else { return ENODEV; } } /* * If there are package conflicts bail out. */ xbps_transaction_conflicts(xhp, pkgs); array = xbps_dictionary_get(xhp->transd, "conflicts"); if (xbps_array_count(array)) return EAGAIN; /* * Check for unresolved shared libraries. */ if (xbps_transaction_shlibs(xhp, pkgs, xbps_dictionary_get(xhp->transd, "missing_shlibs"))) { if (xhp->flags & XBPS_FLAG_FORCE_REMOVE_REVDEPS) { xbps_dbg_printf(xhp, "[trans] continuing with unresolved shared libraries!"); } else { return ENOEXEC; } } /* * Add transaction stats for total download/installed size, * number of packages to be installed, updated, configured * and removed to the transaction dictionary. */ if ((rv = compute_transaction_stats(xhp)) != 0) { return rv; } /* * Remove now unneeded objects. */ xbps_dictionary_remove(xhp->transd, "missing_shlibs"); xbps_dictionary_remove(xhp->transd, "missing_deps"); xbps_dictionary_remove(xhp->transd, "conflicts"); xbps_dictionary_make_immutable(xhp->transd); return 0; }
int xbps_init(struct xbps_handle *xhp) { struct utsname un; char cwd[PATH_MAX-1], *buf; const char *repodir, *native_arch; int rv; assert(xhp != NULL); /* get cwd */ if (getcwd(cwd, sizeof(cwd)) == NULL) return ENOTSUP; /* set conffile */ if (xhp->conffile[0] == '\0') { snprintf(xhp->conffile, sizeof(xhp->conffile), XBPS_CONF_DEF); } else { buf = strdup(xhp->conffile); snprintf(xhp->conffile, sizeof(xhp->conffile), "%s/%s", cwd, buf); free(buf); } /* Set rootdir */ if (xhp->rootdir[0] == '\0') { xhp->rootdir[0] = '/'; xhp->rootdir[1] = '\0'; } else if (xhp->rootdir[0] != '/') { buf = strdup(xhp->rootdir); snprintf(xhp->rootdir, sizeof(xhp->rootdir), "%s/%s", cwd, buf); free(buf); } /* parse configuration file */ xbps_dbg_printf(xhp, "%s\n", XBPS_RELVER); if ((rv = parse_file(xhp, cwd, xhp->conffile, false, false)) != 0) { xbps_dbg_printf(xhp, "Using built-in defaults\n"); } /* Set cachedir */ if (xhp->cachedir[0] == '\0') { snprintf(xhp->cachedir, sizeof(xhp->cachedir), "%s/%s", strcmp(xhp->rootdir, "/") ? xhp->rootdir : "", XBPS_CACHE_PATH); } else if (xhp->cachedir[0] != '/') { /* relative path */ buf = strdup(xhp->cachedir); snprintf(xhp->cachedir, sizeof(xhp->cachedir), "%s/%s", strcmp(xhp->rootdir, "/") ? xhp->rootdir : "", buf); free(buf); } /* Set metadir */ if (xhp->metadir[0] == '\0') { snprintf(xhp->metadir, sizeof(xhp->metadir), "%s/%s", strcmp(xhp->rootdir, "/") ? xhp->rootdir : "", XBPS_META_PATH); } else if (xhp->metadir[0] != '/') { /* relative path */ buf = strdup(xhp->metadir); snprintf(xhp->metadir, sizeof(xhp->metadir), "%s/%s", strcmp(xhp->rootdir, "/") ? xhp->rootdir : "", buf); free(buf); } /* process virtualpkg.d dirs */ if ((rv = parse_dir(xhp, cwd, XBPS_SYS_VPKG_PATH, XBPS_VPKG_PATH, true)) != 0) return rv; /* process repo.d dirs */ if ((rv = parse_dir(xhp, cwd, XBPS_SYS_REPOD_PATH, XBPS_REPOD_PATH, false)) != 0) return rv; /* process preserve.d dirs */ if ((rv = parse_dir(xhp, cwd, XBPS_SYS_PRESERVED_PATH, XBPS_PRESERVED_PATH, false)) != 0) return rv; xhp->target_arch = getenv("XBPS_TARGET_ARCH"); if ((native_arch = getenv("XBPS_ARCH")) != NULL) { strlcpy(xhp->native_arch, native_arch, sizeof(xhp->native_arch)); } else { uname(&un); strlcpy(xhp->native_arch, un.machine, sizeof(xhp->native_arch)); } assert(xhp->native_arch); xbps_fetch_set_cache_connection(XBPS_FETCH_CACHECONN, XBPS_FETCH_CACHECONN_HOST); xbps_dbg_printf(xhp, "rootdir=%s\n", xhp->rootdir); xbps_dbg_printf(xhp, "metadir=%s\n", xhp->metadir); xbps_dbg_printf(xhp, "cachedir=%s\n", xhp->cachedir); xbps_dbg_printf(xhp, "syslog=%s\n", xhp->flags & XBPS_FLAG_DISABLE_SYSLOG ? "false" : "true"); xbps_dbg_printf(xhp, "Architecture: %s\n", xhp->native_arch); xbps_dbg_printf(xhp, "Target Architecture: %s\n", xhp->target_arch); if (xhp->flags & XBPS_FLAG_DEBUG) { for (unsigned int i = 0; i < xbps_array_count(xhp->repositories); i++) { xbps_array_get_cstring_nocopy(xhp->repositories, i, &repodir); xbps_dbg_printf(xhp, "Repository[%u]=%s\n", i, repodir); } } /* Going back to old working directory */ if (chdir(cwd) == -1) xbps_dbg_printf(xhp, "%s: cannot chdir to %s: %s\n", __func__, cwd, strerror(errno)); return 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; }
void HIDDEN xbps_transaction_revdeps(struct xbps_handle *xhp) { xbps_array_t mdeps, unsorted, pkgrdeps, rundeps; xbps_dictionary_t revpkgd; xbps_object_t obj; const char *pkgver, *curdep, *revpkgver, *curpkgver, *tract; char *pkgname, *curdepname, *curpkgname, *str; unsigned int i, j, x; unsorted = xbps_dictionary_get(xhp->transd, "unsorted_deps"); for (i = 0; i < xbps_array_count(unsorted); i++) { obj = xbps_array_get(unsorted, i); /* * Only check packages in transaction being updated. */ xbps_dictionary_get_cstring_nocopy(obj, "transaction", &tract); if (strcmp(tract, "update")) continue; /* * if pkg in transaction is not installed, * pass to next one. */ xbps_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver); pkgname = xbps_pkg_name(pkgver); assert(pkgname); if (xbps_pkg_is_installed(xhp, pkgname) == 0) { free(pkgname); continue; } /* * If pkg is installed but does not have revdeps, * pass to next one. */ pkgrdeps = xbps_pkgdb_get_pkg_revdeps(xhp, pkgname); if (!xbps_array_count(pkgrdeps)) { free(pkgname); continue; } free(pkgname); /* * Time to validate revdeps for current pkg. */ for (x = 0; x < xbps_array_count(pkgrdeps); x++) { bool found = false; xbps_array_get_cstring_nocopy(pkgrdeps, x, &curpkgver); revpkgd = xbps_pkgdb_get_pkg(xhp, curpkgver); /* * First try to match any supported virtual package. */ if (check_virtual_pkgs(xhp, obj, revpkgd)) continue; /* * Try to match real dependencies. */ rundeps = xbps_dictionary_get(revpkgd, "run_depends"); /* * Find out what dependency is it. */ curpkgname = xbps_pkg_name(pkgver); assert(curpkgname); for (j = 0; j < xbps_array_count(rundeps); j++) { xbps_array_get_cstring_nocopy(rundeps, j, &curdep); if (((curdepname = xbps_pkg_name(curdep)) == NULL) && ((curdepname = xbps_pkgpattern_name(curdep)) == NULL)) abort(); if (strcmp(curdepname, curpkgname) == 0) { free(curdepname); found = true; break; } free(curdepname); } if (!found) continue; if (xbps_match_pkgdep_in_array(rundeps, pkgver)) continue; /* * Installed package conflicts with package * in transaction being updated, check * if a new version of this conflicting package * is in the transaction. */ pkgname = xbps_pkg_name(curpkgver); if (xbps_find_pkg_in_array(unsorted, pkgname)) { free(pkgname); continue; } free(pkgname); mdeps = xbps_dictionary_get(xhp->transd, "missing_deps"); xbps_dictionary_get_cstring_nocopy(revpkgd, "pkgver", &revpkgver); str = xbps_xasprintf("CONFLICT: `%s' " "update breaks `%s', needs `%s'", pkgver, revpkgver, curdep); xbps_array_add_cstring(mdeps, str); free(str); } } }
int xbps_alternatives_unregister(struct xbps_handle *xhp, xbps_dictionary_t pkgd) { xbps_array_t allkeys; xbps_dictionary_t alternatives, pkg_alternatives; const char *pkgver; char *pkgname; bool update = false; int rv = 0; assert(xhp); alternatives = xbps_dictionary_get(xhp->pkgdb, "_XBPS_ALTERNATIVES_"); if (alternatives == NULL) return 0; pkg_alternatives = xbps_dictionary_get(pkgd, "alternatives"); if (!xbps_dictionary_count(pkg_alternatives)) return 0; xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver); if ((pkgname = xbps_pkg_name(pkgver)) == NULL) return EINVAL; xbps_dictionary_get_bool(pkgd, "alternatives-update", &update); allkeys = xbps_dictionary_all_keys(pkg_alternatives); for (unsigned int i = 0; i < xbps_array_count(allkeys); i++) { xbps_array_t array; xbps_object_t keysym; const char *first = NULL, *keyname; keysym = xbps_array_get(allkeys, i); keyname = xbps_dictionary_keysym_cstring_nocopy(keysym); array = xbps_dictionary_get(alternatives, keyname); if (array == NULL) continue; xbps_array_get_cstring_nocopy(array, 0, &first); if (strcmp(pkgname, first) == 0) { /* this pkg is the current alternative for this group */ rv = remove_symlinks(xhp, xbps_dictionary_get(pkg_alternatives, keyname), keyname); if (rv != 0) break; } xbps_set_cb_state(xhp, XBPS_STATE_ALTGROUP_REMOVED, 0, NULL, "%s: unregistered '%s' alternatives group", pkgver, keyname); if (!update) xbps_remove_string_from_array(array, pkgname); if (xbps_array_count(array) == 0) { xbps_dictionary_remove(alternatives, keyname); } else { xbps_dictionary_t curpkgd; first = NULL; xbps_array_get_cstring_nocopy(array, 0, &first); curpkgd = xbps_pkgdb_get_pkg(xhp, first); assert(curpkgd); xbps_set_cb_state(xhp, XBPS_STATE_ALTGROUP_SWITCHED, 0, NULL, "Switched '%s' alternatives group to '%s'", keyname, first); pkg_alternatives = xbps_dictionary_get(curpkgd, "alternatives"); rv = create_symlinks(xhp, xbps_dictionary_get(pkg_alternatives, keyname), keyname); if (rv != 0) break; } } xbps_object_release(allkeys); free(pkgname); return rv; }
static xbps_array_t revdeps_match(struct xbps_repo *repo, xbps_dictionary_t tpkgd, const char *str) { xbps_dictionary_t pkgd; xbps_array_t revdeps = NULL, pkgdeps, provides; xbps_object_iterator_t iter; xbps_object_t obj; const char *pkgver, *tpkgver, *arch, *vpkg; iter = xbps_dictionary_iterator(repo->idx); assert(iter); while ((obj = xbps_object_iterator_next(iter))) { pkgd = xbps_dictionary_get_keysym(repo->idx, obj); if (xbps_dictionary_equals(pkgd, tpkgd)) continue; pkgdeps = xbps_dictionary_get(pkgd, "run_depends"); if (!xbps_array_count(pkgdeps)) continue; /* * Try to match passed in string. */ if (str) { if (!xbps_match_pkgdep_in_array(pkgdeps, str)) continue; xbps_dictionary_get_cstring_nocopy(pkgd, "architecture", &arch); if (!xbps_pkg_arch_match(repo->xhp, arch, NULL)) continue; xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &tpkgver); /* match */ if (revdeps == NULL) revdeps = xbps_array_create(); if (!xbps_match_string_in_array(revdeps, tpkgver)) xbps_array_add_cstring_nocopy(revdeps, tpkgver); continue; } /* * Try to match any virtual package. */ provides = xbps_dictionary_get(tpkgd, "provides"); for (unsigned int i = 0; i < xbps_array_count(provides); i++) { xbps_array_get_cstring_nocopy(provides, i, &vpkg); if (!xbps_match_pkgdep_in_array(pkgdeps, vpkg)) continue; xbps_dictionary_get_cstring_nocopy(pkgd, "architecture", &arch); if (!xbps_pkg_arch_match(repo->xhp, arch, NULL)) continue; xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &tpkgver); /* match */ if (revdeps == NULL) revdeps = xbps_array_create(); if (!xbps_match_string_in_array(revdeps, tpkgver)) xbps_array_add_cstring_nocopy(revdeps, tpkgver); } /* * Try to match by pkgver. */ xbps_dictionary_get_cstring_nocopy(tpkgd, "pkgver", &pkgver); if (!xbps_match_pkgdep_in_array(pkgdeps, pkgver)) continue; xbps_dictionary_get_cstring_nocopy(pkgd, "architecture", &arch); if (!xbps_pkg_arch_match(repo->xhp, arch, NULL)) continue; xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &tpkgver); /* match */ if (revdeps == NULL) revdeps = xbps_array_create(); if (!xbps_match_string_in_array(revdeps, tpkgver)) xbps_array_add_cstring_nocopy(revdeps, tpkgver); } xbps_object_iterator_release(iter); return revdeps; }
static bool repodata_commit(struct xbps_handle *xhp, const char *repodir, xbps_dictionary_t idx, xbps_dictionary_t meta, xbps_dictionary_t stage) { const char *pkgname; xbps_object_iterator_t iter; xbps_object_t keysym; int rv; if(xbps_dictionary_count(stage) == 0) { // Nothing to do. return true; } /* * Find old shlibs-provides */ xbps_dictionary_t oldshlibs = xbps_dictionary_create(); xbps_dictionary_t usedshlibs = xbps_dictionary_create(); iter = xbps_dictionary_iterator(stage); while ((keysym = xbps_object_iterator_next(iter))) { pkgname = xbps_dictionary_keysym_cstring_nocopy(keysym); xbps_dictionary_t oldpkg = xbps_dictionary_get(idx, pkgname); xbps_array_t pkgshlibs = xbps_dictionary_get(oldpkg, "shlib-provides"); for(unsigned int i = 0; i < xbps_array_count(pkgshlibs); i++) { const char *shlib = NULL; xbps_array_get_cstring_nocopy(pkgshlibs, i, &shlib); xbps_dictionary_set_cstring(oldshlibs, shlib, pkgname); } } xbps_object_iterator_release(iter); /* * throw away all unused shlibs */ iter = xbps_dictionary_iterator(idx); while ((keysym = xbps_object_iterator_next(iter))) { pkgname = xbps_dictionary_keysym_cstring_nocopy(keysym); xbps_dictionary_t pkg = xbps_dictionary_get(stage, pkgname); if(!pkg) pkg = xbps_dictionary_get_keysym(idx, keysym); xbps_array_t pkgshlibs = xbps_dictionary_get(pkg, "shlib-requires"); for(unsigned int i = 0; i < xbps_array_count(pkgshlibs); i++) { const char *shlib = NULL, *user = NULL; xbps_array_get_cstring_nocopy(pkgshlibs, i, &shlib); xbps_dictionary_get_cstring_nocopy(pkg, shlib, &user); if(!user) continue; xbps_array_t users = xbps_dictionary_get(usedshlibs, shlib); if(!users) { users = xbps_array_create(); xbps_dictionary_set(usedshlibs, shlib, users); } xbps_array_add_cstring(users, user); } } xbps_object_iterator_release(iter); /* * purge all packages that are fullfilled by the stage */ iter = xbps_dictionary_iterator(stage); while ((keysym = xbps_object_iterator_next(iter))) { pkgname = xbps_dictionary_keysym_cstring_nocopy(keysym); xbps_dictionary_t newpkg = xbps_dictionary_get(idx, pkgname); xbps_array_t pkgshlibs = xbps_dictionary_get(newpkg, "shlib-provides"); for(unsigned int i = 0; i < xbps_array_count(pkgshlibs); i++) { const char *shlib; xbps_array_get_cstring_nocopy(pkgshlibs, i, &shlib); xbps_dictionary_remove(usedshlibs, shlib); } } xbps_object_iterator_release(iter); if(xbps_dictionary_count(usedshlibs) != 0) { puts("Unfullfilled shlibs:"); iter = xbps_dictionary_iterator(usedshlibs); while ((keysym = xbps_object_iterator_next(iter))) { const char *shlib = xbps_dictionary_keysym_cstring_nocopy(keysym), *provider = NULL; xbps_array_t users = xbps_dictionary_get(usedshlibs, shlib); xbps_dictionary_get_cstring_nocopy(usedshlibs, shlib, &provider); printf(" %s (provided by: %s; used by: ", shlib, provider); const char *pre = ""; for(unsigned int i = 0; i < xbps_array_count(users); i++) { const char *user; xbps_array_get_cstring_nocopy(users, i, &user); xbps_dictionary_remove(usedshlibs, shlib); printf("%s%s",pre, user); pre = ", "; } puts(")"); } puts("Changes are commit to stage."); xbps_object_iterator_release(iter); // TODO FLUSH STAGE rv = true; } else { iter = xbps_dictionary_iterator(stage); while ((keysym = xbps_object_iterator_next(iter))) { pkgname = xbps_dictionary_keysym_cstring_nocopy(keysym); xbps_dictionary_t newpkg = xbps_dictionary_get_keysym(stage, keysym); xbps_dictionary_set(idx, pkgname, newpkg); } xbps_object_iterator_release(iter); rv = repodata_flush(xhp, repodir, idx, meta); } xbps_object_release(usedshlibs); xbps_object_release(oldshlibs); return rv; }
static xbps_dictionary_t collect_shlibs(struct xbps_handle *xhp, xbps_array_t pkgs, bool req) { xbps_object_t obj; xbps_object_iterator_t iter; xbps_dictionary_t d, pd; const char *pkgver; d = xbps_dictionary_create(); assert(d); /* copy pkgdb to out temporary dictionary */ pd = xbps_dictionary_copy(xhp->pkgdb); assert(pd); /* * copy pkgs from transaction to our dictionary, overriding them * if they were there from pkgdb. */ iter = xbps_array_iterator(pkgs); assert(iter); while ((obj = xbps_object_iterator_next(iter))) { char *pkgname; if (!xbps_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver)) continue; pkgname = xbps_pkg_name(pkgver); assert(pkgname); xbps_dictionary_set(pd, pkgname, obj); free(pkgname); } xbps_object_iterator_release(iter); /* * iterate over our dictionary to collect shlib-{requires,provides}. */ iter = xbps_dictionary_iterator(pd); assert(iter); while ((obj = xbps_object_iterator_next(iter))) { xbps_array_t shobjs; xbps_dictionary_t pkgd; const char *trans; pkgd = xbps_dictionary_get_keysym(pd, obj); if (xbps_dictionary_get_cstring_nocopy(pkgd, "transaction", &trans)) { if (!strcmp(trans, "remove")) continue; } /* * If pkg does not have the required obj, pass to next one. */ xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver); shobjs = xbps_dictionary_get(pkgd, req ? "shlib-requires" : "shlib-provides"); if (shobjs == NULL) continue; for (unsigned int i = 0; i < xbps_array_count(shobjs); i++) { const char *shlib; xbps_array_get_cstring_nocopy(shobjs, i, &shlib); xbps_dbg_printf(xhp, "%s: registering %s for %s\n", pkgver, shlib, req ? "shlib-requires" : "shlib-provides"); if (req) shlib_register(d, shlib, pkgver); else xbps_dictionary_set_cstring_nocopy(d, shlib, pkgver); } } xbps_object_iterator_release(iter); return d; }