pkg: store size, installed size and installed time info in blob buffer
[oweals/opkg-lede.git] / libopkg / pkg.c
index d662664a362b119424aafe9fd6a4459b6e2ddda8..7b10c1ae101dec372f740a46f2217416b1634824 100644 (file)
    General Public License for more details.
 */
 
-#include "includes.h"
-#include <ctype.h>
+#include "config.h"
+
+#include <stdio.h>
 #include <string.h>
-#include <errno.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <libgen.h>
 
 #include "pkg.h"
 
 #include "opkg_message.h"
 #include "opkg_utils.h"
 
+#include "libbb/libbb.h"
 #include "sprintf_alloc.h"
 #include "file_util.h"
-#include "str_util.h"
 #include "xsystem.h"
 #include "opkg_conf.h"
 
 typedef struct enum_map enum_map_t;
-struct enum_map
-{
-     int value;
-     char *str;
+struct enum_map {
+       unsigned int value;
+       const char *str;
 };
 
 static const enum_map_t pkg_state_want_map[] = {
-     SW_UNKNOWN, "unknown"},
-     SW_INSTALL, "install"},
-     SW_DEINSTALL, "deinstall"},
-     SW_PURGE, "purge"}
+       {SW_UNKNOWN, "unknown"},
+       {SW_INSTALL, "install"},
+       {SW_DEINSTALL, "deinstall"},
+       {SW_PURGE, "purge"}
 };
 
 static const enum_map_t pkg_state_flag_map[] = {
-     SF_OK, "ok"},
-     SF_REINSTREQ, "reinstreq"},
-     SF_HOLD, "hold"},
-     SF_REPLACE, "replace"},
-     SF_NOPRUNE, "noprune"},
-     SF_PREFER, "prefer"},
-     SF_OBSOLETE, "obsolete"},
-     SF_USER, "user"},
+       {SF_OK, "ok"},
+       {SF_REINSTREQ, "reinstreq"},
+       {SF_HOLD, "hold"},
+       {SF_REPLACE, "replace"},
+       {SF_NOPRUNE, "noprune"},
+       {SF_PREFER, "prefer"},
+       {SF_OBSOLETE, "obsolete"},
+       {SF_USER, "user"},
 };
 
 static const enum_map_t pkg_state_status_map[] = {
-     { SS_NOT_INSTALLED, "not-installed" },
-     { SS_UNPACKED, "unpacked" },
-     { SS_HALF_CONFIGURED, "half-configured" },
-     { SS_INSTALLED, "installed" },
-     { SS_HALF_INSTALLED, "half-installed" },
-     { SS_CONFIG_FILES, "config-files" },
-     { SS_POST_INST_FAILED, "post-inst-failed" },
-     { SS_REMOVAL_FAILED, "removal-failed" }
+       {SS_NOT_INSTALLED, "not-installed"},
+       {SS_UNPACKED, "unpacked"},
+       {SS_HALF_CONFIGURED, "half-configured"},
+       {SS_INSTALLED, "installed"},
+       {SS_HALF_INSTALLED, "half-installed"},
+       {SS_CONFIG_FILES, "config-files"},
+       {SS_POST_INST_FAILED, "post-inst-failed"},
+       {SS_REMOVAL_FAILED, "removal-failed"}
 };
 
-static int verrevcmp(const char *val, const char *ref);
-
+static void pkg_init(pkg_t * pkg)
+{
+       pkg->name = NULL;
+       pkg->dest = NULL;
+       pkg->src = NULL;
+       pkg->state_want = SW_UNKNOWN;
+       pkg->state_flag = SF_OK;
+       pkg->state_status = SS_NOT_INSTALLED;
+       pkg->depends_str = NULL;
+       pkg->provides_str = NULL;
+       pkg->depends_count = 0;
+       pkg->depends = NULL;
+       pkg->suggests_str = NULL;
+       pkg->recommends_str = NULL;
+       pkg->suggests_count = 0;
+       pkg->recommends_count = 0;
+
+       active_list_init(&pkg->list);
+
+       pkg->conflicts = NULL;
+       pkg->conflicts_count = 0;
+
+       pkg->replaces = NULL;
+       pkg->replaces_count = 0;
+
+       pkg->pre_depends_count = 0;
+       pkg->pre_depends_str = NULL;
+       pkg->provides_count = 0;
+       pkg->provides = NULL;
+       pkg->tmp_unpack_dir = NULL;
+       conffile_list_init(&pkg->conffiles);
+       pkg->installed_files = NULL;
+       pkg->installed_files_ref_cnt = 0;
+       pkg->essential = 0;
+       pkg->provided_by_hand = 0;
+
+       blob_buf_init(&pkg->blob, 0);
+}
 
 pkg_t *pkg_new(void)
 {
-     pkg_t *pkg;
-
-     pkg = malloc(sizeof(pkg_t));
-     if (pkg == NULL) {
-         fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
-         return NULL;
-     }
+       pkg_t *pkg;
 
-     pkg_init(pkg);
+       pkg = xcalloc(1, sizeof(pkg_t));
+       pkg_init(pkg);
 
-     return pkg;
+       return pkg;
 }
 
-int pkg_init(pkg_t *pkg)
+void *pkg_set_raw(pkg_t *pkg, int id, const void *val, size_t len)
 {
-     memset(pkg, 0, sizeof(pkg_t));
-     pkg->name = NULL;
-     pkg->epoch = 0;
-     pkg->version = NULL;
-     pkg->revision = NULL;
-     pkg->dest = NULL;
-     pkg->src = NULL;
-     pkg->architecture = NULL;
-     pkg->maintainer = NULL;
-     pkg->section = NULL;
-     pkg->description = NULL;
-     pkg->state_want = SW_UNKNOWN;
-     pkg->state_flag = SF_OK;
-     pkg->state_status = SS_NOT_INSTALLED;
-     pkg->depends_str = NULL;
-     pkg->provides_str = NULL;
-     pkg->depends_count = 0;
-     pkg->depends = NULL;
-     pkg->suggests_str = NULL;
-     pkg->recommends_str = NULL;
-     pkg->suggests_count = 0;
-     pkg->recommends_count = 0;
-
-     /* Abhaya: added init for conflicts fields */
-     pkg->conflicts = NULL;
-     pkg->conflicts_count = 0;
-
-     /* added for replaces.  Jamey 7/23/2002 */
-     pkg->replaces = NULL;
-     pkg->replaces_count = 0;
-    
-     pkg->pre_depends_count = 0;
-     pkg->pre_depends_str = NULL;
-     pkg->provides_count = 0;
-     pkg->provides = NULL;
-     pkg->filename = NULL;
-     pkg->local_filename = NULL;
-     pkg->tmp_unpack_dir = NULL;
-     pkg->md5sum = NULL;
-     pkg->size = NULL;
-     pkg->installed_size = NULL;
-     pkg->priority = NULL;
-     pkg->source = NULL;
-     conffile_list_init(&pkg->conffiles);
-     pkg->installed_files = NULL;
-     pkg->installed_files_ref_cnt = 0;
-     pkg->essential = 0;
-     pkg->provided_by_hand = 0;
-
-     return 0;
+       int rem;
+       struct blob_attr *cur;
+
+       blob_for_each_attr(cur, pkg->blob.head, rem) {
+               if (blob_id(cur) == id) {
+                       if (blob_len(cur) < len) {
+                               fprintf(stderr, "ERROR: truncating field %d <%p> to %d byte",
+                                       id, val, blob_len(cur));
+                       }
+                       memcpy(blob_data(cur), val, blob_len(cur));
+                       return blob_data(cur);
+               }
+       }
+
+       cur = blob_put(&pkg->blob, id, val, len);
+       return cur ? blob_data(cur) : NULL;
 }
 
-void compound_depend_deinit (compound_depend_t *depends)
+void *pkg_get_raw(const pkg_t * pkg, int id)
 {
-    int i;
-    for (i = 0; i < depends->possibility_count; i++)
-    {
-        depend_t *d;
-        d = depends->possibilities[i];
-        free (d->version);
-        free (d);
-    }
-    free (depends->possibilities);
+       int rem;
+       struct blob_attr *cur;
+
+       blob_for_each_attr(cur, pkg->blob.head, rem)
+               if (blob_id(cur) == id)
+                       return blob_data(cur);
+
+       return NULL;
 }
 
-void pkg_deinit(pkg_t *pkg)
+char *pkg_set_string(pkg_t *pkg, int id, const char *s)
 {
-     int i;
-
-     free(pkg->name);
-     pkg->name = NULL;
-     pkg->epoch = 0;
-     free(pkg->version);
-     pkg->version = NULL;
-     /* revision shares storage with version, so
-       don't free */
-     pkg->revision = NULL;
-     /* owned by opkg_conf_t */
-     pkg->dest = NULL;
-     /* owned by opkg_conf_t */
-     pkg->src = NULL;
-     free(pkg->architecture);
-     pkg->architecture = NULL;
-     free(pkg->maintainer);
-     pkg->maintainer = NULL;
-     free(pkg->section);
-     pkg->section = NULL;
-     free(pkg->description);
-     pkg->description = NULL;
-     pkg->state_want = SW_UNKNOWN;
-     pkg->state_flag = SF_OK;
-     pkg->state_status = SS_NOT_INSTALLED;
-
-     //for (i = 0; i < pkg->replaces_count; i++)
-     free (pkg->replaces);
-     pkg->replaces = NULL;
-
-     for (i = 0; i < pkg->depends_count; i++)
-       free (pkg->depends_str[i]);
-     free(pkg->depends_str);
-     pkg->depends_str = NULL;
-
-     for (i = 0; i < pkg->provides_count; i++)
-       free (pkg->provides_str[i]);
-     free(pkg->provides_str);
-     pkg->provides_str = NULL;
-
-     for (i = 0; i < pkg->conflicts_count; i++)
-       free (pkg->conflicts_str[i]);
-     free(pkg->conflicts_str);
-     pkg->conflicts_str = NULL;
-
-     for (i = 0; i < pkg->replaces_count; i++)
-       free (pkg->replaces_str[i]);
-     free(pkg->replaces_str);
-     pkg->replaces_str = NULL;
-
-     for (i = 0; i < pkg->recommends_count; i++)
-       free (pkg->recommends_str[i]);
-     free(pkg->recommends_str);
-     pkg->recommends_str = NULL;
-
-     for (i = 0; i < pkg->suggests_count; i++)
-       free (pkg->suggests_str[i]);
-     free(pkg->suggests_str);
-     pkg->suggests_str = NULL;
-
-     if (pkg->depends)
-     {
-       int count = pkg->pre_depends_count + pkg->depends_count + pkg->recommends_count + pkg->suggests_count;
-       int x;
-
-       for (x = 0; x < count; x++)
-        compound_depend_deinit (&pkg->depends[x]);
-       free (pkg->depends);
-     }
-
-     if (pkg->conflicts)
-     {
-       int x;
-       for (x = 0; x < pkg->conflicts_count; x++)
-         compound_depend_deinit (&pkg->conflicts[x]);
-       free (pkg->conflicts);
-     }
-
-     free (pkg->provides);
-
-     pkg->pre_depends_count = 0;
-     free(pkg->pre_depends_str);
-     pkg->pre_depends_str = NULL;
-     pkg->provides_count = 0;
-     free(pkg->filename);
-     pkg->filename = NULL;
-     free(pkg->local_filename);
-     pkg->local_filename = NULL;
-     /* CLEANUP: It'd be nice to pullin the cleanup function from
-       opkg_install.c here. See comment in
-       opkg_install.c:cleanup_temporary_files */
-     free(pkg->tmp_unpack_dir);
-     pkg->tmp_unpack_dir = NULL;
-     free(pkg->md5sum);
-     pkg->md5sum = NULL;
-     free(pkg->size);
-     pkg->size = NULL;
-     free(pkg->installed_size);
-     pkg->installed_size = NULL;
-     free(pkg->priority);
-     pkg->priority = NULL;
-     free(pkg->source);
-     pkg->source = NULL;
-     conffile_list_deinit(&pkg->conffiles);
-     /* XXX: QUESTION: Is forcing this to 1 correct? I suppose so,
-       since if they are calling deinit, they should know. Maybe do an
-       assertion here instead? */
-     pkg->installed_files_ref_cnt = 1;
-     pkg_free_installed_files(pkg);
-     pkg->essential = 0;
-     free (pkg->tags);
-     pkg->tags = NULL;
+       size_t len;
+       char *p;
+
+       if (!s)
+               return NULL;
+
+       len = strlen(s);
+
+       while (isspace(*s)) {
+               s++;
+               len--;
+       }
+
+       while (len > 0 && isspace(s[len - 1]))
+               len--;
+
+       if (!len)
+               return NULL;
+
+       p = pkg_set_raw(pkg, id, s, len + 1);
+       p[len] = 0;
+
+       return p;
 }
 
