reduce a meory leak
[oweals/opkg-lede.git] / libopkg / pkg.c
index 93fd20aa9842bca54a88c3bea351c57b5c9d4e8c..98a929cd4d0d788d00fdaabd3f3724d7c307defb 100644 (file)
@@ -1,4 +1,4 @@
-/* pkg.c - the itsy package management system
+/* pkg.c - the opkg package management system
 
    Carl D. Worth
 
 
    Carl D. Worth
 
    General Public License for more details.
 */
 
    General Public License for more details.
 */
 
-#include "opkg.h"
+#include "includes.h"
 #include <ctype.h>
 #include <ctype.h>
+#include <alloca.h>
 #include <string.h>
 #include <string.h>
+#include <stdbool.h>
 #include <errno.h>
 
 #include "pkg.h"
 #include <errno.h>
 
 #include "pkg.h"
@@ -76,7 +78,7 @@ pkg_t *pkg_new(void)
 {
      pkg_t *pkg;
 
 {
      pkg_t *pkg;
 
-     pkg = malloc(sizeof(pkg_t));
+     pkg = calloc(1, sizeof(pkg_t));
      if (pkg == NULL) {
          fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
          return NULL;
      if (pkg == NULL) {
          fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
          return NULL;
@@ -89,12 +91,10 @@ pkg_t *pkg_new(void)
 
 int pkg_init(pkg_t *pkg)
 {
 
 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->name = NULL;
      pkg->epoch = 0;
      pkg->version = NULL;
      pkg->revision = NULL;
-     pkg->familiar_revision = NULL;
      pkg->dest = NULL;
      pkg->src = NULL;
      pkg->architecture = NULL;
      pkg->dest = NULL;
      pkg->src = NULL;
      pkg->architecture = NULL;
@@ -112,6 +112,8 @@ int pkg_init(pkg_t *pkg)
      pkg->recommends_str = NULL;
      pkg->suggests_count = 0;
      pkg->recommends_count = 0;
      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;
 
      /* Abhaya: added init for conflicts fields */
      pkg->conflicts = NULL;
@@ -142,17 +144,31 @@ int pkg_init(pkg_t *pkg)
      return 0;
 }
 
      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)
 {
 void pkg_deinit(pkg_t *pkg)
 {
+     int i;
+
      free(pkg->name);
      pkg->name = NULL;
      pkg->epoch = 0;
      free(pkg->version);
      pkg->version = NULL;
      free(pkg->name);
      pkg->name = NULL;
      pkg->epoch = 0;
      free(pkg->version);
      pkg->version = NULL;
-     /* revision and familiar_revision share storage with version, so
+     /* revision shares storage with version, so
        don't free */
      pkg->revision = NULL;
        don't free */
      pkg->revision = NULL;
-     pkg->familiar_revision = NULL;
      /* owned by opkg_conf_t */
      pkg->dest = NULL;
      /* owned by opkg_conf_t */
      /* owned by opkg_conf_t */
      pkg->dest = NULL;
      /* owned by opkg_conf_t */
@@ -168,18 +184,66 @@ void pkg_deinit(pkg_t *pkg)
      pkg->state_want = SW_UNKNOWN;
      pkg->state_flag = SF_OK;
      pkg->state_status = SS_NOT_INSTALLED;
      pkg->state_want = SW_UNKNOWN;
      pkg->state_flag = SF_OK;
      pkg->state_status = SS_NOT_INSTALLED;
+
+     active_list_clear(&pkg->list);
+
+     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;
      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;
      free(pkg->provides_str);
      pkg->provides_str = NULL;
-     pkg->depends_count = 0;
-     /* XXX: CLEANUP: MEMORY_LEAK: how to free up pkg->depends ? */
+
+     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;
      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);
      free(pkg->filename);
      pkg->filename = NULL;
      free(pkg->local_filename);
@@ -206,6 +270,8 @@ void pkg_deinit(pkg_t *pkg)
      pkg->installed_files_ref_cnt = 1;
      pkg_free_installed_files(pkg);
      pkg->essential = 0;
      pkg->installed_files_ref_cnt = 1;
      pkg_free_installed_files(pkg);
      pkg->essential = 0;
+     free (pkg->tags);
+     pkg->tags = NULL;
 }
 
 int pkg_init_from_file(pkg_t *pkg, const char *filename)
 }
 
 int pkg_init_from_file(pkg_t *pkg, const char *filename)
@@ -347,8 +413,8 @@ int pkg_merge(pkg_t *oldpkg, pkg_t *newpkg, int set_status)
          oldpkg->priority = str_dup_safe(newpkg->priority);
      if (!oldpkg->source)
          oldpkg->source = str_dup_safe(newpkg->source);
          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;
+     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){
          conffile_list_init(&newpkg->conffiles);
      }
      if (!oldpkg->installed_files){
@@ -366,7 +432,7 @@ abstract_pkg_t *abstract_pkg_new(void)
 {
      abstract_pkg_t * ab_pkg;
 
 {
      abstract_pkg_t * ab_pkg;
 
-     ab_pkg = malloc(sizeof(abstract_pkg_t));
+     ab_pkg = calloc(1, sizeof(abstract_pkg_t));
 
      if (ab_pkg == NULL) {
          fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
 
      if (ab_pkg == NULL) {
          fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
@@ -381,8 +447,6 @@ abstract_pkg_t *abstract_pkg_new(void)
 
 int abstract_pkg_init(abstract_pkg_t *ab_pkg)
 {
 
 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;
      ab_pkg->provided_by = abstract_pkg_vec_alloc();
      if (ab_pkg->provided_by==NULL){
         return -1;
@@ -398,7 +462,10 @@ void set_flags_from_control(opkg_conf_t *conf, pkg_t *pkg){
      char **raw =NULL;
      char **raw_start=NULL; 
 
      char **raw =NULL;
      char **raw_start=NULL; 
 
-     temp_str = (char *) malloc (strlen(pkg->dest->info_dir)+strlen(pkg->name)+12);
+     size_t str_size = strlen(pkg->dest->info_dir)+strlen(pkg->name)+12;
+     temp_str = (char *) alloca (str_size);
+     memset(temp_str, 0 , str_size);
+     
      if (temp_str == NULL ){
         opkg_message(conf, OPKG_INFO, "Out of memory in  %s\n", __FUNCTION__);
         return;
      if (temp_str == NULL ){
         opkg_message(conf, OPKG_INFO, "Out of memory in  %s\n", __FUNCTION__);
         return;
@@ -423,102 +490,132 @@ void set_flags_from_control(opkg_conf_t *conf, pkg_t *pkg){
      }
 
      free(raw_start); 
      }
 
      free(raw_start); 
-     free(temp_str);
 
      return ;
 
 }
 
 
      return ;
 
 }
 
+#define CHECK_BUFF_SIZE(buff, line, buf_size, page_size) do { \
+        if (strlen(buff) + strlen(line) >= (buf_size)) { \
+            buf_size += page_size; \
+            buff = realloc(buff, buf_size); \
+        } \
+    } while(0)
 char * pkg_formatted_info(pkg_t *pkg )
 {
      char *line;
      char * buff;
 char * pkg_formatted_info(pkg_t *pkg )
 {
      char *line;
      char * buff;
+     const size_t page_size = 8192;
+     size_t buff_size = page_size;
 
 
-     buff = malloc(8192);
+     buff = calloc(1, buff_size);
      if (buff == NULL) {
          fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
          return NULL;
      }
 
      if (buff == NULL) {
          fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
          return NULL;
      }
 
-     buff[0] = '\0';
-
      line = pkg_formatted_field(pkg, "Package");
      line = pkg_formatted_field(pkg, "Package");
+     CHECK_BUFF_SIZE(buff, line, buff_size, page_size);
      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, "Version");
+     CHECK_BUFF_SIZE(buff, line, buff_size, page_size);
      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, "Depends");
+     CHECK_BUFF_SIZE(buff, line, buff_size, page_size);
      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, "Recommends");
+     CHECK_BUFF_SIZE(buff, line, buff_size, page_size);
      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, "Suggests");
+     CHECK_BUFF_SIZE(buff, line, buff_size, page_size);
      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, "Provides");
+     CHECK_BUFF_SIZE(buff, line, buff_size, page_size);
      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, "Replaces");
+     CHECK_BUFF_SIZE(buff, line, buff_size, page_size);
      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, "Conflicts");
+     CHECK_BUFF_SIZE(buff, line, buff_size, page_size);
      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, "Status");
+     CHECK_BUFF_SIZE(buff, line, buff_size, page_size);
      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, "Section");
