static xbps_dictionary_t get_pkg_metadata(struct xbps_handle *xhp, xbps_dictionary_t pkgd) { xbps_dictionary_t pkg_metad; const char *pkgver; char *pkgname, *plist; xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver); pkgname = xbps_pkg_name(pkgver); assert(pkgname); if ((pkg_metad = xbps_dictionary_get(xhp->pkg_metad, pkgname)) != NULL) { free(pkgname); return pkg_metad; } plist = xbps_xasprintf("%s/.%s.plist", xhp->metadir, pkgname); pkg_metad = xbps_dictionary_internalize_from_file(plist); free(plist); if (pkg_metad == NULL) { xbps_dbg_printf(xhp, "[pkgdb] cannot read %s metadata: %s\n", pkgver, strerror(errno)); free(pkgname); return NULL; } if (xhp->pkg_metad == NULL) xhp->pkg_metad = xbps_dictionary_create(); xbps_dictionary_set(xhp->pkg_metad, pkgname, pkg_metad); xbps_object_release(pkg_metad); free(pkgname); return pkg_metad; }
int xbps_pkgdb_update(struct xbps_handle *xhp, bool flush, bool update) { xbps_dictionary_t pkgdb_storage; static int cached_rv; int rv = 0; if (cached_rv && !flush) return cached_rv; if (xhp->pkgdb && update) { pkgdb_storage = xbps_dictionary_internalize_from_file(xhp->pkgdb_plist); if (pkgdb_storage == NULL || !xbps_dictionary_equals(xhp->pkgdb, pkgdb_storage)) { /* flush dictionary to storage */ if (!xbps_dictionary_externalize_to_file(xhp->pkgdb, xhp->pkgdb_plist)) return errno; } if (pkgdb_storage) xbps_object_release(pkgdb_storage); xbps_object_release(xhp->pkgdb); xhp->pkgdb = NULL; cached_rv = 0; } if (!update) return rv; /* update copy in memory */ if ((xhp->pkgdb = xbps_dictionary_internalize_from_file(xhp->pkgdb_plist)) == NULL) { rv = errno; if (!rv) rv = EINVAL; if (rv == ENOENT) xhp->pkgdb = xbps_dictionary_create(); else xbps_error_printf("cannot access to pkgdb: %s\n", strerror(rv)); cached_rv = rv = errno; } return rv; }
int xbps_pkgdb_update(struct xbps_handle *xhp, bool flush) { xbps_dictionary_t pkgdb_storage; char *plist; static int cached_rv; int rv = 0; if (cached_rv && !flush) return cached_rv; plist = xbps_xasprintf("%s/%s", xhp->metadir, XBPS_PKGDB); if (xhp->pkgdb && flush) { pkgdb_storage = xbps_dictionary_internalize_from_file(plist); if (pkgdb_storage == NULL || !xbps_dictionary_equals(xhp->pkgdb, pkgdb_storage)) { /* flush dictionary to storage */ if (!xbps_dictionary_externalize_to_file(xhp->pkgdb, plist)) { free(plist); return errno; } } if (pkgdb_storage) xbps_object_release(pkgdb_storage); xbps_object_release(xhp->pkgdb); xhp->pkgdb = NULL; cached_rv = 0; } /* update copy in memory */ if ((xhp->pkgdb = xbps_dictionary_internalize_from_file(plist)) == NULL) { if (errno == ENOENT) xhp->pkgdb = xbps_dictionary_create(); else xbps_error_printf("cannot access to pkgdb: %s\n", strerror(errno)); cached_rv = rv = errno; } free(plist); return rv; }
int HIDDEN xbps_remove_pkg(struct xbps_handle *xhp, const char *pkgver, bool update, bool soft_replace) { xbps_dictionary_t pkgd = NULL; char *pkgname, *buf = NULL; int rv = 0; pkg_state_t state = 0; assert(xhp); assert(pkgver); pkgname = xbps_pkg_name(pkgver); assert(pkgname); if ((rv = xbps_pkg_state_installed(xhp, pkgname, &state)) != 0) 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 dictionary from metadir */ buf = xbps_xasprintf("%s/.%s.plist", xhp->metadir, pkgname); pkgd = xbps_dictionary_internalize_from_file(buf); free(buf); if (pkgd == 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. */ if (pkgd) { 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; } } /* * 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) { if (pkgd) xbps_object_release(pkgd); free(pkgname); return 0; } else if (soft_replace) { /* * Soft replace a package. Do not remove its files, but * execute PURGE action, remove metadata files and unregister * from pkgdb. */ goto softreplace; } if (pkgd) { /* Remove regular files */ if ((rv = xbps_remove_pkg_files(xhp, pkgd, "files", pkgver)) != 0) goto out; /* Remove configuration files */ if ((rv = xbps_remove_pkg_files(xhp, pkgd, "conf_files", pkgver)) != 0) goto out; /* Remove links */ if ((rv = xbps_remove_pkg_files(xhp, pkgd, "links", pkgver)) != 0) goto out; /* Remove dirs */ if ((rv = xbps_remove_pkg_files(xhp, pkgd, "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; } } softreplace: /* * 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. */ if (pkgd) { 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; } xbps_object_release(pkgd); } /* * Remove package metadata plist. */ buf = xbps_xasprintf("%s/.%s.plist", xhp->metadir, pkgname); if (remove(buf) == -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)); } } free(buf); /* * Unregister package from pkgdb. */ xbps_dictionary_remove(xhp->pkgdb, pkgname); if ((rv = xbps_pkgdb_update(xhp, true)) != 0) goto out; 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); return rv; }
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; }