Use the filename arg as a base for the temp file. Clean up function while here.
[oweals/opkg-lede.git] / libopkg / pkg.c
index 93fd20aa9842bca54a88c3bea351c57b5c9d4e8c..0c0a7d9e8127e2360b753416a83e3712e47a9f0f 100644 (file)
@@ -1,4 +1,4 @@
-/* pkg.c - the itsy package management system
+/* pkg.c - the opkg package management system
 
    Carl D. Worth
 
    General Public License for more details.
 */
 
-#include "opkg.h"
+#include "includes.h"
 #include <ctype.h>
+#include <alloca.h>
 #include <string.h>
+#include <stdbool.h>
 #include <errno.h>
 
 #include "pkg.h"
@@ -27,6 +29,7 @@
 #include "opkg_message.h"
 #include "opkg_utils.h"
 
+#include "libbb/libbb.h"
 #include "sprintf_alloc.h"
 #include "file_util.h"
 #include "str_util.h"
@@ -76,12 +79,7 @@ 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 = xcalloc(1, sizeof(pkg_t));
      pkg_init(pkg);
 
      return pkg;
@@ -89,12 +87,10 @@ pkg_t *pkg_new(void)
 
 int pkg_init(pkg_t *pkg)
 {
-     memset(pkg, 0, sizeof(pkg_t));
      pkg->name = NULL;
      pkg->epoch = 0;
      pkg->version = NULL;
      pkg->revision = NULL;
-     pkg->familiar_revision = NULL;
      pkg->dest = NULL;
      pkg->src = NULL;
      pkg->architecture = NULL;
@@ -112,6 +108,8 @@ int pkg_init(pkg_t *pkg)
      pkg->recommends_str = NULL;
      pkg->suggests_count = 0;
      pkg->recommends_count = 0;
+     
+     active_list_init(&pkg->list);
 
      /* Abhaya: added init for conflicts fields */
      pkg->conflicts = NULL;
@@ -129,6 +127,9 @@ int pkg_init(pkg_t *pkg)
      pkg->local_filename = NULL;
      pkg->tmp_unpack_dir = NULL;
      pkg->md5sum = NULL;
+#if defined HAVE_SHA256
+     pkg->sha256sum = NULL;
+#endif
      pkg->size = NULL;
      pkg->installed_size = NULL;
      pkg->priority = NULL;
@@ -142,94 +143,220 @@ int pkg_init(pkg_t *pkg)
      return 0;
 }
 
+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);
+}
+
 void pkg_deinit(pkg_t *pkg)
 {
-     free(pkg->name);
-     pkg->name = NULL;
-     pkg->epoch = 0;
-     free(pkg->version);
-     pkg->version = NULL;
-     /* revision and familiar_revision share storage with version, so
-       don't free */
-     pkg->revision = NULL;
-     pkg->familiar_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;
-     free(pkg->depends_str);
-     pkg->depends_str = NULL;
-     free(pkg->provides_str);
-     pkg->provides_str = NULL;
-     pkg->depends_count = 0;
-     /* XXX: CLEANUP: MEMORY_LEAK: how to free up pkg->depends ? */
-     pkg->pre_depends_count = 0;
-     free(pkg->pre_depends_str);
-     pkg->pre_depends_str = NULL;
-     pkg->provides_count = 0;
-     /* XXX: CLEANUP: MEMORY_LEAK: how to free up pkg->provides ? */
-     /* XXX: CLEANUP: MEMORY_LEAK: how to free up pkg->suggests ? */
-     free(pkg->filename);
-     pkg->filename = NULL;
-     free(pkg->local_filename);
-     pkg->local_filename = NULL;
+       int i;
+
+       if (pkg->name)
+               free(pkg->name);
+       pkg->name = NULL;
+
+       pkg->epoch = 0;
+
+       if (pkg->version)
+               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;
+
+       if (pkg->architecture)
+               free(pkg->architecture);
+       pkg->architecture = NULL;
+
+       if (pkg->maintainer)
+               free(pkg->maintainer);
+       pkg->maintainer = NULL;
+
+       if (pkg->section)
+               free(pkg->section);
+       pkg->section = NULL;
+
+       if (pkg->description)
+               free(pkg->description);
+       pkg->description = 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;
+
+       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-1; 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;
+
+               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;
+       if (pkg->pre_depends_str)
+               free(pkg->pre_depends_str);
+       pkg->pre_depends_str = NULL;
+       
+       pkg->provides_count = 0;
+       
+       if (pkg->filename)
+               free(pkg->filename);
+       pkg->filename = NULL;
+       
+       if (pkg->local_filename)
+               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;
-}
+       if (pkg->tmp_unpack_dir)
+               free(pkg->tmp_unpack_dir);
+       pkg->tmp_unpack_dir = NULL;
 