+     CHECK_BUFF_SIZE(buff, line, buff_size, page_size);
      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, "Essential"); /* @@@@ should be removed in future release. *//* I do not agree with this Pigi*/
+     CHECK_BUFF_SIZE(buff, line, buff_size, page_size);
      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, "Architecture");
+     CHECK_BUFF_SIZE(buff, line, buff_size, page_size);
      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, "Maintainer");
+     CHECK_BUFF_SIZE(buff, line, buff_size, page_size);
      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, "MD5sum");
+     CHECK_BUFF_SIZE(buff, line, buff_size, page_size);
      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, "Size");
+     CHECK_BUFF_SIZE(buff, line, buff_size, page_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, "Filename");
+     CHECK_BUFF_SIZE(buff, line, buff_size, page_size);
      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, "Conffiles");
+     CHECK_BUFF_SIZE(buff, line, buff_size, page_size);
      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, "Source");
+     CHECK_BUFF_SIZE(buff, line, buff_size, page_size);
      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, "Description");
+     CHECK_BUFF_SIZE(buff, line, buff_size, page_size);
      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, "Installed-Time");
+     CHECK_BUFF_SIZE(buff, line, buff_size, page_size);
+     strncat(buff ,line, strlen(line));
+     free(line);
+
+     line = pkg_formatted_field(pkg, "Tags");
+     CHECK_BUFF_SIZE(buff, line, buff_size, page_size);
      strncat(buff ,line, strlen(line));
      free(line);
 
      strncat(buff ,line, strlen(line));
      free(line);
 
