Various cleanups in opkg_remove.{c,h}
[oweals/opkg-lede.git] / libopkg / opkg_install.c
index a3893c7131f54e89cc2fc926d15d57f00af2e2cf..6003f4f34081feb62127dbfb067becff27ccde44 100644 (file)
@@ -21,7 +21,6 @@
 #include <glob.h>
 #include <time.h>
 #include <signal.h>
-typedef void (*sighandler_t)(int);
 
 #include "pkg.h"
 #include "pkg_hash.h"
@@ -34,7 +33,7 @@ typedef void (*sighandler_t)(int);
 
 #include "opkg_utils.h"
 #include "opkg_message.h"
-#include "opkg_state.h"
+#include "opkg_cmd.h"
 #include "opkg_defines.h"
 
 #include "sprintf_alloc.h"
@@ -42,330 +41,10 @@ typedef void (*sighandler_t)(int);
 #include "str_util.h"
 #include "xsystem.h"
 #include "user.h"
+#include "libbb/libbb.h"
 
-int satisfy_dependencies_for(opkg_conf_t *conf, pkg_t *pkg);
-static int verify_pkg_installable(opkg_conf_t *conf, pkg_t *pkg);
-static int unpack_pkg_control_files(opkg_conf_t *conf, pkg_t *pkg);
-
-static int prerm_upgrade_old_pkg(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg);
-static int prerm_upgrade_old_pkg_unwind(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg);
-static int prerm_deconfigure_conflictors(opkg_conf_t *conf, pkg_t *pkg, pkg_vec_t *conflictors);
-static int prerm_deconfigure_conflictors_unwind(opkg_conf_t *conf, pkg_t *pkg, pkg_vec_t *conflictors);
-static int preinst_configure(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg);
-static int preinst_configure_unwind(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg);
-static int check_data_file_clashes(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg);
-static int check_data_file_clashes_change(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg);
-static int check_data_file_clashes_unwind(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg);
-static int backup_modified_conffiles(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg);
-static int backup_modified_conffiles_unwind(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg);
-static int postrm_upgrade_old_pkg(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg);
-static int postrm_upgrade_old_pkg_unwind(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg);
-
-static int remove_obsolesced_files(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg);
-static int install_maintainer_scripts(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg);
-static int remove_disappeared(opkg_conf_t *conf, pkg_t *pkg);
-static int install_data_files(opkg_conf_t *conf, pkg_t *pkg);
-static int resolve_conffiles(opkg_conf_t *conf, pkg_t *pkg);
-
-static int cleanup_temporary_files(opkg_conf_t *conf, pkg_t *pkg);
-
-static int user_prefers_old_conffile(const char *file, const char *backup);
-
-static char *backup_filename_alloc(const char *file_name);
-static int backup_make_backup(opkg_conf_t *conf, const char *file_name);
-static int backup_exists_for(const char *file_name);
-static int backup_remove(const char *file_name);
-
-
-int opkg_install_from_file(opkg_conf_t *conf, const char *filename)
-{
-     int err, cmp;
-     pkg_t *pkg, *old;
-     char *old_version, *new_version;
-
-     pkg = pkg_new();
-     if (pkg == NULL) {
-         return ENOMEM;
-     }
-
-     err = pkg_init_from_file(pkg, filename);
-     if (err) {
-         return err;
-     }
-
-     if (!pkg->architecture) {
-         opkg_message(conf, OPKG_ERROR, "Package %s has no Architecture defined.\n", pkg->name);
-         return -EINVAL;
-     }
-
-     /* XXX: CLEANUP: hash_insert_pkg has a nasty side effect of possibly
-       freeing the pkg that we pass in. It might be nice to clean this up
-       if possible.  */
-     pkg = hash_insert_pkg(&conf->pkg_hash, pkg, 1,conf);
-     old = pkg_hash_fetch_installed_by_name(&conf->pkg_hash, pkg->name);
-
-     pkg->local_filename = strdup(filename);
-
-     if (old) {
-         old_version = pkg_version_str_alloc(old);
-         new_version = pkg_version_str_alloc(pkg);
-
-         cmp = pkg_compare_versions(old, pkg);
-          if ( (conf->force_downgrade==1) && (cmp > 0) ){     /* We've been asked to allow downgrade  and version is precedent */
-             cmp = -1 ;                                       /* then we force opkg to downgrade */ 
-                                                              /* We need to use a value < 0 because in the 0 case we are asking to */
-                                                              /* reinstall, and some check could fail asking the "force-reinstall" option */
-          } 
-         if (cmp > 0) {
-                opkg_message(conf, OPKG_NOTICE,
-                             "Not downgrading package %s on %s from %s to %s.\n",
-                             old->name, old->dest->name, old_version, new_version);
-                pkg->state_want = SW_DEINSTALL;
-                pkg->state_flag |= SF_OBSOLETE;
-                free(old_version);
-                free(new_version);
-                return 0;
-         } else {
-              free(old_version);
-              free(new_version);
-         }
-     }
-
-     opkg_message(conf, OPKG_DEBUG2,"Function: %s calling opkg_install_pkg \n",__FUNCTION__);
-     return opkg_install_pkg(conf, pkg,0);
-}
-
-opkg_error_t opkg_install_by_name(opkg_conf_t *conf, const char *pkg_name)
-{
-     int cmp, err;
-     pkg_t *old, *new;
-     char *old_version, *new_version;
-
-     opkg_message(conf, OPKG_DEBUG2, " Getting old  from pkg_hash_fetch \n" );
-     old = pkg_hash_fetch_installed_by_name(&conf->pkg_hash, pkg_name);
-     if ( old ) 
-        opkg_message(conf, OPKG_DEBUG2, " Old versions from pkg_hash_fetch %s \n",  old->version );
-    
-     opkg_message(conf, OPKG_DEBUG2, " Getting new  from pkg_hash_fetch \n" );
-     new = pkg_hash_fetch_best_installation_candidate_by_name(conf, pkg_name, &err);
-     if ( new ) 
-        opkg_message(conf, OPKG_DEBUG2, " New versions from pkg_hash_fetch %s \n",  new->version );
-
-/* Pigi Basically here is broken the version stuff.
-   What's happening is that nothing provide the version to differents 
-   functions, so the returned struct is always the latest.
-   That's why the install by name don't work.
-*/
-     opkg_message(conf, OPKG_DEBUG2, " Versions from pkg_hash_fetch in %s ", __FUNCTION__ );
-
-     if ( old ) 
-        opkg_message(conf, OPKG_DEBUG2, " old %s ", old->version );
-     if ( new ) 
-        opkg_message(conf, OPKG_DEBUG2, " new %s ", new->version );
-     opkg_message(conf, OPKG_DEBUG2, " \n");
-
-     if (new == NULL) {
-         if (err)
-           return err;
-         else
-           return OPKG_PKG_HAS_NO_CANDIDATE;
-     }
-
-     new->state_flag |= SF_USER;
-     if (old) {
-         old_version = pkg_version_str_alloc(old);
-         new_version = pkg_version_str_alloc(new);
-
-         cmp = pkg_compare_versions(old, new);
-          if ( (conf->force_downgrade==1) && (cmp > 0) ){     /* We've been asked to allow downgrade  and version is precedent */
-            opkg_message(conf, OPKG_DEBUG, " Forcing downgrade \n");
-             cmp = -1 ;                                       /* then we force opkg to downgrade */ 
-                                                              /* We need to use a value < 0 because in the 0 case we are asking to */
-                                                              /* reinstall, and some check could fail asking the "force-reinstall" option */
-          } 
-         opkg_message(conf, OPKG_DEBUG, 
-                      "Comparing visible versions of pkg %s:"
-                      "\n\t%s is installed "
-                      "\n\t%s is available "
-                      "\n\t%d was comparison result\n",
-                      pkg_name, old_version, new_version, cmp);
-         if (cmp == 0 && !conf->force_reinstall) {
-              opkg_message(conf, OPKG_NOTICE,
-                           "Package %s (%s) installed in %s is up to date.\n",
-                           old->name, old_version, old->dest->name);
-              free(old_version);
-              free(new_version);
-              return 0;
-         } else if (cmp > 0) {
-              opkg_message(conf, OPKG_NOTICE,
-                           "Not downgrading package %s on %s from %s to %s.\n",
-                           old->name, old->dest->name, old_version, new_version);
-              free(old_version);
-              free(new_version);
-              return 0;
-         } else if (cmp < 0) {
-              new->dest = old->dest;
-              old->state_want = SW_DEINSTALL;    /* Here probably the problem for bug 1277 */
-         }
-     }
-
-     /* XXX: CLEANUP: The error code of opkg_install_by_name is really
-       supposed to be an opkg_error_t, but opkg_install_pkg could
-       return any kind of integer, (might be errno from a syscall,
-       etc.). This is a real mess and will need to be cleaned up if
-       anyone ever wants to make a nice libopkg. */
-
-     opkg_message(conf, OPKG_DEBUG2,"Function: %s calling opkg_install_pkg \n",__FUNCTION__);
-     return opkg_install_pkg(conf, new,0);
-}
-
-opkg_error_t opkg_install_multi_by_name(opkg_conf_t *conf, const char *pkg_name)
-{
-     abstract_pkg_vec_t *providers = pkg_hash_fetch_all_installation_candidates (&conf->pkg_hash, pkg_name);
-     int i;
-     opkg_error_t err;
-     abstract_pkg_t *ppkg ;
-
-     if (providers == NULL)
-         return OPKG_PKG_HAS_NO_CANDIDATE;
-
-     for (i = 0; i < providers->len; i++) {
-         ppkg = abstract_pkg_vec_get(providers, i);
-          opkg_message(conf, OPKG_DEBUG2,"Function: %s calling opkg_install_by_name %d \n",__FUNCTION__, i);
-         err = opkg_install_by_name(conf, ppkg->name);
-         if (err)
-              return err;
-/* XXX Maybe ppkg should be freed ? */
-     }
-     return 0;
-}
-
-/*
- * Walk dependence graph starting with pkg, collect packages to be
- * installed into pkgs_needed, in dependence order.
- */
-int pkg_mark_dependencies_for_installation(opkg_conf_t *conf, pkg_t *pkg, pkg_vec_t *pkgs_needed)
-{
-     int i, err;
-     pkg_vec_t *depends = pkg_vec_alloc();
-     char **unresolved = NULL;
-     int ndepends;
-
-     ndepends = pkg_hash_fetch_unsatisfied_dependencies(conf, 
-                                                       pkg, depends, 
-                                                       &unresolved);
-
-     if (unresolved) {
-         opkg_message(conf, OPKG_ERROR,
-                      "%s: Cannot satisfy the following dependencies for %s:\n\t",
-                      conf->force_depends ? "Warning" : "ERROR", pkg->name);
-         while (*unresolved) {
-              opkg_message(conf, OPKG_ERROR, " %s", *unresolved);
-              unresolved++;
-         }
-         opkg_message(conf, OPKG_ERROR, "\n");
-         if (! conf->force_depends) {
-              opkg_message(conf, OPKG_INFO,
-                           "This could mean that your package list is out of date or that the packages\n"
-                           "mentioned above do not yet exist (try 'opkg update'). To proceed in spite\n"
-                           "of this problem try again with the '-force-depends' option.\n");
-              pkg_vec_free(depends);
-              return OPKG_PKG_DEPS_UNSATISFIED;
-         }
-     }
-
-     if (ndepends <= 0) {
-         pkg_vec_free(depends);
-         return 0;
-     }
-
-     for (i = 0; i < depends->len; i++) {
-         pkg_t *dep = depends->pkgs[i];
-         /* The package was uninstalled when we started, but another
-            dep earlier in this loop may have depended on it and pulled
-            it in, so check first. */
-         if ((dep->state_status != SS_INSTALLED)
-             && (dep->state_status != SS_UNPACKED)
-             && (dep->state_want != SW_INSTALL)) {
-
-              /* Mark packages as to-be-installed */
-              dep->state_want = SW_INSTALL;
-
-              /* Dependencies should be installed the same place as pkg */
-              if (dep->dest == NULL) {
-                   dep->dest = pkg->dest;
-              }
-
-              err = pkg_mark_dependencies_for_installation(conf, dep, pkgs_needed);
-              if (err) {
-                   pkg_vec_free(depends);
-                   return err;
-              }
-         }
-     }
-     if (pkgs_needed)
-         pkg_vec_insert(pkgs_needed, pkg);
-
-     pkg_vec_free(depends);
-
-     return 0;
-}
-#if 0
-int name_mark_dependencies_for_installation(opkg_conf_t *conf, const char *pkg_name, pkg_vec_t *pkgs_needed)
-{
-     int cmp;
-     pkg_t *old, *new;
-     char *old_version, *new_version;
-
-     old = pkg_hash_fetch_installed_by_name(&conf->pkg_hash, pkg_name);
-    
-     new = pkg_hash_fetch_best_installation_candidate_by_name(conf, pkg_name);
-     if (new == NULL) {
-         return OPKG_PKG_HAS_NO_CANDIDATE;
-     }
-     if (old) {
-         old_version = pkg_version_str_alloc(old);
-         new_version = pkg_version_str_alloc(new);
-
-         cmp = pkg_compare_versions(old, new);
-          if ( (conf->force_downgrade==1) && (cmp > 0) ){     /* We've been asked to allow downgrade  and version is precedent */
-           opkg_message(conf, OPKG_DEBUG, " Forcing downgrade ");
-             cmp = -1 ;                                       /* then we force opkg to downgrade */ 
-                                                              /* We need to use a value < 0 because in the 0 case we are asking to */
-                                                              /* reinstall, and some check could fail asking the "force-reinstall" option */
-          } 
-         opkg_message(conf, OPKG_DEBUG, 
-                      "comparing visible versions of pkg %s:"
-                      "\n\t%s is installed "
-                      "\n\t%s is available "
-                      "\n\t%d was comparison result\n",
-                      pkg_name, old_version, new_version, cmp);
-         if (cmp == 0 && !conf->force_reinstall) {
-              opkg_message(conf, OPKG_NOTICE,
-                           "Package %s (%s) installed in %s is up to date.\n",
-                           old->name, old_version, old->dest->name);
-              free(old_version);
-              free(new_version);
-              return 0;
-         } else if (cmp > 0) {
-              opkg_message(conf, OPKG_NOTICE,
-                           "Not downgrading package %s on %s from %s to %s.\n",
-                           old->name, old->dest->name, old_version, new_version);
-              free(old_version);
-              free(new_version);
-              return 0;
-         } else if (cmp < 0) {
-              new->dest = old->dest;
-              old->state_want = SW_DEINSTALL;
-              old->state_flag |= SF_OBSOLETE;
-         }
-     }
-     return pkg_mark_dependencies_for_installation(conf, new, pkgs_needed);
-}
-
-#endif
-
-int satisfy_dependencies_for(opkg_conf_t *conf, pkg_t *pkg)
+static int
+satisfy_dependencies_for(opkg_conf_t *conf, pkg_t *pkg)
 {
      int i, err;
      pkg_vec_t *depends = pkg_vec_alloc();
@@ -434,26 +113,8 @@ int satisfy_dependencies_for(opkg_conf_t *conf, pkg_t *pkg)
      return 0;
 }
 