-int pkg_init_from_file(pkg_t *pkg, const char *filename)
-{
-     int err;
-     char **raw;
-     FILE *control_file;
+       if (pkg->md5sum)
+               free(pkg->md5sum);
+       pkg->md5sum = NULL;
 
-     err = pkg_init(pkg);
-     if (err) { return err; }
+#if defined HAVE_SHA256
+       if (pkg->sha256sum)
+               free(pkg->sha256sum);
+       pkg->sha256sum = NULL;
+#endif
 
-     pkg->local_filename = strdup(filename);
-    
-     control_file = tmpfile();
-     err = pkg_extract_control_file_to_stream(pkg, control_file);
-     if (err) { return err; }
+       if (pkg->size)
+               free(pkg->size);
+       pkg->size = NULL;
 
-     rewind(control_file);
-     raw = read_raw_pkgs_from_stream(control_file);
-     pkg_parse_raw(pkg, &raw, NULL, NULL);
+       if (pkg->installed_size)
+               free(pkg->installed_size);
+       pkg->installed_size = NULL;
 
-     fclose(control_file);
+       if (pkg->priority)
+               free(pkg->priority);
+       pkg->priority = NULL;
 
-     return 0;
+       if (pkg->source)
+               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;
+
+       if (pkg->tags)
+               free (pkg->tags);
+       pkg->tags = NULL;
+}
+
+int
+pkg_init_from_file(pkg_t *pkg, const char *filename)
+{
+       int fd, err = 0;
+       FILE *control_file;
+       char *control_path;
+
+       pkg_init(pkg);
+
+       pkg->local_filename = xstrdup(filename);
+
+       sprintf_alloc(&control_path, "%s.control.XXXXXX", filename);
+       fd = mkstemp(control_path);
+       if (fd == -1) {
+               perror_msg("%s: mkstemp(%s)", __FUNCTION__, control_path);
+               err = -1;
+               goto err0;
+       }
+
+       control_file = fdopen(fd, "rw");
+       if (control_file == NULL) {
+               perror_msg("%s: fdopen", __FUNCTION__, control_path);
+               close(fd);
+               err = -1;
+               goto err1;
+       }
+
+       err = pkg_extract_control_file_to_stream(pkg, control_file);
+       if (err)
+               goto err2;
+
+       rewind(control_file);
+       pkg_parse_from_stream(pkg, control_file, PFM_ALL);
+
+err2:
+       fclose(control_file);
+err1:
+       unlink(control_path);
+err0:
+       free(control_path);
+
+       return err;
 }
 
 /* Merge any new information in newpkg into oldpkg */
@@ -251,15 +378,15 @@ int pkg_merge(pkg_t *oldpkg, pkg_t *newpkg, int set_status)
      if (!oldpkg->dest)
          oldpkg->dest = newpkg->dest;
      if (!oldpkg->architecture)
-         oldpkg->architecture = str_dup_safe(newpkg->architecture);
+         oldpkg->architecture = xstrdup(newpkg->architecture);
      if (!oldpkg->arch_priority)
          oldpkg->arch_priority = newpkg->arch_priority;
      if (!oldpkg->section)
-         oldpkg->section = str_dup_safe(newpkg->section);
+         oldpkg->section = xstrdup(newpkg->section);
      if(!oldpkg->maintainer)
-         oldpkg->maintainer = str_dup_safe(newpkg->maintainer);
+         oldpkg->maintainer = xstrdup(newpkg->maintainer);
      if(!oldpkg->description)
-         oldpkg->description = str_dup_safe(newpkg->description);
+         oldpkg->description = xstrdup(newpkg->description);
      if (set_status) {
          /* merge the state_flags from the new package */
          oldpkg->state_want = newpkg->state_want;
@@ -304,8 +431,10 @@ int pkg_merge(pkg_t *oldpkg, pkg_t *newpkg, int set_status)
          oldpkg->provides_count = newpkg->provides_count;
          newpkg->provides_count = 0;
 
-         oldpkg->provides = newpkg->provides;
-         newpkg->provides = NULL;
+         if (!oldpkg->provides) {
+               oldpkg->provides = newpkg->provides;
+               newpkg->provides = NULL;
+         }
      }
 
      if (!oldpkg->conflicts_str) {
@@ -329,26 +458,27 @@ int pkg_merge(pkg_t *oldpkg, pkg_t *newpkg, int set_status)
      }
 
      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);