-int pkg_init_from_file(pkg_t *pkg, const char *filename)
-{
-     int err;
-     char **raw;
-     FILE *control_file;
 
-     err = pkg_init(pkg);
-     if (err) { return err; }
+static void compound_depend_deinit(compound_depend_t * depends)
+{
+       int i;
+       for (i = 0; i < depends->possibility_count; i++) {
+               depend_t *d;
+               d = depends->possibilities[i];
+               free(d->version);
+               free(d);
+       }
+       free(depends->possibilities);
+}
 
-     pkg->local_filename = strdup(filename);
-    
-     control_file = tmpfile();
-     err = pkg_extract_control_file_to_stream(pkg, control_file);
-     if (err) { return err; }
+void pkg_deinit(pkg_t * pkg)
+{
+       int i;
+
+       if (pkg->name)
+               free(pkg->name);
+       pkg->name = NULL;
+
+       /* owned by opkg_conf_t */
+       pkg->dest = NULL;
+       /* owned by opkg_conf_t */
+       pkg->src = NULL;
+
+       pkg->state_want = SW_UNKNOWN;
+       pkg->state_flag = SF_OK;
+       pkg->state_status = SS_NOT_INSTALLED;
+
+       active_list_clear(&pkg->list);
+
+       if (pkg->replaces)
+               free(pkg->replaces);
+       pkg->replaces = NULL;
+
+       if (pkg->depends) {
+               int count = pkg->pre_depends_count
+                   + pkg->depends_count
+                   + pkg->recommends_count + pkg->suggests_count;
+
+               for (i = 0; i < count; i++)
+                       compound_depend_deinit(&pkg->depends[i]);
+               free(pkg->depends);
+       }
+
+       if (pkg->conflicts) {
+               for (i = 0; i < pkg->conflicts_count; i++)
+                       compound_depend_deinit(&pkg->conflicts[i]);
+               free(pkg->conflicts);
+       }
+
+       if (pkg->provides)
+               free(pkg->provides);
+
+       pkg->pre_depends_count = 0;
+       pkg->provides_count = 0;
+
+       /* CLEANUP: It'd be nice to pullin the cleanup function from
+          opkg_install.c here. See comment in
+          opkg_install.c:cleanup_temporary_files */
+       if (pkg->tmp_unpack_dir)
+               free(pkg->tmp_unpack_dir);
+       pkg->tmp_unpack_dir = NULL;
+
+       conffile_list_deinit(&pkg->conffiles);
+
+       /* XXX: QUESTION: Is forcing this to 1 correct? I suppose so,
+          since if they are calling deinit, they should know. Maybe do an
+          assertion here instead? */
+       pkg->installed_files_ref_cnt = 1;
+       pkg_free_installed_files(pkg);
+       pkg->essential = 0;
+
+       blob_buf_free(&pkg->blob);
+}
 
-     rewind(control_file);
-     raw = read_raw_pkgs_from_stream(control_file);
-     pkg_parse_raw(pkg, &raw, NULL, NULL);
+int pkg_init_from_file(pkg_t * pkg, const char *filename)
+{
+       int fd, err = 0;
+       FILE *control_file;
+       char *control_path, *tmp;
+
+       pkg_init(pkg);
+
+       pkg_set_string(pkg, PKG_LOCAL_FILENAME, filename);
+
+       tmp = xstrdup(filename);
+       sprintf_alloc(&control_path, "%s/%s.control.XXXXXX",
+                     conf->tmp_dir, basename(tmp));
+       free(tmp);
+       fd = mkstemp(control_path);
+       if (fd == -1) {
+               opkg_perror(ERROR, "Failed to make temp file %s", control_path);
+               err = -1;
+               goto err0;
+       }
+
+       control_file = fdopen(fd, "r+");
+       if (control_file == NULL) {
+               opkg_perror(ERROR, "Failed to fdopen %s", control_path);
+               close(fd);
+               err = -1;
+               goto err1;
+       }
+
+       err = pkg_extract_control_file_to_stream(pkg, control_file);
+       if (err) {
+               opkg_msg(ERROR, "Failed to extract control file from %s.\n",
+                        filename);
+               goto err2;
+       }
+
+       rewind(control_file);
+
+       if ((err = pkg_parse_from_stream(pkg, control_file, 0))) {
+               if (err == 1) {
+                       opkg_msg(ERROR, "Malformed package file %s.\n",
+                                filename);
+               }
+               err = -1;
+       }
 
-     fclose(control_file);
+err2:
+       fclose(control_file);
+err1:
+       unlink(control_path);
+err0:
+       free(control_path);
 
-     return 0;
+       return err;
 }
 
 /* Merge any new information in newpkg into oldpkg */
-/* XXX: CLEANUP: This function shouldn't actually modify anything in
-   newpkg, but should leave it usable. This rework is so that
-   pkg_hash_insert doesn't clobber the pkg that you pass into it. */
-/* 
- * uh, i thought that i had originally written this so that it took 
- * two pkgs and returned a new one?  we can do that again... -sma
- */
-int pkg_merge(pkg_t *oldpkg, pkg_t *newpkg, int set_status)
+int pkg_merge(pkg_t * oldpkg, pkg_t * newpkg)
 {
-     if (oldpkg == newpkg) {
-         return 0;
-     }
-
-     if (!oldpkg->src)
-         oldpkg->src = newpkg->src;
-     if (!oldpkg->dest)
-         oldpkg->dest = newpkg->dest;
-     if (!oldpkg->architecture)
-         oldpkg->architecture = str_dup_safe(newpkg->architecture);
-     if (!oldpkg->arch_priority)
-         oldpkg->arch_priority = newpkg->arch_priority;
-     if (!oldpkg->section)
-         oldpkg->section = str_dup_safe(newpkg->section);
-     if(!oldpkg->maintainer)
-         oldpkg->maintainer = str_dup_safe(newpkg->maintainer);
-     if(!oldpkg->description)
-         oldpkg->description = str_dup_safe(newpkg->description);
-     if (set_status) {
-         /* merge the state_flags from the new package */
-         oldpkg->state_want = newpkg->state_want;
-         oldpkg->state_status = newpkg->state_status;
-         oldpkg->state_flag = newpkg->state_flag;
-     } else {
-         if (oldpkg->state_want == SW_UNKNOWN)
-              oldpkg->state_want = newpkg->state_want;
-         if (oldpkg->state_status == SS_NOT_INSTALLED)
-              oldpkg->state_status = newpkg->state_status;
-         oldpkg->state_flag |= newpkg->state_flag;
-     }
-
-     if (!oldpkg->depends_str && !oldpkg->pre_depends_str && !oldpkg->recommends_str && !oldpkg->suggests_str) {
-         oldpkg->depends_str = newpkg->depends_str;
-         newpkg->depends_str = NULL;
-         oldpkg->depends_count = newpkg->depends_count;
-         newpkg->depends_count = 0;
-
-         oldpkg->depends = newpkg->depends;
-         newpkg->depends = NULL;
-
-         oldpkg->pre_depends_str = newpkg->pre_depends_str;
-         newpkg->pre_depends_str = NULL;
-         oldpkg->pre_depends_count = newpkg->pre_depends_count;
-         newpkg->pre_depends_count = 0;
-
-         oldpkg->recommends_str = newpkg->recommends_str;
-         newpkg->recommends_str = NULL;
-         oldpkg->recommends_count = newpkg->recommends_count;
-         newpkg->recommends_count = 0;
-
-         oldpkg->suggests_str = newpkg->suggests_str;
-         newpkg->suggests_str = NULL;
-         oldpkg->suggests_count = newpkg->suggests_count;
-         newpkg->suggests_count = 0;
-     }
-
-     if (!oldpkg->provides_str) {
-         oldpkg->provides_str = newpkg->provides_str;
-         newpkg->provides_str = NULL;
-         oldpkg->provides_count = newpkg->provides_count;
-         newpkg->provides_count = 0;
-
-         oldpkg->provides = newpkg->provides;
-         newpkg->provides = NULL;
-     }
-
-     if (!oldpkg->conflicts_str) {
-         oldpkg->conflicts_str = newpkg->conflicts_str;
-         newpkg->conflicts_str = NULL;
-         oldpkg->conflicts_count = newpkg->conflicts_count;
-         newpkg->conflicts_count = 0;
-
-         oldpkg->conflicts = newpkg->conflicts;
-         newpkg->conflicts = NULL;
-     }
-
-     if (!oldpkg->replaces_str) {
-         oldpkg->replaces_str = newpkg->replaces_str;
-         newpkg->replaces_str = NULL;
-         oldpkg->replaces_count = newpkg->replaces_count;
-         newpkg->replaces_count = 0;
-
-         oldpkg->replaces = newpkg->replaces;
-         newpkg->replaces = NULL;
-     }
-
-     if (!oldpkg->filename)
-         oldpkg->filename = str_dup_safe(newpkg->filename);
-     if (0)
-     fprintf(stdout, "pkg=%s old local_filename=%s new local_filename=%s\n", 
-            oldpkg->name, oldpkg->local_filename, newpkg->local_filename);
-     if (!oldpkg->local_filename)
-         oldpkg->local_filename = str_dup_safe(newpkg->local_filename);
-     if (!oldpkg->tmp_unpack_dir)
-         oldpkg->tmp_unpack_dir = str_dup_safe(newpkg->tmp_unpack_dir);
-     if (!oldpkg->md5sum)
-         oldpkg->md5sum = str_dup_safe(newpkg->md5sum);
-     if (!oldpkg->size)
-         oldpkg->size = str_dup_safe(newpkg->size);
-     if (!oldpkg->installed_size)
-         oldpkg->installed_size = str_dup_safe(newpkg->installed_size);
-     if (!oldpkg->priority)
-         oldpkg->priority = str_dup_safe(newpkg->priority);
-     if (!oldpkg->source)
-         oldpkg->source = str_dup_safe(newpkg->source);
-     if (oldpkg->conffiles.head == NULL){
-         oldpkg->conffiles = newpkg->conffiles;
-         conffile_list_init(&newpkg->conffiles);
-     }
-     if (!oldpkg->installed_files){
-         oldpkg->installed_files = newpkg->installed_files;
-         oldpkg->installed_files_ref_cnt = newpkg->installed_files_ref_cnt;
-         newpkg->installed_files = NULL;
-     }
-     if (!oldpkg->essential)
-         oldpkg->essential = newpkg->essential;
-
-     return 0;
+       if (oldpkg == newpkg) {
+               return 0;
+       }
+
+       if (!oldpkg->auto_installed)
+               oldpkg->auto_installed = newpkg->auto_installed;
+
+       if (!oldpkg->src)
+               oldpkg->src = newpkg->src;
+       if (!oldpkg->dest)
+               oldpkg->dest = newpkg->dest;
+       if (!pkg_get_string(oldpkg, PKG_ARCHITECTURE))
+               pkg_set_string(oldpkg, PKG_ARCHITECTURE, pkg_get_string(newpkg, PKG_ARCHITECTURE));
+       if (!oldpkg->arch_priority)
+               oldpkg->arch_priority = newpkg->arch_priority;
+       if (!pkg_get_string(oldpkg, PKG_SECTION))
+               pkg_set_string(oldpkg, PKG_SECTION, pkg_get_string(newpkg, PKG_SECTION));
+       if (!pkg_get_string(oldpkg, PKG_MAINTAINER))
+               pkg_set_string(oldpkg, PKG_MAINTAINER, pkg_get_string(newpkg, PKG_MAINTAINER));
+       if (!pkg_get_string(oldpkg, PKG_DESCRIPTION))
+               pkg_set_string(oldpkg, PKG_DESCRIPTION, pkg_get_string(newpkg, PKG_DESCRIPTION));
+
+       if (!oldpkg->depends_count && !oldpkg->pre_depends_count
+           && !oldpkg->recommends_count && !oldpkg->suggests_count) {
+               oldpkg->depends_count = newpkg->depends_count;
+               newpkg->depends_count = 0;
+
+               oldpkg->depends = newpkg->depends;
+               newpkg->depends = NULL;
+
+               oldpkg->pre_depends_count = newpkg->pre_depends_count;
+               newpkg->pre_depends_count = 0;
+
+               oldpkg->recommends_count = newpkg->recommends_count;
+               newpkg->recommends_count = 0;
+
+               oldpkg->suggests_count = newpkg->suggests_count;
+               newpkg->suggests_count = 0;
+       }
+
+       if (oldpkg->provides_count <= 1) {
+               oldpkg->provides_count = newpkg->provides_count;
+               newpkg->provides_count = 0;
+
+               if (!oldpkg->provides) {
+                       oldpkg->provides = newpkg->provides;
+                       newpkg->provides = NULL;
+               }
+       }
+
+       if (!oldpkg->conflicts_count) {
+               oldpkg->conflicts_count = newpkg->conflicts_count;
+               newpkg->conflicts_count = 0;
+
+               oldpkg->conflicts = newpkg->conflicts;
+               newpkg->conflicts = NULL;
+       }
+
+       if (!oldpkg->replaces_count) {
+               oldpkg->replaces_count = newpkg->replaces_count;
+               newpkg->replaces_count = 0;
+
+               oldpkg->replaces = newpkg->replaces;
+               newpkg->replaces = NULL;
+       }
+
+       if (!pkg_get_string(oldpkg, PKG_FILENAME))
+               pkg_set_string(oldpkg, PKG_FILENAME, pkg_get_string(newpkg, PKG_FILENAME));
+       if (!pkg_get_string(oldpkg, PKG_LOCAL_FILENAME))
+               pkg_set_string(oldpkg, PKG_LOCAL_FILENAME, pkg_get_string(newpkg, PKG_LOCAL_FILENAME));
+       if (!oldpkg->tmp_unpack_dir)
+               oldpkg->tmp_unpack_dir = xstrdup(newpkg->tmp_unpack_dir);
+       if (!pkg_get_string(oldpkg, PKG_MD5SUM))
+               pkg_set_string(oldpkg, PKG_MD5SUM, pkg_get_string(newpkg, PKG_MD5SUM));
+       if (!pkg_get_string(oldpkg, PKG_SHA256SUM))
+               pkg_set_string(oldpkg, PKG_SHA256SUM, pkg_get_string(newpkg, PKG_SHA256SUM));
+       if (!pkg_get_int(oldpkg, PKG_SIZE))
+               pkg_set_int(oldpkg, PKG_SIZE, pkg_get_int(newpkg, PKG_SIZE));
+       if (!pkg_get_int(oldpkg, PKG_INSTALLED_SIZE))
+               pkg_set_int(oldpkg, PKG_INSTALLED_SIZE, pkg_get_int(newpkg, PKG_INSTALLED_SIZE));
+       if (!pkg_get_string(oldpkg, PKG_PRIORITY))
+               pkg_set_string(oldpkg, PKG_PRIORITY, pkg_get_string(newpkg, PKG_PRIORITY));
+       if (!pkg_get_string(oldpkg, PKG_SOURCE))
+               pkg_set_string(oldpkg, PKG_SOURCE, pkg_get_string(newpkg, PKG_SOURCE));
+
+       if (nv_pair_list_empty(&oldpkg->conffiles)) {
+               list_splice_init(&newpkg->conffiles.head,
+                                &oldpkg->conffiles.head);
+       }
+
+       if (!oldpkg->installed_files) {
+               oldpkg->installed_files = newpkg->installed_files;
+               oldpkg->installed_files_ref_cnt =
+                   newpkg->installed_files_ref_cnt;
+               newpkg->installed_files = NULL;
+       }
+
+       if (!oldpkg->essential)
+               oldpkg->essential = newpkg->essential;
+
+       return 0;
+}
+
+static void abstract_pkg_init(abstract_pkg_t * ab_pkg)
+{
+       ab_pkg->provided_by = abstract_pkg_vec_alloc();
+       ab_pkg->dependencies_checked = 0;
+       ab_pkg->state_status = SS_NOT_INSTALLED;
 }
 
 abstract_pkg_t *abstract_pkg_new(void)
 {
-     abstract_pkg_t * ab_pkg;
+       abstract_pkg_t *ab_pkg;
+
+       ab_pkg = xcalloc(1, sizeof(abstract_pkg_t));
+       abstract_pkg_init(ab_pkg);
+
+       return ab_pkg;
+}
+
+void set_flags_from_control(pkg_t * pkg)
+{
+       char *file_name;
+       FILE *fp;
+
+       sprintf_alloc(&file_name, "%s/%s.control", pkg->dest->info_dir,
+                     pkg->name);
+
+       fp = fopen(file_name, "r");
+       if (fp == NULL) {
+               opkg_perror(ERROR, "Failed to open %s", file_name);
+               free(file_name);
+               return;
+       }
 
-     ab_pkg = malloc(sizeof(abstract_pkg_t));
+       free(file_name);
 
-     if (ab_pkg == NULL) {
-         fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
-         return NULL;
-     }
+       if (pkg_parse_from_stream(pkg, fp, PFM_ALL ^ PFM_ESSENTIAL)) {
+               opkg_msg(DEBUG,
+                        "Unable to read control file for %s. May be empty.\n",
+                        pkg->name);
+       }
 
-     if ( abstract_pkg_init(ab_pkg) < 0 ) 
-        return NULL;
+       fclose(fp);
 
-     return ab_pkg;
+       return;
 }
 
-int abstract_pkg_init(abstract_pkg_t *ab_pkg)
+static const char *pkg_state_want_to_str(pkg_state_want_t sw)
 {
-     memset(ab_pkg, 0, sizeof(abstract_pkg_t));
+       int i;
 
-     ab_pkg->provided_by = abstract_pkg_vec_alloc();
-     if (ab_pkg->provided_by==NULL){
-        return -1;
-     }
-     ab_pkg->dependencies_checked = 0;
-     ab_pkg->state_status = SS_NOT_INSTALLED;
+       for (i = 0; i < ARRAY_SIZE(pkg_state_want_map); i++) {
+               if (pkg_state_want_map[i].value == sw) {
+                       return pkg_state_want_map[i].str;
+               }
+       }
 
-     return 0;
+       opkg_msg(ERROR, "Internal error: state_want=%d\n", sw);
+       return "<STATE_WANT_UNKNOWN>";
 }
 
-void set_flags_from_control(opkg_conf_t *conf, pkg_t *pkg){
-     char * temp_str;
-     char **raw =NULL;
-     char **raw_start=NULL; 
-
-     temp_str = (char *) malloc (strlen(pkg->dest->info_dir)+strlen(pkg->name)+12);
-     if (temp_str == NULL ){
-        opkg_message(conf, OPKG_INFO, "Out of memory in  %s\n", __FUNCTION__);
-        return;
-     }
-     sprintf( temp_str,"%s/%s.control",pkg->dest->info_dir,pkg->name);
-   
-     raw = raw_start = read_raw_pkgs_from_file(temp_str);
-     if (raw == NULL ){
-        opkg_message(conf, OPKG_ERROR, "Unable to open the control file in  %s\n", __FUNCTION__);
-        return;
-     }
-
-     while(*raw){
-        if (!pkg_valorize_other_field(pkg, &raw ) == 0) {
-            opkg_message(conf, OPKG_DEBUG, "unable to read control file for %s. May be empty\n", pkg->name);
-        }
-     }
-     raw = raw_start;
-     while (*raw) {
-        if (raw!=NULL)
-          free(*raw++);
-     }
-
-     free(raw_start); 
-     free(temp_str);
-
-     return ;
+pkg_state_want_t pkg_state_want_from_str(char *str)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(pkg_state_want_map); i++) {
+               if (strcmp(str, pkg_state_want_map[i].str) == 0) {
+                       return pkg_state_want_map[i].value;
+               }
+       }
 
+       opkg_msg(ERROR, "Internal error: state_want=%s\n", str);
+       return SW_UNKNOWN;
 }
 
