123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450 |
- /* opkg_remove.c - the opkg package management system
- Carl D. Worth
- Copyright (C) 2001 University of Southern California
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2, or (at
- your option) any later version.
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
- */
- #include <stdio.h>
- #include <glob.h>
- #include <unistd.h>
- #include "opkg_message.h"
- #include "opkg_remove.h"
- #include "opkg_cmd.h"
- #include "file_util.h"
- #include "sprintf_alloc.h"
- #include "libbb/libbb.h"
- /*
- * Returns number of the number of packages depending on the packages provided by this package.
- * Every package implicitly provides itself.
- */
- int pkg_has_installed_dependents(pkg_t * pkg, abstract_pkg_t *** pdependents)
- {
- abstract_pkg_t **provider, **provides = pkg_get_ptr(pkg, PKG_PROVIDES);
- unsigned int i, n_installed_dependents = 0;
- provider = provides;
- while (provider && *provider) {
- abstract_pkg_t *providee = *provider++;
- abstract_pkg_t **dependers = providee->depended_upon_by;
- abstract_pkg_t *dep_ab_pkg;
- if (dependers == NULL)
- continue;
- while ((dep_ab_pkg = *dependers++) != NULL) {
- if (dep_ab_pkg->state_status == SS_INSTALLED) {
- n_installed_dependents++;
- }
- }
- }
- /* if caller requested the set of installed dependents */
- if (pdependents) {
- int p = 0;
- abstract_pkg_t **dependents =
- xcalloc((n_installed_dependents + 1),
- sizeof(abstract_pkg_t *));
- provider = provides;
- *pdependents = dependents;
- while (provider && *provider) {
- abstract_pkg_t *providee = *provider++;
- abstract_pkg_t **dependers = providee->depended_upon_by;
- abstract_pkg_t *dep_ab_pkg;
- if (dependers == NULL)
- continue;
- while ((dep_ab_pkg = *dependers++) != NULL) {
- if (dep_ab_pkg->state_status == SS_INSTALLED
- && !(dep_ab_pkg->state_flag & SF_MARKED)) {
- dependents[p++] = dep_ab_pkg;
- dep_ab_pkg->state_flag |= SF_MARKED;
- }
- }
- }
- dependents[p] = NULL;
- /* now clear the marks */
- for (i = 0; i < p; i++) {
- abstract_pkg_t *dep_ab_pkg = dependents[i];
- dep_ab_pkg->state_flag &= ~SF_MARKED;
- }
- }
- return n_installed_dependents;
- }
- static int opkg_remove_dependent_pkgs(pkg_t * pkg, abstract_pkg_t ** dependents)
- {
- int i;
- int a;
- int count;
- pkg_vec_t *dependent_pkgs;
- abstract_pkg_t *ab_pkg;
- if ((ab_pkg = pkg->parent) == NULL) {
- opkg_msg(ERROR, "Internal error: pkg %s isn't in hash table\n",
- pkg->name);
- return 0;
- }
- if (dependents == NULL)
- return 0;
- // here i am using the dependencies_checked
- if (ab_pkg->dependencies_checked == 2) // variable to make out whether this package
- return 0; // has already been encountered in the process
- // of marking packages for removal - Karthik
- ab_pkg->dependencies_checked = 2;
- i = 0;
- count = 1;
- dependent_pkgs = pkg_vec_alloc();
- while (dependents[i] != NULL) {
- abstract_pkg_t *dep_ab_pkg = dependents[i];
- if (dep_ab_pkg->dependencies_checked == 2) {
- i++;
- continue;
- }
- if (dep_ab_pkg->state_status == SS_INSTALLED) {
- for (a = 0; a < dep_ab_pkg->pkgs->len; a++) {
- pkg_t *dep_pkg = dep_ab_pkg->pkgs->pkgs[a];
- if (dep_pkg->state_status == SS_INSTALLED) {
- pkg_vec_insert(dependent_pkgs, dep_pkg);
- count++;
- }
- }
- }
- i++;
- /* 1 - to keep track of visited ab_pkgs when checking for possiblility of a broken removal of pkgs.
- * 2 - to keep track of pkgs whose deps have been checked alrdy - Karthik */
- }
- if (count == 1) {
- pkg_vec_free(dependent_pkgs);
- return 0;
- }
- int err = 0;
- for (i = 0; i < dependent_pkgs->len; i++) {
- err = opkg_remove_pkg(dependent_pkgs->pkgs[i], 0);
- if (err) {
- break;
- }
- }
- pkg_vec_free(dependent_pkgs);
- return err;
- }
- static void print_dependents_warning(pkg_t * pkg, abstract_pkg_t ** dependents)
- {
- abstract_pkg_t *dep_ab_pkg;
- opkg_msg(ERROR, "Package %s is depended upon by packages:\n",
- pkg->name);
- while ((dep_ab_pkg = *dependents++) != NULL) {
- if (dep_ab_pkg->state_status == SS_INSTALLED)
- opkg_msg(ERROR, "\t%s\n", dep_ab_pkg->name);
- }
- opkg_msg(ERROR,
- "These might cease to work if package %s is removed.\n\n",
- pkg->name);
- opkg_msg(ERROR,
- "Force removal of this package with --force-depends.\n");
- opkg_msg(ERROR, "Force removal of this package and its dependents\n");
- opkg_msg(ERROR, "with --force-removal-of-dependent-packages.\n");
- }
- /*
- * Find and remove packages that were autoinstalled and are orphaned
- * by the removal of pkg.
- */
- static int remove_autoinstalled(pkg_t * pkg)
- {
- int j;
- int err = 0;
- int n_deps;
- pkg_t *p;
- struct compound_depend *cdep;
- abstract_pkg_t **dependents;
- for (cdep = pkg_get_ptr(pkg, PKG_DEPENDS); cdep && cdep->type; cdep++) {
- if (cdep->type != PREDEPEND
- && cdep->type != DEPEND && cdep->type != RECOMMEND)
- continue;
- for (j = 0; j < cdep->possibility_count; j++) {
- p = pkg_hash_fetch_installed_by_name(cdep->
- possibilities[j]->
- pkg->name);
- /* If the package is not installed, this could have
- * been a circular dependency and the package has
- * already been removed.
- */
- if (!p)
- return -1;
- if (!p->auto_installed)
- continue;
- n_deps = pkg_has_installed_dependents(p, &dependents);
- if (n_deps == 0) {
- opkg_msg(NOTICE, "%s was autoinstalled and is "
- "now orphaned, removing.\n", p->name);
- if (opkg_remove_pkg(p, 0) != 0) {
- err = -1;
- }
- } else
- opkg_msg(INFO, "%s was autoinstalled and is "
- "still required by %d "
- "installed packages.\n",
- p->name, n_deps);
- if (dependents)
- free(dependents);
- }
- }
- return err;
- }
- int opkg_remove_pkg(pkg_t * pkg, int from_upgrade)
- {
- int err;
- abstract_pkg_t *parent_pkg = NULL;
- /*
- * If called from an upgrade and not from a normal remove,
- * ignore the essential flag.
- */
- if (pkg->essential && !from_upgrade) {
- if (conf->force_removal_of_essential_packages) {
- opkg_msg(NOTICE,
- "Removing essential package %s under your coercion.\n"
- "\tIf your system breaks, you get to keep both pieces\n",
- pkg->name);
- } else {
- opkg_msg(NOTICE,
- "Refusing to remove essential package %s.\n"
- "\tRemoving an essential package may lead to an unusable system, but if\n"
- "\tyou enjoy that kind of pain, you can force opkg to proceed against\n"
- "\tits will with the option: --force-removal-of-essential-packages\n",
- pkg->name);
- return -1;
- }
- }
- if ((parent_pkg = pkg->parent) == NULL)
- return 0;
- /* only attempt to remove dependent installed packages if
- * force_depends is not specified or the package is being
- * replaced.
- */
- if (!conf->force_depends && !(pkg->state_flag & SF_REPLACE)) {
- abstract_pkg_t **dependents;
- int has_installed_dependents =
- pkg_has_installed_dependents(pkg, &dependents);
- if (has_installed_dependents) {
- /*
- * if this package is depended upon by others, then either we should
- * not remove it or we should remove it and all of its dependents
- */
- if (!conf->force_removal_of_dependent_packages) {
- print_dependents_warning(pkg, dependents);
- free(dependents);
- return -1;
- }
- /* remove packages depending on this package - Karthik */
- err = opkg_remove_dependent_pkgs(pkg, dependents);
- if (err) {
- free(dependents);
- return err;
- }
- }
- if (dependents)
- free(dependents);
- }
- if (from_upgrade == 0) {
- opkg_msg(NOTICE, "Removing package %s from %s...\n",
- pkg->name, pkg->dest->name);
- }
- pkg->state_flag |= SF_FILELIST_CHANGED;
- pkg->state_want = SW_DEINSTALL;
- opkg_state_changed++;
- if (pkg_run_script(pkg, "prerm", "remove") != 0) {
- if (!conf->force_remove) {
- opkg_msg(ERROR, "not removing package \"%s\", "
- "prerm script failed\n", pkg->name);
- opkg_msg(NOTICE,
- "You can force removal of packages with failed "
- "prerm scripts with the option: \n"
- "\t--force-remove\n");
- return -1;
- }
- }
- /* DPKG_INCOMPATIBILITY: dpkg is slightly different here. It
- maintains an empty filelist rather than deleting it. That seems
- like a big pain, and I don't see that that should make a big
- difference, but for anyone who wants tighter compatibility,
- feel free to fix this. */
- remove_data_files_and_list(pkg);
- err = pkg_run_script(pkg, "postrm", "remove");
- remove_maintainer_scripts(pkg);
- pkg->state_status = SS_NOT_INSTALLED;
- if (parent_pkg)
- parent_pkg->state_status = SS_NOT_INSTALLED;
- /* remove autoinstalled packages that are orphaned by the removal of this one */
- if (conf->autoremove) {
- if (remove_autoinstalled(pkg) != 0) {
- err = -1;
- }
- }
- return err;
- }
- void remove_data_files_and_list(pkg_t * pkg)
- {
- str_list_t installed_dirs;
- str_list_t *installed_files;
- str_list_elt_t *iter;
- char *file_name;
- conffile_t *conffile;
- int removed_a_dir;
- pkg_t *owner;
- int rootdirlen = 0;
- installed_files = pkg_get_installed_files(pkg);
- if (installed_files == NULL) {
- opkg_msg(ERROR, "Failed to determine installed "
- "files for %s. None removed.\n", pkg->name);
- return;
- }
- str_list_init(&installed_dirs);
- /* don't include trailing slash */
- if (conf->offline_root)
- rootdirlen = strlen(conf->offline_root);
- for (iter = str_list_first(installed_files); iter;
- iter = str_list_next(installed_files, iter)) {
- file_name = (char *)iter->data;
- owner = file_hash_get_file_owner(file_name);
- if (owner != pkg)
- /* File may have been claimed by another package. */
- continue;
- if (file_is_dir(file_name)) {
- str_list_append(&installed_dirs, file_name);
- continue;
- }
- conffile = pkg_get_conffile(pkg, file_name + rootdirlen);
- if (conffile) {
- if (conffile_has_been_modified(conffile)) {
- opkg_msg(NOTICE,
- "Not deleting modified conffile %s.\n",
- file_name);
- continue;
- }
- }
- if (!conf->noaction) {
- opkg_msg(INFO, "Deleting %s.\n", file_name);
- unlink(file_name);
- } else
- opkg_msg(INFO, "Not deleting %s. (noaction)\n",
- file_name);
- file_hash_remove(file_name);
- }
- /* Remove empty directories */
- if (!conf->noaction) {
- do {
- removed_a_dir = 0;
- for (iter = str_list_first(&installed_dirs); iter;
- iter = str_list_next(&installed_dirs, iter)) {
- file_name = (char *)iter->data;
- if (rmdir(file_name) == 0) {
- opkg_msg(INFO, "Deleting %s.\n",
- file_name);
- removed_a_dir = 1;
- str_list_remove(&installed_dirs, &iter);
- }
- }
- } while (removed_a_dir);
- }
- pkg_free_installed_files(pkg);
- pkg_remove_installed_files_list(pkg);
- /* Don't print warning for dirs that are provided by other packages */
- for (iter = str_list_first(&installed_dirs); iter;
- iter = str_list_next(&installed_dirs, iter)) {
- file_name = (char *)iter->data;
- owner = file_hash_get_file_owner(file_name);
- if (owner) {
- free(iter->data);
- iter->data = NULL;
- str_list_remove(&installed_dirs, &iter);
- }
- }
- /* cleanup */
- while (!void_list_empty(&installed_dirs)) {
- iter = str_list_pop(&installed_dirs);
- free(iter->data);
- free(iter);
- }
- str_list_deinit(&installed_dirs);
- }
- void remove_maintainer_scripts(pkg_t * pkg)
- {
- int i, err;
- char *globpattern;
- glob_t globbuf;
- if (conf->noaction)
- return;
- sprintf_alloc(&globpattern, "%s/%s.*", pkg->dest->info_dir, pkg->name);
- err = glob(globpattern, 0, NULL, &globbuf);
- free(globpattern);
- if (err)
- return;
- for (i = 0; i < globbuf.gl_pathc; i++) {
- opkg_msg(INFO, "Deleting %s.\n", globbuf.gl_pathv[i]);
- unlink(globbuf.gl_pathv[i]);
- }
- globfree(&globbuf);
- }
|