ATF_TC_BODY(pkgdb_get_pkg_test, tc) { xbps_dictionary_t pkgd; struct xbps_handle xh; const char *tcsdir, *pkgver; /* 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); pkgd = xbps_pkgdb_get_pkg(&xh, "mixed"); ATF_REQUIRE_EQ(xbps_object_type(pkgd), XBPS_TYPE_DICTIONARY); xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver); ATF_REQUIRE_STREQ(pkgver, "mixed-0.1_1"); pkgd = xbps_pkgdb_get_pkg(&xh, "mixed>0"); ATF_REQUIRE_EQ(xbps_object_type(pkgd), XBPS_TYPE_DICTIONARY); xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver); ATF_REQUIRE_STREQ(pkgver, "mixed-0.1_1"); pkgd = xbps_pkgdb_get_pkg(&xh, "mixed<2"); ATF_REQUIRE_EQ(xbps_object_type(pkgd), XBPS_TYPE_DICTIONARY); xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver); ATF_REQUIRE_STREQ(pkgver, "mixed-0.1_1"); pkgd = xbps_pkgdb_get_pkg(&xh, "mixed-0.1_1"); ATF_REQUIRE_EQ(xbps_object_type(pkgd), XBPS_TYPE_DICTIONARY); xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver); ATF_REQUIRE_STREQ(pkgver, "mixed-0.1_1"); }
xbps_dictionary_t xbps_pkgdb_get_pkg_files(struct xbps_handle *xhp, const char *pkg) { xbps_dictionary_t pkgd, pkgfilesd; const char *pkgver; char *pkgname, *plist; if (pkg == NULL) return NULL; pkgd = xbps_pkgdb_get_pkg(xhp, pkg); if (pkgd == NULL) return NULL; xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver); pkgname = xbps_pkg_name(pkgver); assert(pkgname); plist = xbps_xasprintf("%s/.%s-files.plist", xhp->metadir, pkgname); free(pkgname); pkgfilesd = xbps_plist_dictionary_from_file(xhp, plist); free(plist); if (pkgfilesd == NULL) { xbps_dbg_printf(xhp, "[pkgdb] cannot read %s metadata: %s\n", pkgver, strerror(errno)); return NULL; } return pkgfilesd; }
xbps_dictionary_t xbps_pkgdb_get_pkg_metadata(struct xbps_handle *xhp, const char *pkg) { xbps_dictionary_t pkgd; pkgd = xbps_pkgdb_get_pkg(xhp, pkg); if (pkgd == NULL) return NULL; return get_pkg_metadata(xhp, pkgd); }
int xbps_set_pkg_state_installed(struct xbps_handle *xhp, const char *pkgver, pkg_state_t state) { xbps_dictionary_t pkgd; char *pkgname; int rv = 0; assert(pkgver != NULL); pkgd = xbps_pkgdb_get_pkg(xhp, pkgver); if (pkgd == NULL) { pkgd = xbps_dictionary_create(); if (pkgd == NULL) return ENOMEM; if (!xbps_dictionary_set_cstring_nocopy(pkgd, "pkgver", pkgver)) { xbps_object_release(pkgd); return EINVAL; } if ((rv = set_new_state(pkgd, state)) != 0) { xbps_object_release(pkgd); return rv; } pkgname = xbps_pkg_name(pkgver); assert(pkgname); if (!xbps_dictionary_set(xhp->pkgdb, pkgname, pkgd)) { xbps_object_release(pkgd); free(pkgname); return EINVAL; } free(pkgname); xbps_object_release(pkgd); } else { if ((rv = set_new_state(pkgd, state)) != 0) return rv; pkgname = xbps_pkg_name(pkgver); assert(pkgname); if (!xbps_dictionary_set(xhp->pkgdb, pkgname, pkgd)) { free(pkgname); return EINVAL; } free(pkgname); } return rv; }
int show_pkg_deps(struct xbps_handle *xhp, const char *pkgname, bool full) { xbps_array_t rdeps; xbps_dictionary_t pkgd; int indent = 0; pkgd = xbps_pkgdb_get_pkg(xhp, pkgname); if (pkgd == NULL) return ENOENT; rdeps = xbps_dictionary_get(pkgd, "run_depends"); if (rdeps != NULL) print_rdeps(xhp, rdeps, full, false, true, &indent); return 0; }
xbps_array_t xbps_pkgdb_get_pkg_revdeps(struct xbps_handle *xhp, const char *pkg) { xbps_array_t res; xbps_dictionary_t pkgd; const char *pkgver; char *pkgname; if ((pkgd = xbps_pkgdb_get_pkg(xhp, pkg)) == NULL) return NULL; generate_full_revdeps_tree(xhp); xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver); pkgname = xbps_pkg_name(pkgver); res = xbps_dictionary_get(xhp->pkgdb_revdeps, pkgname); free(pkgname); return res; }
static void show_package_list(struct transaction *trans, const char *match, int cols) { xbps_object_t obj; while ((obj = xbps_object_iterator_next(trans->iter)) != NULL) { const char *pkgver, *tract; char *buf = NULL; bool dload = false; xbps_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver); xbps_dictionary_get_cstring_nocopy(obj, "transaction", &tract); xbps_dictionary_get_bool(obj, "download", &dload); if (match && strcmp(tract, "update") == 0) { xbps_dictionary_t ipkgd; const char *ipkgver, *iversion, *version; char *pkgname; /* get installed pkgver */ pkgname = xbps_pkg_name(pkgver); assert(pkgname); ipkgd = xbps_pkgdb_get_pkg(trans->xhp, pkgname); assert(ipkgd); xbps_dictionary_get_cstring_nocopy(ipkgd, "pkgver", &ipkgver); version = xbps_pkg_version(pkgver); iversion = xbps_pkg_version(ipkgver); buf = xbps_xasprintf("%s (%s -> %s)", pkgname, iversion, version); free(pkgname); } if ((match && (strcmp(match, tract) == 0)) || (!match && dload)) { if (buf) { print_package_line(buf, cols, false); free(buf); } else { print_package_line(pkgver, cols, false); } } } xbps_object_iterator_reset(trans->iter); print_package_line(NULL, cols, true); }
int xbps_pkg_state_installed(struct xbps_handle *xhp, const char *pkgver, pkg_state_t *state) { xbps_dictionary_t pkgd; assert(pkgver != NULL); assert(state != NULL); pkgd = xbps_pkgdb_get_pkg(xhp, pkgver); if (pkgd == NULL) return ENOENT; *state = get_state(pkgd); if (*state == 0) return EINVAL; return 0; }
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 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)--; }
int xbps_pkg_is_installed(struct xbps_handle *xhp, const char *pkg) { xbps_dictionary_t dict; pkg_state_t state; assert(xhp); assert(pkg); if (((dict = xbps_pkgdb_get_virtualpkg(xhp, pkg)) == NULL) && ((dict = xbps_pkgdb_get_pkg(xhp, pkg)) == NULL)) return 0; /* not installed */ /* * Check that package state is fully installed, not * unpacked or something else. */ if (xbps_pkg_state_dictionary(dict, &state) != 0) return -1; /* error */ if (state == XBPS_PKG_STATE_INSTALLED || state == XBPS_PKG_STATE_UNPACKED) return 1; return 0; /* not fully installed */ }
ATF_TC_BODY(pkgdb_pkg_reverts_test, tc) { struct xbps_handle xh; const char *tcsdir; xbps_dictionary_t pkgd; /* 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); pkgd = xbps_pkgdb_get_pkg(&xh, "reverts"); ATF_REQUIRE_EQ(xbps_object_type(pkgd), XBPS_TYPE_DICTIONARY); ATF_REQUIRE_EQ(xbps_pkg_reverts(pkgd, "reverts-0.2_1"), 0); ATF_REQUIRE_EQ(xbps_pkg_reverts(pkgd, "reverts-0.3_1"), 1); ATF_REQUIRE_EQ(xbps_pkg_reverts(pkgd, "reverts-0.4_1"), 1); ATF_REQUIRE_EQ(xbps_pkg_reverts(pkgd, "reverts-0.5_1"), 0); }
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; }
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; }
int xbps_alternatives_set(struct xbps_handle *xhp, const char *pkgname, const char *group) { xbps_array_t allkeys; xbps_dictionary_t alternatives, pkg_alternatives, pkgd; const char *pkgver; int rv = 0; assert(xhp); assert(pkgname); alternatives = xbps_dictionary_get(xhp->pkgdb, "_XBPS_ALTERNATIVES_"); if (alternatives == NULL) return ENOENT; pkgd = xbps_pkgdb_get_pkg(xhp, pkgname); if (pkgd == NULL) return ENOENT; pkg_alternatives = xbps_dictionary_get(pkgd, "alternatives"); if (!xbps_dictionary_count(pkg_alternatives)) return ENOENT; xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver); 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; xbps_string_t kstr; const char *keyname; keysym = xbps_array_get(allkeys, i); keyname = xbps_dictionary_keysym_cstring_nocopy(keysym); if (group && strcmp(keyname, group)) { rv = ENOENT; continue; } array = xbps_dictionary_get(alternatives, keyname); if (array == NULL) continue; /* put this alternative group at the head */ xbps_remove_string_from_array(array, pkgname); kstr = xbps_string_create_cstring(pkgname); xbps_array_add_first(array, kstr); xbps_object_release(kstr); /* apply the alternatives group */ xbps_set_cb_state(xhp, XBPS_STATE_ALTGROUP_ADDED, 0, NULL, "%s: applying '%s' alternatives group", pkgver, keyname); rv = create_symlinks(xhp, xbps_dictionary_get(pkg_alternatives, keyname), keyname); if (rv != 0) break; } xbps_object_release(allkeys); return rv; }
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); }
int HIDDEN xbps_remove_pkg(struct xbps_handle *xhp, const char *pkgver, bool update) { xbps_dictionary_t pkgd = NULL, pkgfilesd = NULL; char *pkgname, metafile[PATH_MAX]; int rv = 0; pkg_state_t state = 0; uid_t euid; assert(xhp); assert(pkgver); pkgname = xbps_pkg_name(pkgver); assert(pkgname); euid = geteuid(); if ((pkgd = xbps_pkgdb_get_pkg(xhp, pkgname)) == NULL) { rv = errno; xbps_dbg_printf(xhp, "[remove] cannot find %s in pkgdb: %s\n", pkgver, strerror(rv)); goto out; } if ((rv = xbps_pkg_state_dictionary(pkgd, &state)) != 0) { xbps_dbg_printf(xhp, "[remove] cannot find %s in pkgdb: %s\n", pkgver, strerror(rv)); goto out; } xbps_dbg_printf(xhp, "attempting to remove %s state %d\n", pkgver, state); if (!update) xbps_set_cb_state(xhp, XBPS_STATE_REMOVE, 0, pkgver, NULL); if (chdir(xhp->rootdir) == -1) { rv = errno; xbps_set_cb_state(xhp, XBPS_STATE_REMOVE_FAIL, rv, pkgver, "%s: [remove] failed to chdir to rootdir `%s': %s", pkgver, xhp->rootdir, strerror(rv)); goto out; } /* internalize pkg files dictionary from metadir */ snprintf(metafile, sizeof(metafile), "%s/.%s-files.plist", xhp->metadir, pkgname); pkgfilesd = xbps_plist_dictionary_from_file(xhp, metafile); if (pkgfilesd == NULL) xbps_dbg_printf(xhp, "WARNING: metaplist for %s " "doesn't exist!\n", pkgver); /* If package was "half-removed", remove it fully. */ if (state == XBPS_PKG_STATE_HALF_REMOVED) goto purge; /* * Run the pre remove action and show pre-remove message if exists. */ rv = xbps_pkg_exec_script(xhp, pkgd, "remove-script", "pre", update); if (rv != 0) { xbps_set_cb_state(xhp, XBPS_STATE_REMOVE_FAIL, errno, pkgver, "%s: [remove] REMOVE script failed to " "execute pre ACTION: %s", pkgver, strerror(rv)); goto out; } /* show remove-msg if exists */ if ((rv = xbps_cb_message(xhp, pkgd, "remove-msg")) != 0) goto out; /* unregister alternatives */ if (update) xbps_dictionary_set_bool(pkgd, "alternatives-update", true); if ((rv = xbps_alternatives_unregister(xhp, pkgd)) != 0) goto out; /* * If updating a package, we just need to execute the current * pre-remove action target and we are done. Its files will be * overwritten later in unpack phase. */ if (update) { free(pkgname); return 0; } if (pkgfilesd) { /* * Do the removal in 2 phases: * 1- check if user has enough perms to remove all entries * 2- perform removal */ if (check_remove_pkg_files(xhp, pkgfilesd, pkgver, euid)) { rv = EPERM; goto out; } /* Remove links */ if ((rv = remove_pkg_files(xhp, pkgfilesd, "links", pkgver)) != 0) goto out; /* Remove regular files */ if ((rv = remove_pkg_files(xhp, pkgfilesd, "files", pkgver)) != 0) goto out; /* Remove configuration files */ if ((rv = remove_pkg_files(xhp, pkgfilesd, "conf_files", pkgver)) != 0) goto out; /* Remove dirs */ if ((rv = remove_pkg_files(xhp, pkgfilesd, "dirs", pkgver)) != 0) goto out; } /* * Execute the post REMOVE action if file exists and we aren't * updating the package. */ rv = xbps_pkg_exec_script(xhp, pkgd, "remove-script", "post", false); if (rv != 0) { xbps_set_cb_state(xhp, XBPS_STATE_REMOVE_FAIL, rv, pkgver, "%s: [remove] REMOVE script failed to execute " "post ACTION: %s", pkgver, strerror(rv)); goto out; } /* * Set package state to "half-removed". */ rv = xbps_set_pkg_state_installed(xhp, pkgver, XBPS_PKG_STATE_HALF_REMOVED); if (rv != 0) { xbps_set_cb_state(xhp, XBPS_STATE_REMOVE_FAIL, rv, pkgver, "%s: [remove] failed to set state to half-removed: %s", pkgver, strerror(rv)); goto out; } purge: /* * Execute the purge REMOVE action if file exists. */ rv = xbps_pkg_exec_script(xhp, pkgd, "remove-script", "purge", false); if (rv != 0) { xbps_set_cb_state(xhp, XBPS_STATE_REMOVE_FAIL, rv, pkgver, "%s: REMOVE script failed to execute " "purge ACTION: %s", pkgver, strerror(rv)); goto out; } /* * Remove package metadata plist. */ if (remove(metafile) == -1) { if (errno != ENOENT) { xbps_set_cb_state(xhp, XBPS_STATE_REMOVE_FAIL, rv, pkgver, "%s: failed to remove metadata file: %s", pkgver, strerror(errno)); } } /* * Unregister package from pkgdb. */ xbps_dictionary_remove(xhp->pkgdb, pkgname); xbps_dbg_printf(xhp, "[remove] unregister %s returned %d\n", pkgver, rv); xbps_set_cb_state(xhp, XBPS_STATE_REMOVE_DONE, 0, pkgver, NULL); out: if (pkgname != NULL) free(pkgname); if (rv != 0) { xbps_set_cb_state(xhp, XBPS_STATE_REMOVE_FAIL, rv, pkgver, "%s: failed to remove package: %s", pkgver, strerror(rv)); } return rv; }
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; }
static int compute_transaction_stats(struct xbps_handle *xhp) { xbps_dictionary_t pkg_metad; xbps_object_iterator_t iter; xbps_object_t obj; struct statvfs svfs; uint64_t rootdir_free_size, tsize, dlsize, instsize, rmsize; uint32_t inst_pkgcnt, up_pkgcnt, cf_pkgcnt, rm_pkgcnt, dl_pkgcnt; const char *tract, *pkgver, *repo; inst_pkgcnt = up_pkgcnt = cf_pkgcnt = rm_pkgcnt = dl_pkgcnt = 0; rootdir_free_size = tsize = dlsize = instsize = rmsize = 0; iter = xbps_array_iter_from_dict(xhp->transd, "packages"); if (iter == NULL) return EINVAL; while ((obj = xbps_object_iterator_next(iter)) != NULL) { bool preserve = false; /* * Count number of pkgs to be removed, configured, * installed and updated. */ xbps_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver); xbps_dictionary_get_cstring_nocopy(obj, "transaction", &tract); xbps_dictionary_get_cstring_nocopy(obj, "repository", &repo); xbps_dictionary_get_bool(obj, "preserve", &preserve); if (strcmp(tract, "configure") == 0) { cf_pkgcnt++; continue; } else if (strcmp(tract, "install") == 0) { inst_pkgcnt++; } else if (strcmp(tract, "update") == 0) { up_pkgcnt++; } else if (strcmp(tract, "remove") == 0) { rm_pkgcnt++; } tsize = 0; if ((strcmp(tract, "install") == 0) || (strcmp(tract, "update") == 0)) { xbps_dictionary_get_uint64(obj, "installed_size", &tsize); instsize += tsize; if (xbps_repository_is_remote(repo) && !xbps_binpkg_exists(xhp, obj)) { xbps_dictionary_get_uint64(obj, "filename-size", &tsize); /* signature file: 512 bytes */ tsize += 512; dlsize += tsize; instsize += tsize; dl_pkgcnt++; xbps_dictionary_set_bool(obj, "download", true); } } /* * If removing or updating a package, get installed_size * from pkg's metadata dictionary. */ if ((strcmp(tract, "remove") == 0) || ((strcmp(tract, "update") == 0) && !preserve)) { char *pkgname; pkgname = xbps_pkg_name(pkgver); assert(pkgname); pkg_metad = xbps_pkgdb_get_pkg(xhp, pkgname); free(pkgname); if (pkg_metad == NULL) continue; xbps_dictionary_get_uint64(pkg_metad, "installed_size", &tsize); rmsize += tsize; } } xbps_object_iterator_release(iter); if (instsize > rmsize) { instsize -= rmsize; rmsize = 0; } else if (rmsize > instsize) { rmsize -= instsize; instsize = 0; } else { instsize = rmsize = 0; } if (!xbps_dictionary_set_uint32(xhp->transd, "total-install-pkgs", inst_pkgcnt)) return EINVAL; if (!xbps_dictionary_set_uint32(xhp->transd, "total-update-pkgs", up_pkgcnt)) return EINVAL; if (!xbps_dictionary_set_uint32(xhp->transd, "total-configure-pkgs", cf_pkgcnt)) return EINVAL; if (!xbps_dictionary_set_uint32(xhp->transd, "total-remove-pkgs", rm_pkgcnt)) return EINVAL; if (!xbps_dictionary_set_uint32(xhp->transd, "total-download-pkgs", dl_pkgcnt)) return EINVAL; if (!xbps_dictionary_set_uint64(xhp->transd, "total-installed-size", instsize)) return EINVAL; if (!xbps_dictionary_set_uint64(xhp->transd, "total-download-size", dlsize)) return EINVAL; if (!xbps_dictionary_set_uint64(xhp->transd, "total-removed-size", rmsize)) return EINVAL; /* Get free space from target rootdir: return ENOSPC if there's not enough space */ if (statvfs(xhp->rootdir, &svfs) == -1) { xbps_dbg_printf(xhp, "%s: statvfs failed: %s\n", __func__, strerror(errno)); return 0; } /* compute free space on disk */ rootdir_free_size = svfs.f_bfree * svfs.f_bsize; if (!xbps_dictionary_set_uint64(xhp->transd, "disk-free-size", rootdir_free_size)) return EINVAL; if (instsize > rootdir_free_size) return ENOSPC; return 0; }
int HIDDEN xbps_transaction_package_replace(struct xbps_handle *xhp) { xbps_array_t replaces, unsorted; xbps_dictionary_t instd, reppkgd, filesd; xbps_object_t obj, obj2; xbps_object_iterator_t iter; const char *pattern, *pkgver, *curpkgver; char *buf, *pkgname, *curpkgname; bool instd_auto, sr; unsigned int i; unsorted = xbps_dictionary_get(xhp->transd, "unsorted_deps"); for (i = 0; i < xbps_array_count(unsorted); i++) { obj = xbps_array_get(unsorted, i); replaces = xbps_dictionary_get(obj, "replaces"); if (replaces == NULL || xbps_array_count(replaces) == 0) continue; iter = xbps_array_iterator(replaces); assert(iter); while ((obj2 = xbps_object_iterator_next(iter)) != NULL) { 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(obj, "pkgver", &pkgver); xbps_dictionary_get_cstring_nocopy(instd, "pkgver", &curpkgver); pkgname = xbps_pkg_name(pkgver); assert(pkgname); curpkgname = xbps_pkg_name(curpkgver); assert(curpkgver); /* * Check that we are not replacing the same package, * due to virtual packages. */ if (strcmp(pkgname, curpkgname) == 0) { free(pkgname); free(curpkgname); continue; } xbps_dbg_printf(xhp, "Package `%s' will be replaced by `%s', " "matched with `%s'\n", curpkgver, pkgver, pattern); instd_auto = false; xbps_dictionary_get_bool(instd, "automatic-install", &instd_auto); /* * Package contains replaces="pkgpattern", but the * package that should be replaced is also in the * transaction and it's going to be updated. */ if ((reppkgd = xbps_find_pkg_in_array(unsorted, curpkgname))) { xbps_dbg_printf(xhp, "found replaced pkg " "in transaction\n"); xbps_dictionary_set_bool(instd, "remove-and-update", true); xbps_dictionary_set_bool(reppkgd, "automatic-install", instd_auto); xbps_dictionary_set_bool(reppkgd, "skip-obsoletes", true); xbps_array_replace_dict_by_name(unsorted, reppkgd, curpkgname); } /* * 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, true) || xbps_match_virtual_pkg_in_dict(instd, pkgname, false)) { xbps_dictionary_set_bool(obj, "automatic-install", instd_auto); } sr = false; xbps_dictionary_get_bool(obj, "softreplace", &sr); if (sr) { xbps_dictionary_set_bool(obj, "automatic-install", instd_auto); xbps_dictionary_set_bool(instd, "softreplace", true); buf = xbps_xasprintf("%s/.%s.plist", xhp->metadir, curpkgname); filesd = xbps_dictionary_internalize_from_file(buf); free(buf); assert(filesd != NULL); buf = xbps_xasprintf("%s/.%s.plist", xhp->metadir, pkgname); if (!xbps_dictionary_externalize_to_file(filesd, buf)) { free(buf); xbps_object_release(filesd); xbps_object_iterator_release(iter); free(pkgname); free(curpkgname); return errno; } xbps_object_release(filesd); free(buf); } /* * Add package dictionary into the transaction and mark * it as to be "removed". */ xbps_dictionary_set_cstring_nocopy(instd, "transaction", "remove"); xbps_array_add(unsorted, instd); free(pkgname); free(curpkgname); } xbps_object_iterator_release(iter); } return 0; }
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); } } }