@@ -576,14 +673,14 @@ char * pkg_formatted_field(pkg_t *pkg, const char *field )
               conffile_list_elt_t *iter;
                char confstr[LINE_LEN];
 
               conffile_list_elt_t *iter;
                char confstr[LINE_LEN];
 
-              if (pkg->conffiles.head == NULL) {
+              if (nv_pair_list_empty(&pkg->conffiles)) {
                    return temp;
               }
 
                len = 14 ;
                    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);
+              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) {
+                       len = len + (strlen(((conffile_t *)iter->data)->name)+strlen(((conffile_t *)iter->data)->value)+5);
                    }
               }
                temp = (char *)realloc(temp,len);
                    }
               }
                temp = (char *)realloc(temp,len);
@@ -593,9 +690,11 @@ char * pkg_formatted_field(pkg_t *pkg, const char *field )
                }
                temp[0]='\0';
                strncpy(temp, "Conffiles:\n", 12);
                }
                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);
+              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) {
+                         snprintf(confstr, LINE_LEN, "%s %s\n", 
+                                 ((conffile_t *)iter->data)->name, 
+                                 ((conffile_t *)iter->data)->value);
                          strncat(temp, confstr, strlen(confstr));           
                    }
               }
                          strncat(temp, confstr, strlen(confstr));           
                    }
               }