+         oldpkg->filename = xstrdup(newpkg->filename);
      if (!oldpkg->local_filename)
-         oldpkg->local_filename = str_dup_safe(newpkg->local_filename);
+         oldpkg->local_filename = xstrdup(newpkg->local_filename);
      if (!oldpkg->tmp_unpack_dir)
-         oldpkg->tmp_unpack_dir = str_dup_safe(newpkg->tmp_unpack_dir);
+         oldpkg->tmp_unpack_dir = xstrdup(newpkg->tmp_unpack_dir);
      if (!oldpkg->md5sum)
-         oldpkg->md5sum = str_dup_safe(newpkg->md5sum);
+         oldpkg->md5sum = xstrdup(newpkg->md5sum);
+#if defined HAVE_SHA256
+     if (!oldpkg->sha256sum)
+         oldpkg->sha256sum = xstrdup(newpkg->sha256sum);
+#endif
      if (!oldpkg->size)
-         oldpkg->size = str_dup_safe(newpkg->size);
+         oldpkg->size = xstrdup(newpkg->size);
      if (!oldpkg->installed_size)
-         oldpkg->installed_size = str_dup_safe(newpkg->installed_size);
+         oldpkg->installed_size = xstrdup(newpkg->installed_size);
      if (!oldpkg->priority)
-         oldpkg->priority = str_dup_safe(newpkg->priority);
+         oldpkg->priority = xstrdup(newpkg->priority);
      if (!oldpkg->source)
-         oldpkg->source = str_dup_safe(newpkg->source);
-     if (oldpkg->conffiles.head == NULL){
-         oldpkg->conffiles = newpkg->conffiles;
+         oldpkg->source = xstrdup(newpkg->source);
+     if (nv_pair_list_empty(&oldpkg->conffiles)){
+         list_splice_init(&newpkg->conffiles.head, &oldpkg->conffiles.head);
          conffile_list_init(&newpkg->conffiles);
      }
      if (!oldpkg->installed_files){
@@ -366,7 +496,7 @@ abstract_pkg_t *abstract_pkg_new(void)
 {
      abstract_pkg_t * ab_pkg;
 
-     ab_pkg = malloc(sizeof(abstract_pkg_t));
+     ab_pkg = xcalloc(1, sizeof(abstract_pkg_t));
 
      if (ab_pkg == NULL) {
          fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
@@ -381,8 +511,6 @@ abstract_pkg_t *abstract_pkg_new(void)
 
 int abstract_pkg_init(abstract_pkg_t *ab_pkg)
 {
-     memset(ab_pkg, 0, sizeof(abstract_pkg_t));
-
      ab_pkg->provided_by = abstract_pkg_vec_alloc();
      if (ab_pkg->provided_by==NULL){
         return -1;
@@ -394,177 +522,49 @@ int abstract_pkg_init(abstract_pkg_t *ab_pkg)
 }
 
 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;
-     }
+     char *file_name;
+     FILE *fp;
 
-     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++);
-     }
+     sprintf_alloc(&file_name,"%s/%s.control", pkg->dest->info_dir, pkg->name);
 
-     free(raw_start); 
-     free(temp_str);
-
-     return ;
-
-}
-
-char * pkg_formatted_info(pkg_t *pkg )
-{
-     char *line;
-     char * buff;
-
-     buff = malloc(8192);
-     if (buff == NULL) {
-         fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
-         return NULL;
+     fp = fopen(file_name, "r");
+     if (fp == NULL) {
+            opkg_message(conf, OPKG_ERROR, "fopen(%s): %s\n",
+                            file_name, strerror(errno));
+            free(file_name);
+            return;
      }
 
-     buff[0] = '\0';
+     free(file_name);
 
-     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);
+     if (pkg_parse_from_stream(pkg, fp, PFM_ESSENTIAL)) {
+        opkg_message(conf, OPKG_DEBUG, "unable to read control file for %s. May be empty\n", pkg->name);
+     }
 
-     line = pkg_formatted_field(pkg, "Installed-Time");
-     strncat(buff ,line, strlen(line));
-     free(line);
+     fclose(fp);
 
-     return buff;
+     return;
 }
 
-char * pkg_formatted_field(pkg_t *pkg, const char *field )
+void pkg_formatted_field(FILE *fp, pkg_t *pkg, const char *field)
 {
-     static size_t LINE_LEN = 128;
-     char * temp = (char *)malloc(1);
-     int len = 0;
-     int flag_provide_false = 0;
-
-/*
-  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 )
-*/
+     int i;
 
      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);
+                   fprintf(fp, "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);
-               }
+               if (pkg->auto_installed)
+                   fprintf(fp, "Auto-Installed: yes\n");
          } else {
               goto UNKNOWN_FMT_FIELD;
          }