-char * pkg_formatted_info(pkg_t *pkg )
+static char *pkg_state_flag_to_str(pkg_state_flag_t sf)
 {
-     char *line;
-     char * buff;
-
-     buff = malloc(8192);
-     if (buff == NULL) {
-         fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
-         return NULL;
-     }
-
-     buff[0] = '\0';
-
-     line = pkg_formatted_field(pkg, "Package");
-     strncat(buff ,line, strlen(line));
-     free(line);
-
-     line = pkg_formatted_field(pkg, "Version");
-     strncat(buff ,line, strlen(line));
-     free(line);
-
-     line = pkg_formatted_field(pkg, "Depends");
-     strncat(buff ,line, strlen(line));
-     free(line);
-     
-     line = pkg_formatted_field(pkg, "Recommends");
-     strncat(buff ,line, strlen(line));
-     free(line);
-
-     line = pkg_formatted_field(pkg, "Suggests");
-     strncat(buff ,line, strlen(line));
-     free(line);
-
-     line = pkg_formatted_field(pkg, "Provides");
-     strncat(buff ,line, strlen(line));
-     free(line);
-
-     line = pkg_formatted_field(pkg, "Replaces");
-     strncat(buff ,line, strlen(line));
-     free(line);
-
-     line = pkg_formatted_field(pkg, "Conflicts");
-     strncat(buff ,line, strlen(line));
-     free(line);
-
-     line = pkg_formatted_field(pkg, "Status");
-     strncat(buff ,line, strlen(line));
-     free(line);
-
-     line = pkg_formatted_field(pkg, "Section");
-     strncat(buff ,line, strlen(line));
-     free(line);
-
-     line = pkg_formatted_field(pkg, "Essential"); /* @@@@ should be removed in future release. *//* I do not agree with this Pigi*/
-     strncat(buff ,line, strlen(line));
-     free(line);
-
-     line = pkg_formatted_field(pkg, "Architecture");
-     strncat(buff ,line, strlen(line));
-     free(line);
-
-     line = pkg_formatted_field(pkg, "Maintainer");
-     strncat(buff ,line, strlen(line));
-     free(line);
-
-     line = pkg_formatted_field(pkg, "MD5sum");
-     strncat(buff ,line, strlen(line));
-     free(line);
-
-     line = pkg_formatted_field(pkg, "Size");
-     strncat(buff ,line, strlen(line));
-     free(line);
-
-     line = pkg_formatted_field(pkg, "Filename");
-     strncat(buff ,line, strlen(line));
-     free(line);
-
-     line = pkg_formatted_field(pkg, "Conffiles");
-     strncat(buff ,line, strlen(line));
-     free(line);
-
-     line = pkg_formatted_field(pkg, "Source");
-     strncat(buff ,line, strlen(line));
-     free(line);
-
-     line = pkg_formatted_field(pkg, "Description");
-     strncat(buff ,line, strlen(line));
-     free(line);
-
-     line = pkg_formatted_field(pkg, "Installed-Time");
-     strncat(buff ,line, strlen(line));
-     free(line);
-
-     line = pkg_formatted_field(pkg, "Tags");
-     strncat(buff ,line, strlen(line));
-     free(line);
-
-     return buff;
+       int i;
+       unsigned int len;
+       char *str;
+
+       /* clear the temporary flags before converting to string */
+       sf &= SF_NONVOLATILE_FLAGS;
+
+       if (sf == 0)
+               return xstrdup("ok");
+
+       len = 0;
+       for (i = 0; i < ARRAY_SIZE(pkg_state_flag_map); i++) {
+               if (sf & pkg_state_flag_map[i].value)
+                       len += strlen(pkg_state_flag_map[i].str) + 1;
+       }
+
+       str = xmalloc(len + 1);
+       str[0] = '\0';
+
+       for (i = 0; i < ARRAY_SIZE(pkg_state_flag_map); i++) {
+               if (sf & pkg_state_flag_map[i].value) {
+                       strncat(str, pkg_state_flag_map[i].str, len);
+                       strncat(str, ",", len);
+               }
+       }
+
+       len = strlen(str);
+       str[len - 1] = '\0';    /* squash last comma */
+
+       return str;
 }
 
-char * pkg_formatted_field(pkg_t *pkg, const char *field )
+pkg_state_flag_t pkg_state_flag_from_str(const char *str)
 {
-     static size_t LINE_LEN = 128;
-     char * temp = (char *)malloc(1);
-     int len = 0;
-     int flag_provide_false = 0;
+       int i;
+       int sf = SF_OK;
+       const char *sfname;
+       unsigned int sfname_len;
+
+       if (strcmp(str, "ok") == 0) {
+               return SF_OK;
+       }
+       for (i = 0; i < ARRAY_SIZE(pkg_state_flag_map); i++) {
+               sfname = pkg_state_flag_map[i].str;
+               sfname_len = strlen(sfname);
+               if (strncmp(str, sfname, sfname_len) == 0) {
+                       sf |= pkg_state_flag_map[i].value;
+                       str += sfname_len;
+                       if (str[0] == ',') {
+                               str++;
+                       } else {
+                               break;
+                       }
+               }
+       }
 
-/*
-  Pigi: After some discussion with Florian we decided to modify the full procedure in 
-        dynamic memory allocation. This should avoid any other segv in this area ( except for bugs )
-*/
+       return sf;
+}
 
