Dead code removal.
[oweals/opkg-lede.git] / libopkg / opkg_install.c
index 599ae4d33fdeec0a492a56098d0efc72fa1d84ff..6b69da998908dd68cc15a29412a1820938089f3b 100644 (file)
@@ -1,4 +1,4 @@
-/* opkg_install.c - the itsy package management system
+/* opkg_install.c - the opkg package management system
 
    Carl D. Worth
 
    General Public License for more details.
 */
 
-#include "opkg.h"
+#include "includes.h"
 #include <errno.h>
 #include <dirent.h>
 #include <glob.h>
 #include <time.h>
 #include <signal.h>
+#ifndef __USE_GNU
 typedef void (*sighandler_t)(int);
+#endif
 
 #include "pkg.h"
 #include "pkg_hash.h"
@@ -34,15 +36,16 @@ 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"
 #include "file_util.h"
 #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);
 
@@ -83,9 +86,6 @@ int opkg_install_from_file(opkg_conf_t *conf, const char *filename)
      char *old_version, *new_version;
 
      pkg = pkg_new();
-     if (pkg == NULL) {
-         return ENOMEM;
-     }
 
      err = pkg_init_from_file(pkg, filename);
      if (err) {
@@ -103,8 +103,6 @@ int opkg_install_from_file(opkg_conf_t *conf, const char *filename)
      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);
@@ -136,7 +134,7 @@ int opkg_install_from_file(opkg_conf_t *conf, const char *filename)
 
 opkg_error_t opkg_install_by_name(opkg_conf_t *conf, const char *pkg_name)
 {
-     int cmp;
+     int cmp, err = 0;
      pkg_t *old, *new;
      char *old_version, *new_version;
 
@@ -146,7 +144,7 @@ opkg_error_t opkg_install_by_name(opkg_conf_t *conf, const char *pkg_name)
         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);
+     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 );
 
@@ -164,7 +162,10 @@ opkg_error_t opkg_install_by_name(opkg_conf_t *conf, const char *pkg_name)
      opkg_message(conf, OPKG_DEBUG2, " \n");
 
      if (new == NULL) {
-         return OPKG_PKG_HAS_NO_CANDIDATE;
+         if (err)
+           return err;
+         else
+           return OPKG_PKG_HAS_NO_CANDIDATE;
      }
 
      new->state_flag |= SF_USER;
@@ -307,60 +308,6 @@ int pkg_mark_dependencies_for_installation(opkg_conf_t *conf, pkg_t *pkg, pkg_ve
      return 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);
-}
-
-\f
-
 int satisfy_dependencies_for(opkg_conf_t *conf, pkg_t *pkg)
 {
      int i, err;
@@ -393,6 +340,7 @@ int satisfy_dependencies_for(opkg_conf_t *conf, pkg_t *pkg)
      }
 
      if (ndepends <= 0) {
+         pkg_vec_free(depends);
          return 0;
      }
 
@@ -446,7 +394,6 @@ int opkg_satisfy_all_dependences(opkg_conf_t *conf)
      return 0;
 }
 
-\f
 
 static int check_conflicts_for(opkg_conf_t *conf, pkg_t *pkg)
 {
@@ -481,10 +428,12 @@ static int check_conflicts_for(opkg_conf_t *conf, pkg_t *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_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);
@@ -493,15 +442,19 @@ static int update_file_ownership(opkg_conf_t *conf, pkg_t *new_pkg, pkg_t *old_p
      }
      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;
+         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 */
                    hash_table_insert(&conf->obs_file_hash, old_file, old_pkg);
               }
          }
+          pkg_free_installed_files(old_pkg);
      }
+     pkg_free_installed_files(new_pkg);
      return 0;
 }
 
@@ -514,13 +467,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 */ 
@@ -529,7 +484,7 @@ 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;
          }
      }
@@ -564,7 +519,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;
      }
 
@@ -618,6 +573,58 @@ static int unpack_pkg_control_files(opkg_conf_t *conf, pkg_t *pkg)
      return 0;
 }
 