@@ -572,54 +572,26 @@ char * pkg_formatted_field(pkg_t *pkg, const char *field )
      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;
-              }
+              if (nv_pair_list_empty(&pkg->conffiles))
+                   return;
 
-               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));           
+               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) {
-              int i;
-
               if (pkg->conflicts_count) {
-                    char conflictstr[LINE_LEN];
-                    len = 14 ;
+                    fprintf(fp, "Conflicts:");
                    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;
+                        fprintf(fp, "%s %s", i == 0 ? "" : ",", pkg->conflicts_str[i]);
                     }
-                    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")); 
+                    fprintf(fp, "\n");
               }
          } else {
               goto UNKNOWN_FMT_FIELD;
@@ -628,361 +600,192 @@ char * pkg_formatted_field(pkg_t *pkg, const char *field )
      case 'd':
      case 'D':
          if (strcasecmp(field, "Depends") == 0) {
-              /* Depends */
-              int i;
-
               if (pkg->depends_count) {
-                    char depstr[LINE_LEN];
-                    len = 14 ;
+                    fprintf(fp, "Depends:");
                    for(i = 0; i < pkg->depends_count; i++) {
-                        len = len + (strlen(pkg->depends_str[i])+4);
+                        fprintf(fp, "%s %s", i == 0 ? "" : ",", pkg->depends_str[i]);
                     }
-                    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")); 
+                   fprintf(fp, "\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);
+                   fprintf(fp, "Description: %s\n", pkg->description);
               }
          } else {
               goto UNKNOWN_FMT_FIELD;
          }
-      break;
+          break;
      case 'e':
-     case 'E': {
-         /* Essential */
+     case 'E':
          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");
+              fprintf(fp, "Essential: yes\n");
          }
-     }
          break;
      case 'f':
-     case 'F': {
-         /* Filename */
+     case 'F':
          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);
+              fprintf(fp, "Filename: %s\n", pkg->filename);
          }
-     }
          break;
      case 'i':
-     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);
+               fprintf(fp, "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);
+               fprintf(fp, "Installed-Time: %lu\n", pkg->installed_time);
          }
-     }
          break;
      case 'm':
-     case 'M': {
-         /* Maintainer | MD5sum */
+     case 'M':
          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);
+                   fprintf(fp, "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);
+                   fprintf(fp, "MD5Sum: %s\n", pkg->md5sum);
               }
          } else {
               goto UNKNOWN_FMT_FIELD;
          }
-     }
          break;
      case 'p':
-     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);
+               fprintf(fp, "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);
+               fprintf(fp, "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")); 
+                  fprintf(fp, "Provides:");
+                 for(i = 0; i < pkg->provides_count-1; i++) {
+                      fprintf(fp, "%s %s", i == 0 ? "" : ",", pkg->provides_str[i]);
                   }
+                  fprintf(fp, "\n");
                }
          } else {
               goto UNKNOWN_FMT_FIELD;
          }
-     }
          break;
      case 'r':
-     case 'R': {
-         int i;
-         /* Replaces | Recommends*/
+     case 'R':
          if (strcasecmp (field, "Replaces") == 0) {
               if (pkg->replaces_count) {
-                    char replstr[LINE_LEN];
-                    len = 14;
+                    fprintf(fp, "Replaces:");
                    for (i = 0; i < pkg->replaces_count; i++) {
-                        len = len + (strlen(pkg->replaces_str[i])+5);
+                        fprintf(fp, "%s %s", i == 0 ? "" : ",", pkg->replaces_str[i]);
                     }
-                    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")); 
+                    fprintf(fp, "\n");
               }
          } else if (strcasecmp (field, "Recommends") == 0) {
               if (pkg->recommends_count) {
-                    char recstr[LINE_LEN];
-                    len = 15;
+                    fprintf(fp, "Recommends:");
                    for(i = 0; i < pkg->recommends_count; i++) {
-                         len = len + (strlen( pkg->recommends_str[i])+5);
+                        fprintf(fp, "%s %s", i == 0 ? "" : ",", pkg->recommends_str[i]);
                     }
-                    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")); 
+                    fprintf(fp, "\n");
               }
          } else {
               goto UNKNOWN_FMT_FIELD;
          }
-     }
          break;
      case 's':