-     if (strlen(field) < PKG_MINIMUM_FIELD_NAME_LEN) {
-         goto UNKNOWN_FMT_FIELD;
-     }
-
-     temp[0]='\0'; 
-
-     switch (field[0])
-     {
-     case 'a':
-     case 'A':
-         if (strcasecmp(field, "Architecture") == 0) {
-              /* Architecture */
-              if (pkg->architecture) {
-                   temp = (char *)realloc(temp,strlen(pkg->architecture)+17);
-                   if ( temp == NULL ){
-                     fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
-                     return NULL;
-                   }
-                   temp[0]='\0';
-                   snprintf(temp, (strlen(pkg->architecture)+17), "Architecture: %s\n", pkg->architecture);
-              }
-         } else if (strcasecmp(field, "Auto-Installed") == 0) {
-               /* Auto-Installed flag */
-               if (pkg->auto_installed) {
-                   char * s = "Auto-Installed: yes\n";
-                   temp = (char *)realloc(temp, strlen(s) + 1);
-                   strcpy (temp, s);
+static const char *pkg_state_status_to_str(pkg_state_status_t ss)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(pkg_state_status_map); i++) {
+               if (pkg_state_status_map[i].value == ss) {
+                       return pkg_state_status_map[i].str;
+               }
+       }
+
+       opkg_msg(ERROR, "Internal error: state_status=%d\n", ss);
+       return "<STATE_STATUS_UNKNOWN>";
+}
+
+pkg_state_status_t pkg_state_status_from_str(const char *str)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(pkg_state_status_map); i++) {
+               if (strcmp(str, pkg_state_status_map[i].str) == 0) {
+                       return pkg_state_status_map[i].value;
                }
-         } else {
-              goto UNKNOWN_FMT_FIELD;
-         }
-         break;
-     case 'c':
-     case 'C':
-         if (strcasecmp(field, "Conffiles") == 0) {
-              /* Conffiles */
-              conffile_list_elt_t *iter;
-               char confstr[LINE_LEN];
-
-              if (pkg->conffiles.head == NULL) {
-                   return temp;
-              }
-
-               len = 14 ;
-              for (iter = pkg->conffiles.head; iter; iter = iter->next) {
-                   if (iter->data->name && iter->data->value) {
-                       len = len + (strlen(iter->data->name)+strlen(iter->data->value)+5);
-                   }
-              }
-               temp = (char *)realloc(temp,len);
-               if ( temp == NULL ){
-                 fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
-                 return NULL;
-               }
-               temp[0]='\0';
-               strncpy(temp, "Conffiles:\n", 12);
-              for (iter = pkg->conffiles.head; iter; iter = iter->next) {
-                   if (iter->data->name && iter->data->value) {
-                         snprintf(confstr, LINE_LEN, "%s %s\n", iter->data->name, iter->data->value);
-                         strncat(temp, confstr, strlen(confstr));           
-                   }
-              }
-         } else if (strcasecmp(field, "Conflicts") == 0) {
-              int i;
-
-              if (pkg->conflicts_count) {
-                    char conflictstr[LINE_LEN];
-                    len = 14 ;
-                   for(i = 0; i < pkg->conflicts_count; i++) {
-                        len = len + (strlen(pkg->conflicts_str[i])+5);
-                    }
-                    temp = (char *)realloc(temp,len);
-                    if ( temp == NULL ){
-                      fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
-                      return NULL;
-                    }
-                    temp[0]='\0';
-                    strncpy(temp, "Conflicts:", 11);
-                   for(i = 0; i < pkg->conflicts_count; i++) {
-                        snprintf(conflictstr, LINE_LEN, "%s %s", i == 0 ? "" : ",", pkg->conflicts_str[i]);
-                        strncat(temp, conflictstr, strlen(conflictstr));           
-                    }
-                    strncat(temp, "\n", strlen("\n")); 
-              }
-         } else {
-              goto UNKNOWN_FMT_FIELD;
-         }
-         break;
-     case 'd':
-     case 'D':
-         if (strcasecmp(field, "Depends") == 0) {
-              /* Depends */
-              int i;
-
-              if (pkg->depends_count) {
-                    char depstr[LINE_LEN];
-                    len = 14 ;
-                   for(i = 0; i < pkg->depends_count; i++) {
-                        len = len + (strlen(pkg->depends_str[i])+4);
-                    }
-                    temp = (char *)realloc(temp,len);
-                    if ( temp == NULL ){
-                      fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
-                      return NULL;
-                    }
-                    temp[0]='\0';
-                    strncpy(temp, "Depends:", 10);
-                   for(i = 0; i < pkg->depends_count; i++) {
-                        snprintf(depstr, LINE_LEN, "%s %s", i == 0 ? "" : ",", pkg->depends_str[i]);
-                        strncat(temp, depstr, strlen(depstr));           
-                    }
-                    strncat(temp, "\n", strlen("\n")); 
-              }
-         } else if (strcasecmp(field, "Description") == 0) {
-              /* Description */
-              if (pkg->description) {
-                   temp = (char *)realloc(temp,strlen(pkg->description)+16);
-                   if ( temp == NULL ){
-                     fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
-                     return NULL;
-                   }
-                   temp[0]='\0';
-                   snprintf(temp, (strlen(pkg->description)+16), "Description: %s\n", pkg->description);
-              }
-         } else {
-              goto UNKNOWN_FMT_FIELD;
-         }
-      break;
-     case 'e':
-     case 'E': {
-         /* Essential */
-         if (pkg->essential) {
-              temp = (char *)realloc(temp,16);
-              if ( temp == NULL ){
-                fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
-                return NULL;
-              }
-              temp[0]='\0';
-              snprintf(temp, (16), "Essential: yes\n");
-         }
-     }
-         break;
-     case 'f':
-     case 'F': {
-         /* Filename */
-         if (pkg->filename) {
-              temp = (char *)realloc(temp,strlen(pkg->filename)+12);
-              if ( temp == NULL ){
-                 fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
-                 return NULL;
-              }
-              temp[0]='\0';
-              snprintf(temp, (strlen(pkg->filename)+12), "Filename: %s\n", pkg->filename);
-         }
-     }
-         break;
-     case 'i':
-     case 'I': {
-         if (strcasecmp(field, "Installed-Size") == 0) {
-              /* Installed-Size */
-               temp = (char *)realloc(temp,strlen(pkg->installed_size)+17);
-               if ( temp == NULL ){
-                  fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
-                  return NULL;
-               }
-               temp[0]='\0';
-               snprintf(temp, (strlen(pkg->installed_size)+17), "Installed-Size: %s\n", pkg->installed_size);
-         } else if (strcasecmp(field, "Installed-Time") == 0 && pkg->installed_time) {
-               temp = (char *)realloc(temp,29);
-               if ( temp == NULL ){
-                 fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
-                 return NULL;
-               }
-               temp[0]='\0';
-               snprintf(temp, 29, "Installed-Time: %lu\n", pkg->installed_time);
-         }
-     }
-         break;
-     case 'm':
-     case 'M': {
-         /* Maintainer | MD5sum */
-         if (strcasecmp(field, "Maintainer") == 0) {
-              /* Maintainer */
-              if (pkg->maintainer) {
-                   temp = (char *)realloc(temp,strlen(pkg->maintainer)+14);
-                   if ( temp == NULL ){
-                     fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
-                     return NULL;
-                   }
-                   temp[0]='\0';
-                   snprintf(temp, (strlen(pkg->maintainer)+14), "maintainer: %s\n", pkg->maintainer);
-              }
-         } else if (strcasecmp(field, "MD5sum") == 0) {
-              /* MD5sum */
-              if (pkg->md5sum) {
-                   temp = (char *)realloc(temp,strlen(pkg->md5sum)+11);
-                   if ( temp == NULL ){
-                     fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
-                     return NULL;
-                   }
-                   temp[0]='\0';
-                   snprintf(temp, (strlen(pkg->md5sum)+11), "MD5Sum: %s\n", pkg->md5sum);
-              }
-         } else {
-              goto UNKNOWN_FMT_FIELD;
-         }
-     }
-         break;
-     case 'p':
-     case 'P': {
-         if (strcasecmp(field, "Package") == 0) {
-              /* Package */
-               temp = (char *)realloc(temp,strlen(pkg->name)+11);
-               if ( temp == NULL ){
-                 fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
-                 return NULL;
-               }
-               temp[0]='\0';
-               snprintf(temp, (strlen(pkg->name)+11), "Package: %s\n", pkg->name);
-         } else if (strcasecmp(field, "Priority") == 0) {
-              /* Priority */
-               temp = (char *)realloc(temp,strlen(pkg->priority)+12);
-               if ( temp == NULL ){
-                 fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
-                 return NULL;
-               }
-               temp[0]='\0';
-               snprintf(temp, (strlen(pkg->priority)+12), "Priority: %s\n", pkg->priority);
-         } else if (strcasecmp(field, "Provides") == 0) {
-              /* Provides */
-              int i;
-
-              if (pkg->provides_count) {
-               /* Here we check if the opkg_internal_use_only is used, and we discard it.*/
-                  for ( i=0; i < pkg->provides_count; i++ ){
-                     if (strstr(pkg->provides_str[i],"opkg_internal_use_only")!=NULL) {
-                         memset (pkg->provides_str[i],'\x0',strlen(pkg->provides_str[i])); /* Pigi clear my trick flag, just in case */
-                         flag_provide_false = 1;
-                      }
-                  }
-                  if ( !flag_provide_false ||                                             /* Pigi there is not my trick flag */
-                     ((flag_provide_false) &&  (pkg->provides_count > 1))){             /* Pigi There is, but we also have others Provides */
-                     char provstr[LINE_LEN];
-                     len = 15;
-                    for(i = 0; i < pkg->provides_count; i++) {
-                         len = len + (strlen(pkg->provides_str[i])+5);
-                     }
-                     temp = (char *)realloc(temp,len);
-                     if ( temp == NULL ){
-                       fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
-                       return NULL;
-                     }
-                     temp[0]='\0';
-                     strncpy(temp, "Provides:", 12);
-                    for(i = 0; i < pkg->provides_count; i++) {
-                         if (strlen(pkg->provides_str[i])>0){;
-                            snprintf(provstr, LINE_LEN, "%s %s", i == 1 ? "" : ",", pkg->provides_str[i]);
-                            strncat(temp, provstr, strlen(provstr));           
-                         }
-                     }
-                     strncat(temp, "\n", strlen("\n")); 
-                  }
-               }
-         } else {
-              goto UNKNOWN_FMT_FIELD;
-         }
-     }
-         break;
-     case 'r':
-     case 'R': {
-         int i;
-         /* Replaces | Recommends*/
-         if (strcasecmp (field, "Replaces") == 0) {
-              if (pkg->replaces_count) {
-                    char replstr[LINE_LEN];
-                    len = 14;
-                   for (i = 0; i < pkg->replaces_count; i++) {
-                        len = len + (strlen(pkg->replaces_str[i])+5);
-                    }
-                    temp = (char *)realloc(temp,len);
-                    if ( temp == NULL ){
-                      fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
-                      return NULL;
-                    }
-                    temp[0]='\0';
-                    strncpy(temp, "Replaces:", 12);
-                   for (i = 0; i < pkg->replaces_count; i++) {
-                        snprintf(replstr, LINE_LEN, "%s %s", i == 0 ? "" : ",", pkg->replaces_str[i]);
-                        strncat(temp, replstr, strlen(replstr));           
-                    }
-                    strncat(temp, "\n", strlen("\n")); 
-              }
-         } else if (strcasecmp (field, "Recommends") == 0) {
-              if (pkg->recommends_count) {
-                    char recstr[LINE_LEN];
-                    len = 15;
-                   for(i = 0; i < pkg->recommends_count; i++) {
-                         len = len + (strlen( pkg->recommends_str[i])+5);
-                    }
-                    temp = (char *)realloc(temp,len);
-                   if ( temp == NULL ){
-                     fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
-                     return NULL;
-                   }
-                    temp[0]='\0';
-                    strncpy(temp, "Recommends:", 13);
-                   for(i = 0; i < pkg->recommends_count; i++) {
-                        snprintf(recstr, LINE_LEN, "%s %s", i == 0 ? "" : ",", pkg->recommends_str[i]);
-                        strncat(temp, recstr, strlen(recstr));           
-                    }
-                    strncat(temp, "\n", strlen("\n")); 
-              }
-         } else {
-              goto UNKNOWN_FMT_FIELD;
-         }
-     }
-         break;
-     case 's':
-     case 'S': {
-         /* Section | Size | Source | Status | Suggests */
-         if (strcasecmp(field, "Section") == 0) {
-              /* Section */
-              if (pkg->section) {
-                   temp = (char *)realloc(temp,strlen(pkg->section)+11);
-                   if ( temp == NULL ){
-                     fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
-                     return NULL;
-                   }
-                   temp[0]='\0';
-                   snprintf(temp, (strlen(pkg->section)+11), "Section: %s\n", pkg->section);
-              }
-         } else if (strcasecmp(field, "Size") == 0) {
-              /* Size */
-              if (pkg->size) {
-                   temp = (char *)realloc(temp,strlen(pkg->size)+8);
-                   if ( temp == NULL ){
-                     fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
-                     return NULL;
-                   }
-                   temp[0]='\0';
-                   snprintf(temp, (strlen(pkg->size)+8), "Size: %s\n", pkg->size);
-              }
-         } else if (strcasecmp(field, "Source") == 0) {
-              /* Source */
-              if (pkg->source) {
-                   temp = (char *)realloc(temp,strlen(pkg->source)+10);
-                   if ( temp == NULL ){
-                     fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
-                     return NULL;
-                   }
-                   temp[0]='\0';
-                   snprintf(temp, (strlen(pkg->source)+10), "Source: %s\n", pkg->source);
-               }
-         } else if (strcasecmp(field, "Status") == 0) {
-              /* Status */
-               /* Benjamin Pineau note: we should avoid direct usage of 
-                * strlen(arg) without keeping "arg" for later free()
-                */
-               char *pflag=pkg_state_flag_to_str(pkg->state_flag);
-               char *pstat=pkg_state_status_to_str(pkg->state_status);
-               char *pwant=pkg_state_want_to_str(pkg->state_want);
-
-               size_t sum_of_sizes = (size_t) ( strlen(pwant)+ strlen(pflag)+ strlen(pstat) + 12 );
-               temp = (char *)realloc(temp,sum_of_sizes);
-               if ( temp == NULL ){
-                   fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
-                   return NULL;
-                }
-                temp[0]='\0';
-                snprintf(temp, sum_of_sizes , "Status: %s %s %s\n", pwant, pflag, pstat);
-                free(pflag);
-                free(pwant);
-               if(pstat) /* pfstat can be NULL if ENOMEM */
-                   free(pstat);
-         } else if (strcasecmp(field, "Suggests") == 0) {
-              if (pkg->suggests_count) {
-                   int i;
-                    char sugstr[LINE_LEN];
-                    len = 13;
-                   for(i = 0; i < pkg->suggests_count; i++) {
-                        len = len + (strlen(pkg->suggests_str[i])+5);
-                    }
-                    temp = (char *)realloc(temp,len);
-                    if ( temp == NULL ){
-                      fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
-                      return NULL;
-                    }
-                    temp[0]='\0';
-                    strncpy(temp, "Suggests:", 10);
-                   for(i = 0; i < pkg->suggests_count; i++) {
-                        snprintf(sugstr, LINE_LEN, "%s %s", i == 0 ? "" : ",", pkg->suggests_str[i]);
-                        strncat(temp, sugstr, strlen(sugstr));           
-                    }
-                    strncat(temp, "\n", strlen("\n")); 
-              }
-         } else {
-              goto UNKNOWN_FMT_FIELD;
-         }
-     }
-         break;
-     case 't':
-     case 'T':
-         if (strcasecmp(field, "Tags") == 0) {
-              /* Tags */
-              if (pkg->tags) {
-                   temp = (char *)realloc(temp,strlen(pkg->tags)+8);
-                   if ( temp == NULL ){
-                     fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
-                     return NULL;
-                   }
-                   temp[0]='\0';
-                   snprintf(temp, (strlen(pkg->tags)+8), "Tags: %s\n", pkg->tags);
-              }
-         }
-         break;
-     case 'v':
-     case 'V': {
-         /* Version */
-         char *version = pkg_version_str_alloc(pkg);
-          temp = (char *)realloc(temp,strlen(version)+14);
-          if ( temp == NULL ){
-             fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
-             return NULL;
-          }
-          temp[0]='\0';
-          snprintf(temp, (strlen(version)+12), "Version: %s\n", version);
-         free(version);
-     }
-         break;
-     default:
-         goto UNKNOWN_FMT_FIELD;
-     }
-
-     if ( strlen(temp)<2 ) {
-          temp[0]='\0';
-     }
-     return temp;
-
- UNKNOWN_FMT_FIELD:
-     fprintf(stderr, "%s: ERROR: Unknown field name: %s\n", __FUNCTION__, field);
-     if ( strlen(temp)<2 ) {
-          temp[0]='\0';
-     }
-
-     return temp;
+       }
+
+       opkg_msg(ERROR, "Internal error: state_status=%s\n", str);
+       return SS_NOT_INSTALLED;
 }
 