+static int pkg_remove_orphan_dependent(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg) 
+{
+    int i, j, found;
+    char *buf, *d_str;
+    pkg_t *p;
+
+    if (!old_pkg) 
+        return 0;
+
+    if (old_pkg->depends_count == 0) 
+        return 0;
+
+    for (i=0;i<old_pkg->depends_count;i++) {
+        found = 0;
+        for (j=0;j<pkg->depends_count;j++) {
+            if (!strcmp(old_pkg->depends_str[i], pkg->depends_str[j])) {
+                found = 1;
+                break;
+            }
+        }
+        if (found)
+            continue;
+        d_str = old_pkg->depends_str[i];
+        buf = xcalloc(1, strlen (d_str) + 1);
+        j=0;
+        while (d_str[j] != '\0' && d_str[j] != ' ') {
+            buf[j]=d_str[j];
+            ++j;
+        }
+        buf[j]='\0';
+        buf = xrealloc (buf, strlen (buf) + 1);
+        p = pkg_hash_fetch_installed_by_name (&conf->pkg_hash, buf);
+        if (!p) {
+            fprintf(stderr, "The pkg %s had been removed!!\n", buf);
+            free(buf);
+            continue;
+        }
+        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_NOTICE,"%s was autoinstalled but is now orphaned, remove it.\n", buf);
+                opkg_remove_pkg(conf, p, 0);
+            } else 
+                opkg_message (conf, OPKG_INFO, "%s was autoinstalled and is still required by %d installed packages\n", buf, deps);
+        }
+        free(buf);
+    }
+    return 0;
+}
+
 /* returns number of installed replacees */
 int pkg_get_installed_replacees(opkg_conf_t *conf, pkg_t *pkg, pkg_vec_t *installed_replacees)
 {
@@ -673,12 +680,6 @@ 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)
 {        
@@ -742,7 +743,9 @@ static int opkg_install_check_downgrade(opkg_conf_t *conf, pkg_t *pkg, pkg_t *ol
      }
 }
 
-/* and now the meat... */
+/**
+ *  @brief Really install a pkg_t 
+ */
 int opkg_install_pkg(opkg_conf_t *conf, pkg_t *pkg, int from_upgrade)
 {
      int err = 0;
@@ -752,16 +755,17 @@ int opkg_install_pkg(opkg_conf_t *conf, pkg_t *pkg, int from_upgrade)
      abstract_pkg_t *ab_pkg = NULL;
      int old_state_flag;
      char* file_md5;
-     char *pkgid;
+#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,
                       "INTERNAL ERROR: null pkg passed to opkg_install_pkg\n");
-         return -EINVAL;
+         return OPKG_INSTALL_ERR_INTERNAL;
      }
 
      opkg_message(conf, OPKG_DEBUG2, "Function: %s calling pkg_arch_supported %s \n", __FUNCTION__, __FUNCTION__);
@@ -769,11 +773,11 @@ int opkg_install_pkg(opkg_conf_t *conf, pkg_t *pkg, int from_upgrade)
      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 -EINVAL;
+         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 err; }
+         if (err) { return OPKG_INSTALL_ERR_DEPENDENCIES; }
 
          opkg_message(conf, OPKG_NOTICE,
                       "Package %s is already installed in %s.\n", 
@@ -788,7 +792,7 @@ int opkg_install_pkg(opkg_conf_t *conf, pkg_t *pkg, int from_upgrade)
      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 err; }
+     if (err) { return OPKG_INSTALL_ERR_NO_DOWNGRADE; }
 
      pkg->state_want = SW_INSTALL;
      if (old_pkg){                          
@@ -798,7 +802,7 @@ int opkg_install_pkg(opkg_conf_t *conf, pkg_t *pkg, int from_upgrade)
 
      /* Abhaya: conflicts check */
      err = check_conflicts_for(conf, pkg);
-     if (err) { return err; }
+     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
@@ -808,7 +812,7 @@ int opkg_install_pkg(opkg_conf_t *conf, pkg_t *pkg, int from_upgrade)
         && conf->force_reinstall == 0) return 0;
     
      err = verify_pkg_installable(conf, pkg);
-     if (err) { return err; }
+     if (err) { return OPKG_INSTALL_ERR_NO_SPACE; }
 
      if (pkg->local_filename == NULL) {
          err = opkg_download_pkg(conf, pkg, conf->tmp_dir);
@@ -816,24 +820,76 @@ int opkg_install_pkg(opkg_conf_t *conf, pkg_t *pkg, int from_upgrade)
               opkg_message(conf, OPKG_ERROR,
                            "Failed to download %s. Perhaps you need to run 'opkg update'?\n",
                            pkg->name);
-              return err;
+              return OPKG_INSTALL_ERR_DOWNLOAD;
          }
      }
 
