int HIDDEN xbps_pkgdb_init(struct xbps_handle *xhp) { int rv; assert(xhp != NULL); if (xhp->pkgdb_plist == NULL) xhp->pkgdb_plist = xbps_xasprintf("%s/%s", xhp->metadir, XBPS_PKGDB); #if 0 if ((rv = xbps_pkgdb_conversion(xhp)) != 0) return rv; #endif if (xhp->pkgdb != NULL) return 0; if ((rv = xbps_pkgdb_update(xhp, false, true)) != 0) { if (rv != ENOENT) xbps_dbg_printf(xhp, "[pkgdb] cannot internalize " "pkgdb array: %s\n", strerror(rv)); return rv; } if ((rv = pkgdb_map_vpkgs(xhp)) != 0) { xbps_dbg_printf(xhp, "[pkgdb] pkgdb_map_vpkgs %s\n", strerror(rv)); return rv; } assert(xhp->pkgdb); xbps_dbg_printf(xhp, "[pkgdb] initialized ok.\n"); return 0; }
/** * @file lib/pkgdb.c * @brief Package database handling routines * @defgroup pkgdb Package database handling functions * * Functions to manipulate the main package database plist file (pkgdb). * * The following image shown below shows the proplib structure used * by the main package database plist: * * @image html images/xbps_pkgdb_array.png * * Legend: * - <b>Salmon filled box</b>: \a XBPS_PKGDB file internalized. * - <b>White filled box</b>: mandatory objects. * - <b>Grey filled box</b>: optional objects. * - <b>Green filled box</b>: possible value set in the object, only one * of them is set. * * Text inside of white boxes are the key associated with the object, its * data type is specified on its edge, i.e array, bool, integer, string, * dictionary. */ int HIDDEN xbps_pkgdb_init(struct xbps_handle *xhp) { int rv; assert(xhp != NULL); if (xhp->pkgdb != NULL) return 0; if ((rv = xbps_pkgdb_update(xhp, false)) != 0) { if (rv != ENOENT) xbps_dbg_printf(xhp, "[pkgdb] cannot internalize " "pkgdb array: %s\n", strerror(rv)); return rv; } xbps_dbg_printf(xhp, "[pkgdb] initialized ok.\n"); return 0; }
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 xbps_transaction_commit(struct xbps_handle *xhp) { prop_object_t obj; prop_object_iterator_t iter; size_t i; const char *pkgname, *version, *pkgver, *tract; int rv = 0; bool update, install, sr; assert(prop_object_type(xhp->transd) == PROP_TYPE_DICTIONARY); update = install = false; iter = xbps_array_iter_from_dict(xhp->transd, "packages"); if (iter == NULL) return EINVAL; /* * Download binary packages (if they come from a remote repository). */ xbps_set_cb_state(xhp, XBPS_STATE_TRANS_DOWNLOAD, 0, NULL, NULL, NULL); if ((rv = download_binpkgs(xhp, iter)) != 0) goto out; /* * Check SHA256 hashes for binary packages in transaction. */ xbps_set_cb_state(xhp, XBPS_STATE_TRANS_VERIFY, 0, NULL, NULL, NULL); if ((rv = check_binpkgs_hash(xhp, iter)) != 0) goto out; /* * Install, update, configure or remove packages as specified * in the transaction dictionary. */ xbps_set_cb_state(xhp, XBPS_STATE_TRANS_RUN, 0, NULL, NULL, NULL); i = 0; while ((obj = prop_object_iterator_next(iter)) != NULL) { if ((xhp->transaction_frequency_flush > 0) && (++i >= xhp->transaction_frequency_flush)) { rv = xbps_pkgdb_update(xhp, true); if (rv != 0 && rv != ENOENT) goto out; i = 0; } update = false; prop_dictionary_get_cstring_nocopy(obj, "transaction", &tract); prop_dictionary_get_cstring_nocopy(obj, "pkgname", &pkgname); prop_dictionary_get_cstring_nocopy(obj, "version", &version); prop_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver); if (strcmp(tract, "remove") == 0) { update = false; sr = false; /* * Remove package. */ prop_dictionary_get_bool(obj, "remove-and-update", &update); prop_dictionary_get_bool(obj, "softreplace", &sr); rv = xbps_remove_pkg(xhp, pkgname, version, update, sr); if (rv != 0) goto out; } else if (strcmp(tract, "configure") == 0) { /* * Reconfigure pending package. */ rv = xbps_configure_pkg(xhp, pkgname, false, false, false); if (rv != 0) goto out; } else { /* * Install or update a package. */ if (strcmp(tract, "update") == 0) update = true; else install = true; if (update) { /* * Update a package: execute pre-remove * action if found before unpacking. */ xbps_set_cb_state(xhp, XBPS_STATE_UPDATE, 0, pkgname, version, NULL); rv = xbps_remove_pkg(xhp, pkgname, version, true, false); if (rv != 0) { xbps_set_cb_state(xhp, XBPS_STATE_UPDATE_FAIL, rv, pkgname, version, "%s: [trans] failed to update " "package to `%s': %s", pkgver, version, strerror(rv)); goto out; } } else { /* Install a package */ xbps_set_cb_state(xhp, XBPS_STATE_INSTALL, 0, pkgname, version, NULL); } /* * Unpack binary package. */ if ((rv = xbps_unpack_binary_pkg(xhp, obj)) != 0) goto out; /* * Register package. */ if ((rv = xbps_register_pkg(xhp, obj, false)) != 0) goto out; } } prop_object_iterator_reset(iter); /* force a flush now packages were removed/unpacked */ if ((rv = xbps_pkgdb_update(xhp, true)) != 0) goto out; /* if there are no packages to install or update we are done */ if (!update && !install) goto out; /* * Configure all unpacked packages. */ xbps_set_cb_state(xhp, XBPS_STATE_TRANS_CONFIGURE, 0, NULL, NULL, NULL); i = 0; while ((obj = prop_object_iterator_next(iter)) != NULL) { if (xhp->transaction_frequency_flush > 0 && ++i >= xhp->transaction_frequency_flush) { if ((rv = xbps_pkgdb_update(xhp, true)) != 0) goto out; i = 0; } prop_dictionary_get_cstring_nocopy(obj, "transaction", &tract); if ((strcmp(tract, "remove") == 0) || (strcmp(tract, "configure") == 0)) continue; prop_dictionary_get_cstring_nocopy(obj, "pkgname", &pkgname); prop_dictionary_get_cstring_nocopy(obj, "version", &version); update = false; if (strcmp(tract, "update") == 0) update = true; rv = xbps_configure_pkg(xhp, pkgname, false, update, false); if (rv != 0) goto out; /* * Notify client callback when a package has been * installed or updated. */ if (update) { xbps_set_cb_state(xhp, XBPS_STATE_UPDATE_DONE, 0, pkgname, version, NULL); } else { xbps_set_cb_state(xhp, XBPS_STATE_INSTALL_DONE, 0, pkgname, version, NULL); } } /* Force a flush now that packages are configured */ rv = xbps_pkgdb_update(xhp, true); out: prop_object_iterator_release(iter); return rv; }