-void pkg_print_info(pkg_t *pkg, FILE *file)
+void pkg_formatted_field(FILE * fp, pkg_t * pkg, const char *field)
 {
-     char * buff;
-     if (pkg == NULL) {
+       int i, j;
+       char *str;
+       const char *p;
+       int depends_count = pkg->pre_depends_count +
+           pkg->depends_count + pkg->recommends_count + pkg->suggests_count;
+
+       if (strlen(field) < PKG_MINIMUM_FIELD_NAME_LEN) {
+               goto UNKNOWN_FMT_FIELD;
+       }
+
+       switch (field[0]) {
+       case 'a':
+       case 'A':
+               if (strcasecmp(field, "Architecture") == 0) {
+                       p = pkg_get_string(pkg, PKG_ARCHITECTURE);
+                       if (p) {
+                               fprintf(fp, "Architecture: %s\n",
+                                       p);
+                       }
+               } else if (strcasecmp(field, "Auto-Installed") == 0) {
+                       if (pkg->auto_installed)
+                               fprintf(fp, "Auto-Installed: yes\n");
+               } else {
+                       goto UNKNOWN_FMT_FIELD;
+               }
+               break;
+       case 'c':
+       case 'C':
+               if (strcasecmp(field, "Conffiles") == 0) {
+                       conffile_list_elt_t *iter;
+
+                       if (nv_pair_list_empty(&pkg->conffiles))
+                               return;
+
+                       fprintf(fp, "Conffiles:\n");
+                       for (iter = nv_pair_list_first(&pkg->conffiles); iter;
+                            iter = nv_pair_list_next(&pkg->conffiles, iter)) {
+                               if (((conffile_t *) iter->data)->name
+                                   && ((conffile_t *) iter->data)->value) {
+                                       fprintf(fp, " %s %s\n",
+                                               ((conffile_t *) iter->data)->
+                                               name,
+                                               ((conffile_t *) iter->data)->
+                                               value);
+                               }
+                       }
+               } else if (strcasecmp(field, "Conflicts") == 0) {
+                       struct depend *cdep;
+                       if (pkg->conflicts_count) {
+                               fprintf(fp, "Conflicts:");
+                               for (i = 0; i < pkg->conflicts_count; i++) {
+                                       cdep =
+                                           pkg->conflicts[i].possibilities[0];
+                                       fprintf(fp, "%s %s", i == 0 ? "" : ",",
+                                               cdep->pkg->name);
+                                       if (cdep->version) {
+                                               fprintf(fp, " (%s%s)",
+                                                       constraint_to_str(cdep->
+                                                                         constraint),
+                                                       cdep->version);
+                                       }
+                               }
+                               fprintf(fp, "\n");
+                       }
+               } else {
+                       goto UNKNOWN_FMT_FIELD;
+               }
+               break;
+       case 'd':
+       case 'D':
+               if (strcasecmp(field, "Depends") == 0) {
+                       if (pkg->depends_count) {
+                               fprintf(fp, "Depends:");
+                               for (j = 0, i = 0; i < depends_count; i++) {
+                                       if (pkg->depends[i].type != DEPEND)
+                                               continue;
+                                       str = pkg_depend_str(pkg, i);
+                                       fprintf(fp, "%s %s", j == 0 ? "" : ",",
+                                               str);
+                                       free(str);
+                                       j++;
+                               }
+                               fprintf(fp, "\n");
+                       }
+               } else if (strcasecmp(field, "Description") == 0) {
+                       p = pkg_get_string(pkg, PKG_DESCRIPTION);
+                       if (p) {
+                               fprintf(fp, "Description: %s\n",
+                                       p);
+                       }
+               } else {
+                       goto UNKNOWN_FMT_FIELD;
+               }
+               break;
+       case 'e':
+       case 'E':
+               if (pkg->essential) {
+                       fprintf(fp, "Essential: yes\n");
+               }
+               break;
+       case 'f':
+       case 'F':
+               p = pkg_get_string(pkg, PKG_FILENAME);
+               if (p) {
+                       fprintf(fp, "Filename: %s\n", p);
+               }
+               break;
+       case 'i':
+       case 'I':
+               if (strcasecmp(field, "Installed-Size") == 0) {
+                       fprintf(fp, "Installed-Size: %lu\n",
+                               (unsigned long) pkg_get_int(pkg, PKG_INSTALLED_SIZE));
+               } else if (strcasecmp(field, "Installed-Time") == 0) {
+                       i = pkg_get_int(pkg, PKG_INSTALLED_TIME);
+                       if (i) {
+                               fprintf(fp, "Installed-Time: %lu\n",
+                                       (unsigned long) i);
+                       }
+               }
+               break;
+       case 'm':
+       case 'M':
+               if (strcasecmp(field, "Maintainer") == 0) {
+                       p = pkg_get_string(pkg, PKG_MAINTAINER);
+                       if (p) {
+                               fprintf(fp, "Maintainer: %s\n", p);
+                       }
+               } else if (strcasecmp(field, "MD5sum") == 0) {
+                       p = pkg_get_string(pkg, PKG_MD5SUM);
+                       if (p) {
+                               fprintf(fp, "MD5Sum: %s\n", p);
+                       }
+               } else {
+                       goto UNKNOWN_FMT_FIELD;
+               }
+               break;
+       case 'p':
+       case 'P':
+               if (strcasecmp(field, "Package") == 0) {
+                       fprintf(fp, "Package: %s\n", pkg->name);
+               } else if (strcasecmp(field, "Priority") == 0) {
+                       fprintf(fp, "Priority: %s\n", pkg_get_string(pkg, PKG_PRIORITY));
+               } else if (strcasecmp(field, "Provides") == 0) {
+                       if (pkg->provides_count > 1) {
+                               fprintf(fp, "Provides:");
+                               for (i = 1; i < pkg->provides_count; i++) {
+                                       fprintf(fp, "%s %s", i == 1 ? "" : ",",
+                                               pkg->provides[i]->name);
+                               }
+                               fprintf(fp, "\n");
+                       }
+               } else {
+                       goto UNKNOWN_FMT_FIELD;
+               }
+               break;
+       case 'r':
+       case 'R':
+               if (strcasecmp(field, "Replaces") == 0) {
+                       if (pkg->replaces_count) {
+                               fprintf(fp, "Replaces:");
+                               for (i = 0; i < pkg->replaces_count; i++) {
+                                       fprintf(fp, "%s %s", i == 0 ? "" : ",",
+                                               pkg->replaces[i]->name);
+                               }
+                               fprintf(fp, "\n");
+                       }
+               } else if (strcasecmp(field, "Recommends") == 0) {
+                       if (pkg->recommends_count) {
+                               fprintf(fp, "Recommends:");
+                               for (j = 0, i = 0; i < depends_count; i++) {
+                                       if (pkg->depends[i].type != RECOMMEND)
+                                               continue;
+                                       str = pkg_depend_str(pkg, i);
+                                       fprintf(fp, "%s %s", j == 0 ? "" : ",",
+                                               str);
+                                       free(str);
+                                       j++;
+                               }
+                               fprintf(fp, "\n");
+                       }
+               } else {
+                       goto UNKNOWN_FMT_FIELD;
+               }
+               break;
+       case 's':
+       case 'S':
+               if (strcasecmp(field, "Section") == 0) {
+                       p = pkg_get_string(pkg, PKG_SECTION);
+                       if (p) {
+                               fprintf(fp, "Section: %s\n", p);
+                       }
+#if defined HAVE_SHA256
+               } else if (strcasecmp(field, "SHA256sum") == 0) {
+                       p = pkg_get_string(pkg, PKG_SHA256SUM);
+                       if (p) {
+                               fprintf(fp, "SHA256sum: %s\n", p);
+                       }
+#endif
+               } else if (strcasecmp(field, "Size") == 0) {
+                       i = pkg_get_int(pkg, PKG_SIZE);
+                       if (i) {
+                               fprintf(fp, "Size: %lu\n", (unsigned long) i);
+                       }
+               } else if (strcasecmp(field, "Source") == 0) {
+                       p = pkg_get_string(pkg, PKG_SOURCE);
+                       if (p) {
+                               fprintf(fp, "Source: %s\n", p);
+                       }
+               } else if (strcasecmp(field, "Status") == 0) {
+                       char *pflag = pkg_state_flag_to_str(pkg->state_flag);
+                       fprintf(fp, "Status: %s %s %s\n",
+                               pkg_state_want_to_str(pkg->state_want),
+                               pflag,
+                               pkg_state_status_to_str(pkg->state_status));
+                       free(pflag);
+               } else if (strcasecmp(field, "Suggests") == 0) {
+                       if (pkg->suggests_count) {
+                               fprintf(fp, "Suggests:");
+                               for (j = 0, i = 0; i < depends_count; i++) {
+                                       if (pkg->depends[i].type != SUGGEST)
+                                               continue;
+                                       str = pkg_depend_str(pkg, i);
+                                       fprintf(fp, "%s %s", j == 0 ? "" : ",",
+                                               str);
+                                       free(str);
+                                       j++;
+                               }
+                               fprintf(fp, "\n");
+                       }
+               } else {
+                       goto UNKNOWN_FMT_FIELD;
+               }
+               break;
+       case 't':
+       case 'T':
+               if (strcasecmp(field, "Tags") == 0) {
+                       p = pkg_get_string(pkg, PKG_TAGS);
+                       if (p) {
+                               fprintf(fp, "Tags: %s\n", p);
+                       }
+               }
+               break;
+       case 'v':
+       case 'V':
+               {
+                       char *version = pkg_version_str_alloc(pkg);
+                       if (version == NULL)
+                               return;
+                       fprintf(fp, "Version: %s\n", version);
+                       free(version);
+               }
+               break;
+       default:
+               goto UNKNOWN_FMT_FIELD;
+       }
+
        return;
-     }
-
-     buff = pkg_formatted_info(pkg);
-     if ( buff == NULL ) 
-         return;
-     if (strlen(buff)>2){
-         fwrite(buff, 1, strlen(buff), file);
-     } 
-     free(buff);
+
+UNKNOWN_FMT_FIELD:
+       opkg_msg(ERROR, "Internal error: field=%s\n", field);
 }
 
-void pkg_print_status(pkg_t * pkg, FILE * file)
+void pkg_formatted_info(FILE * fp, pkg_t * pkg)
 {
-     if (pkg == NULL) {
-         return;
-     }
-
-     /* XXX: QUESTION: Do we actually want more fields here? The
-       original idea was to save space by installing only what was
-       needed for actual computation, (package, version, status,
-       essential, conffiles). The assumption is that all other fields
-       can be found in th available file.
-
-       But, someone proposed the idea to make it possible to
-       reconstruct a .opk from an installed package, (ie. for beaming
-       from one handheld to another). So, maybe we actually want a few
-       more fields here, (depends, suggests, etc.), so that that would
-       be guaranteed to work even in the absence of more information
-       from the available file.
-
-       28-MAR-03: kergoth and I discussed this yesterday.  We think
-       the essential info needs to be here for all installed packages
-       because they may not appear in the Packages files on various
-       feeds.  Furthermore, one should be able to install from URL or
-       local storage without requiring a Packages file from any feed.
-       -Jamey
-     */
-     pkg_print_field(pkg, file, "Package");
-     pkg_print_field(pkg, file, "Version");
-     pkg_print_field(pkg, file, "Depends");
-     pkg_print_field(pkg, file, "Recommends");
-     pkg_print_field(pkg, file, "Suggests");
-     pkg_print_field(pkg, file, "Provides");
-     pkg_print_field(pkg, file, "Replaces");
-     pkg_print_field(pkg, file, "Conflicts");
-     pkg_print_field(pkg, file, "Status");
-     pkg_print_field(pkg, file, "Essential"); /* @@@@ should be removed in future release. */
-     pkg_print_field(pkg, file, "Architecture");
-     pkg_print_field(pkg, file, "Conffiles");
-     pkg_print_field(pkg, file, "Installed-Time");
-     pkg_print_field(pkg, file, "Auto-Installed");
-     fputs("\n", file);
+       pkg_formatted_field(fp, pkg, "Package");
+       pkg_formatted_field(fp, pkg, "Version");
+       pkg_formatted_field(fp, pkg, "Depends");
+       pkg_formatted_field(fp, pkg, "Recommends");
+       pkg_formatted_field(fp, pkg, "Suggests");
+       pkg_formatted_field(fp, pkg, "Provides");
+       pkg_formatted_field(fp, pkg, "Replaces");
+       pkg_formatted_field(fp, pkg, "Conflicts");
+       pkg_formatted_field(fp, pkg, "Status");
+       pkg_formatted_field(fp, pkg, "Section");
+       pkg_formatted_field(fp, pkg, "Essential");
+       pkg_formatted_field(fp, pkg, "Architecture");
+       pkg_formatted_field(fp, pkg, "Maintainer");
+       pkg_formatted_field(fp, pkg, "MD5sum");
+       pkg_formatted_field(fp, pkg, "Size");
+       pkg_formatted_field(fp, pkg, "Filename");
+       pkg_formatted_field(fp, pkg, "Conffiles");
+       pkg_formatted_field(fp, pkg, "Source");
+       pkg_formatted_field(fp, pkg, "Description");
+       pkg_formatted_field(fp, pkg, "Installed-Time");
+       pkg_formatted_field(fp, pkg, "Tags");
+       fputs("\n", fp);
 }
 
