Fix leak when downgrading a package.
[oweals/opkg-lede.git] / libopkg / opkg_install.c
index 370410a6604b116b3a583df6975a677df11b2883..a76322d12358aa45ca8bf89374e0b37ec5c0459d 100644 (file)
@@ -36,7 +36,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"
@@ -44,8 +44,8 @@ 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);
 
@@ -86,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) {
@@ -106,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);
@@ -139,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, err;
+     int cmp, err = 0;
      pkg_t *old, *new;
      char *old_version, *new_version;
 
@@ -208,6 +203,8 @@ opkg_error_t opkg_install_by_name(opkg_conf_t *conf, const char *pkg_name)
          } 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);
          }
      }
 
@@ -312,60 +309,6 @@ int pkg_mark_dependencies_for_installation(opkg_conf_t *conf, pkg_t *pkg, pkg_ve
 
      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)
 {
@@ -453,7 +396,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)
 {
@@ -488,10 +430,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);
@@ -500,8 +444,10 @@ 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 */
@@ -527,9 +473,11 @@ static int verify_pkg_installable(opkg_conf_t *conf, pkg_t *pkg)
      * 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 */ 
@@ -538,7 +486,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;
          }
      }
@@ -573,7 +521,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;
      }
 
@@ -627,6 +575,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)
 {
@@ -682,12 +682,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)
 {        
@@ -751,7 +745,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;
@@ -761,8 +757,10 @@ 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 */
 
@@ -829,11 +827,11 @@ int opkg_install_pkg(opkg_conf_t *conf, pkg_t *pkg, int from_upgrade)
      }
 
      /* check that the repository is valid */
-     #if HAVE_GPGME
+     #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 (pkg->src)
+     if (conf->check_signature && pkg->src)
      {
        sprintf_alloc (&lists_dir, "%s",
                      (conf->restrict_to_default_dest)
@@ -844,8 +842,15 @@ int opkg_install_pkg(opkg_conf_t *conf, pkg_t *pkg, int from_upgrade)
 
        if (file_exists (sig_file_name))
        {
-         if (opkg_verify_file (conf, list_file_name, 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);
@@ -858,7 +863,7 @@ int opkg_install_pkg(opkg_conf_t *conf, pkg_t *pkg, int from_upgrade)
      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",
@@ -866,9 +871,28 @@ int opkg_install_pkg(opkg_conf_t *conf, pkg_t *pkg, int from_upgrade)
               free(file_md5);
               return OPKG_INSTALL_ERR_MD5;
          }
-         free(file_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);
      }
@@ -882,32 +906,27 @@ int opkg_install_pkg(opkg_conf_t *conf, pkg_t *pkg, int from_upgrade)
      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);
 
-     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);
-         }
+
+         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 
           */
@@ -995,10 +1014,7 @@ 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;
      
@@ -1024,15 +1040,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);
+
+         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)
@@ -1107,7 +1120,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);
@@ -1143,7 +1156,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;
@@ -1161,9 +1174,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)) {
@@ -1187,13 +1200,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;
@@ -1216,14 +1229,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;
@@ -1303,25 +1318,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) {
@@ -1335,7 +1358,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);
 
@@ -1376,6 +1402,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;
@@ -1384,16 +1411,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;
          }
@@ -1413,53 +1445,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,
@@ -1542,15 +1541,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 */
@@ -1566,18 +1563,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);