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); }
/* * 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; }
void list_files (xbps_dictionary_t filesd, const char *pkgver, void *arg) { xbps_array_t pkgfiles; const char *pkgname; struct config *cfg = arg; pkgname = xbps_pkg_name (pkgver); if (strcmp (pkgname, cfg->pattern) != 0) return; pkgfiles = xbps_dictionary_get (filesd, pkgver); for (unsigned int i = 0; i < xbps_array_count (pkgfiles); i++) { char *filestr = NULL; xbps_array_get_cstring (pkgfiles, i, &filestr); if (filestr == NULL) continue; printf ("%s: %s\n", pkgver, filestr); free (filestr); } }
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 int remove_symlinks(struct xbps_handle *xhp, xbps_array_t a, const char *grname) { unsigned int i, cnt; cnt = xbps_array_count(a); for (i = 0; i < cnt; i++) { xbps_string_t str; char *l, *lnk; str = xbps_array_get(a, i); l = left(xbps_string_cstring_nocopy(str)); assert(l); if (l[0] != '/') { const char *tgt; char *tgt_dup, *tgt_dir; tgt = right(xbps_string_cstring_nocopy(str)); tgt_dup = strdup(tgt); assert(tgt_dup); tgt_dir = dirname(tgt_dup); lnk = xbps_xasprintf("%s%s/%s", xhp->rootdir, tgt_dir, l); free(tgt_dup); } else { lnk = xbps_xasprintf("%s%s", xhp->rootdir, l); } xbps_set_cb_state(xhp, XBPS_STATE_ALTGROUP_LINK_REMOVED, 0, NULL, "Removing '%s' alternatives group symlink: %s", grname, l); unlink(lnk); free(lnk); free(l); } return 0; }
ATF_TC_BODY(find_all_orphans_test, tc) { struct xbps_handle xh; xbps_array_t res; xbps_dictionary_t pkgd; xbps_string_t pstr; const char *pkgver, *tcsdir; unsigned int i; /* get test source dir */ tcsdir = atf_tc_get_config_var(tc, "srcdir"); memset(&xh, 0, sizeof(xh)); xbps_strlcpy(xh.rootdir, tcsdir, sizeof(xh.rootdir)); xbps_strlcpy(xh.metadir, tcsdir, sizeof(xh.metadir)); ATF_REQUIRE_EQ(xbps_init(&xh), 0); pstr = xbps_string_create(); res = xbps_find_pkg_orphans(&xh, NULL); for (i = 0; i < xbps_array_count(res); i++) { pkgd = xbps_array_get(res, i); xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver); xbps_string_append_cstring(pstr, pkgver); xbps_string_append_cstring(pstr, "\n"); } printf("%s", xbps_string_cstring_nocopy(pstr)); ATF_REQUIRE_STREQ(xbps_string_cstring_nocopy(pstr), expected_output_all); }
static bool check_remove_pkg_files(struct xbps_handle *xhp, xbps_dictionary_t pkgd, const char *pkgver, uid_t euid) { struct stat st; xbps_array_t array; xbps_object_iterator_t iter; xbps_object_t obj; const char *objs[] = { "files", "conf_files", "links", "dirs" }; const char *file; char path[PATH_MAX]; bool fail = false; for (uint8_t i = 0; i < __arraycount(objs); i++) { array = xbps_dictionary_get(pkgd, objs[i]); if (array == NULL || xbps_array_count(array) == 0) continue; iter = xbps_array_iter_from_dict(pkgd, objs[i]); if (iter == NULL) continue; while ((obj = xbps_object_iterator_next(iter))) { xbps_dictionary_get_cstring_nocopy(obj, "file", &file); snprintf(path, sizeof(path), "%s/%s", xhp->rootdir, file); /* * Check if effective user ID owns the file; this is * enough to ensure the user has write permissions * on the directory. */ if (euid == 0 || (!lstat(path, &st) && euid == st.st_uid)) { /* success */ continue; } if (errno != ENOENT) { /* * only bail out if something else than ENOENT * is returned. */ int rv = errno; if (rv == 0) { /* lstat succeeds but euid != uid */ rv = EPERM; } fail = true; xbps_set_cb_state(xhp, XBPS_STATE_REMOVE_FILE_FAIL, rv, pkgver, "%s: cannot remove `%s': %s", pkgver, file, strerror(rv)); } errno = 0; } xbps_object_iterator_release(iter); } return fail; }
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); } }
/* * Returns true if entry is a configuration file, false otherwise. */ int HIDDEN xbps_entry_is_a_conf_file(xbps_dictionary_t filesd, const char *entry_pname) { xbps_array_t array; xbps_dictionary_t d; const char *cffile; array = xbps_dictionary_get(filesd, "conf_files"); if (xbps_array_count(array) == 0) return false; for (unsigned int i = 0; i < xbps_array_count(array); i++) { d = xbps_array_get(array, i); xbps_dictionary_get_cstring_nocopy(d, "file", &cffile); if (strcmp(cffile, entry_pname) == 0) return true; } return false; }
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; }
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; }
bool xbps_pkg_has_rundeps(xbps_dictionary_t pkgd) { xbps_array_t array; assert(xbps_object_type(pkgd) == XBPS_TYPE_DICTIONARY); array = xbps_dictionary_get(pkgd, "run_depends"); if (xbps_array_count(array)) return true; return false; }
/* * 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; }
static xbps_array_t merge_filelist(xbps_dictionary_t d) { xbps_array_t a, result; xbps_dictionary_t filed; unsigned int i; result = xbps_array_create(); assert(result); if ((a = xbps_dictionary_get(d, "files"))) { for (i = 0; i < xbps_array_count(a); i++) { filed = xbps_array_get(a, i); xbps_array_add(result, filed); } } if ((a = xbps_dictionary_get(d, "links"))) { for (i = 0; i < xbps_array_count(a); i++) { filed = xbps_array_get(a, i); xbps_array_add(result, filed); } } if ((a = xbps_dictionary_get(d, "conf_files"))) { for (i = 0; i < xbps_array_count(a); i++) { filed = xbps_array_get(a, i); xbps_array_add(result, filed); } } if ((a = xbps_dictionary_get(d, "dirs"))) { for (i = 0; i < xbps_array_count(a); i++) { filed = xbps_array_get(a, i); xbps_array_add(result, filed); } } return result; }
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 check_pkg_symlinks(struct xbps_handle *xhp, const char *pkgname, void *arg) { xbps_array_t array; xbps_object_t obj; xbps_dictionary_t filesd = arg; int rv = 0; array = xbps_dictionary_get(filesd, "links"); if (array == NULL) return 0; for (unsigned int i = 0; i < xbps_array_count(array); i++) { const char *file = NULL, *tgt = NULL; char path[PATH_MAX], *lnk = NULL; obj = xbps_array_get(array, i); if (!xbps_dictionary_get_cstring_nocopy(obj, "file", &file)) continue; if (!xbps_dictionary_get_cstring_nocopy(obj, "target", &tgt)) { xbps_warn_printf("%s: `%s' symlink with " "empty target object!\n", pkgname, file); continue; } if (tgt[0] == '\0') { xbps_warn_printf("%s: `%s' symlink with " "empty target object!\n", pkgname, file); continue; } snprintf(path, sizeof(path), "%s/%s", xhp->rootdir, file); if ((lnk = xbps_symlink_target(xhp, path, tgt)) == NULL) { xbps_error_printf("%s: broken symlink %s (target: %s)\n", pkgname, file, tgt); rv = -1; continue; } if (strcmp(lnk, tgt)) { xbps_warn_printf("%s: modified symlink %s " "points to %s (shall be %s)\n", pkgname, file, lnk, tgt); rv = -1; } free(lnk); } return rv; }
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; }
/* * 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)--; }
void match_files_by_pattern (xbps_dictionary_t filesd, const char *pkgver, void *arg) { xbps_array_t pkgfiles; struct config *cfg = arg; pkgfiles = xbps_dictionary_get (filesd, pkgver); for (unsigned int i = 0; i < xbps_array_count (pkgfiles); i++) { char *filestr = NULL; xbps_array_get_cstring (pkgfiles, i, &filestr); if (filestr == NULL) continue; if (fnmatch (cfg->pattern, filestr, FNM_PERIOD) == 0) printf ("\033[0;1m%s:\033[0m %s\n", pkgver, filestr); free (filestr); } }
int HIDDEN xbps_repository_find_deps(struct xbps_handle *xhp, xbps_array_t unsorted, xbps_dictionary_t repo_pkgd) { xbps_array_t pkg_rdeps, pkg_provides = NULL; const char *pkgver; unsigned short depth = 0; pkg_rdeps = xbps_dictionary_get(repo_pkgd, "run_depends"); if (xbps_array_count(pkg_rdeps) == 0) return 0; xbps_dictionary_get_cstring_nocopy(repo_pkgd, "pkgver", &pkgver); xbps_dbg_printf(xhp, "Finding required dependencies for '%s':\n", pkgver); /* * This will find direct and indirect deps, if any of them is not * there it will be added into the missing_deps array. */ pkg_provides = xbps_dictionary_get(repo_pkgd, "provides"); return find_repo_deps(xhp, unsorted, pkg_rdeps, pkg_provides, pkgver, &depth); }
static const char * find_pkg_symlink_target(xbps_dictionary_t d, const char *file) { xbps_array_t links; xbps_object_t obj; unsigned int i; const char *pkgfile, *tgt = NULL; char *rfile; assert(d); links = xbps_dictionary_get(d, "links"); for (i = 0; i < xbps_array_count(links); i++) { rfile = strchr(file, '.') + 1; obj = xbps_array_get(links, i); xbps_dictionary_get_cstring_nocopy(obj, "file", &pkgfile); if (strcmp(rfile, pkgfile) == 0) { xbps_dictionary_get_cstring_nocopy(obj, "target", &tgt); break; } } return tgt; }
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; }
int HIDDEN xbps_remove_pkg_files(struct xbps_handle *xhp, xbps_dictionary_t dict, const char *key, const char *pkgver) { struct stat st; xbps_array_t array; xbps_object_iterator_t iter; xbps_object_t obj; const char *file, *sha256, *curobj = NULL; char *path = NULL, *pkgname = NULL; char buf[PATH_MAX]; int rv = 0; assert(xbps_object_type(dict) == XBPS_TYPE_DICTIONARY); assert(key != NULL); array = xbps_dictionary_get(dict, key); if (xbps_array_count(array) == 0) return 0; iter = xbps_array_iter_from_dict(dict, key); if (iter == NULL) return ENOMEM; if (strcmp(key, "files") == 0) curobj = "file"; else if (strcmp(key, "conf_files") == 0) curobj = "configuration file"; else if (strcmp(key, "links") == 0) curobj = "link"; else if (strcmp(key, "dirs") == 0) curobj = "directory"; pkgname = xbps_pkg_name(pkgver); assert(pkgname); while ((obj = xbps_object_iterator_next(iter))) { xbps_dictionary_get_cstring_nocopy(obj, "file", &file); path = xbps_xasprintf("%s/%s", xhp->rootdir, file); if ((strcmp(key, "files") == 0) || (strcmp(key, "conf_files") == 0)) { /* * Check SHA256 hash in regular files and * configuration files. */ xbps_dictionary_get_cstring_nocopy(obj, "sha256", &sha256); rv = xbps_file_hash_check(path, sha256); if (rv == ENOENT) { /* missing file, ignore it */ xbps_set_cb_state(xhp, XBPS_STATE_REMOVE_FILE_HASH_FAIL, rv, pkgver, "%s: failed to check hash for %s `%s': %s", pkgver, curobj, file, strerror(rv)); free(path); rv = 0; continue; } else if (rv == ERANGE) { rv = 0; if ((xhp->flags & XBPS_FLAG_FORCE_REMOVE_FILES) == 0) { xbps_set_cb_state(xhp, XBPS_STATE_REMOVE_FILE_HASH_FAIL, 0, pkgver, "%s: %s `%s' SHA256 mismatch, " "preserving file", pkgver, curobj, file); free(path); continue; } else { xbps_set_cb_state(xhp, XBPS_STATE_REMOVE_FILE_HASH_FAIL, 0, pkgver, "%s: %s `%s' SHA256 mismatch, " "forcing removal", pkgver, curobj, file); } } else if (rv != 0 && rv != ERANGE) { xbps_set_cb_state(xhp, XBPS_STATE_REMOVE_FILE_HASH_FAIL, rv, pkgver, "%s: [remove] failed to check hash for " "%s `%s': %s", pkgver, curobj, file, strerror(rv)); free(path); break; } } else if (strcmp(key, "links") == 0) { /* * All regular files from package were removed at this * point, so we will only remove dangling symlinks. */ if (realpath(path, buf) == NULL) { if (errno != ENOENT && errno != ELOOP) { free(path); rv = errno; break; } } if (stat(buf, &st) == 0) { free(path); continue; } } /* * Remove the object if possible. */ if (remove(path) == -1) { xbps_set_cb_state(xhp, XBPS_STATE_REMOVE_FILE_FAIL, errno, pkgver, "%s: failed to remove %s `%s': %s", pkgver, curobj, file, strerror(errno)); errno = 0; } else { /* success */ xbps_set_cb_state(xhp, XBPS_STATE_REMOVE_FILE, 0, pkgver, "Removed %s `%s'", curobj, file); } free(path); } xbps_object_iterator_release(iter); free(pkgname); return rv; }
int HIDDEN xbps_transaction_package_replace(struct xbps_handle *xhp, xbps_array_t pkgs) { for (unsigned int i = 0; i < xbps_array_count(pkgs); i++) { xbps_array_t replaces; xbps_object_t obj, obj2; xbps_object_iterator_t iter; const char *pkgver; char *pkgname; obj = xbps_array_get(pkgs, i); replaces = xbps_dictionary_get(obj, "replaces"); if (replaces == NULL || xbps_array_count(replaces) == 0) continue; iter = xbps_array_iterator(replaces); assert(iter); xbps_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver); pkgname = xbps_pkg_name(pkgver); assert(pkgname); while ((obj2 = xbps_object_iterator_next(iter)) != NULL) { xbps_dictionary_t instd, reppkgd; const char *tract, *pattern, *curpkgver; char *curpkgname; bool instd_auto = false; pattern = xbps_string_cstring_nocopy(obj2); /* * Find the installed package that matches the pattern * to be replaced. */ if (((instd = xbps_pkgdb_get_pkg(xhp, pattern)) == NULL) && ((instd = xbps_pkgdb_get_virtualpkg(xhp, pattern)) == NULL)) continue; xbps_dictionary_get_cstring_nocopy(instd, "pkgver", &curpkgver); curpkgname = xbps_pkg_name(curpkgver); assert(curpkgname); /* * Check that we are not replacing the same package, * due to virtual packages. */ if (strcmp(pkgname, curpkgname) == 0) { free(curpkgname); continue; } /* * Make sure to not add duplicates. */ xbps_dictionary_get_bool(instd, "automatic-install", &instd_auto); reppkgd = xbps_find_pkg_in_array(pkgs, curpkgname, NULL); if (reppkgd) { xbps_dictionary_get_cstring_nocopy(reppkgd, "transaction", &tract); if (strcmp(tract, "remove") == 0) continue; /* * Package contains replaces="pkgpattern", but the * package that should be replaced is also in the * transaction and it's going to be updated. */ xbps_dictionary_set_bool(reppkgd, "automatic-install", instd_auto); xbps_array_replace_dict_by_name(pkgs, reppkgd, curpkgname); continue; } /* * If new package is providing a virtual package to the * package that we want to replace we should respect * the automatic-install object. */ if (xbps_match_virtual_pkg_in_dict(obj, pattern)) { xbps_dictionary_set_bool(obj, "automatic-install", instd_auto); } xbps_dbg_printf(xhp, "Package `%s' will be replaced by `%s', " "matched with `%s'\n", curpkgver, pkgver, pattern); /* * Add package dictionary into the transaction and mark * it as to be "removed". */ xbps_dictionary_set_cstring_nocopy(instd, "transaction", "remove"); if (!xbps_array_add_first(pkgs, instd)) return EINVAL; free(curpkgname); } xbps_object_iterator_release(iter); free(pkgname); } 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; }