-     case 'S': {
-         /* Section | Size | Source | Status | Suggests */
+     case 'S':
          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);
+                   fprintf(fp, "Section: %s\n", pkg->section);
               }
+#if defined HAVE_SHA256
+         } else if (strcasecmp(field, "SHA256sum") == 0) {
+              if (pkg->sha256sum) {
+                   fprintf(fp, "SHA256sum: %s\n", pkg->sha256sum);
+              }
+#endif
          } 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);
+                   fprintf(fp, "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);
+                   fprintf(fp, "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);
+               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);
+
+              if (pflag == NULL || pstat == NULL || pwant == NULL)
+                      return;
+
+               fprintf(fp, "Status: %s %s %s\n", pwant, pflag, pstat);
+
+               free(pflag);
+               free(pwant);
+               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);
+                    fprintf(fp, "Suggests:");
                    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));           
+                        fprintf(fp, "%s %s", i == 0 ? "" : ",", pkg->suggests_str[i]);
                     }
-                    strncat(temp, "\n", strlen("\n")); 
+                    fprintf(fp, "\n");
               }
          } else {
               goto UNKNOWN_FMT_FIELD;
          }
-     }
+         break;
+     case 't':
+     case 'T':
+         if (strcasecmp(field, "Tags") == 0) {
+              if (pkg->tags) {
+                   fprintf(fp, "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;
+     case 'V':
+         {
+              char *version = pkg_version_str_alloc(pkg);
+              if (version == NULL)
+                   return;
+               fprintf(fp, "Version: %s\n", version);
+              free(version);
           }
-          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;
+     return;
 
- UNKNOWN_FMT_FIELD:
+UNKNOWN_FMT_FIELD:
      fprintf(stderr, "%s: ERROR: Unknown field name: %s\n", __FUNCTION__, field);
-     if ( strlen(temp)<2 ) {
-          temp[0]='\0';
-     }
-
-     return temp;
 }
 
-void pkg_print_info(pkg_t *pkg, FILE *file)
+void pkg_formatted_info(FILE *fp, pkg_t *pkg)
 {
-     char * buff;
-     if (pkg == NULL) {
-       return;
-     }
-
-     buff = pkg_formatted_info(pkg);
-     if ( buff == NULL ) 
-         return;
-     if (strlen(buff)>2){
-         fwrite(buff, 1, strlen(buff), file);
-     } 
-     free(buff);
+       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_status(pkg_t * pkg, FILE * file)
@@ -998,7 +801,7 @@ void pkg_print_status(pkg_t * pkg, FILE * file)
        can be found in th available file.
 
        But, someone proposed the idea to make it possible to
-       reconstruct a .ipk from an installed package, (ie. for beaming
+       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
@@ -1011,39 +814,23 @@ void pkg_print_status(pkg_t * pkg, FILE * file)
        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");
+     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);
 }
 
-void pkg_print_field(pkg_t *pkg, FILE *file, const char *field)
-{
-     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;
-}
-
 /*
  * libdpkg - Debian packaging suite library routines
  * vercmp.c - comparison of version numbers
@@ -1138,10 +925,10 @@ int pkg_version_satisfied(pkg_t *it, pkg_t *ref, const char *op)
      return 0;
 }
 
-int pkg_name_version_and_architecture_compare(void *p1, void *p2)
+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;
+     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) {
@@ -1168,7 +955,7 @@ int pkg_name_version_and_architecture_compare(void *p1, void *p2)
      return 0;
 }
 
-int abstract_pkg_name_compare(void *p1, void *p2)
+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;
@@ -1181,42 +968,37 @@ int abstract_pkg_name_compare(void *p1, void *p2)
 }
 
 
-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;
-
-     if (pkg->epoch) {
-         sprintf_alloc(&epoch_str, "%d:", pkg->epoch);
-     } else {
-         epoch_str = strdup("");
-     }
-
-     if (pkg->revision && strlen(pkg->revision)) {
-         sprintf_alloc(&revision_str, "-%s", pkg->revision);
-     } else {
-         revision_str = strdup("");
-     }
-
-
-     sprintf_alloc(&complete_version, "%s%s%s",
-                  epoch_str, pkg->version, revision_str);
-
-     free(epoch_str);
-     free(revision_str);
-
-     return complete_version;
+       char *version;
+
+       if (pkg->epoch) {
+               if (pkg->revision)
+                       sprintf_alloc(&version, "%d:%s-%s",
+                               pkg->epoch, pkg->version, pkg->revision);
+               else
+                       sprintf_alloc(&version, "%d:%s",
+                               pkg->epoch, pkg->version);
+       } else {
+               if (pkg->revision)
+                       sprintf_alloc(&version, "%s-%s",
+                               pkg->version, pkg->revision);
+               else
+                       version = xstrdup(pkg->version);
+       }
+
+       return version;
 }
 
-str_list_t *pkg_get_installed_files(pkg_t *pkg)
+str_list_t *pkg_get_installed_files(opkg_conf_t *conf, pkg_t *pkg)
 {
      int err;
      char *list_file_name = NULL;
      FILE *list_file = NULL;
      char *line;
      char *installed_file_name;
-     int rootdirlen;
+     int rootdirlen = 0;
 
      pkg->installed_files_ref_cnt++;
 
@@ -1225,12 +1007,8 @@ str_list_t *pkg_get_installed_files(pkg_t *pkg)
      }
 
      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 uninstalled packages, get the file list directly 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) {
@@ -1268,7 +1046,9 @@ str_list_t *pkg_get_installed_files(pkg_t *pkg)
          free(list_file_name);
      }
 
-     rootdirlen = strlen( pkg->dest->root_dir );
+     if (conf->offline_root)
+          rootdirlen = strlen(conf->offline_root);
+
      while (1) {
          char *file_name;
        
@@ -1279,24 +1059,27 @@ str_list_t *pkg_get_installed_files(pkg_t *pkg)
          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 (pkg->state_status == SS_NOT_INSTALLED) {
               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);
+              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);
+              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);
      }
 
@@ -1312,22 +1095,13 @@ str_list_t *pkg_get_installed_files(pkg_t *pkg)
    work. */
 int pkg_free_installed_files(pkg_t *pkg)
 {
-     str_list_elt_t *iter;
-
      pkg->installed_files_ref_cnt--;
-     if (pkg->installed_files_ref_cnt > 0) {
+
+     if (pkg->installed_files_ref_cnt > 0)
          return 0;
-     }
 
      if (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;
-         }
-
-         str_list_deinit(pkg->installed_files);
+         str_list_purge(pkg->installed_files);
      }
 
      pkg->installed_files = NULL;
@@ -1365,8 +1139,8 @@ conffile_t *pkg_get_conffile(pkg_t *pkg, const char *file_name)
          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;
@@ -1383,6 +1157,33 @@ int pkg_run_script(opkg_conf_t *conf, pkg_t *pkg,
      char *path;
      char *cmd;
 
+     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. */
+     /*
+      * Attempt to provide a restricted environment for offline operation
+      * Need the following set as a minimum:
+      * OPKG_OFFLINE_ROOT = absolute path to root dir
+      * D                 = absolute path to root dir (for OE generated postinst)
+      * PATH              = something safe (a restricted set of utilities)
+      */
+
+     if (conf->offline_root) {
+          if (conf->offline_root_path) {
+            setenv("PATH", conf->offline_root_path, 1);
+          } else {
+            opkg_message(conf, OPKG_NOTICE, 
+               "(offline root mode: not running %s.%s)\n", pkg->name, script);
+           return 0;
+          }
+         setenv("OPKG_OFFLINE_ROOT", conf->offline_root, 1);
+         setenv("D", conf->offline_root, 1);
+     }
+
      /* XXX: FEATURE: When conf->offline_root is set, we should run the
        maintainer script within a chroot environment. */
 
@@ -1405,15 +1206,6 @@ int pkg_run_script(opkg_conf_t *conf, pkg_t *pkg,
      }
 
      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);
@@ -1423,16 +1215,12 @@ int pkg_run_script(opkg_conf_t *conf, pkg_t *pkg,
          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);
+     {
+         const char *argv[] = {"sh", "-c", cmd, NULL};
+         err = xsystem(argv);
+     }
      free(cmd);
 
      if (err) {
@@ -1449,13 +1237,13 @@ char *pkg_state_want_to_str(pkg_state_want_t sw)
 
      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);
+              return xstrdup(pkg_state_want_map[i].str);
          }
      }
 
      fprintf(stderr, "%s: ERROR: Illegal value for state_want: %d\n",
             __FUNCTION__, sw);