-/* Check for md5 values */
+     /* 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 (strcmp(file_md5, pkg->md5sum))
+         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 err;
+              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;
          }
-         free(file_md5);
+        if (file_sha256)
+              free(file_sha256);
      }
+#endif
 
      if (pkg->tmp_unpack_dir == NULL) {
          unpack_pkg_control_files(conf, pkg);
@@ -843,37 +899,32 @@ int opkg_install_pkg(opkg_conf_t *conf, pkg_t *pkg, int from_upgrade)
 /* 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 err; }
+     if (err) { return OPKG_ERR_UNKNOWN; }
 
      if (conf->nodeps == 0) {
          err = satisfy_dependencies_for(conf, pkg);
-         if (err) { return err; }
+         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);
 
-     sprintf_alloc (&pkgid, "%s;%s;%s;", pkg->name, pkg->version, pkg->architecture);
-     opkg_set_current_state (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);
-         }
+
+         sigemptyset(&newset);
+         sigaddset(&newset, SIGINT);
+         sigprocmask(SIG_BLOCK, &newset, &oldset);
 
          opkg_state_changed++;
          pkg->state_flag |= SF_FILELIST_CHANGED;
 
+          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 
           */
@@ -961,11 +1012,8 @@ int opkg_install_pkg(opkg_conf_t *conf, pkg_t *pkg, int from_upgrade)
 
          opkg_message(conf, OPKG_INFO, "Done.\n");
 
-         if (use_signal)
-              signal(SIGINT, old_handler);
-         else
-              sigprocmask(SIG_UNBLOCK, &newset, &oldset);
-
+         sigprocmask(SIG_UNBLOCK, &newset, &oldset);
+          pkg_vec_free (replacees);
          return 0;
      
 
@@ -990,14 +1038,12 @@ int opkg_install_pkg(opkg_conf_t *conf, pkg_t *pkg, int from_upgrade)
 
          opkg_message(conf, OPKG_INFO,
                       "Failed.\n");
-         if (use_signal)
-              signal(SIGINT, old_handler);
-         else
-              sigprocmask(SIG_UNBLOCK, &newset, &oldset);
 
-         return err;
+         sigprocmask(SIG_UNBLOCK, &newset, &oldset);
+
+          pkg_vec_free (replacees);
+         return OPKG_ERR_UNKNOWN;
      }
-     opkg_set_current_state (OPKG_STATE_NONE, NULL);
 }
 
 static int prerm_upgrade_old_pkg(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg)
@@ -1072,7 +1118,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);
@@ -1108,7 +1154,7 @@ static int backup_modified_conffiles(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_p
 
      /* Backup all modified conffiles */
      if (old_pkg) {
-         for (iter = old_pkg->conffiles.head; iter; iter = iter->next) {
+         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;
@@ -1126,9 +1172,9 @@ static int backup_modified_conffiles(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_p
      }
 
      /* 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)) {
@@ -1152,13 +1198,13 @@ static int backup_modified_conffiles_unwind(opkg_conf_t *conf, pkg_t *pkg, pkg_t
      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;
@@ -1181,14 +1227,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) {
+     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;
@@ -1268,25 +1316,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;
+     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) {
@@ -1300,7 +1356,10 @@ 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);
 
@@ -1341,6 +1400,7 @@ static int remove_obsolesced_files(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg
      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;
@@ -1349,16 +1409,21 @@ static int remove_obsolesced_files(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg
      old_files = pkg_get_installed_files(old_pkg);
      new_files = pkg_get_installed_files(pkg);
 
-     for (of = old_files->head; of; of = of->next) {
+     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 = 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;
          }
@@ -1378,53 +1443,20 @@ 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)
 {
      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,
@@ -1507,15 +1539,13 @@ static int resolve_conffiles(opkg_conf_t *conf, pkg_t *pkg)
      conffile_list_elt_t *iter;
      conffile_t *cf;
      char *cf_backup;
+     char *md5sum;
 
-    char *md5sum;
-
-    
      if (conf->noaction) return 0;
 
-     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 *root_filename;
-         cf = iter->data;
+         cf = (conffile_t *)iter->data;
          root_filename = root_filename_alloc(conf, cf->name);
 
          /* Might need to initialize the md5sum for each conffile */
@@ -1531,18 +1561,21 @@ static int resolve_conffiles(opkg_conf_t *conf, pkg_t *pkg)
          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);
-         }
+          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(cf->name, cf_backup) ) {
+                      rename(cf_backup, root_filename);
+                  }
+              }
+              unlink(cf_backup);
+             if (md5sum)
+                  free(md5sum);
+          }
 
          free(cf_backup);
          free(root_filename);