-void pkg_print_field(pkg_t *pkg, FILE *file, const char *field)
+void pkg_print_status(pkg_t * pkg, FILE * file)
 {
-     char *buff;
-     if (strlen(field) < PKG_MINIMUM_FIELD_NAME_LEN) {
-       fprintf(stderr, "%s: ERROR: Unknown field name: %s\n",
-            __FUNCTION__, field);
-     }
-     buff = pkg_formatted_field(pkg, field);
-     if (strlen(buff)>2) {
-       fprintf(file, "%s", buff);
-       fflush(file);
-     }
-     free(buff);
-     return;
+       if (pkg == NULL) {
+               return;
+       }
+
+       pkg_formatted_field(file, pkg, "Package");
+       pkg_formatted_field(file, pkg, "Version");
+       pkg_formatted_field(file, pkg, "Depends");
+       pkg_formatted_field(file, pkg, "Recommends");
+       pkg_formatted_field(file, pkg, "Suggests");
+       pkg_formatted_field(file, pkg, "Provides");
+       pkg_formatted_field(file, pkg, "Replaces");
+       pkg_formatted_field(file, pkg, "Conflicts");
+       pkg_formatted_field(file, pkg, "Status");
+       pkg_formatted_field(file, pkg, "Essential");
+       pkg_formatted_field(file, pkg, "Architecture");
+       pkg_formatted_field(file, pkg, "Conffiles");
+       pkg_formatted_field(file, pkg, "Installed-Time");
+       pkg_formatted_field(file, pkg, "Auto-Installed");
+       fputs("\n", file);
 }
 
 /*
@@ -1131,30 +899,6 @@ void pkg_print_field(pkg_t *pkg, FILE *file, const char *field)
  *
  * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
  */
-int pkg_compare_versions(const pkg_t *pkg, const pkg_t *ref_pkg)
-{
-     int r;
-
-     if (pkg->epoch > ref_pkg->epoch) {
-         return 1;
-     }
-
-     if (pkg->epoch < ref_pkg->epoch) {
-         return -1;
-     }
-
-     r = verrevcmp(pkg->version, ref_pkg->version);
-     if (r) {
-         return r;
-     }
-
-     r = verrevcmp(pkg->revision, ref_pkg->revision);
-     if (r) {
-         return r;
-     }
-
-     return r;
-}
 
 /* assume ascii; warning: evaluates x multiple times! */
 #define order(x) ((x) == '~' ? -1 \
@@ -1163,227 +907,304 @@ int pkg_compare_versions(const pkg_t *pkg, const pkg_t *ref_pkg)
                : isalpha((x)) ? (x) \
                : (x) + 256)
 
