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_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; }