-     return strdup("<STATE_WANT_UNKNOWN>");
+     return xstrdup("<STATE_WANT_UNKNOWN>");
 }
 
 pkg_state_want_t pkg_state_want_from_str(char *str)
@@ -1483,7 +1271,7 @@ char *pkg_state_flag_to_str(pkg_state_flag_t sf)
      sf &= SF_NONVOLATILE_FLAGS;
 
      if (sf == 0) {
-         return strdup("ok");
+         return xstrdup("ok");
      } else {
 
          for (i=0; i < ARRAY_SIZE(pkg_state_flag_map); i++) {
@@ -1491,11 +1279,7 @@ char *pkg_state_flag_to_str(pkg_state_flag_t sf)
                    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 = xmalloc(len);
          str[0] = 0;
          for (i=0; i < ARRAY_SIZE(pkg_state_flag_map); i++) {
               if (sf & pkg_state_flag_map[i].value) {
@@ -1540,13 +1324,13 @@ char *pkg_state_status_to_str(pkg_state_status_t ss)
 
      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);
+              return xstrdup(pkg_state_status_map[i].str);
          }
      }
 
      fprintf(stderr, "%s: ERROR: Illegal value for state_status: %d\n",
             __FUNCTION__, ss);
-     return strdup("<STATE_STATUS_UNKNOWN>");
+     return xstrdup("<STATE_STATUS_UNKNOWN>");
 }
 
 pkg_state_status_t pkg_state_status_from_str(const char *str)
