#include "opkg_remove.h"
#include "opkg_error.h"
-#include "opkg_state.h"
+#include "opkg_cmd.h"
#include "file_util.h"
#include "sprintf_alloc.h"
#include "str_util.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(opkg_conf_t *conf, abstract_pkg_t *parent_apkg, pkg_t *pkg, abstract_pkg_t *** pdependents)
+int
+pkg_has_installed_dependents(opkg_conf_t *conf, abstract_pkg_t *parent_apkg, pkg_t *pkg, abstract_pkg_t *** pdependents)
{
int nprovides = pkg->provides_count;
abstract_pkg_t **provides = pkg->provides;
int n_installed_dependents = 0;
int i;
- for (i = 0; i <= nprovides; i++) {
+ for (i = 0; i < nprovides; i++) {
abstract_pkg_t *providee = provides[i];
abstract_pkg_t **dependers = providee->depended_upon_by;
abstract_pkg_t *dep_ab_pkg;
/* if caller requested the set of installed dependents */
if (pdependents) {
int p = 0;
- abstract_pkg_t **dependents = (abstract_pkg_t **)calloc((n_installed_dependents+1), sizeof(abstract_pkg_t *));
-
- if ( dependents == NULL ){
- fprintf(stderr,"%s Unable to allocate memory. REPORT THIS BUG IN BUGZILLA PLEASE\n", __FUNCTION__);
- return -1;
- }
+ abstract_pkg_t **dependents = xcalloc((n_installed_dependents+1), sizeof(abstract_pkg_t *));
*pdependents = dependents;
- for (i = 0; i <= nprovides; i++) {
+ for (i = 0; i < nprovides; i++) {
abstract_pkg_t *providee = provides[i];
abstract_pkg_t **dependers = providee->depended_upon_by;
abstract_pkg_t *dep_ab_pkg;
return n_installed_dependents;
}
-int opkg_remove_dependent_pkgs (opkg_conf_t *conf, pkg_t *pkg, abstract_pkg_t **dependents)
+static int
+opkg_remove_dependent_pkgs (opkg_conf_t *conf, pkg_t *pkg, abstract_pkg_t **dependents)
{
int i;
int a;
}
if (count == 1) {
- free(dependent_pkgs);
+ pkg_vec_free(dependent_pkgs);
return 0;
}
int err=0;
for (i = 0; i < dependent_pkgs->len; i++) {
err = opkg_remove_pkg(conf, dependent_pkgs->pkgs[i],0);
- if (err)
+ if (err) {
+ pkg_vec_free(dependent_pkgs);
break;
+ }
}
- free(dependent_pkgs);
+ pkg_vec_free(dependent_pkgs);
return err;
}
-static int user_prefers_removing_dependents(opkg_conf_t *conf, abstract_pkg_t *abpkg, pkg_t *pkg, abstract_pkg_t **dependents)
+static void
+print_dependents_warning(opkg_conf_t *conf, abstract_pkg_t *abpkg, pkg_t *pkg, abstract_pkg_t **dependents)
{
abstract_pkg_t *dep_ab_pkg;
opkg_message(conf, OPKG_ERROR, "Package %s is depended upon by packages:\n", pkg->name);
}
opkg_message(conf, OPKG_ERROR, "These might cease to work if package %s is removed.\n\n", pkg->name);
opkg_message(conf, OPKG_ERROR, "");
- opkg_message(conf, OPKG_ERROR, "You can force removal of this package with -force-depends.\n");
+ opkg_message(conf, OPKG_ERROR, "You can force removal of this package with --force-depends.\n");
opkg_message(conf, OPKG_ERROR, "You can force removal of this package and its dependents\n");
- opkg_message(conf, OPKG_ERROR, "with -force-removal-of-dependent-packages or -recursive\n");
- opkg_message(conf, OPKG_ERROR, "or by setting option force_removal_of_dependent_packages\n");
- opkg_message(conf, OPKG_ERROR, "in opkg.conf.\n");
- return 0;
+ opkg_message(conf, OPKG_ERROR, "with --force-removal-of-dependent-packages\n");
}
-static int remove_autoinstalled (opkg_conf_t *conf, pkg_t *pkg)
+/*
+ * Find and remove packages that were autoinstalled and are orphaned
+ * by the removal of pkg.
+ */
+static int
+remove_autoinstalled(opkg_conf_t *conf, pkg_t *pkg)
{
- /*
- * find and remove packages that were autoinstalled and are orphaned by the removal of pkg
- */
-
- char *buffer, *d_str;
- int i;
-
- for (i = 0; i < pkg->depends_count; ++i)
- {
- int x = 0;
- pkg_t *p;
- d_str = pkg->depends_str[i];
- buffer = calloc (1, strlen (d_str) + 1);
- if (!buffer)
- {
- fprintf(stderr,"%s Unable to allocate memory.\n", __FUNCTION__);
- return -1;
- }
-
- while (d_str[x] != '\0' && d_str[x] != ' ')
- {
- buffer[x] = d_str[x];
- ++x;
- }
- buffer[x] = '\0';
- buffer = realloc (buffer, strlen (buffer) + 1);
- p = pkg_hash_fetch_installed_by_name (&conf->pkg_hash, buffer);
-
- /* if the package is not installed, this could have been a circular
- * depenancy and the package has already been removed */
- if (!p)
- return -1;
-
- if (p->auto_installed)
- {
- int deps;
- abstract_pkg_t **dependents;
-
- deps = pkg_has_installed_dependents(conf, NULL, p, &dependents);
- if (deps == 0)
- {
- opkg_message (conf, OPKG_INFO,
- "%s was autoinstalled but is now orphaned\n", buffer);
- opkg_remove_pkg(conf, p,0);
- }
- else
- opkg_message (conf, OPKG_INFO, "%s was autoinstalled and is still required by "
- "%d installed packages\n", buffer, deps);
- }
- free (buffer);
- }
+ int i, j;
+ int n_deps;
+ pkg_t *p;
+ struct compound_depend *cdep;
+ abstract_pkg_t **dependents;
+
+ int count = pkg->pre_depends_count +
+ pkg->depends_count +
+ pkg->recommends_count +
+ pkg->suggests_count;
+
+ for (i=0; i<count; i++) {
+ cdep = &pkg->depends[i];
+ if (cdep->type != DEPEND)
+ continue;
+ for (j=0; j<cdep->possibility_count; j++) {
+ p = pkg_hash_fetch_installed_by_name (&conf->pkg_hash,
+ 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(conf, NULL, p,
+ &dependents);
+ if (n_deps == 0) {
+ opkg_message(conf, OPKG_NOTICE,
+ "%s was autoinstalled and is "
+ "now orphaned, removing\n",
+ p->name);
+ opkg_remove_pkg(conf, p, 0);
+ } else
+ opkg_message(conf, OPKG_INFO,
+ "%s was autoinstalled and is "
+ "still required by %d "
+ "installed packages.\n",
+ p->name, n_deps);
+
+ if (dependents)
+ free(dependents);
+ }
+ }
- return 0;
+ return 0;
}
-int opkg_remove_pkg(opkg_conf_t *conf, pkg_t *pkg,int message)
+int
+opkg_remove_pkg(opkg_conf_t *conf, pkg_t *pkg, int from_upgrade)
{
-/* Actually, when "message == 1" I have been called from an upgrade, and not from a normal remove
- thus I wan't check for essential, as I'm upgrading.
- I hope it won't break anything :)
-*/
int err;
abstract_pkg_t *parent_pkg = NULL;
- if (pkg->essential && !message) {
+/*
+ * 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) {
fprintf(stderr, "WARNING: Removing essential package %s under your coercion.\n"
"\tIf your system breaks, you get to keep both pieces\n",
fprintf(stderr, "ERROR: 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",
+ "\tits will with the option: --force-removal-of-essential-packages\n",
pkg->name);
return OPKG_PKG_IS_ESSENTIAL;
}
if (has_installed_dependents) {
/*
- * if this package is depended up by others, then either we should
+ * 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
- && !user_prefers_removing_dependents(conf, parent_pkg, pkg, dependents)) {
+ if (!conf->force_removal_of_dependent_packages) {
+ print_dependents_warning(conf, parent_pkg, pkg, dependents);
+ free(dependents);
return OPKG_PKG_HAS_DEPENDENTS;
}
free(dependents);
}
- if ( message==0 ){
+ if (from_upgrade == 0) {
opkg_message (conf, OPKG_NOTICE,
"Removing package %s from %s...\n", pkg->name, pkg->dest->name);
- fflush(stdout);
}
pkg->state_flag |= SF_FILELIST_CHANGED;
pkg_run_script(conf, pkg, "postrm", "remove");
- remove_maintainer_scripts_except_postrm(conf, pkg);
-
- /* Aman Gupta - Since opkg is made for handheld devices with limited
- * space, it doesn't make sense to leave extra configurations, files,
- * and maintainer scripts left around. So, we make remove like purge,
- * and take out all the crap :) */
-
- remove_postrm(conf, pkg);
+ remove_maintainer_scripts(conf, 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)
remove_autoinstalled (conf, pkg);
-
-
return 0;
}
-int opkg_purge_pkg(opkg_conf_t *conf, pkg_t *pkg)
-{
- opkg_remove_pkg(conf, pkg,0);
- return 0;
-}
-
-int remove_data_files_and_list(opkg_conf_t *conf, pkg_t *pkg)
+void
+remove_data_files_and_list(opkg_conf_t *conf, pkg_t *pkg)
{
str_list_t installed_dirs;
str_list_t *installed_files;
conffile_t *conffile;
int removed_a_dir;
pkg_t *owner;
+ int rootdirlen = 0;
str_list_init(&installed_dirs);
- installed_files = pkg_get_installed_files(pkg);
+ installed_files = pkg_get_installed_files(conf, pkg);
- for (iter = installed_files->head; iter; iter = iter->next) {
- file_name = iter->data;
+ /* 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;
if (file_is_dir(file_name)) {
- str_list_append(&installed_dirs, strdup(file_name));
+ str_list_append(&installed_dirs, file_name);
continue;
}
- conffile = pkg_get_conffile(pkg, file_name);
+ conffile = pkg_get_conffile(pkg, file_name+rootdirlen);
if (conffile) {
- /* XXX: QUESTION: Is this right? I figure we only need to
- save the conffile if it has been modified. Is that what
- dpkg does? Or does dpkg preserve all conffiles? If so,
- this seems like a better thing to do to conserve
- space. */
if (conffile_has_been_modified(conf, conffile)) {
opkg_message (conf, OPKG_NOTICE,
" not deleting modified conffile %s\n", file_name);
- fflush(stdout);
continue;
}
}
unlink(file_name);
}
+ /* Remove empty directories */
if (!conf->noaction) {
do {
removed_a_dir = 0;
- for (iter = installed_dirs.head; iter; iter = iter->next) {
- file_name = iter->data;
+ 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_message(conf, OPKG_INFO, " deleting %s\n", file_name);
}
pkg_free_installed_files(pkg);
- /* We have to remove the file list now, so that
- find_pkg_owning_file does not always just report this package */
pkg_remove_installed_files_list(conf, pkg);
/* Don't print warning for dirs that are provided by other packages */
- for (iter = installed_dirs.head; iter; iter = iter->next) {
- file_name = iter->data;
+ 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(conf, file_name);
if (owner) {
}
/* cleanup */
- for (iter = installed_dirs.head; iter; iter = iter->next) {
- free(iter->data);
- iter->data = NULL;
+ while (!void_list_empty(&installed_dirs)) {
+ iter = str_list_pop(&installed_dirs);
+ free(iter->data);
+ free(iter);
}
str_list_deinit(&installed_dirs);
-
- return 0;
}
-int remove_maintainer_scripts_except_postrm(opkg_conf_t *conf, pkg_t *pkg)
+void
+remove_maintainer_scripts(opkg_conf_t *conf, pkg_t *pkg)
{
- int i, err;
- char *globpattern;
- glob_t globbuf;
-
- if (conf->noaction) return 0;
+ int i, err;
+ char *globpattern;
+ glob_t globbuf;
- sprintf_alloc(&globpattern, "%s/%s.*",
- pkg->dest->info_dir, pkg->name);
- err = glob(globpattern, 0, NULL, &globbuf);
- free(globpattern);
- if (err) {
- return 0;
- }
+ if (conf->noaction)
+ return;
- for (i = 0; i < globbuf.gl_pathc; i++) {
- if (str_ends_with(globbuf.gl_pathv[i], ".postrm")) {
- continue;
- }
- opkg_message(conf, OPKG_INFO, " deleting %s\n", globbuf.gl_pathv[i]);
- unlink(globbuf.gl_pathv[i]);
- }
- globfree(&globbuf);
-
- return 0;
-}
+ sprintf_alloc(&globpattern, "%s/%s.*",
+ pkg->dest->info_dir, pkg->name);
-int remove_postrm(opkg_conf_t *conf, pkg_t *pkg)
-{
- char *postrm_file_name;
-
- if (conf->noaction) return 0;
+ err = glob(globpattern, 0, NULL, &globbuf);
+ free(globpattern);
+ if (err)
+ return;
- sprintf_alloc(&postrm_file_name, "%s/%s.postrm",
- pkg->dest->info_dir, pkg->name);
- unlink(postrm_file_name);
- free(postrm_file_name);
-
- return 0;
+ for (i = 0; i < globbuf.gl_pathc; i++) {
+ opkg_message(conf, OPKG_INFO, "deleting %s\n",
+ globbuf.gl_pathv[i]);
+ unlink(globbuf.gl_pathv[i]);
+ }
+ globfree(&globbuf);
}