Add sha256 ckecksums to okpg
[oweals/opkg-lede.git] / libopkg / pkg.c
index 6793c826ee0188fc5bc8df7f625142d9cb888828..0c7bb5ae5eaf68074213037fab4787ba492fc0dd 100644 (file)
@@ -17,7 +17,9 @@
 
 #include "includes.h"
 #include <ctype.h>
+#include <alloca.h>
 #include <string.h>
+#include <stdbool.h>
 #include <errno.h>
 
 #include "pkg.h"
@@ -76,7 +78,7 @@ pkg_t *pkg_new(void)
 {
      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;
@@ -89,12 +91,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 +112,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 +131,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;
@@ -164,10 +169,9 @@ void pkg_deinit(pkg_t *pkg)
      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;
-     pkg->familiar_revision = NULL;
      /* owned by opkg_conf_t */
      pkg->dest = NULL;
      /* owned by opkg_conf_t */
@@ -184,7 +188,8 @@ void pkg_deinit(pkg_t *pkg)
      pkg->state_flag = SF_OK;
      pkg->state_status = SS_NOT_INSTALLED;
 
-     //for (i = 0; i < pkg->replaces_count; i++)
+     active_list_clear(&pkg->list);
+
      free (pkg->replaces);
      pkg->replaces = NULL;
 
@@ -253,6 +258,10 @@ void pkg_deinit(pkg_t *pkg)
      pkg->tmp_unpack_dir = NULL;
      free(pkg->md5sum);
      pkg->md5sum = NULL;
+#if defined HAVE_SHA256
+     free(pkg->sha256sum);
+     pkg->sha256sum = NULL;
+#endif
      free(pkg->size);
      pkg->size = NULL;
      free(pkg->installed_size);
@@ -403,6 +412,10 @@ int pkg_merge(pkg_t *oldpkg, pkg_t *newpkg, int set_status)
          oldpkg->tmp_unpack_dir = str_dup_safe(newpkg->tmp_unpack_dir);
      if (!oldpkg->md5sum)
          oldpkg->md5sum = str_dup_safe(newpkg->md5sum);
+#if defined HAVE_SHA256
+     if (!oldpkg->sha256sum)
+         oldpkg->sha256sum = str_dup_safe(newpkg->sha256sum);
+#endif
      if (!oldpkg->size)
          oldpkg->size = str_dup_safe(newpkg->size);
      if (!oldpkg->installed_size)
@@ -411,8 +424,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);
-     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){
@@ -430,7 +443,7 @@ abstract_pkg_t *abstract_pkg_new(void)
 {
      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__);
@@ -445,8 +458,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;
@@ -462,7 +473,10 @@ void set_flags_from_control(opkg_conf_t *conf, pkg_t *pkg){
      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;
@@ -487,106 +501,132 @@ void set_flags_from_control(opkg_conf_t *conf, pkg_t *pkg){
      }
 
      free(raw_start); 
-     free(temp_str);
 
      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;
+     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;
      }
 
-     buff[0] = '\0';
-
      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");
+     CHECK_BUFF_SIZE(buff, line, buff_size, page_size);
      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");
+     CHECK_BUFF_SIZE(buff, line, buff_size, page_size);
      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");
+     CHECK_BUFF_SIZE(buff, line, buff_size, page_size);
      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");
+     CHECK_BUFF_SIZE(buff, line, buff_size, page_size);
      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");
+     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*/
+     CHECK_BUFF_SIZE(buff, line, buff_size, page_size);
      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");
+     CHECK_BUFF_SIZE(buff, line, buff_size, page_size);
      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");
+     CHECK_BUFF_SIZE(buff, line, buff_size, page_size);
      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");
+     CHECK_BUFF_SIZE(buff, line, buff_size, page_size);
      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");
+     CHECK_BUFF_SIZE(buff, line, buff_size, page_size);
      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);
 
@@ -644,14 +684,14 @@ char * pkg_formatted_field(pkg_t *pkg, const char *field )
               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 ;
-              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);
@@ -661,9 +701,11 @@ char * pkg_formatted_field(pkg_t *pkg, const char *field )
                }
                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));           
                    }
               }
@@ -924,7 +966,7 @@ char * pkg_formatted_field(pkg_t *pkg, const char *field )
          break;
      case 's':
      case 'S': {
-         /* Section | Size | Source | Status | Suggests */
+         /* Section | SHA256sum | Size | Source | Status | Suggests */
          if (strcasecmp(field, "Section") == 0) {
               /* Section */
               if (pkg->section) {
@@ -936,6 +978,19 @@ char * pkg_formatted_field(pkg_t *pkg, const char *field )
                    temp[0]='\0';
                    snprintf(temp, (strlen(pkg->section)+11), "Section: %s\n", pkg->section);
               }
+#if defined HAVE_SHA256
+         } else if (strcasecmp(field, "SHA256sum") == 0) {
+              /* SHA256sum */
+              if (pkg->sha256sum) {
+                   temp = (char *)realloc(temp,strlen(pkg->sha256sum)+13);
+                   if ( temp == NULL ){
+                     fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
+                     return NULL;
+                   }
+                   temp[0]='\0';
+                   snprintf(temp, (strlen(pkg->sha256sum)+13), "SHA256sum: %s\n", pkg->sha256sum);
+              }
+#endif
          } else if (strcasecmp(field, "Size") == 0) {
               /* Size */
               if (pkg->size) {
@@ -1054,6 +1109,7 @@ char * pkg_formatted_field(pkg_t *pkg, const char *field )
 
 void pkg_print_info(pkg_t *pkg, FILE *file)
 {
+  int t=0;
      char * buff;
      if (pkg == NULL) {
        return;
@@ -1063,7 +1119,7 @@ void pkg_print_info(pkg_t *pkg, FILE *file)
      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);
 }
@@ -1081,7 +1137,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
@@ -1313,7 +1369,7 @@ str_list_t *pkg_get_installed_files(pkg_t *pkg)
          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) {
@@ -1380,6 +1436,7 @@ str_list_t *pkg_get_installed_files(pkg_t *pkg)
               sprintf_alloc(&installed_file_name, "%s", file_name);
          }
          str_list_append(pkg->installed_files, installed_file_name);
+          free(installed_file_name);
          free(line);
      }
 
@@ -1395,23 +1452,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);
-         free (pkg->installed_files);
+         str_list_purge(pkg->installed_files);
      }
 
      pkg->installed_files = NULL;
@@ -1449,8 +1496,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;
@@ -1495,8 +1542,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. */
+     /*
+      * 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);
+         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",
@@ -1507,7 +1570,7 @@ int pkg_run_script(opkg_conf_t *conf, pkg_t *pkg,
          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;
@@ -1655,15 +1718,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);
@@ -1674,15 +1734,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;
 }
@@ -1715,7 +1772,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;
@@ -1729,16 +1786,19 @@ int pkg_info_preinstall_check(opkg_conf_t *conf)
      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_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);
 
@@ -1791,6 +1851,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;
 }