@@ -1571,15 +1355,12 @@ int pkg_arch_supported(opkg_conf_t *conf, pkg_t *pkg)
      if (!pkg->architecture)
          return 1;
 
-     l = conf->arch_list.head;
-
-     while (l) {
-         nv_pair_t *nv = l->data;
+     list_for_each_entry(l , &conf->arch_list.head, node) {
+         nv_pair_t *nv = (nv_pair_t *)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;
      }
 
      opkg_message(conf, OPKG_DEBUG, "arch %s unsupported for pkg %s\n", pkg->architecture, pkg->name);
@@ -1590,15 +1371,12 @@ int pkg_get_arch_priority(opkg_conf_t *conf, const char *archname)
 {
      nv_pair_list_elt_t *l;
 
-     l = conf->arch_list.head;
-
-     while (l) {
-         nv_pair_t *nv = l->data;
+     list_for_each_entry(l , &conf->arch_list.head, node) {
+         nv_pair_t *nv = (nv_pair_t *)l->data;
          if (strcmp(nv->name, archname) == 0) {
               int priority = strtol(nv->value, NULL, 0);
               return priority;
          }
-         l = l->next;
      }
      return 0;
 }
@@ -1631,7 +1409,7 @@ int pkg_info_preinstall_check(opkg_conf_t *conf)
          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_NOTICE, "Clearing state_want and state_flag for pkg=%s (arch_priority=%d flag=%d want=%d)\n", 
+              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;
@@ -1644,17 +1422,20 @@ int pkg_info_preinstall_check(opkg_conf_t *conf)
      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;
+         str_list_t *installed_files = pkg_get_installed_files(conf, pkg); /* this causes installed_files to be cached */
+         str_list_elt_t *iter, *niter;
          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;
+         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;
               // 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);
 
@@ -1707,6 +1488,8 @@ int pkg_write_filelist(opkg_conf_t *conf, pkg_t *pkg)
      fclose(data.stream);
      free(list_file_name);
 
+     pkg->state_flag &= ~SF_FILELIST_CHANGED;
+
      return err;
 }
 
@@ -1730,5 +1513,6 @@ int pkg_write_changed_filelists(opkg_conf_t *conf)
                    opkg_message(conf, OPKG_NOTICE, "pkg_write_filelist pkg=%s returned %d\n", pkg->name, err);
          }
      }
+     pkg_vec_free (installed_pkgs);
      return 0;
 }