-static int verrevcmp(const char *val, const char *ref) {
-  if (!val) val= "";
-  if (!ref) ref= "";
-
-  while (*val || *ref) {
-    int first_diff= 0;
-
-    while ( (*val && !isdigit(*val)) || (*ref && !isdigit(*ref)) ) {
-      int vc= order(*val), rc= order(*ref);
-      if (vc != rc) return vc - rc;
-      val++; ref++;
-    }
-
-    while ( *val == '0' ) val++;
-    while ( *ref == '0' ) ref++;
-    while (isdigit(*val) && isdigit(*ref)) {
-      if (!first_diff) first_diff= *val - *ref;
-      val++; ref++;
-    }
-    if (isdigit(*val)) return 1;
-    if (isdigit(*ref)) return -1;
-    if (first_diff) return first_diff;
-  }
-  return 0;
+static int verrevcmp(const char *val, const char *ref)
+{
+       if (!val)
+               val = "";
+       if (!ref)
+               ref = "";
+
+       while (*val || *ref) {
+               int first_diff = 0;
+
+               while ((*val && !isdigit(*val)) || (*ref && !isdigit(*ref))) {
+                       int vc = order(*val), rc = order(*ref);
+                       if (vc != rc)
+                               return vc - rc;
+                       val++;
+                       ref++;
+               }
+
+               while (*val == '0')
+                       val++;
+               while (*ref == '0')
+                       ref++;
+               while (isdigit(*val) && isdigit(*ref)) {
+                       if (!first_diff)
+                               first_diff = *val - *ref;
+                       val++;
+                       ref++;
+               }
+               if (isdigit(*val))
+                       return 1;
+               if (isdigit(*ref))
+                       return -1;
+               if (first_diff)
+                       return first_diff;
+       }
+       return 0;
+}
+
+int pkg_compare_versions(const pkg_t * pkg, const pkg_t * ref_pkg)
+{
+       unsigned int epoch1 = (unsigned int) pkg_get_int(pkg, PKG_EPOCH);
+       unsigned int epoch2 = (unsigned int) pkg_get_int(ref_pkg, PKG_EPOCH);
+       char *revision1 = pkg_get_ptr(pkg, PKG_REVISION);
+       char *revision2 = pkg_get_ptr(ref_pkg, PKG_REVISION);
+       const char *version1 = pkg_get_string(pkg, PKG_VERSION);
+       const char *version2 = pkg_get_string(ref_pkg, PKG_VERSION);
+       int r;
+
+       if (epoch1 > epoch2) {
+               return 1;
+       }
+
+       if (epoch1 < epoch2) {
+               return -1;
+       }
+
+       r = verrevcmp(version1, version2);
+       if (r) {
+               return r;
+       }
+
+       r = verrevcmp(revision1, revision2);
+       if (r) {
+               return r;
+       }
+
+       return r;
 }
 
-int pkg_version_satisfied(pkg_t *it, pkg_t *ref, const char *op)
+int pkg_version_satisfied(pkg_t * it, pkg_t * ref, const char *op)
 {
-     int r;
+       int r;
 
-     r = pkg_compare_versions(it, ref);
+       r = pkg_compare_versions(it, ref);
 
-     if (strcmp(op, "<=") == 0 || strcmp(op, "<") == 0) {
-         return r <= 0;
-     }
+       if (strcmp(op, "<=") == 0 || strcmp(op, "<") == 0) {
+               return r <= 0;
+       }
 
-     if (strcmp(op, ">=") == 0 || strcmp(op, ">") == 0) {
-         return r >= 0;
-     }
+       if (strcmp(op, ">=") == 0 || strcmp(op, ">") == 0) {
+               return r >= 0;
+       }
 
-     if (strcmp(op, "<<") == 0) {
-         return r < 0;
-     }
+       if (strcmp(op, "<<") == 0) {
+               return r < 0;
+       }
 
-     if (strcmp(op, ">>") == 0) {
-         return r > 0;
-     }
+       if (strcmp(op, ">>") == 0) {
+               return r > 0;
+       }
 
-     if (strcmp(op, "=") == 0) {
-         return r == 0;
-     }
+       if (strcmp(op, "=") == 0) {
+               return r == 0;
+       }
 
-     fprintf(stderr, "unknown operator: %s", op);
-     return 0;
+       opkg_msg(ERROR, "Unknown operator: %s.\n", op);
+       return 0;
 }
 
 int pkg_name_version_and_architecture_compare(const void *p1, const void *p2)
 {
-     const pkg_t *a = *(const pkg_t**) p1;
-     const pkg_t *b = *(const pkg_t**) p2;
-     int namecmp;
-     int vercmp;
-     if (!a->name || !b->name) {
-       fprintf(stderr, "pkg_name_version_and_architecture_compare: a=%p a->name=%p b=%p b->name=%p\n",
-              a, a->name, b, b->name);
-       return 0;
-     }
-       
-     namecmp = strcmp(a->name, b->name);
-     if (namecmp)
-         return namecmp;
-     vercmp = pkg_compare_versions(a, b);
-     if (vercmp)
-         return vercmp;
-     if (!a->arch_priority || !b->arch_priority) {
-       fprintf(stderr, "pkg_name_version_and_architecture_compare: a=%p a->arch_priority=%i b=%p b->arch_priority=%i\n",
-              a, a->arch_priority, b, b->arch_priority);
-       return 0;
-     }
-     if (a->arch_priority > b->arch_priority)
-         return 1;
-     if (a->arch_priority < b->arch_priority)
-         return -1;
-     return 0;
+       const pkg_t * a = *(const pkg_t **)p1;
+       const pkg_t * b = *(const pkg_t **)p2;
+       int namecmp;
+       int vercmp;
+       if (!a->name || !b->name) {
+               opkg_msg(ERROR, "Internal error: a->name=%p, b->name=%p.\n",
+                        a->name, b->name);
+               return 0;
+       }
+
+       namecmp = strcmp(a->name, b->name);
+       if (namecmp)
+               return namecmp;
+       vercmp = pkg_compare_versions(a, b);
+       if (vercmp)
+               return vercmp;
+       if (!a->arch_priority || !b->arch_priority) {
+               opkg_msg(ERROR,
+                        "Internal error: a->arch_priority=%i b->arch_priority=%i.\n",
+                        a->arch_priority, b->arch_priority);
+               return 0;
+       }
+       if (a->arch_priority > b->arch_priority)
+               return 1;
+       if (a->arch_priority < b->arch_priority)
+               return -1;
+       return 0;
 }
 
 int abstract_pkg_name_compare(const void *p1, const void *p2)
 {
-     const abstract_pkg_t *a = *(const abstract_pkg_t **)p1;
-     const abstract_pkg_t *b = *(const abstract_pkg_t **)p2;
-     if (!a->name || !b->name) {
-       fprintf(stderr, "abstract_pkg_name_compare: a=%p a->name=%p b=%p b->name=%p\n",
-              a, a->name, b, b->name);
-       return 0;
-     }
-     return strcmp(a->name, b->name);
+       const abstract_pkg_t *a = *(const abstract_pkg_t **)p1;
+       const abstract_pkg_t *b = *(const abstract_pkg_t **)p2;
+       if (!a->name || !b->name) {
+               opkg_msg(ERROR, "Internal error: a->name=%p b->name=%p.\n",
+                        a->name, b->name);
+               return 0;
+       }
+       return strcmp(a->name, b->name);
 }
 
-
-char *pkg_version_str_alloc(pkg_t *pkg)
+char *pkg_version_str_alloc(pkg_t * pkg)
 {
-     char *complete_version;
-     char *epoch_str;
-     char *revision_str;
+       const char *verstr;
+       char *version, *revptr;
+       unsigned int epoch = (unsigned int) pkg_get_int(pkg, PKG_EPOCH);
+
+       revptr = pkg_get_ptr(pkg, PKG_REVISION);
+       verstr = pkg_get_string(pkg, PKG_VERSION);
+
+       if (epoch) {
+               if (revptr)
+                       sprintf_alloc(&version, "%d:%s-%s",
+                                     epoch, verstr, revptr);
+               else
+                       sprintf_alloc(&version, "%d:%s",
+                                     epoch, verstr);
+       } else {
+               if (revptr)
+                       sprintf_alloc(&version, "%s-%s",
+                                     verstr, revptr);
+               else
+                       version = xstrdup(verstr);
+       }
+
+       return version;
+}
 
-     if (pkg->epoch) {
-         sprintf_alloc(&epoch_str, "%d:", pkg->epoch);
-     } else {
-         epoch_str = strdup("");
-     }
+/*
+ * XXX: this should be broken into two functions
+ */
+str_list_t *pkg_get_installed_files(pkg_t * pkg)
+{
+       int err, fd;
+       char *list_file_name = NULL;
+       FILE *list_file = NULL;
+       char *line;
+       char *installed_file_name;
+       unsigned int rootdirlen = 0;
+       int list_from_package;
+       const char *local_filename;
+
+       pkg->installed_files_ref_cnt++;
+
+       if (pkg->installed_files) {
+               return pkg->installed_files;
+       }
+
+       pkg->installed_files = str_list_alloc();
+
+       /*
+        * For installed packages, look at the package.list file in the database.
+        * For uninstalled packages, get the file list directly from the package.
+        */
+       if (pkg->state_status == SS_NOT_INSTALLED || pkg->dest == NULL)
+               list_from_package = 1;
+       else
+               list_from_package = 0;
+
+       if (list_from_package) {
+               local_filename = pkg_get_string(pkg, PKG_LOCAL_FILENAME);
+
+               if (!local_filename) {
+                       return pkg->installed_files;
+               }
+               /* XXX: CLEANUP: Maybe rewrite this to avoid using a temporary
+                  file. In other words, change deb_extract so that it can
+                  simply return the file list as a char *[] rather than
+                  insisting on writing it to a FILE * as it does now. */
+               sprintf_alloc(&list_file_name, "%s/%s.list.XXXXXX",
+                             conf->tmp_dir, pkg->name);
+               fd = mkstemp(list_file_name);
+               if (fd == -1) {
+                       opkg_perror(ERROR, "Failed to make temp file %s.",
+                                   list_file_name);
+                       free(list_file_name);
+                       return pkg->installed_files;
+               }
+               list_file = fdopen(fd, "r+");
+               if (list_file == NULL) {
+                       opkg_perror(ERROR, "Failed to fdopen temp file %s.",
+                                   list_file_name);
+                       close(fd);
+                       unlink(list_file_name);
+                       free(list_file_name);
+                       return pkg->installed_files;
+               }
+               err = pkg_extract_data_file_names_to_stream(pkg, list_file);
+               if (err) {
+                       opkg_msg(ERROR, "Error extracting file list from %s.\n",
+                                local_filename);
+                       fclose(list_file);
+                       unlink(list_file_name);
+                       free(list_file_name);
+                       str_list_deinit(pkg->installed_files);
+                       pkg->installed_files = NULL;
+                       return NULL;
+               }
+               rewind(list_file);
+       } else {
+               sprintf_alloc(&list_file_name, "%s/%s.list",
+                             pkg->dest->info_dir, pkg->name);
+               list_file = fopen(list_file_name, "r");
+               if (list_file == NULL) {
+                       opkg_perror(ERROR, "Failed to open %s", list_file_name);
+                       free(list_file_name);
+                       return pkg->installed_files;
+               }
+               free(list_file_name);
+       }
 
-     if (pkg->revision && strlen(pkg->revision)) {
-         sprintf_alloc(&revision_str, "-%s", pkg->revision);
-     } else {
-         revision_str = strdup("");
-     }
+       if (conf->offline_root)
+               rootdirlen = strlen(conf->offline_root);
 
+       while (1) {
+               char *file_name;
 
-     sprintf_alloc(&complete_version, "%s%s%s",
-                  epoch_str, pkg->version, revision_str);
+               line = file_read_line_alloc(list_file);
+               if (line == NULL) {
+                       break;
+               }
+               file_name = line;
+
+               if (list_from_package) {
+                       if (*file_name == '.') {
+                               file_name++;
+                       }
+                       if (*file_name == '/') {
+                               file_name++;
+                       }
+                       sprintf_alloc(&installed_file_name, "%s%s",
+                                     pkg->dest->root_dir, file_name);
+               } else {
+                       if (conf->offline_root &&
+                           strncmp(conf->offline_root, file_name,
+                                   rootdirlen)) {
+                               sprintf_alloc(&installed_file_name, "%s%s",
+                                             conf->offline_root, file_name);
+                       } else {
+                               // already contains root_dir as header -> ABSOLUTE
+                               sprintf_alloc(&installed_file_name, "%s",
+                                             file_name);
+                       }
+               }
+               str_list_append(pkg->installed_files, installed_file_name);
+               free(installed_file_name);
+               free(line);
+       }
 
-     free(epoch_str);
-     free(revision_str);
+       fclose(list_file);
 
-     return complete_version;
-}
+       if (list_from_package) {
+               unlink(list_file_name);
+               free(list_file_name);
+       }
 
-str_list_t *pkg_get_installed_files(pkg_t *pkg)
-{
-     int err;
-     char *list_file_name = NULL;
-     FILE *list_file = NULL;
-     char *line;
-     char *installed_file_name;
-     int rootdirlen;
-
-     pkg->installed_files_ref_cnt++;
-
-     if (pkg->installed_files) {
-         return pkg->installed_files;
-     }
-
-     pkg->installed_files = str_list_alloc();
-     if (pkg->installed_files == NULL) {
-         fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
-         return NULL;
-     }
-
-     /* For uninstalled packages, get the file list firectly from the package.
-       For installed packages, look at the package.list file in the database.
-     */
-     if (pkg->state_status == SS_NOT_INSTALLED || pkg->dest == NULL) {
-         if (pkg->local_filename == NULL) {
-              return pkg->installed_files;
-         }
-         /* XXX: CLEANUP: Maybe rewrite this to avoid using a temporary
-            file. In other words, change deb_extract so that it can
-            simply return the file list as a char *[] rather than
-            insisting on writing in to a FILE * as it does now. */
-         list_file = tmpfile();
-         err = pkg_extract_data_file_names_to_stream(pkg, list_file);
-         if (err) {
-              fclose(list_file);
-              fprintf(stderr, "%s: Error extracting file list from %s: %s\n",
-                      __FUNCTION__, pkg->local_filename, strerror(err));
-              return pkg->installed_files;
-         }
-         rewind(list_file);
-     } else {
-         sprintf_alloc(&list_file_name, "%s/%s.list",
-                       pkg->dest->info_dir, pkg->name);
-         if (! file_exists(list_file_name)) {
-              free(list_file_name);
-              return pkg->installed_files;
-         }
-
-         list_file = fopen(list_file_name, "r");
-         if (list_file == NULL) {
-              fprintf(stderr, "WARNING: Cannot open %s: %s\n",
-                      list_file_name, strerror(errno));
-              free(list_file_name);
-              return pkg->installed_files;
-         }
-         free(list_file_name);
-     }
-
-     rootdirlen = strlen( pkg->dest->root_dir );
-     while (1) {
-         char *file_name;
-       
-         line = file_read_line_alloc(list_file);
-         if (line == NULL) {
-              break;
-         }
-         str_chomp(line);
-         file_name = line;
-
-         /* Take pains to avoid uglies like "/./" in the middle of file_name. */
-         if( strncmp( pkg->dest->root_dir, 
-                      file_name, 
-                      rootdirlen ) ) {
-              if (*file_name == '.') {
-                   file_name++;
-              }
-              if (*file_name == '/') {
-                   file_name++;
-              }
-
-              /* Freed in pkg_free_installed_files */
-              sprintf_alloc(&installed_file_name, "%s%s", pkg->dest->root_dir, file_name);
-         } else {
-              // already contains root_dir as header -> ABSOLUTE
-              sprintf_alloc(&installed_file_name, "%s", file_name);
-         }
-         str_list_append(pkg->installed_files, installed_file_name);
-         free(line);
-     }
-
-     fclose(list_file);
-
-     return pkg->installed_files;
+       return pkg->installed_files;
 }
 
 /* XXX: CLEANUP: This function and it's counterpart,
@@ -1391,428 +1212,242 @@ str_list_t *pkg_get_installed_files(pkg_t *pkg)
    convention. Nor the alloc/free convention. But, then again, neither
    of these conventions currrently fit the way these two functions
    work. */
-int pkg_free_installed_files(pkg_t *pkg)
+void pkg_free_installed_files(pkg_t * pkg)
 {
-     str_list_elt_t *iter;
+       pkg->installed_files_ref_cnt--;
 
-     pkg->installed_files_ref_cnt--;
-     if (pkg->installed_files_ref_cnt > 0) {
-         return 0;
-     }
+       if (pkg->installed_files_ref_cnt > 0)
+               return;
 
-     if (pkg->installed_files) {
+       if (pkg->installed_files) {
+               str_list_purge(pkg->installed_files);
+       }
 
-         for (iter = pkg->installed_files->head; iter; iter = iter->next) {
-              /* malloced in pkg_get_installed_files */
-              free (iter->data);
-              iter->data = NULL;
-         }
+       pkg->installed_files = NULL;
+}
 
-         str_list_deinit(pkg->installed_files);
-         free (pkg->installed_files);
-     }
+void pkg_remove_installed_files_list(pkg_t * pkg)
+{
+       char *list_file_name;
 
-     pkg->installed_files = NULL;
+       sprintf_alloc(&list_file_name, "%s/%s.list",
+                     pkg->dest->info_dir, pkg->name);
 
-     return 0;
-}
+       if (!conf->noaction)
+               (void)unlink(list_file_name);
 
-int pkg_remove_installed_files_list(opkg_conf_t *conf, pkg_t *pkg)
-{
-     int err;
-     char *list_file_name;
-
-     //I don't think pkg_free_installed_files should be called here. Jamey
-     //pkg_free_installed_files(pkg);
-
-     sprintf_alloc(&list_file_name, "%s/%s.list",
-                  pkg->dest->info_dir, pkg->name);
-     if (!conf->noaction) {
-         err = unlink(list_file_name);
-         free(list_file_name);
-
-         if (err) {
-              return errno;
-         }
-     }
-     return 0;
+       free(list_file_name);
 }
 
-conffile_t *pkg_get_conffile(pkg_t *pkg, const char *file_name)
+conffile_t *pkg_get_conffile(pkg_t * pkg, const char *file_name)
 {
-     conffile_list_elt_t *iter;
-     conffile_t *conffile;
+       conffile_list_elt_t *iter;
+       conffile_t *conffile;
 
-     if (pkg == NULL) {
-         return NULL;
-     }
+       if (pkg == NULL) {
+               return NULL;
+       }
 
-     for (iter = pkg->conffiles.head; iter; iter = iter->next) {
-         conffile = iter->data;
+       for (iter = nv_pair_list_first(&pkg->conffiles); iter;
+            iter = nv_pair_list_next(&pkg->conffiles, iter)) {
+               conffile = (conffile_t *) iter->data;
 
-         if (strcmp(conffile->name, file_name) == 0) {
-              return conffile;
-         }
-     }
+               if (strcmp(conffile->name, file_name) == 0) {
+                       return conffile;
+               }
+       }
 
-     return NULL;
+       return NULL;
 }
 
-int pkg_run_script(opkg_conf_t *conf, pkg_t *pkg,
-                  const char *script, const char *args)
+int pkg_run_script(pkg_t * pkg, const char *script, const char *args)
 {
-     int err;
-     char *path;
-     char *cmd;
-
-     /* XXX: FEATURE: When conf->offline_root is set, we should run the
-       maintainer script within a chroot environment. */
-
-     /* Installed packages have scripts in pkg->dest->info_dir, uninstalled packages
-       have scripts in pkg->tmp_unpack_dir. */
-     if (pkg->state_status == SS_INSTALLED || pkg->state_status == SS_UNPACKED) {
-         if (pkg->dest == NULL) {
-              fprintf(stderr, "%s: ERROR: installed package %s has a NULL dest\n",
-                      __FUNCTION__, pkg->name);
-              return EINVAL;
-         }
-         sprintf_alloc(&path, "%s/%s.%s", pkg->dest->info_dir, pkg->name, script);
-     } else {
-         if (pkg->tmp_unpack_dir == NULL) {
-              fprintf(stderr, "%s: ERROR: uninstalled package %s has a NULL tmp_unpack_dir\n",
-                      __FUNCTION__, pkg->name);
-              return EINVAL;
-         }
-         sprintf_alloc(&path, "%s/%s", pkg->tmp_unpack_dir, script);
-     }
-
-     opkg_message(conf, OPKG_INFO, "Running script %s\n", path);
-     if (conf->noaction) return 0;
-
-     /* XXX: CLEANUP: There must be a better way to handle maintainer
-       scripts when running with offline_root mode and/or a dest other
-       than '/'. I've been playing around with some clever chroot
-       tricks and I might come up with something workable. */
-     if (conf->offline_root) {
-         setenv("OPKG_OFFLINE_ROOT", conf->offline_root, 1);
-     }
-
-     setenv("PKG_ROOT",
-           pkg->dest ? pkg->dest->root_dir : conf->default_dest->root_dir, 1);
-
-     if (! file_exists(path)) {
-         free(path);
-         return 0;
-     }
-
-     if (conf->offline_root) {
-         fprintf(stderr, "(offline root mode: not running %s.%s)\n", pkg->name, script);
-         free(path);
-         return 0;
-     }
-
-     sprintf_alloc(&cmd, "%s %s", path, args);
-     free(path);
-
-     err = xsystem(cmd);
-     free(cmd);
-
-     if (err) {
-         fprintf(stderr, "%s script returned status %d\n", script, err);
-         return err;
-     }
-
-     return 0;
+       int err;
+       char *path;
+       char *cmd;
+
+       if (conf->noaction)
+               return 0;
+
+       /* XXX: FEATURE: When conf->offline_root is set, we should run the
+          maintainer script within a chroot environment. */
+       if (conf->offline_root && !conf->force_postinstall) {
+               opkg_msg(INFO, "Offline root mode: not running %s.%s.\n",
+                        pkg->name, script);
+               return 0;
+       }
+
+       /* Installed packages have scripts in pkg->dest->info_dir, uninstalled packages
+          have scripts in pkg->tmp_unpack_dir. */
+       if (pkg->state_status == SS_INSTALLED
+           || pkg->state_status == SS_UNPACKED) {
+               if (pkg->dest == NULL) {
+                       opkg_msg(ERROR, "Internal error: %s has a NULL dest.\n",
+                                pkg->name);
+                       return -1;
+               }
+               sprintf_alloc(&path, "%s/%s.%s", pkg->dest->info_dir, pkg->name,
+                             script);
+       } else {
+               if (pkg->tmp_unpack_dir == NULL) {
+                       opkg_msg(ERROR,
+                                "Internal error: %s has a NULL tmp_unpack_dir.\n",
+                                pkg->name);
+                       return -1;
+               }
+               sprintf_alloc(&path, "%s/%s", pkg->tmp_unpack_dir, script);
+       }
+
+       opkg_msg(INFO, "Running script %s.\n", path);
+
+       setenv("PKG_ROOT",
+              pkg->dest ? pkg->dest->root_dir : conf->default_dest->root_dir,
+              1);
+
+       if (pkg->is_upgrade)
+               setenv("PKG_UPGRADE", "1", 1);
+       else
+               setenv("PKG_UPGRADE", "0", 1);
+
+       if (!file_exists(path)) {
+               free(path);
+               return 0;
+       }
+
+       sprintf_alloc(&cmd, "%s %s", path, args);
+       free(path);
+       {
+               const char *argv[] = { "sh", "-c", cmd, NULL };
+               err = xsystem(argv);
+       }
+       free(cmd);
+
+       if (err) {
+               opkg_msg(ERROR,
+                        "package \"%s\" %s script returned status %d.\n",
+                        pkg->name, script, err);
+               return err;
+       }
+
+       return 0;
 }
 
-char *pkg_state_want_to_str(pkg_state_want_t sw)
+int pkg_arch_supported(pkg_t * pkg)
 {
-     int i;
-
-     for (i=0; i < ARRAY_SIZE(pkg_state_want_map); i++) {
-         if (pkg_state_want_map[i].value == sw) {
-              return strdup(pkg_state_want_map[i].str);
-         }
-     }
-
-     fprintf(stderr, "%s: ERROR: Illegal value for state_want: %d\n",
-            __FUNCTION__, sw);
-     return strdup("<STATE_WANT_UNKNOWN>");
-}
-
-pkg_state_want_t pkg_state_want_from_str(char *str)
-{
-     int i;
-
-     for (i=0; i < ARRAY_SIZE(pkg_state_want_map); i++) {
-         if (strcmp(str, pkg_state_want_map[i].str) == 0) {
-              return pkg_state_want_map[i].value;
-         }
-     }
+       nv_pair_list_elt_t *l;
+       char *architecture = pkg_get_string(pkg, PKG_ARCHITECTURE);
+
+       if (!architecture)
+               return 1;
+
+       list_for_each_entry(l, &conf->arch_list.head, node) {
+               nv_pair_t *nv = (nv_pair_t *) l->data;
+               if (strcmp(nv->name, architecture) == 0) {
+                       opkg_msg(DEBUG,
+                                "Arch %s (priority %s) supported for pkg %s.\n",
+                                nv->name, nv->value, pkg->name);
+                       return 1;
+               }
+       }
 
-     fprintf(stderr, "%s: ERROR: Illegal value for state_want string: %s\n",
-            __FUNCTION__, str);
-     return SW_UNKNOWN;
+       opkg_msg(DEBUG, "Arch %s unsupported for pkg %s.\n",
+                architecture, pkg->name);
+       return 0;
 }
 
-char *pkg_state_flag_to_str(pkg_state_flag_t sf)
+void pkg_info_preinstall_check(void)
 {
-     int i;
-     int len = 3; /* ok\000 is minimum */
-     char *str = NULL;
-
-     /* clear the temporary flags before converting to string */
-     sf &= SF_NONVOLATILE_FLAGS;
-
-     if (sf == 0) {
-         return strdup("ok");
-     } else {
-
-         for (i=0; i < ARRAY_SIZE(pkg_state_flag_map); i++) {
-              if (sf & pkg_state_flag_map[i].value) {
-                   len += strlen(pkg_state_flag_map[i].str) + 1;
-              }
-         }
-         str = malloc(len);
-          if ( str == NULL ) {
-             fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
-              return NULL;
-          }
-         str[0] = 0;
-         for (i=0; i < ARRAY_SIZE(pkg_state_flag_map); i++) {
-              if (sf & pkg_state_flag_map[i].value) {
-                   strcat(str, pkg_state_flag_map[i].str);
-                   strcat(str, ",");
-              }
-         }
-         len = strlen(str);
-         str[len-1] = 0; /* squash last comma */
-         return str;
-     }
+       int i;
+       pkg_vec_t *installed_pkgs = pkg_vec_alloc();
+
+       /* update the file owner data structure */
+       opkg_msg(INFO, "Updating file owner list.\n");
+       pkg_hash_fetch_all_installed(installed_pkgs);
+       for (i = 0; i < installed_pkgs->len; i++) {
+               pkg_t *pkg = installed_pkgs->pkgs[i];
+               str_list_t *installed_files = pkg_get_installed_files(pkg);     /* this causes installed_files to be cached */
+               str_list_elt_t *iter, *niter;
+               if (installed_files == NULL) {
+                       opkg_msg(ERROR, "Failed to determine installed "
+                                "files for pkg %s.\n", pkg->name);
+                       break;
+               }
+               for (iter = str_list_first(installed_files), niter =
+                    str_list_next(installed_files, iter); iter;
+                    iter = niter, niter =
+                    str_list_next(installed_files, iter)) {
+                       char *installed_file = (char *)iter->data;
+                       file_hash_set_file_owner(installed_file, pkg);
+               }
+               pkg_free_installed_files(pkg);
+       }
+       pkg_vec_free(installed_pkgs);
 }
 
-pkg_state_flag_t pkg_state_flag_from_str(const char *str)
-{
-     int i;
-     int sf = SF_OK;
-
-     if (strcmp(str, "ok") == 0) {
-         return SF_OK;
-     }
-     for (i=0; i < ARRAY_SIZE(pkg_state_flag_map); i++) {
-         const char *sfname = pkg_state_flag_map[i].str;
-         int sfname_len = strlen(sfname);
-         if (strncmp(str, sfname, sfname_len) == 0) {
-              sf |= pkg_state_flag_map[i].value;
-              str += sfname_len;
-              if (str[0] == ',') {
-                   str++;
-              } else {
-                   break;
-              }
-         }
-     }
-
-     return sf;
-}
+struct pkg_write_filelist_data {
+       pkg_t *pkg;
+       FILE *stream;
+};
 
-char *pkg_state_status_to_str(pkg_state_status_t ss)
+static void
+pkg_write_filelist_helper(const char *key, void *entry_, void *data_)
 {
-     int i;
-
-     for (i=0; i < ARRAY_SIZE(pkg_state_status_map); i++) {
-         if (pkg_state_status_map[i].value == ss) {
-              return strdup(pkg_state_status_map[i].str);
-         }
-     }
-
-     fprintf(stderr, "%s: ERROR: Illegal value for state_status: %d\n",
-            __FUNCTION__, ss);
-     return strdup("<STATE_STATUS_UNKNOWN>");
+       struct pkg_write_filelist_data *data = data_;
+       pkg_t *entry = entry_;
+       if (entry == data->pkg) {
+               fprintf(data->stream, "%s\n", key);
+       }
 }
 
-pkg_state_status_t pkg_state_status_from_str(const char *str)
+int pkg_write_filelist(pkg_t * pkg)
 {
-     int i;
+       struct pkg_write_filelist_data data;
+       char *list_file_name;
 
-     for (i=0; i < ARRAY_SIZE(pkg_state_status_map); i++) {
-         if (strcmp(str, pkg_state_status_map[i].str) == 0) {
-              return pkg_state_status_map[i].value;
-         }
-     }
+       sprintf_alloc(&list_file_name, "%s/%s.list",
+                     pkg->dest->info_dir, pkg->name);
 
-     fprintf(stderr, "%s: ERROR: Illegal value for state_status string: %s\n",
-            __FUNCTION__, str);
-     return SS_NOT_INSTALLED;
-}
+       opkg_msg(INFO, "Creating %s file for pkg %s.\n",
+                list_file_name, pkg->name);
 
-int pkg_arch_supported(opkg_conf_t *conf, pkg_t *pkg)
-{
-     nv_pair_list_elt_t *l;
-
-     if (!pkg->architecture)
-         return 1;
+       data.stream = fopen(list_file_name, "w");
+       if (!data.stream) {
+               opkg_perror(ERROR, "Failed to open %s", list_file_name);
+               free(list_file_name);
+               return -1;
+       }
 
-     l = conf->arch_list.head;
+       data.pkg = pkg;
+       hash_table_foreach(&conf->file_hash, pkg_write_filelist_helper, &data);
+       fclose(data.stream);
+       free(list_file_name);
 
-     while (l) {
-         nv_pair_t *nv = l->data;
-         if (strcmp(nv->name, pkg->architecture) == 0) {
-              opkg_message(conf, OPKG_DEBUG, "arch %s (priority %s) supported for pkg %s\n", nv->name, nv->value, pkg->name);
-              return 1;
-         }
-         l = l->next;
-     }
+       pkg->state_flag &= ~SF_FILELIST_CHANGED;
 
-     opkg_message(conf, OPKG_DEBUG, "arch %s unsupported for pkg %s\n", pkg->architecture, pkg->name);
-     return 0;
+       return 0;
 }
 
-int pkg_get_arch_priority(opkg_conf_t *conf, const char *archname)
+int pkg_write_changed_filelists(void)
 {
-     nv_pair_list_elt_t *l;
-
-     l = conf->arch_list.head;
-
-     while (l) {
-         nv_pair_t *nv = l->data;
-         if (strcmp(nv->name, archname) == 0) {
-              int priority = strtol(nv->value, NULL, 0);
-              return priority;
-         }
-         l = l->next;
-     }
-     return 0;
-}
+       pkg_vec_t *installed_pkgs = pkg_vec_alloc();
+       int i, err, ret = 0;
 
-int pkg_info_preinstall_check(opkg_conf_t *conf)
-{
-     int i;
-     hash_table_t *pkg_hash = &conf->pkg_hash;
-     pkg_vec_t *available_pkgs = pkg_vec_alloc();
-     pkg_vec_t *installed_pkgs = pkg_vec_alloc();
-
-     opkg_message(conf, OPKG_INFO, "pkg_info_preinstall_check: updating arch priority for each package\n");
-     pkg_hash_fetch_available(pkg_hash, available_pkgs);
-     /* update arch_priority for each package */
-     for (i = 0; i < available_pkgs->len; i++) {
-         pkg_t *pkg = available_pkgs->pkgs[i];
-         int arch_priority = 1;
-         if (!pkg)
-              continue;
-         // opkg_message(conf, OPKG_DEBUG2, " package %s version=%s arch=%p:", pkg->name, pkg->version, pkg->architecture);
-         if (pkg->architecture) 
-              arch_priority = pkg_get_arch_priority(conf, pkg->architecture);
-         else 
-              opkg_message(conf, OPKG_ERROR, "pkg_info_preinstall_check: no architecture for package %s\n", pkg->name);
-         // opkg_message(conf, OPKG_DEBUG2, "%s arch_priority=%d\n", pkg->architecture, arch_priority);
-         pkg->arch_priority = arch_priority;
-     }
-
-     for (i = 0; i < available_pkgs->len; i++) {
-         pkg_t *pkg = available_pkgs->pkgs[i];
-         if (!pkg->arch_priority && (pkg->state_flag || (pkg->state_want != SW_UNKNOWN))) {
-              /* clear flags and want for any uninstallable package */
-              opkg_message(conf, OPKG_DEBUG, "Clearing state_want and state_flag for pkg=%s (arch_priority=%d flag=%d want=%d)\n", 
-                           pkg->name, pkg->arch_priority, pkg->state_flag, pkg->state_want);
-              pkg->state_want = SW_UNKNOWN;
-              pkg->state_flag = 0;
-         }
-     }
-     pkg_vec_free(available_pkgs);
-
-     /* update the file owner data structure */
-     opkg_message(conf, OPKG_INFO, "pkg_info_preinstall_check: update file owner list\n");
-     pkg_hash_fetch_all_installed(pkg_hash, installed_pkgs);
-     for (i = 0; i < installed_pkgs->len; i++) {
-         pkg_t *pkg = installed_pkgs->pkgs[i];
-         str_list_t *installed_files = pkg_get_installed_files(pkg); /* this causes installed_files to be cached */
-         str_list_elt_t *iter;
-         if (installed_files == NULL) {
-              opkg_message(conf, OPKG_ERROR, "No installed files for pkg %s\n", pkg->name);
-              break;
-         }
-         for (iter = installed_files->head; iter; iter = iter->next) {
-              char *installed_file = iter->data;
-              // opkg_message(conf, OPKG_DEBUG2, "pkg %s: file=%s\n", pkg->name, installed_file);
-              file_hash_set_file_owner(conf, installed_file, pkg);
-         }
-         pkg_free_installed_files(pkg);
-     }
-     pkg_vec_free(installed_pkgs);
-
-     return 0;
-}
+       if (conf->noaction)
+               return 0;
 
-struct pkg_write_filelist_data {
-     opkg_conf_t *conf;
-     pkg_t *pkg;
-     FILE *stream;
-};
+       opkg_msg(INFO, "Saving changed filelists.\n");
 
-void pkg_write_filelist_helper(const char *key, void *entry_, void *data_)
-{
-     struct pkg_write_filelist_data *data = data_;
-     pkg_t *entry = entry_;
-     if (entry == data->pkg) {
-         fprintf(data->stream, "%s\n", key);
-     }
-}
+       pkg_hash_fetch_all_installed(installed_pkgs);
+       for (i = 0; i < installed_pkgs->len; i++) {
+               pkg_t *pkg = installed_pkgs->pkgs[i];
+               if (pkg->state_flag & SF_FILELIST_CHANGED) {
+                       err = pkg_write_filelist(pkg);
+                       if (err)
+                               ret = -1;
+               }
+       }
 
-int pkg_write_filelist(opkg_conf_t *conf, pkg_t *pkg)
-{
-     struct pkg_write_filelist_data data;
-     char *list_file_name = NULL;
-     int err = 0;
-
-     if (!pkg) {
-         opkg_message(conf, OPKG_ERROR, "Null pkg\n");
-         return -EINVAL;
-     }
-     opkg_message(conf, OPKG_INFO,
-                 "    creating %s.list file\n", pkg->name);
-     sprintf_alloc(&list_file_name, "%s/%s.list", pkg->dest->info_dir, pkg->name);
-     if (!list_file_name) {
-         opkg_message(conf, OPKG_ERROR, "Failed to alloc list_file_name\n");
-         return -ENOMEM;
-     }
-     opkg_message(conf, OPKG_INFO,
-                 "    creating %s file for pkg %s\n", list_file_name, pkg->name);
-     data.stream = fopen(list_file_name, "w");
-     if (!data.stream) {
-         opkg_message(conf, OPKG_ERROR, "Could not open %s for writing: %s\n",
-                      list_file_name, strerror(errno));
-                      return errno;
-     }
-     data.pkg = pkg;
-     data.conf = conf;
-     hash_table_foreach(&conf->file_hash, pkg_write_filelist_helper, &data);
-     fclose(data.stream);
-     free(list_file_name);
-
-     return err;
-}
+       pkg_vec_free(installed_pkgs);
 
-int pkg_write_changed_filelists(opkg_conf_t *conf)
-{
-     pkg_vec_t *installed_pkgs = pkg_vec_alloc();
-     hash_table_t *pkg_hash = &conf->pkg_hash;
-     int i;
-     int err;
-     if (conf->noaction)
-         return 0;
-
-     opkg_message(conf, OPKG_INFO, "%s: saving changed filelists\n", __FUNCTION__);
-     pkg_hash_fetch_all_installed(pkg_hash, installed_pkgs);
-     for (i = 0; i < installed_pkgs->len; i++) {
-         pkg_t *pkg = installed_pkgs->pkgs[i];
-         if (pkg->state_flag & SF_FILELIST_CHANGED) {
-               opkg_message(conf, OPKG_DEBUG, "Calling pkg_write_filelist for pkg=%s from %s\n", pkg->name, __FUNCTION__);
-              err = pkg_write_filelist(conf, pkg);
-              if (err)
-                   opkg_message(conf, OPKG_NOTICE, "pkg_write_filelist pkg=%s returned %d\n", pkg->name, err);
-         }
-     }
-     pkg_vec_free (installed_pkgs);
-     return 0;
+       return ret;
 }