@@ -1702,251 +1735,3 @@ static int backup_remove(const char *file_name)
      return 0;
 }
 
-\f
-
-#ifdef CONFIG_OPKG_PROCESS_ACTIONS
-
-int opkg_remove_packages(opkg_conf_t *conf, pkg_vec_t *pkgs_to_remove) 
-{
-     /* first, remove the packages that need removing */
-     for (i = 0 ; i < pkgs_to_remove->len; i++ ) {
-         pkg_t *pkg = pkgs_to_remove->pkgs[i];
-         err = opkg_remove_pkg(conf, pkg,0);
-         if (err) return err;
-     }
-     return 0;
-}
-
-int opkg_process_actions_sanity_check(opkg_conf_t *conf, pkg_vec_t *pkgs_to_remove, pkg_vec_t *pkgs_superseded, pkg_vec_t *pkgs_to_install)
-{
-     int i;
-     /* now one more pass checking on the ones that need to be installed */
-     for (i = 0 ; i < pkgs_to_install->len; i++ ) {
-         pkg_t *pkg = pkgs_to_install->pkgs[i];
-         if (pkg->dest == NULL)
-              pkg->dest = conf->default_dest;
-
-         pkg->state_want = SW_INSTALL;
-
-         /* Abhaya: conflicts check */
-         err = check_conflicts_for(conf, pkg);
-         if (err) { return err; }
-     }
-     return 0;
-}
-
-int opkg_process_actions_unpack_packages(opkg_conf_t *conf, pkg_vec_t *pkgs_to_remove, pkg_vec_t *pkgs_to_install)
-{
-     int i;
-     /* now one more pass checking on the ones that need to be installed */
-     for (i = 0 ; i < pkgs_to_install->len; i++ ) {
-         pkg_t *pkg = pkgs_to_install->pkgs[i];
-
-         /* XXX: FEATURE: Need to really support Provides/Replaces: here at some point */
-         pkg_vec_t *replacees = pkg_vec_alloc();
-         pkg_get_installed_replacees(conf, pkg, replacees);
-
-         /* 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) return err;
-         pkg->state_flag |= SF_REMOVED_REPLACEES;
-     }
-     return 0;
-}
-
-int opkg_process_actions_unpack_packages(opkg_conf_t *conf, pkg_vec_t *pkgs_to_remove, pkg_vec_t *pkgs_to_install)
-{
-     int i;
-     /* now one more pass checking on the ones that need to be installed */
-     for (i = 0 ; i < pkgs_to_install->len; i++ ) {
-         pkg_t *pkg = pkgs_to_install->pkgs[i];
-         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 err;
-              }
-         }
-         if (pkg->tmp_unpack_dir == NULL) {
-              err = unpack_pkg_control_files(conf, pkg);
-              if (err) return err;
-         }
-     }
-     return 0;
-}
-
-int opkg_process_actions_prerm(opkg_conf_t *conf, pkg_vec_t *pkgs_to_install)
-{
-     int i;
-     /* now one more pass checking on the ones that need to be installed */
-     for (i = 0 ; i < pkgs_to_install->len; i++ ) {
-         pkg_t *pkg = pkgs_to_install->pkgs[i];
-         pkg_t *old_pkg = pkg->old_pkg;
-
-         err = prerm_upgrade_old_pkg(conf, pkg, old_pkg);
-         if (err) return err;
-
-         err = prerm_deconfigure_conflictors(conf, pkg, replacees);
-         if (err) return err;
-
-         err = preinst_configure(conf, pkg, old_pkg);
-         if (err) return err;
-
-         err = backup_modified_conffiles(conf, pkg, old_pkg);
-         if (err) return err;
-
-         err = postrm_upgrade_old_pkg(conf, pkg, old_pkg);
-         if (err) return err;
-     }
-     return 0;
-}
-
-int opkg_process_actions_install(opkg_conf_t *conf, pkg_vec_t *pkgs_to_install)
-{
-     int i;
-     /* now one more pass checking on the ones that need to be installed */
-     for (i = 0 ; i < pkgs_to_install->len; i++ ) {
-         pkg_t *pkg = pkgs_to_install->pkgs[i];
-         pkg_t *old_pkg = pkg->old_pkg;
-
-         if (old_pkg) {
-              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);
-              }
-         }
-
-         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);
-
-         opkg_message(conf, OPKG_INFO,
-                      "  resolving conf files\n");
-         resolve_conffiles(conf, pkg);
-
-         pkg->state_status = SS_UNPACKED;
-
-         if (old_pkg) {
-              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);
-
-         if (pkg->parent)
-              pkg->parent->state_status = pkg->state_status;
-     }
-     return 0;
-}
-
-int opkg_process_actions_unwind_prerm(opkg_conf_t *conf, pkg_vec_t *pkgs_to_install)
-{
-     int i;
-     /* now one more pass checking on the ones that need to be installed */
-     for (i = 0 ; i < pkgs_to_install->len; i++ ) {
-         pkg_t *pkg = pkgs_to_install->pkgs[i];
-         pkg_t *old_pkg = pkg->old_pkg;
-
-         if (old_pkg) {
-              if (old_pkg->state_flags & SF_POSTRM_UPGRADE)
-                   postrm_upgrade_old_pkg_unwind(conf, pkg, old_pkg);
-              if (old_pkg->state_flags & SF_CHECK_DATA_FILE_CLASHES)
-                   check_data_file_clashes_unwind(conf, pkg, old_pkg);
-              if (old_pkg->state_flags & SF_BACKUP_MODIFIED_CONFFILES)
-                   backup_modified_conffiles_unwind(conf, pkg, old_pkg);
-              if (old_pkg->state_flags & SF_PREINST_CONFIGURE)
-                   preinst_configure_unwind(conf, pkg, old_pkg);
-              if (old_pkg->state_flags & SF_DECONFIGURE_CONFLICTORS)
-                   prerm_deconfigure_conflictors_unwind(conf, pkg, replacees);
-              if (old_pkg->state_flags & SF_PRERM_UPGRADE)
-                   prerm_upgrade_old_pkg_unwind(conf, pkg, old_pkg);
-
-              if (old_pkg->state_flags & SF_REMOVED_REPLACEES)
-                   remove_installed_replacees_unwind(conf, pkg, old_pkg);
-
-         }
-     }
-     return 0;
-}
-
-/* 
- * Perform all the actions.
- *
- * pkgs_to_remove are packages marked for removal.
- * pkgs_superseded are the old packages being replaced by upgrades.
- *
- * Assumes pkgs_to_install includes all dependences, recursively, sorted in installable order.
- */
-int opkg_process_actions(opkg_conf_t *conf, pkg_vec_t *pkgs_to_remove, pkg_vec_t *pkgs_superseded, pkg_vec_t *pkgs_to_install)
-{
-     int err;
-     int i;
-
-     err = opkg_remove_packages(conf, pkgs_to_remove);
-     if (err) return err;
-
-     err = opkg_process_actions_sanity_check(conf, pkgs_superseded, pkgs_to_install);
-     if (err) return err;
-
-     err = opkg_process_actions_remove_replacees(conf, pkgs_to_install);
-     if (err) goto UNWIND;
-
-     /* @@@@ look at opkg_install_pkg for handling replacements */
-     err = opkg_process_actions_unpack_packages(conf, pkgs_to_install);
-     if (err) goto UNWIND;
-
-     /* 
-      * Now that we have the packages unpacked, we can look for data
-      * file clashes.  First, we mark the files from the superseded
-      * packages as obsolete.  Then we scan the files in
-      * pkgs_to_install, and only complain about clashes with
-      * non-obsolete files.
-      */
-
-     err = opkg_process_actions_check_data_file_clashes(conf, pkgs_superseded, pkgs_to_install);
-     if (err) goto UNWIND;
-
-     /* this was before checking data file clashes */
-     err = opkg_process_actions_prerm(conf, pkgs_superseded, pkgs_to_install);
-     if (err) goto UNWIND;
-
-     /* point of no return: no unwinding after this */
-     err = opkg_process_actions_install(conf, pkgs_to_install);
-     if (err) return err;
-
-     opkg_message(conf, OPKG_INFO, "Done.\n");
-     return 0;
-
- UNWIND:
-     opkg_process_actions_unwind(conf, pkgs_to_install);
-
-     opkg_message(conf, OPKG_INFO,
-                 "  cleanup temp files\n");
-     cleanup_temporary_files(conf, pkg);
-
-     opkg_message(conf, OPKG_INFO,
-                 "Failed.\n");
-     return err;
-}
-
-#endif