-
-/* check all packages have their dependences satisfied, e.g., in case an upgraded package split */ 
-int opkg_satisfy_all_dependences(opkg_conf_t *conf)
-{
-     if (conf->nodeps == 0) {
-         int i;
-         pkg_vec_t *installed = pkg_vec_alloc();
-         pkg_hash_fetch_all_installed(&conf->pkg_hash, installed);
-         for (i = 0; i < installed->len; i++) {
-              pkg_t *pkg = installed->pkgs[i];
-              satisfy_dependencies_for(conf, pkg);
-         }
-         pkg_vec_free(installed);
-     }
-     return 0;
-}
-
-\f
-
-static int check_conflicts_for(opkg_conf_t *conf, pkg_t *pkg)
+static int
+check_conflicts_for(opkg_conf_t *conf, pkg_t *pkg)
 {
      int i;
      pkg_vec_t *conflicts = NULL;
@@ -483,13 +144,16 @@ static int check_conflicts_for(opkg_conf_t *conf, pkg_t *pkg)
      return 0;
 }
 
-static int update_file_ownership(opkg_conf_t *conf, pkg_t *new_pkg, pkg_t *old_pkg)
+static int
+update_file_ownership(opkg_conf_t *conf, pkg_t *new_pkg, pkg_t *old_pkg)
 {
-     str_list_t *new_list = pkg_get_installed_files(new_pkg);
-     str_list_elt_t *iter;
+     str_list_t *new_list = pkg_get_installed_files(conf, new_pkg);
+     str_list_elt_t *iter, *niter;
 
-     for (iter = new_list->head; iter; iter = iter->next) {
-         char *new_file = iter->data;
+     for (iter = str_list_first(new_list), niter = str_list_next(new_list, iter); 
+             iter; 
+             iter = niter, niter = str_list_next(new_list, niter)) {
+         char *new_file = (char *)iter->data;
          pkg_t *owner = file_hash_get_file_owner(conf, new_file);
          if (!new_file)
               opkg_message(conf, OPKG_ERROR, "Null new_file for new_pkg=%s\n", new_pkg->name);
@@ -497,9 +161,11 @@ static int update_file_ownership(opkg_conf_t *conf, pkg_t *new_pkg, pkg_t *old_p
               file_hash_set_file_owner(conf, new_file, new_pkg);
      }
      if (old_pkg) {
-         str_list_t *old_list = pkg_get_installed_files(old_pkg);
-         for (iter = old_list->head; iter; iter = iter->next) {
-              char *old_file = iter->data;
+         str_list_t *old_list = pkg_get_installed_files(conf, old_pkg);
+         for (iter = str_list_first(old_list), niter = str_list_next(old_list, iter); 
+                  iter; 
+                  iter = niter, niter = str_list_next(old_list, niter)) {
+              char *old_file = (char *)iter->data;
               pkg_t *owner = file_hash_get_file_owner(conf, old_file);
               if (owner == old_pkg) {
                    /* obsolete */
@@ -512,7 +178,8 @@ static int update_file_ownership(opkg_conf_t *conf, pkg_t *new_pkg, pkg_t *old_p
      return 0;
 }
 
-static int verify_pkg_installable(opkg_conf_t *conf, pkg_t *pkg)
+static int
+verify_pkg_installable(opkg_conf_t *conf, pkg_t *pkg)
 {
     /* XXX: FEATURE: Anything else needed here? Maybe a check on free space? */
 
@@ -521,13 +188,15 @@ static int verify_pkg_installable(opkg_conf_t *conf, pkg_t *pkg)
      * XXX: BUG easy for cworth
      * 1) please point the call below to the correct current root destination
      * 2) we need to resolve how to check the required space for a pending pkg, 
-     *    my diddling with the .ipk file size below isn't going to cut it.
+     *    my diddling with the .opk file size below isn't going to cut it.
      * 3) return a proper error code instead of 1
      */
      int comp_size, blocks_available;
+     char *root_dir;
     
      if (!conf->force_space && pkg->installed_size != NULL) {
-         blocks_available = get_available_blocks(conf->default_dest->root_dir);
+          root_dir = pkg->dest ? pkg->dest->root_dir : conf->default_dest->root_dir;
+         blocks_available = get_available_blocks(root_dir);
 
          comp_size = strtoul(pkg->installed_size, NULL, 0);
          /* round up a blocks count without doing fancy-but-slow casting jazz */ 
@@ -536,14 +205,15 @@ static int verify_pkg_installable(opkg_conf_t *conf, pkg_t *pkg)
          if (comp_size >= blocks_available) {
               opkg_message(conf, OPKG_ERROR,
                            "Only have %d available blocks on filesystem %s, pkg %s needs %d\n", 
-                           blocks_available, conf->default_dest->root_dir, pkg->name, comp_size);
+                           blocks_available, root_dir, pkg->name, comp_size);
               return ENOSPC;
          }
      }
      return 0;
 }
 
-static int unpack_pkg_control_files(opkg_conf_t *conf, pkg_t *pkg)
+static int
+unpack_pkg_control_files(opkg_conf_t *conf, pkg_t *pkg)
 {
      int err;
      char *conffiles_file_name;
@@ -571,7 +241,7 @@ static int unpack_pkg_control_files(opkg_conf_t *conf, pkg_t *pkg)
        move all of unpack_pkg_control_files to that function. */
 
      /* Don't need to re-read conffiles if we already have it */
-     if (pkg->conffiles.head) {
+     if (!nv_pair_list_empty(&pkg->conffiles)) {
          return 0;
      }
 
@@ -625,8 +295,97 @@ static int unpack_pkg_control_files(opkg_conf_t *conf, pkg_t *pkg)
      return 0;
 }
 
+/*
+ * Remove packages which were auto_installed due to a dependency by old_pkg,
+ * which are no longer a dependency in the new (upgraded) pkg.
+ */
+static int
+pkg_remove_orphan_dependent(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg) 
+{
+       int i, j, k, l, found;
+       int n_deps;
+       pkg_t *p;
+       struct compound_depend *cd0, *cd1;
+        abstract_pkg_t **dependents;
+
+       int count0 = old_pkg->pre_depends_count +
+                               old_pkg->depends_count +
+                               old_pkg->recommends_count +
+                               old_pkg->suggests_count;
+       int count1 = pkg->pre_depends_count +
+                               pkg->depends_count +
+                               pkg->recommends_count +
+                               pkg->suggests_count;
+
+       for (i=0; i<count0; i++) {
+               cd0 = &old_pkg->depends[i];
+               if (cd0->type != DEPEND)
+                       continue;
+               for (j=0; j<cd0->possibility_count; j++) {
+
+                       found = 0;
+
+                       for (k=0; k<count1; k++) {
+                               cd1 = &pkg->depends[i];
+                               if (cd1->type != DEPEND)
+                                       continue;
+                               for (l=0; l<cd1->possibility_count; l++) {
+                                       if (cd0->possibilities[j]
+                                        == cd1->possibilities[l]) {
+                                               found = 1;
+                                               break;
+                                       }
+                               }
+                               if (found)
+                                       break;
+                       }
+
+                       if (found)
+                               continue;
+
+                       /*
+                        * old_pkg has a dependency that pkg does not.
+                        */
+                       p = pkg_hash_fetch_installed_by_name (&conf->pkg_hash,
+                                       cd0->possibilities[j]->pkg->name);
+
+                       if (!p)
+                               continue;
+
+                       if (!p->auto_installed)
+                               continue;
+
+                       n_deps = pkg_has_installed_dependents(conf, NULL, p,
+                                       &dependents);
+                       n_deps--; /* don't count old_pkg */
+
+                       if (n_deps == 0) {
+                               opkg_message (conf, OPKG_NOTICE,
+                                               "%s was autoinstalled and is "
+                                               "now orphaned, removing.\n",
+                                               p->name);
+
+                               /* p has one installed dependency (old_pkg),
+                                * which we need to ignore during removal. */
+                               p->state_flag |= SF_REPLACE;
+
+                               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);
+
+               }
+       }
+
+       return 0;
+}
+
 /* returns number of installed replacees */
-int pkg_get_installed_replacees(opkg_conf_t *conf, pkg_t *pkg, pkg_vec_t *installed_replacees)
+static int
+pkg_get_installed_replacees(opkg_conf_t *conf, pkg_t *pkg, pkg_vec_t *installed_replacees)
 {
      abstract_pkg_t **replaces = pkg->replaces;
      int replaces_count = pkg->replaces_count;
@@ -648,7 +407,8 @@ int pkg_get_installed_replacees(opkg_conf_t *conf, pkg_t *pkg, pkg_vec_t *instal
      return installed_replacees->len;
 }
 
-int pkg_remove_installed_replacees(opkg_conf_t *conf, pkg_vec_t *replacees)
+static int
+pkg_remove_installed_replacees(opkg_conf_t *conf, pkg_vec_t *replacees)
 {
      int i;
      int replaces_count = replacees->len;
@@ -664,7 +424,8 @@ int pkg_remove_installed_replacees(opkg_conf_t *conf, pkg_vec_t *replacees)
 }
 
 /* to unwind the removal: make sure they are installed */
-int pkg_remove_installed_replacees_unwind(opkg_conf_t *conf, pkg_vec_t *replacees)
+static int
+pkg_remove_installed_replacees_unwind(opkg_conf_t *conf, pkg_vec_t *replacees)
 {
      int i, err;
      int replaces_count = replacees->len;
@@ -680,14 +441,9 @@ int pkg_remove_installed_replacees_unwind(opkg_conf_t *conf, pkg_vec_t *replacee
      return 0;
 }
 
-int caught_sigint = 0;
-static void opkg_install_pkg_sigint_handler(int sig)
-{
-     caught_sigint = sig;
-}
-
 /* compares versions of pkg and old_pkg, returns 0 if OK to proceed with installation of pkg, 1 otherwise */
-static int opkg_install_check_downgrade(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg, int message)
+static int
+opkg_install_check_downgrade(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg, int message)
 {        
      if (old_pkg) {
           char message_out[15];
@@ -749,291 +505,9 @@ static int opkg_install_check_downgrade(opkg_conf_t *conf, pkg_t *pkg, pkg_t *ol
      }
 }
 
-/* and now the meat... */
-int opkg_install_pkg(opkg_conf_t *conf, pkg_t *pkg, int from_upgrade)
-{
-     int err = 0;
-     int message = 0;
-     pkg_t *old_pkg = NULL;
-     pkg_vec_t *replacees;
-     abstract_pkg_t *ab_pkg = NULL;
-     int old_state_flag;
-     char* file_md5;
-     char *pkgid;
-    
-     if ( from_upgrade ) 
-        message = 1;            /* Coming from an upgrade, and should change the output message */
 
-     if (!pkg) {
-         opkg_message(conf, OPKG_ERROR,
-                      "INTERNAL ERROR: null pkg passed to opkg_install_pkg\n");
-         return OPKG_INSTALL_ERR_INTERNAL;
-     }
-
-     opkg_message(conf, OPKG_DEBUG2, "Function: %s calling pkg_arch_supported %s \n", __FUNCTION__, __FUNCTION__);
-
-     if (!pkg_arch_supported(conf, pkg)) {
-         opkg_message(conf, OPKG_ERROR, "INTERNAL ERROR: architecture %s for pkg %s is unsupported.\n",
-                      pkg->architecture, pkg->name);
-         return OPKG_INSTALL_ERR_INTERNAL;
-     }
-     if (pkg->state_status == SS_INSTALLED && conf->force_reinstall == 0 && conf->nodeps == 0) {
-         err = satisfy_dependencies_for(conf, pkg);
-         if (err) { return OPKG_INSTALL_ERR_DEPENDENCIES; }
-
-         opkg_message(conf, OPKG_NOTICE,
-                      "Package %s is already installed in %s.\n", 
-                      pkg->name, pkg->dest->name);
-         return 0;
-     }
-
-     if (pkg->dest == NULL) {
-         pkg->dest = conf->default_dest;
-     }
-
-     old_pkg = pkg_hash_fetch_installed_by_name(&conf->pkg_hash, pkg->name);
-
-     err = opkg_install_check_downgrade(conf, pkg, old_pkg, message);
-     if (err) { return OPKG_INSTALL_ERR_NO_DOWNGRADE; }
-
-     pkg->state_want = SW_INSTALL;
-     if (old_pkg){                          
-         old_pkg->state_want = SW_DEINSTALL; /* needed for check_data_file_clashes of dependences */
-     }
-
-
-     /* Abhaya: conflicts check */
-     err = check_conflicts_for(conf, pkg);
-     if (err) { return OPKG_INSTALL_ERR_CONFLICTS; }
-    
-     /* this setup is to remove the upgrade scenario in the end when
-       installing pkg A, A deps B & B deps on A. So both B and A are
-       installed. Then A's installation is started resulting in an
-       uncecessary upgrade */ 
-     if (pkg->state_status == SS_INSTALLED
-        && conf->force_reinstall == 0) return 0;
-    
-     err = verify_pkg_installable(conf, pkg);
-     if (err) { return OPKG_INSTALL_ERR_NO_SPACE; }
-
-     if (pkg->local_filename == NULL) {
-         err = opkg_download_pkg(conf, pkg, conf->tmp_dir);
-         if (err) {
-              opkg_message(conf, OPKG_ERROR,
-                           "Failed to download %s. Perhaps you need to run 'opkg update'?\n",
-                           pkg->name);
-              return OPKG_INSTALL_ERR_DOWNLOAD;
-         }
-     }
-
-     /* check that the repository is valid */
-     #if HAVE_GPGME
-     char *list_file_name, *sig_file_name, *lists_dir;
-
-     /* check to ensure the package has come from a repository */
-     if (pkg->src)
-     {
-       sprintf_alloc (&lists_dir, "%s",
-                     (conf->restrict_to_default_dest)
-                      ? conf->default_dest->lists_dir
-                      : conf->lists_dir);
-       sprintf_alloc (&list_file_name, "%s/%s", lists_dir, pkg->src->name);
-       sprintf_alloc (&sig_file_name, "%s/%s.sig", lists_dir, pkg->src->name);
-
-       if (file_exists (sig_file_name))
-       {
-         if (opkg_verify_file (conf, list_file_name, sig_file_name))
-           return OPKG_INSTALL_ERR_SIGNATURE;
-       }
-
-       free (lists_dir);
-       free (list_file_name);
-       free (sig_file_name);
-     }
-     #endif
-
-     /* Check for md5 values */
-     if (pkg->md5sum)
-     {
-         file_md5 = file_md5sum_alloc(pkg->local_filename);
-         if (strcmp(file_md5, pkg->md5sum))
-         {
-              opkg_message(conf, OPKG_ERROR,
-                           "Package %s md5sum mismatch. Either the opkg or the package index are corrupt. Try 'opkg update'.\n",
-                           pkg->name);
-              free(file_md5);
-              return OPKG_INSTALL_ERR_MD5;
-         }
-         free(file_md5);
-     }
-
-     if (pkg->tmp_unpack_dir == NULL) {
-         unpack_pkg_control_files(conf, pkg);
-     }
-
-     /* We should update the filelist here, so that upgrades of packages that split will not fail. -Jamey 27-MAR-03 */
-/* Pigi: check if it will pass from here when replacing. It seems to fail */
-/* That's rather strange that files don't change owner. Investigate !!!!!!*/
-     err = update_file_ownership(conf, pkg, old_pkg);
-     if (err) { return OPKG_ERR_UNKNOWN; }
-
-     if (conf->nodeps == 0) {
-         err = satisfy_dependencies_for(conf, pkg);
-         if (err) { return OPKG_INSTALL_ERR_DEPENDENCIES; }
-     }
-
-     replacees = pkg_vec_alloc();
-     pkg_get_installed_replacees(conf, pkg, replacees);
-
-     sprintf_alloc (&pkgid, "%s;%s;%s;", pkg->name, pkg->version, pkg->architecture);
-     opkg_set_current_state (conf, OPKG_STATE_INSTALLING_PKG, pkgid);
-     free (pkgid);
-
-     /* this next section we do with SIGINT blocked to prevent inconsistency between opkg database and filesystem */
-     {
-         sigset_t newset, oldset;
-         sighandler_t old_handler = NULL;
-         int use_signal = 0;
-         caught_sigint = 0;
-         if (use_signal) {
-              old_handler = signal(SIGINT, opkg_install_pkg_sigint_handler);
-         } else {
-              sigemptyset(&newset);
-              sigaddset(&newset, SIGINT);
-              sigprocmask(SIG_BLOCK, &newset, &oldset);
-         }
-
-         opkg_state_changed++;
-         pkg->state_flag |= SF_FILELIST_CHANGED;
-
-         /* XXX: BUG: we really should treat replacement more like an upgrade
-          *      Instead, we're going to remove the replacees 
-          */
-         err = pkg_remove_installed_replacees(conf, replacees);
-         if (err) goto UNWIND_REMOVE_INSTALLED_REPLACEES;
-
-         err = prerm_upgrade_old_pkg(conf, pkg, old_pkg);
-         if (err) goto UNWIND_PRERM_UPGRADE_OLD_PKG;
-
-         err = prerm_deconfigure_conflictors(conf, pkg, replacees);
-         if (err) goto UNWIND_PRERM_DECONFIGURE_CONFLICTORS;
-
-         err = preinst_configure(conf, pkg, old_pkg);
-         if (err) goto UNWIND_PREINST_CONFIGURE;
-
-         err = backup_modified_conffiles(conf, pkg, old_pkg);
-         if (err) goto UNWIND_BACKUP_MODIFIED_CONFFILES;
-
-         err = check_data_file_clashes(conf, pkg, old_pkg);
-         if (err) goto UNWIND_CHECK_DATA_FILE_CLASHES;
-
-         err = postrm_upgrade_old_pkg(conf, pkg, old_pkg);
-         if (err) goto UNWIND_POSTRM_UPGRADE_OLD_PKG;
-
-         if (conf->noaction) return 0;
-
-         /* point of no return: no unwinding after this */
-         if (old_pkg && !conf->force_reinstall) {
-              old_pkg->state_want = SW_DEINSTALL;
-
-              if (old_pkg->state_flag & SF_NOPRUNE) {
-                   opkg_message(conf, OPKG_INFO,
-                                "  not removing obsolesced files because package marked noprune\n");
-              } else {
-                   opkg_message(conf, OPKG_INFO,
-                                "  removing obsolesced files\n");
-                   remove_obsolesced_files(conf, pkg, old_pkg);
-              }
-               /* removing files from old package, to avoid ghost files */ 
-               remove_data_files_and_list(conf, old_pkg);
-/* Pigi : It should be better to remove also maintainer and postrem scripts here, just in case*/
-               remove_maintainer_scripts_except_postrm(conf, old_pkg);
-               remove_postrm(conf, old_pkg);
-/* Pigi */
-
-         }
-
-
-         opkg_message(conf, OPKG_INFO,
-                      "  installing maintainer scripts\n");
-         install_maintainer_scripts(conf, pkg, old_pkg);
-
-         /* the following just returns 0 */
-         remove_disappeared(conf, pkg);
-
-         opkg_message(conf, OPKG_INFO,
-                      "  installing data files\n");
-         install_data_files(conf, pkg);
-
-/* read comments from function for detail but I will execute this here as all other tests are ok.*/
-         err = check_data_file_clashes_change(conf, pkg, old_pkg);
-
-         opkg_message(conf, OPKG_INFO,
-                      "  resolving conf files\n");
-         resolve_conffiles(conf, pkg);
-
-         pkg->state_status = SS_UNPACKED;
-         old_state_flag = pkg->state_flag;
-         pkg->state_flag &= ~SF_PREFER;
-         opkg_message(conf, OPKG_DEBUG, "   pkg=%s old_state_flag=%x state_flag=%x\n", pkg->name, old_state_flag, pkg->state_flag);
-
-         if (old_pkg && !conf->force_reinstall) {
-              old_pkg->state_status = SS_NOT_INSTALLED;
-         }
-
-         time(&pkg->installed_time);
-
-         opkg_message(conf, OPKG_INFO,
-                      "  cleanup temp files\n");
-         cleanup_temporary_files(conf, pkg);
-
-         ab_pkg = pkg->parent;
-         if (ab_pkg)
-              ab_pkg->state_status = pkg->state_status;
-
-         opkg_message(conf, OPKG_INFO, "Done.\n");
-
-         if (use_signal)
-              signal(SIGINT, old_handler);
-         else
-              sigprocmask(SIG_UNBLOCK, &newset, &oldset);
-          pkg_vec_free (replacees);
-         return 0;
-     
-
-     UNWIND_POSTRM_UPGRADE_OLD_PKG:
-         postrm_upgrade_old_pkg_unwind(conf, pkg, old_pkg);
-     UNWIND_CHECK_DATA_FILE_CLASHES:
-         check_data_file_clashes_unwind(conf, pkg, old_pkg);
-     UNWIND_BACKUP_MODIFIED_CONFFILES:
-         backup_modified_conffiles_unwind(conf, pkg, old_pkg);
-     UNWIND_PREINST_CONFIGURE:
-         preinst_configure_unwind(conf, pkg, old_pkg);
-     UNWIND_PRERM_DECONFIGURE_CONFLICTORS:
-         prerm_deconfigure_conflictors_unwind(conf, pkg, replacees);
-     UNWIND_PRERM_UPGRADE_OLD_PKG:
-         prerm_upgrade_old_pkg_unwind(conf, pkg, old_pkg);
-     UNWIND_REMOVE_INSTALLED_REPLACEES:
-         pkg_remove_installed_replacees_unwind(conf, replacees);
-
-         opkg_message(conf, OPKG_INFO,
-                      "  cleanup temp files\n");
-         cleanup_temporary_files(conf, pkg);
-
-         opkg_message(conf, OPKG_INFO,
-                      "Failed.\n");
-         if (use_signal)
-              signal(SIGINT, old_handler);
-         else
-              sigprocmask(SIG_UNBLOCK, &newset, &oldset);
-
-          pkg_vec_free (replacees);
-         return OPKG_ERR_UNKNOWN;
-     }
-     opkg_set_current_state (conf, OPKG_STATE_NONE, NULL);
-}
-
-static int prerm_upgrade_old_pkg(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg)
+static int
+prerm_upgrade_old_pkg(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg)
 {
      /* DPKG_INCOMPATIBILITY:
        dpkg does some things here that we don't do yet. Do we care?
@@ -1048,7 +522,8 @@ static int prerm_upgrade_old_pkg(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg)
      return 0;
 }
 
-static int prerm_upgrade_old_pkg_unwind(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg)
+static int
+prerm_upgrade_old_pkg_unwind(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg)
 {
      /* DPKG_INCOMPATIBILITY:
        dpkg does some things here that we don't do yet. Do we care?
@@ -1057,7 +532,8 @@ static int prerm_upgrade_old_pkg_unwind(opkg_conf_t *conf, pkg_t *pkg, pkg_t *ol
      return 0;
 }
 
-static int prerm_deconfigure_conflictors(opkg_conf_t *conf, pkg_t *pkg, pkg_vec_t *conflictors)
+static int
+prerm_deconfigure_conflictors(opkg_conf_t *conf, pkg_t *pkg, pkg_vec_t *conflictors)
 {
      /* DPKG_INCOMPATIBILITY:
        dpkg does some things here that we don't do yet. Do we care?
@@ -1083,7 +559,8 @@ static int prerm_deconfigure_conflictors(opkg_conf_t *conf, pkg_t *pkg, pkg_vec_
      return 0;
 }
 
-static int prerm_deconfigure_conflictors_unwind(opkg_conf_t *conf, pkg_t *pkg, pkg_vec_t *conflictors)
+static int
+prerm_deconfigure_conflictors_unwind(opkg_conf_t *conf, pkg_t *pkg, pkg_vec_t *conflictors)
 {
      /* DPKG_INCOMPATIBILITY: dpkg does some things here that we don't
        do yet. Do we care?  (See prerm_deconfigure_conflictors for
@@ -1091,7 +568,8 @@ static int prerm_deconfigure_conflictors_unwind(opkg_conf_t *conf, pkg_t *pkg, p
      return 0;
 }
 
-static int preinst_configure(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg)
+static int
+preinst_configure(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg)
 {
      int err;
      char *preinst_args;
@@ -1105,7 +583,7 @@ static int preinst_configure(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg)
          sprintf_alloc(&preinst_args, "install %s", pkg_version);
          free(pkg_version);
      } else {
-         preinst_args = strdup("install");
+         preinst_args = xstrdup("install");
      }
 
      err = pkg_run_script(conf, pkg, "preinst", preinst_args);
@@ -1120,7 +598,8 @@ static int preinst_configure(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg)
      return 0;
 }
 
-static int preinst_configure_unwind(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg)
+static int
+preinst_configure_unwind(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg)
 {
      /* DPKG_INCOMPATIBILITY:
        dpkg does the following error unwind, should we?
@@ -1131,37 +610,95 @@ static int preinst_configure_unwind(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pk
      return 0;
 }
 
-static int backup_modified_conffiles(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg)
+static char *
+backup_filename_alloc(const char *file_name)
 {
-     int err;
-     conffile_list_elt_t *iter;
-     conffile_t *cf;
+     char *backup;
 
-     if (conf->noaction) return 0;
+     sprintf_alloc(&backup, "%s%s", file_name, OPKG_BACKUP_SUFFIX);
 
-     /* Backup all modified conffiles */
-     if (old_pkg) {
-         for (iter = old_pkg->conffiles.head; iter; iter = iter->next) {
-              char *cf_name;
-              
-              cf = iter->data;
-              cf_name = root_filename_alloc(conf, cf->name);
+     return backup;
+}
 
-              /* Don't worry if the conffile is just plain gone */
-              if (file_exists(cf_name) && conffile_has_been_modified(conf, cf)) {
-                   err = backup_make_backup(conf, cf_name);
-                   if (err) {
-                        return err;
-                   }
-              }
-              free(cf_name);
-         }
+
+static int
+backup_make_backup(opkg_conf_t *conf, const char *file_name)
+{
+     int err;
+     char *backup;
+    
+     backup = backup_filename_alloc(file_name);
+     err = file_copy(file_name, backup);
+     if (err) {
+         opkg_message(conf, OPKG_ERROR,
+                      "%s: Failed to copy %s to %s\n",
+                      __FUNCTION__, file_name, backup);
+     }
+
+     free(backup);
+
+     return err;
+}
+
+static int
+backup_exists_for(const char *file_name)
+{
+     int ret;
+     char *backup;
+
+     backup = backup_filename_alloc(file_name);
+
+     ret = file_exists(backup);
+
+     free(backup);
+
+     return ret;
+}
+
+static int
+backup_remove(const char *file_name)
+{
+     char *backup;
+
+     backup = backup_filename_alloc(file_name);
+     unlink(backup);
+     free(backup);
+
+     return 0;
+}
+
+static int
+backup_modified_conffiles(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg)
+{
+     int err;
+     conffile_list_elt_t *iter;
+     conffile_t *cf;
+
+     if (conf->noaction) return 0;
+
+     /* Backup all modified conffiles */
+     if (old_pkg) {
+         for (iter = nv_pair_list_first(&old_pkg->conffiles); iter; iter = nv_pair_list_next(&old_pkg->conffiles, iter)) {
+              char *cf_name;
+              
+              cf = iter->data;
+              cf_name = root_filename_alloc(conf, cf->name);
+
+              /* Don't worry if the conffile is just plain gone */
+              if (file_exists(cf_name) && conffile_has_been_modified(conf, cf)) {
+                   err = backup_make_backup(conf, cf_name);
+                   if (err) {
+                        return err;
+                   }
+              }
+              free(cf_name);
+         }
      }
 
      /* Backup all conffiles that were not conffiles in old_pkg */
-     for (iter = pkg->conffiles.head; iter; iter = iter->next) {
+     for (iter = nv_pair_list_first(&pkg->conffiles); iter; iter = nv_pair_list_next(&pkg->conffiles, iter)) {
          char *cf_name;
-         cf = iter->data;
+         cf = (conffile_t *)iter->data;
          cf_name = root_filename_alloc(conf, cf->name);
          /* Ignore if this was a conffile in old_pkg as well */
          if (pkg_get_conffile(old_pkg, cf->name)) {
@@ -1180,25 +717,27 @@ static int backup_modified_conffiles(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_p
      return 0;
 }
 
-static int backup_modified_conffiles_unwind(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg)
+static int
+backup_modified_conffiles_unwind(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg)
 {
      conffile_list_elt_t *iter;
 
      if (old_pkg) {
-         for (iter = old_pkg->conffiles.head; iter; iter = iter->next) {
-              backup_remove(iter->data->name);
+         for (iter = nv_pair_list_first(&old_pkg->conffiles); iter; iter = nv_pair_list_next(&old_pkg->conffiles, iter)) {
+              backup_remove(((nv_pair_t *)iter->data)->name);
          }
      }
 
-     for (iter = pkg->conffiles.head; iter; iter = iter->next) {
-         backup_remove(iter->data->name);
+     for (iter = nv_pair_list_first(&pkg->conffiles); iter; iter = nv_pair_list_next(&pkg->conffiles, iter)) {
+         backup_remove(((nv_pair_t *)iter->data)->name);
      }
 
      return 0;
 }
 
 
-static int check_data_file_clashes(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg)
+static int
+check_data_file_clashes(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg)
 {
      /* DPKG_INCOMPATIBILITY:
        opkg takes a slightly different approach than dpkg at this
@@ -1214,14 +753,16 @@ static int check_data_file_clashes(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg
        other package.
      */
      str_list_t *files_list;
-     str_list_elt_t *iter;
+     str_list_elt_t *iter, *niter;
 
      int clashes = 0;
 
-     files_list = pkg_get_installed_files(pkg);
-     for (iter = files_list->head; iter; iter = iter->next) {
+     files_list = pkg_get_installed_files(conf, pkg);
+     for (iter = str_list_first(files_list), niter = str_list_next(files_list, iter); 
+             iter; 
+             iter = niter, niter = str_list_next(files_list, iter)) {
          char *root_filename;
-         char *filename = iter->data;
+         char *filename = (char *) iter->data;
          root_filename = root_filename_alloc(conf, filename);
          if (file_exists(root_filename) && (! file_is_dir(root_filename))) {
               pkg_t *owner;
@@ -1290,7 +831,8 @@ static int check_data_file_clashes(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg
      return clashes;
 }
 
-static int check_data_file_clashes_change(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg)
+static int
+check_data_file_clashes_change(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg)
 {
     /* Basically that's the worst hack I could do to be able to change ownership of
        file list, but, being that we have no way to unwind the mods, due to structure
@@ -1301,25 +843,33 @@ static int check_data_file_clashes_change(opkg_conf_t *conf, pkg_t *pkg, pkg_t *
        @@@ To change after 1.0 release.
      */
      str_list_t *files_list;
-     str_list_elt_t *iter;
+     str_list_elt_t *iter, *niter;
+
+     char *root_filename = NULL;
 
      int clashes = 0;
 
-     files_list = pkg_get_installed_files(pkg);
-     for (iter = files_list->head; iter; iter = iter->next) {
-         char *root_filename;
-         char *filename = iter->data;
+     files_list = pkg_get_installed_files(conf, pkg);
+     for (iter = str_list_first(files_list), niter = str_list_next(files_list, iter); 
+             iter; 
+             iter = niter, niter = str_list_next(files_list, niter)) {
+         char *filename = (char *) iter->data;
+          if (root_filename) {
+              free(root_filename);
+              root_filename = NULL;
+          }
          root_filename = root_filename_alloc(conf, filename);
          if (file_exists(root_filename) && (! file_is_dir(root_filename))) {
               pkg_t *owner;
 
+              owner = file_hash_get_file_owner(conf, filename);
+
               if (conf->force_overwrite) {
                    /* but we need to change who owns this file */
                    file_hash_set_file_owner(conf, filename, pkg);
                    continue;
               }
 
-              owner = file_hash_get_file_owner(conf, filename);
 
               /* Pre-existing files are OK if owned by a package replaced by new pkg. */
               if (owner) {
@@ -1333,20 +883,25 @@ static int check_data_file_clashes_change(opkg_conf_t *conf, pkg_t *pkg, pkg_t *
               }
 
          }
-         free(root_filename);
+     }
+     if (root_filename) {
+         free(root_filename);
+         root_filename = NULL;
      }
      pkg_free_installed_files(pkg);
 
      return clashes;
 }
 
-static int check_data_file_clashes_unwind(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg)
+static int
+check_data_file_clashes_unwind(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg)
 {
      /* Nothing to do since check_data_file_clashes doesn't change state */
      return 0;
 }
 
-static int postrm_upgrade_old_pkg(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg)
+static int
+postrm_upgrade_old_pkg(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg)
 {
      /* DPKG_INCOMPATIBILITY: dpkg does the following here, should we?
        1. If the package is being upgraded, call
@@ -1358,7 +913,8 @@ static int postrm_upgrade_old_pkg(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg)
      return 0;
 }
 
-static int postrm_upgrade_old_pkg_unwind(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg)
+static int
+postrm_upgrade_old_pkg_unwind(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg)
 {
      /* DPKG_INCOMPATIBILITY:
        dpkg does some things here that we don't do yet. Do we care?
@@ -1367,31 +923,38 @@ static int postrm_upgrade_old_pkg_unwind(opkg_conf_t *conf, pkg_t *pkg, pkg_t *o
     return 0;
 }
 
-static int remove_obsolesced_files(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg)
+static int
+remove_obsolesced_files(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg)
 {
      int err;
      str_list_t *old_files;
      str_list_elt_t *of;
      str_list_t *new_files;
      str_list_elt_t *nf;
+     hash_table_t new_files_table;
 
      if (old_pkg == NULL) {
          return 0;
      }
 
-     old_files = pkg_get_installed_files(old_pkg);
-     new_files = pkg_get_installed_files(pkg);
+     old_files = pkg_get_installed_files(conf, old_pkg);
+     new_files = pkg_get_installed_files(conf, pkg);
+
+     new_files_table.entries = NULL;
+     hash_table_init("new_files" , &new_files_table, 20);
+     for (nf = str_list_first(new_files); nf; nf = str_list_next(new_files, nf)) {
+         if (nf && nf->data)
+            hash_table_insert(&new_files_table, nf->data, nf->data);
+     }
 
-     for (of = old_files->head; of; of = of->next) {
+     for (of = str_list_first(old_files); of; of = str_list_next(old_files, of)) {
          pkg_t *owner;
          char *old, *new;
-         old = of->data;
-         for (nf = new_files->head; nf; nf = nf->next) {
-              new = nf->data;
-              if (strcmp(old, new) == 0) {
-                   goto NOT_OBSOLETE;
-              }
-         }
+         old = (char *)of->data;
+          new = (char *) hash_table_get (&new_files_table, old);
+          if (new)
+               continue;
+
          if (file_is_dir(old)) {
               continue;
          }
@@ -1411,53 +974,21 @@ static int remove_obsolesced_files(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg
                                 strerror(errno));
               }
          }
-
-     NOT_OBSOLETE:
-         ;
      }
 
+     hash_table_deinit(&new_files_table);
      pkg_free_installed_files(old_pkg);
      pkg_free_installed_files(pkg);
 
      return 0;
 }
 
-static int remove_obsolete_maintainer_scripts(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg)
-{
-     int i;
-     int err = 0;
-     char *globpattern;
-     glob_t globbuf;
-     if (0) {
-         if (!pkg->dest) {
-              opkg_message(conf, OPKG_ERROR, "%s: no dest for package %s\n", __FUNCTION__, pkg->name);
-              return -1;
-         }
-         sprintf_alloc(&globpattern, "%s/%s.*", pkg->dest->info_dir, pkg->name);
-         err = glob(globpattern, 0, NULL, &globbuf);
-         free(globpattern);
-         if (err) {
-              return err;
-         }
-         /* XXXX this should perhaps only remove the ones that are not overwritten in new package.  Jamey 11/11/2003 */
-         for (i = 0; i < globbuf.gl_pathc; i++) {
-              opkg_message(conf, OPKG_DEBUG, "Removing control file %s from old_pkg %s\n",
-                           globbuf.gl_pathv[i], old_pkg->name);
-              if (!conf->noaction)
-                   unlink(globbuf.gl_pathv[i]);
-         }
-         globfree(&globbuf);
-     }
-     return err;
-}
-
-static int install_maintainer_scripts(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg)
+static int
+install_maintainer_scripts(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg)
 {
      int ret;
      char *prefix;
 
-     if (old_pkg)
-         remove_obsolete_maintainer_scripts(conf, pkg, old_pkg);
      sprintf_alloc(&prefix, "%s.", pkg->name);
      ret = pkg_extract_control_files_to_dir_with_prefix(pkg,
                                                        pkg->dest->info_dir,
@@ -1466,7 +997,8 @@ static int install_maintainer_scripts(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_
      return ret;
 }
 
-static int remove_disappeared(opkg_conf_t *conf, pkg_t *pkg)
+static int
+remove_disappeared(opkg_conf_t *conf, pkg_t *pkg)
 {
      /* DPKG_INCOMPATIBILITY:
        This is a fairly sophisticated dpkg operation. Shall we
@@ -1486,7 +1018,8 @@ static int remove_disappeared(opkg_conf_t *conf, pkg_t *pkg)
      return 0;
 }
 
-static int install_data_files(opkg_conf_t *conf, pkg_t *pkg)
+static int
+install_data_files(opkg_conf_t *conf, pkg_t *pkg)
 {
      int err;
 
@@ -1535,56 +1068,8 @@ static int install_data_files(opkg_conf_t *conf, pkg_t *pkg)
      return 0;
 }
 
-static int resolve_conffiles(opkg_conf_t *conf, pkg_t *pkg)
-{
-     conffile_list_elt_t *iter;
-     conffile_t *cf;
-     char *cf_backup;
-
-    char *md5sum;
-
-    
-     if (conf->noaction) return 0;
-
-     for (iter = pkg->conffiles.head; iter; iter = iter->next) {
-         char *root_filename;
-         cf = iter->data;
-         root_filename = root_filename_alloc(conf, cf->name);
-
-         /* Might need to initialize the md5sum for each conffile */
-         if (cf->value == NULL) {
-              cf->value = file_md5sum_alloc(root_filename);
-         }
-
-         if (!file_exists(root_filename)) {
-              free(root_filename);
-              continue;
-         }
-
-         cf_backup = backup_filename_alloc(root_filename);
-
-
-         if (file_exists(cf_backup)) {
- /* Let's compute md5 to test if files are changed */
-             md5sum = file_md5sum_alloc(cf_backup);
-               if (strcmp( cf->value,md5sum) != 0 ) {
-                 if (conf->force_defaults
-                     || user_prefers_old_conffile(cf->name, cf_backup) ) {
-                      rename(cf_backup, root_filename);
-                 }
-              }
-              unlink(cf_backup);
-              free(md5sum);
-         }
-
-         free(cf_backup);
-         free(root_filename);
-     }
-
-     return 0;
-}
-
-static int user_prefers_old_conffile(const char *file_name, const char *backup)
+static int
+user_prefers_old_conffile(const char *file_name, const char *backup)
 {
      char *response;
      const char *short_file_name;
@@ -1606,6 +1091,10 @@ static int user_prefers_old_conffile(const char *file_name, const char *backup)
                                       "          D     : show the differences between the versions (if diff is installed)\n"
                                       "     The default action is to keep your current version.\n"
                                       "    *** %s (Y/I/N/O/D) [default=N] ? ", file_name, short_file_name);
+
+         if (response == NULL)
+                 return 1;
+
          if (strcmp(response, "y") == 0
              || strcmp(response, "i") == 0
              || strcmp(response, "yes") == 0) {
@@ -1614,13 +1103,8 @@ static int user_prefers_old_conffile(const char *file_name, const char *backup)
          }
 
          if (strcmp(response, "d") == 0) {
-              char *cmd;
-
-              free(response);
-              /* XXX: BUG rewrite to use exec or busybox's internal diff */
-              sprintf_alloc(&cmd, "diff -u %s %s", backup, file_name);
-              xsystem(cmd);
-              free(cmd);
+              const char *argv[] = {"diff", "-u", backup, file_name, NULL};
+              xsystem(argv);
               printf("    [Press ENTER to continue]\n");
               response = file_read_line_alloc(stdin);
               free(response);
@@ -1632,106 +1116,435 @@ static int user_prefers_old_conffile(const char *file_name, const char *backup)
      }
 }
 
-/* XXX: CLEANUP: I'd like to move all of the code for
-   creating/cleaning pkg->tmp_unpack_dir directly into pkg.c. (Then,
-   it would make sense to cleanup pkg->tmp_unpack_dir directly from
-   pkg_deinit for example). */
-static int cleanup_temporary_files(opkg_conf_t *conf, pkg_t *pkg)
+static int
+resolve_conffiles(opkg_conf_t *conf, pkg_t *pkg)
 {
-     DIR *tmp_dir;
-     struct dirent *dirent;
-     char *tmp_file;
-
-#ifdef OPKG_DEBUG_NO_TMP_CLEANUP
-#error
-     opkg_message(conf, OPKG_DEBUG,
-                 "%s: Not cleaning up %s since opkg compiled with OPKG_DEBUG_NO_TMP_CLEANUP\n",
-                 __FUNCTION__, pkg->tmp_unpack_dir);
-     return 0;
-#endif
+     conffile_list_elt_t *iter;
+     conffile_t *cf;
+     char *cf_backup;
+     char *md5sum;
 
-     if (pkg->tmp_unpack_dir && file_is_dir(pkg->tmp_unpack_dir)) {
-         tmp_dir = opendir(pkg->tmp_unpack_dir);
-         if (tmp_dir) {
-              while (1) {
-                   dirent = readdir(tmp_dir);
-                   if (dirent == NULL) {
-                        break;
-                   }
-                   sprintf_alloc(&tmp_file, "%s/%s",
-                                 pkg->tmp_unpack_dir, dirent->d_name);
-                   if (! file_is_dir(tmp_file)) {
-                        unlink(tmp_file);
-                   }
-                   free(tmp_file);
-              }
-              closedir(tmp_dir);
-              rmdir(pkg->tmp_unpack_dir);
-              free(pkg->tmp_unpack_dir);
-              pkg->tmp_unpack_dir = NULL;
+     if (conf->noaction) return 0;
+
+     for (iter = nv_pair_list_first(&pkg->conffiles); iter; iter = nv_pair_list_next(&pkg->conffiles, iter)) {
+         char *root_filename;
+         cf = (conffile_t *)iter->data;
+         root_filename = root_filename_alloc(conf, cf->name);
+
+         /* Might need to initialize the md5sum for each conffile */
+         if (cf->value == NULL) {
+              cf->value = file_md5sum_alloc(root_filename);
          }
-     }
 
-     opkg_message(conf, OPKG_INFO, "cleanup_temporary_files: pkg=%s local_filename=%s tmp_dir=%s\n",
-                 pkg->name, pkg->local_filename, conf->tmp_dir);
-     if (pkg->local_filename && strncmp(pkg->local_filename, conf->tmp_dir, strlen(conf->tmp_dir)) == 0) {
-         unlink(pkg->local_filename);
-         free(pkg->local_filename);
-         pkg->local_filename = NULL;
+         if (!file_exists(root_filename)) {
+              free(root_filename);
+              continue;
+         }
+
+         cf_backup = backup_filename_alloc(root_filename);
+
+
+          if (file_exists(cf_backup)) {
+              /* Let's compute md5 to test if files are changed */
+              md5sum = file_md5sum_alloc(cf_backup);
+              if (md5sum && cf->value && strcmp(cf->value,md5sum) != 0 ) {
+                  if (conf->force_maintainer) {
+                      opkg_message(conf, OPKG_NOTICE, "Conffile %s using maintainer's setting.\n", cf_backup);
+                  } else if (conf->force_defaults
+                          || user_prefers_old_conffile(root_filename, cf_backup) ) {
+                      rename(cf_backup, root_filename);
+                  }
+              }
+              unlink(cf_backup);
+             if (md5sum)
+                  free(md5sum);
+          }
+
+         free(cf_backup);
+         free(root_filename);
      }
 
      return 0;
 }
 
-static char *backup_filename_alloc(const char *file_name)
+
+opkg_error_t
+opkg_install_by_name(opkg_conf_t *conf, const char *pkg_name)
 {
-     char *backup;
+     int cmp, err = 0;
+     pkg_t *old, *new;
+     char *old_version, *new_version;
 
-     sprintf_alloc(&backup, "%s%s", file_name, OPKG_BACKUP_SUFFIX);
+     opkg_message(conf, OPKG_DEBUG2, " Getting old  from pkg_hash_fetch \n" );
+     old = pkg_hash_fetch_installed_by_name(&conf->pkg_hash, pkg_name);
+     if ( old ) 
+        opkg_message(conf, OPKG_DEBUG2, " Old versions from pkg_hash_fetch %s \n",  old->version );
+    
+     opkg_message(conf, OPKG_DEBUG2, " Getting new  from pkg_hash_fetch \n" );
+     new = pkg_hash_fetch_best_installation_candidate_by_name(conf, pkg_name, &err);
+     if ( new ) 
+        opkg_message(conf, OPKG_DEBUG2, " New versions from pkg_hash_fetch %s \n",  new->version );
 
-     return backup;
+/* Pigi Basically here is broken the version stuff.
+   What's happening is that nothing provide the version to differents 
+   functions, so the returned struct is always the latest.
+   That's why the install by name don't work.
+*/
+     opkg_message(conf, OPKG_DEBUG2, " Versions from pkg_hash_fetch in %s ", __FUNCTION__ );
+
+     if ( old ) 
+        opkg_message(conf, OPKG_DEBUG2, " old %s ", old->version );
+     if ( new ) 
+        opkg_message(conf, OPKG_DEBUG2, " new %s ", new->version );
+     opkg_message(conf, OPKG_DEBUG2, " \n");
+
+     if (new == NULL) {
+         if (err)
+           return err;
+         else
+           return OPKG_PKG_HAS_NO_CANDIDATE;
+     }
+
+     new->state_flag |= SF_USER;
+     if (old) {
+         old_version = pkg_version_str_alloc(old);
+         new_version = pkg_version_str_alloc(new);
+
+         cmp = pkg_compare_versions(old, new);
+          if ( (conf->force_downgrade==1) && (cmp > 0) ){     /* We've been asked to allow downgrade  and version is precedent */
+            opkg_message(conf, OPKG_DEBUG, " Forcing downgrade \n");
+             cmp = -1 ;                                       /* then we force opkg to downgrade */ 
+                                                              /* We need to use a value < 0 because in the 0 case we are asking to */
+                                                              /* reinstall, and some check could fail asking the "force-reinstall" option */
+          } 
+         opkg_message(conf, OPKG_DEBUG, 
+                      "Comparing visible versions of pkg %s:"
+                      "\n\t%s is installed "
+                      "\n\t%s is available "
+                      "\n\t%d was comparison result\n",
+                      pkg_name, old_version, new_version, cmp);
+         if (cmp == 0 && !conf->force_reinstall) {
+              opkg_message(conf, OPKG_NOTICE,
+                           "Package %s (%s) installed in %s is up to date.\n",
+                           old->name, old_version, old->dest->name);
+              free(old_version);
+              free(new_version);
+              return 0;
+         } else if (cmp > 0) {
+              opkg_message(conf, OPKG_NOTICE,
+                           "Not downgrading package %s on %s from %s to %s.\n",
+                           old->name, old->dest->name, old_version, new_version);
+              free(old_version);
+              free(new_version);
+              return 0;
+         } else if (cmp < 0) {
+              new->dest = old->dest;
+              old->state_want = SW_DEINSTALL;    /* Here probably the problem for bug 1277 */
+         }
+         free(old_version);
+         free(new_version);
+     }
+
+     /* XXX: CLEANUP: The error code of opkg_install_by_name is really
+       supposed to be an opkg_error_t, but opkg_install_pkg could
+       return any kind of integer, (might be errno from a syscall,
+       etc.). This is a real mess and will need to be cleaned up if
+       anyone ever wants to make a nice libopkg. */
+
+     opkg_message(conf, OPKG_DEBUG2,"Function: %s calling opkg_install_pkg \n",__FUNCTION__);
+     return opkg_install_pkg(conf, new,0);
 }
 
-int backup_make_backup(opkg_conf_t *conf, const char *file_name)
+/**
+ *  @brief Really install a pkg_t 
+ */
+int
+opkg_install_pkg(opkg_conf_t *conf, pkg_t *pkg, int from_upgrade)
 {
-     int err;
-     char *backup;
-    
-     backup = backup_filename_alloc(file_name);
-     err = file_copy(file_name, backup);
-     if (err) {
+     int err = 0;
+     int message = 0;
+     pkg_t *old_pkg = NULL;
+     pkg_vec_t *replacees;
+     abstract_pkg_t *ab_pkg = NULL;
+     int old_state_flag;
+     char* file_md5;
+#ifdef HAVE_SHA256
+     char* file_sha256;
+#endif
+
+     if ( from_upgrade ) 
+        message = 1;            /* Coming from an upgrade, and should change the output message */
+
+     if (!pkg) {
          opkg_message(conf, OPKG_ERROR,
-                      "%s: Failed to copy %s to %s\n",
-                      __FUNCTION__, file_name, backup);
+                      "INTERNAL ERROR: null pkg passed to opkg_install_pkg\n");
+         return OPKG_INSTALL_ERR_INTERNAL;
      }
 
-     free(backup);
+     opkg_message(conf, OPKG_DEBUG2, "Function: %s calling pkg_arch_supported %s \n", __FUNCTION__, __FUNCTION__);
 
-     return err;
-}
+     if (!pkg_arch_supported(conf, pkg)) {
+         opkg_message(conf, OPKG_ERROR, "INTERNAL ERROR: architecture %s for pkg %s is unsupported.\n",
+                      pkg->architecture, pkg->name);
+         return OPKG_INSTALL_ERR_INTERNAL;
+     }
+     if (pkg->state_status == SS_INSTALLED && conf->force_reinstall == 0 && conf->nodeps == 0) {
+         err = satisfy_dependencies_for(conf, pkg);
+         if (err) { return OPKG_INSTALL_ERR_DEPENDENCIES; }
 
-static int backup_exists_for(const char *file_name)
-{
-     int ret;
-     char *backup;
+         opkg_message(conf, OPKG_NOTICE,
+                      "Package %s is already installed in %s.\n", 
+                      pkg->name, pkg->dest->name);
+         return 0;
+     }
 
-     backup = backup_filename_alloc(file_name);
+     if (pkg->dest == NULL) {
+         pkg->dest = conf->default_dest;
+     }
 
-     ret = file_exists(backup);
+     old_pkg = pkg_hash_fetch_installed_by_name(&conf->pkg_hash, pkg->name);
 
-     free(backup);
+     err = opkg_install_check_downgrade(conf, pkg, old_pkg, message);
+     if (err) { return OPKG_INSTALL_ERR_NO_DOWNGRADE; }
 
-     return ret;
-}
+     pkg->state_want = SW_INSTALL;
+     if (old_pkg){                          
+         old_pkg->state_want = SW_DEINSTALL; /* needed for check_data_file_clashes of dependences */
+     }
 
-static int backup_remove(const char *file_name)
-{
-     char *backup;
 
-     backup = backup_filename_alloc(file_name);
-     unlink(backup);
-     free(backup);
+     /* Abhaya: conflicts check */
+     err = check_conflicts_for(conf, pkg);
+     if (err) { return OPKG_INSTALL_ERR_CONFLICTS; }
+    
+     /* this setup is to remove the upgrade scenario in the end when
+       installing pkg A, A deps B & B deps on A. So both B and A are
+       installed. Then A's installation is started resulting in an
+       uncecessary upgrade */ 
+     if (pkg->state_status == SS_INSTALLED
+        && conf->force_reinstall == 0) return 0;
+    
+     err = verify_pkg_installable(conf, pkg);
+     if (err) { return OPKG_INSTALL_ERR_NO_SPACE; }
 
-     return 0;
-}
+     if (pkg->local_filename == NULL) {
+         err = opkg_download_pkg(conf, pkg, conf->tmp_dir);
+         if (err) {
+              opkg_message(conf, OPKG_ERROR,
+                           "Failed to download %s. Perhaps you need to run 'opkg update'?\n",
+                           pkg->name);
+              return OPKG_INSTALL_ERR_DOWNLOAD;
+         }
+     }
+
+     /* check that the repository is valid */
+     #if defined(HAVE_GPGME) || defined(HAVE_OPENSSL)
+     char *list_file_name, *sig_file_name, *lists_dir;
+
+     /* check to ensure the package has come from a repository */
+     if (conf->check_signature && pkg->src)
+     {
+       sprintf_alloc (&lists_dir, "%s",
+                     (conf->restrict_to_default_dest)
+                      ? conf->default_dest->lists_dir
+                      : conf->lists_dir);
+       sprintf_alloc (&list_file_name, "%s/%s", lists_dir, pkg->src->name);
+       sprintf_alloc (&sig_file_name, "%s/%s.sig", lists_dir, pkg->src->name);
+
+       if (file_exists (sig_file_name))
+       {
+         if (opkg_verify_file (conf, list_file_name, sig_file_name)){
+           opkg_message(conf, OPKG_ERROR, "Failed to verify the signature of: %s\n",
+                           list_file_name);
+           return OPKG_INSTALL_ERR_SIGNATURE;
+         }
+       }else{
+         opkg_message(conf, OPKG_ERROR, "Signature file is missing. "
+                         "Perhaps you need to run 'opkg update'?\n");
+         return OPKG_INSTALL_ERR_SIGNATURE;
+       }
 
+       free (lists_dir);
+       free (list_file_name);
+       free (sig_file_name);
+     }
+     #endif
+
+     /* Check for md5 values */
+     if (pkg->md5sum)
+     {
+         file_md5 = file_md5sum_alloc(pkg->local_filename);
+         if (file_md5 && strcmp(file_md5, pkg->md5sum))
+         {
+              opkg_message(conf, OPKG_ERROR,
+                           "Package %s md5sum mismatch. Either the opkg or the package index are corrupt. Try 'opkg update'.\n",
+                           pkg->name);
+              free(file_md5);
+              return OPKG_INSTALL_ERR_MD5;
+         }
+        if (file_md5)
+              free(file_md5);
+     }
+
+#ifdef HAVE_SHA256
+     /* Check for sha256 value */
+     if(pkg->sha256sum)
+     {
+         file_sha256 = file_sha256sum_alloc(pkg->local_filename);
+         if (file_sha256 && strcmp(file_sha256, pkg->sha256sum))
+         {
+              opkg_message(conf, OPKG_ERROR,
+                           "Package %s sha256sum mismatch. Either the opkg or the package index are corrupt. Try 'opkg update'.\n",
+                           pkg->name);
+              free(file_sha256);
+              return OPKG_INSTALL_ERR_SHA256;
+         }
+        if (file_sha256)
+              free(file_sha256);
+     }
+#endif
+
+     if (pkg->tmp_unpack_dir == NULL) {
+         unpack_pkg_control_files(conf, pkg);
+     }
+
+     /* We should update the filelist here, so that upgrades of packages that split will not fail. -Jamey 27-MAR-03 */
+/* Pigi: check if it will pass from here when replacing. It seems to fail */
+/* That's rather strange that files don't change owner. Investigate !!!!!!*/
+     err = update_file_ownership(conf, pkg, old_pkg);
+     if (err) { return OPKG_ERR_UNKNOWN; }
+
+     if (conf->nodeps == 0) {
+         err = satisfy_dependencies_for(conf, pkg);
+         if (err) { return OPKG_INSTALL_ERR_DEPENDENCIES; }
+          if (pkg->state_status == SS_UNPACKED)
+               /* Circular dependency has installed it for us. */
+               return 0;
+     }
+
+     replacees = pkg_vec_alloc();
+     pkg_get_installed_replacees(conf, pkg, replacees);
+
+     /* this next section we do with SIGINT blocked to prevent inconsistency between opkg database and filesystem */
+     {
+         sigset_t newset, oldset;
+
+         sigemptyset(&newset);
+         sigaddset(&newset, SIGINT);
+         sigprocmask(SIG_BLOCK, &newset, &oldset);
+
+         opkg_state_changed++;
+         pkg->state_flag |= SF_FILELIST_CHANGED;
+
+         if (old_pkg)
+               pkg_remove_orphan_dependent(conf, pkg, old_pkg);
+
+         /* XXX: BUG: we really should treat replacement more like an upgrade
+          *      Instead, we're going to remove the replacees 
+          */
+         err = pkg_remove_installed_replacees(conf, replacees);
+         if (err) goto UNWIND_REMOVE_INSTALLED_REPLACEES;
+
+         err = prerm_upgrade_old_pkg(conf, pkg, old_pkg);
+         if (err) goto UNWIND_PRERM_UPGRADE_OLD_PKG;
+
+         err = prerm_deconfigure_conflictors(conf, pkg, replacees);
+         if (err) goto UNWIND_PRERM_DECONFIGURE_CONFLICTORS;
+
+         err = preinst_configure(conf, pkg, old_pkg);
+         if (err) goto UNWIND_PREINST_CONFIGURE;
+
+         err = backup_modified_conffiles(conf, pkg, old_pkg);
+         if (err) goto UNWIND_BACKUP_MODIFIED_CONFFILES;
+
+         err = check_data_file_clashes(conf, pkg, old_pkg);
+         if (err) goto UNWIND_CHECK_DATA_FILE_CLASHES;
+
+         err = postrm_upgrade_old_pkg(conf, pkg, old_pkg);
+         if (err) goto UNWIND_POSTRM_UPGRADE_OLD_PKG;
+
+         if (conf->noaction) return 0;
+
+         /* point of no return: no unwinding after this */
+         if (old_pkg && !conf->force_reinstall) {
+              old_pkg->state_want = SW_DEINSTALL;
+
+              if (old_pkg->state_flag & SF_NOPRUNE) {
+                   opkg_message(conf, OPKG_INFO,
+                                "  not removing obsolesced files because package marked noprune\n");
+              } else {
+                   opkg_message(conf, OPKG_INFO,
+                                "  removing obsolesced files\n");
+                   remove_obsolesced_files(conf, pkg, old_pkg);
+              }
+
+               /* removing files from old package, to avoid ghost files */ 
+               remove_data_files_and_list(conf, old_pkg);
+               remove_maintainer_scripts(conf, old_pkg);
+         }
+
+
+         opkg_message(conf, OPKG_INFO,
+                      "  installing maintainer scripts\n");
+         install_maintainer_scripts(conf, pkg, old_pkg);
+
+         /* the following just returns 0 */
+         remove_disappeared(conf, pkg);
+
+         opkg_message(conf, OPKG_INFO,
+                      "  installing data files\n");
+         install_data_files(conf, pkg);
+
+/* read comments from function for detail but I will execute this here as all other tests are ok.*/
+         err = check_data_file_clashes_change(conf, pkg, old_pkg);
+
+         opkg_message(conf, OPKG_INFO,
+                      "  resolving conf files\n");
+         resolve_conffiles(conf, pkg);
+
+         pkg->state_status = SS_UNPACKED;
+         old_state_flag = pkg->state_flag;
+         pkg->state_flag &= ~SF_PREFER;
+         opkg_message(conf, OPKG_DEBUG, "   pkg=%s old_state_flag=%x state_flag=%x\n", pkg->name, old_state_flag, pkg->state_flag);
+
+         if (old_pkg && !conf->force_reinstall) {
+              old_pkg->state_status = SS_NOT_INSTALLED;
+         }
+
+         time(&pkg->installed_time);
+
+         ab_pkg = pkg->parent;
+         if (ab_pkg)
+              ab_pkg->state_status = pkg->state_status;
+
+         opkg_message(conf, OPKG_INFO, "Done.\n");
+
+         sigprocmask(SIG_UNBLOCK, &newset, &oldset);
+          pkg_vec_free (replacees);
+         return 0;
+     
+
+     UNWIND_POSTRM_UPGRADE_OLD_PKG:
+         postrm_upgrade_old_pkg_unwind(conf, pkg, old_pkg);
+     UNWIND_CHECK_DATA_FILE_CLASHES:
+         check_data_file_clashes_unwind(conf, pkg, old_pkg);
+     UNWIND_BACKUP_MODIFIED_CONFFILES:
+         backup_modified_conffiles_unwind(conf, pkg, old_pkg);
+     UNWIND_PREINST_CONFIGURE:
+         preinst_configure_unwind(conf, pkg, old_pkg);
+     UNWIND_PRERM_DECONFIGURE_CONFLICTORS:
+         prerm_deconfigure_conflictors_unwind(conf, pkg, replacees);
+     UNWIND_PRERM_UPGRADE_OLD_PKG:
+         prerm_upgrade_old_pkg_unwind(conf, pkg, old_pkg);
+     UNWIND_REMOVE_INSTALLED_REPLACEES:
+         pkg_remove_installed_replacees_unwind(conf, replacees);
+
+         opkg_message(conf, OPKG_INFO,
+                      "Failed.\n");
+
+         sigprocmask(SIG_UNBLOCK, &newset, &oldset);
+
+          pkg_vec_free (replacees);
+         return OPKG_ERR_UNKNOWN;
+     }
+}