@@ -937,6 +1036,21 @@ char * pkg_formatted_field(pkg_t *pkg, const char *field )
          }
      }
          break;
          }
      }
          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 */
      case 'v':
      case 'V': {
          /* Version */
@@ -971,6 +1085,7 @@ char * pkg_formatted_field(pkg_t *pkg, const char *field )
 
 void pkg_print_info(pkg_t *pkg, FILE *file)
 {
 
 void pkg_print_info(pkg_t *pkg, FILE *file)
 {
+  int t=0;
      char * buff;
      if (pkg == NULL) {
        return;
      char * buff;
      if (pkg == NULL) {
        return;
@@ -980,7 +1095,7 @@ void pkg_print_info(pkg_t *pkg, FILE *file)
      if ( buff == NULL ) 
          return;
      if (strlen(buff)>2){
      if ( buff == NULL ) 
          return;
      if (strlen(buff)>2){
-         fwrite(buff, 1, strlen(buff), file);
+       t = fwrite(buff, 1, strlen(buff), file); //#~rzr:TODO
      } 
      free(buff);
 }
      } 
      free(buff);
 }
@@ -998,7 +1113,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
        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
        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
@@ -1138,10 +1253,10 @@ int pkg_version_satisfied(pkg_t *it, pkg_t *ref, const char *op)
      return 0;
 }
 
      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) {
      int namecmp;
      int vercmp;
      if (!a->name || !b->name) {
@@ -1168,7 +1283,7 @@ int pkg_name_version_and_architecture_compare(void *p1, void *p2)
      return 0;
 }
 
      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;
 {
      const abstract_pkg_t *a = *(const abstract_pkg_t **)p1;
      const abstract_pkg_t *b = *(const abstract_pkg_t **)p2;
@@ -1230,7 +1345,7 @@ str_list_t *pkg_get_installed_files(pkg_t *pkg)
          return NULL;
      }
 
          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) {
        For installed packages, look at the package.list file in the database.
      */
      if (pkg->state_status == SS_NOT_INSTALLED || pkg->dest == NULL) {
@@ -1312,22 +1427,13 @@ str_list_t *pkg_get_installed_files(pkg_t *pkg)
    work. */
 int pkg_free_installed_files(pkg_t *pkg)
 {
    work. */
 int 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) {
+
+     if (pkg->installed_files_ref_cnt > 0)
          return 0;
          return 0;
-     }
 
      if (pkg->installed_files) {
 
      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_deinit(pkg->installed_files);
      }
 
      pkg->installed_files = NULL;
      }
 
      pkg->installed_files = NULL;
@@ -1365,8 +1471,8 @@ conffile_t *pkg_get_conffile(pkg_t *pkg, const char *file_name)
          return 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;
@@ -1411,8 +1517,24 @@ int pkg_run_script(opkg_conf_t *conf, pkg_t *pkg,
        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. */
        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)
+      */
+
+     bool AllowOfflineMode = false;
      if (conf->offline_root) {
          setenv("OPKG_OFFLINE_ROOT", conf->offline_root, 1);
      if (conf->offline_root) {
          setenv("OPKG_OFFLINE_ROOT", conf->offline_root, 1);
+         setenv("D", conf->offline_root, 1);
+          if (NULL == conf->offline_root_path || '\0' == conf->offline_root_path[0]) {
+            setenv("PATH", "/dev/null", 1);
+          } else {
+            setenv("PATH", conf->offline_root_path, 1);
+            AllowOfflineMode = true;
+          }
      }
 
      setenv("PKG_ROOT",
      }
 
      setenv("PKG_ROOT",
@@ -1423,7 +1545,7 @@ int pkg_run_script(opkg_conf_t *conf, pkg_t *pkg,
          return 0;
      }
 
          return 0;
      }
 
-     if (conf->offline_root) {
+     if (conf->offline_root && !AllowOfflineMode) {
          fprintf(stderr, "(offline root mode: not running %s.%s)\n", pkg->name, script);
          free(path);
          return 0;
          fprintf(stderr, "(offline root mode: not running %s.%s)\n", pkg->name, script);
          free(path);
          return 0;
@@ -1571,15 +1693,12 @@ int pkg_arch_supported(opkg_conf_t *conf, pkg_t *pkg)
      if (!pkg->architecture)
          return 1;
 
      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;
          }
          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);
      }
 
      opkg_message(conf, OPKG_DEBUG, "arch %s unsupported for pkg %s\n", pkg->architecture, pkg->name);
@@ -1590,15 +1709,12 @@ int pkg_get_arch_priority(opkg_conf_t *conf, const char *archname)
 {
      nv_pair_list_elt_t *l;
 
 {
      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;
          }
          if (strcmp(nv->name, archname) == 0) {
               int priority = strtol(nv->value, NULL, 0);
               return priority;
          }
-         l = l->next;
      }
      return 0;
 }
      }
      return 0;
 }
@@ -1631,7 +1747,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 */
          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;
                            pkg->name, pkg->arch_priority, pkg->state_flag, pkg->state_want);
               pkg->state_want = SW_UNKNOWN;
               pkg->state_flag = 0;
@@ -1650,11 +1766,12 @@ int pkg_info_preinstall_check(opkg_conf_t *conf)
               opkg_message(conf, OPKG_ERROR, "No installed files for pkg %s\n", pkg->name);
               break;
          }
               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); iter; iter = 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);
          }
               // 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);
 
      }
      pkg_vec_free(installed_pkgs);
 
@@ -1707,6 +1824,8 @@ int pkg_write_filelist(opkg_conf_t *conf, pkg_t *pkg)
      fclose(data.stream);
      free(list_file_name);
 
      fclose(data.stream);
      free(list_file_name);
 
+     pkg->state_flag &= ~SF_FILELIST_CHANGED;
+
      return err;
 }
 
      return err;
 }
 
@@ -1730,5 +1849,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);
          }
      }
                    opkg_message(conf, OPKG_NOTICE, "pkg_write_filelist pkg=%s returned %d\n", pkg->name, err);
          }
      }
+     pkg_vec_free (installed_pkgs);
      return 0;
 }
      return 0;
 }