opkg: improve opkg_install error reporting and include a check to verify repository...
[oweals/opkg-lede.git] / libopkg / opkg_cmd.c
index db04a4a680fbd8ace0e114bfa681febf8d01d9eb..d883c7b02b2e0fbf7efae44a40312d822886b869 100644 (file)
@@ -1,4 +1,4 @@
-/* opkg_cmd.c - the itsy package management system
+/* opkg_cmd.c - the opkg package management system
 
    Carl D. Worth
 
    General Public License for more details.
 */
 
-#include <string.h>
 
-#include "opkg.h"
-#include <libgen.h>
-#include <glob.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <signal.h>
-#include <stdio.h>
+#include "includes.h"
 #include <dirent.h>
+#include <glob.h>
 
 #include "opkg_conf.h"
 #include "opkg_cmd.h"
@@ -38,6 +31,8 @@
 #include "file_util.h"
 #include "str_util.h"
 #include "libbb/libbb.h"
+#include "opkg_utils.h"
+#include "opkg_defines.h"
 
 #include <fnmatch.h>
 
 #include "opkg_configure.h"
 #include "opkg_message.h"
 
-#ifdef OPKG_LIB
 #include "libopkg.h"
 static void *p_userdata = NULL;
-#endif
 
 static int opkg_update_cmd(opkg_conf_t *conf, int argc, char **argv);
 static int opkg_upgrade_cmd(opkg_conf_t *conf, int argc, char **argv);
@@ -145,7 +138,6 @@ opkg_cmd_t *opkg_cmd_find(const char *name)
      return NULL;
 }
 
-#ifdef OPKG_LIB
 int opkg_cmd_exec(opkg_cmd_t *cmd, opkg_conf_t *conf, int argc, const char **argv, void *userdata)
 {
        int result;
@@ -175,15 +167,10 @@ int opkg_cmd_exec(opkg_cmd_t *cmd, opkg_conf_t *conf, int argc, const char **arg
        p_userdata = NULL;
        return result;
 }
-#else
-int opkg_cmd_exec(opkg_cmd_t *cmd, opkg_conf_t *conf, int argc, const char **argv)
-{
-     return (cmd->fun)(conf, argc, argv);
-}
-#endif
 
 static int opkg_update_cmd(opkg_conf_t *conf, int argc, char **argv)
 {
+     char *tmp;
      int err;
      int failures;
      char *lists_dir;
@@ -212,6 +199,16 @@ static int opkg_update_cmd(opkg_conf_t *conf, int argc, char **argv)
      } 
 
      failures = 0;
+
+
+     tmp = strdup ("/tmp/opkg.XXXXXX");
+
+     if (mkdtemp (tmp) == NULL) {
+        perror ("mkdtemp");
+        failures++;
+     }
+
+
      for (iter = conf->pkg_src_list.head; iter; iter = iter->next) {
          char *url, *list_file_name;
 
@@ -225,20 +222,11 @@ static int opkg_update_cmd(opkg_conf_t *conf, int argc, char **argv)
 
          sprintf_alloc(&list_file_name, "%s/%s", lists_dir, src->name);
          if (src->gzip) {
-             char *tmp;
              char *tmp_file_name;
              FILE *in, *out;
-
-             tmp = strdup ("/tmp/opkg.XXXXXX");
-
-             if (mkdtemp (tmp) == NULL) {
-                 perror ("mkdtemp");
-                 failures++;
-                 continue;
-             }
              
              sprintf_alloc (&tmp_file_name, "%s/%s.gz", tmp, src->name);
-             err = opkg_download(conf, url, tmp_file_name);
+             err = opkg_download(conf, url, tmp_file_name, NULL, NULL);
              if (err == 0) {
                   opkg_message (conf, OPKG_NOTICE, "Inflating %s\n", url);
                   in = fopen (tmp_file_name, "r");
@@ -252,11 +240,9 @@ static int opkg_update_cmd(opkg_conf_t *conf, int argc, char **argv)
                   if (out)
                        fclose (out);
                   unlink (tmp_file_name);
-                  rmdir (tmp);
-                  free (tmp);
              }
          } else
-             err = opkg_download(conf, url, list_file_name);
+             err = opkg_download(conf, url, list_file_name, NULL, NULL);
          if (err) {
               failures++;
          } else {
@@ -266,6 +252,7 @@ static int opkg_update_cmd(opkg_conf_t *conf, int argc, char **argv)
          }
          free(url);
 
+#ifdef HAVE_GPGME
          /* download detached signitures to verify the package lists */
          /* get the url for the sig file */
          if (src->extra_data)  /* debian style? */
@@ -274,64 +261,36 @@ static int opkg_update_cmd(opkg_conf_t *conf, int argc, char **argv)
          else
              sprintf_alloc(&url, "%s/%s", src->value, "Packages.sig");
 
-         /* create temporary dir for it */
-         char *tmp, *tmp_file_name;
-         tmp = strdup ("/tmp/opkg.XXXXXX");
-         if (mkdtemp (tmp) == NULL) {
-               perror ("mkdtemp");
-               failures++;
-               continue;
-         }
+         /* create temporary file for it */
+         char *tmp_file_name;
+
          sprintf_alloc (&tmp_file_name, "%s/%s", tmp, "Packages.sig");
 
-         err = opkg_download(conf, url, tmp_file_name);
+         err = opkg_download(conf, url, tmp_file_name, NULL, NULL);
          if (err) {
            failures++;
                opkg_message (conf, OPKG_NOTICE, "Signature check failed\n");
          } else {
            int err;
-           err = opkg_verify_file (list_file_name, tmp_file_name);
+           err = opkg_verify_file (conf, list_file_name, tmp_file_name);
            if (err == 0)
                opkg_message (conf, OPKG_NOTICE, "Signature check passed\n");
            else
                opkg_message (conf, OPKG_NOTICE, "Signature check failed\n");
          }
          unlink (tmp_file_name);
-         unlink (tmp);
          free (tmp_file_name);
-
          free (url);
+#else
+         opkg_message (conf, OPKG_NOTICE, "Signiture check for %s skipped "
+              "because GPG support was not enabled in this build\n", src->name);
+#endif
          free(list_file_name);
      }
+     rmdir (tmp);
+     free (tmp);
      free(lists_dir);
 
-#ifdef CONFIG_CLEAR_SW_INSTALL_FLAG
-#warning here
-     /* clear SW_INSTALL on any package where state is SS_NOT_INSTALLED.
-      * this is a hack to work around poor bookkeeping in old opkg upgrade code 
-      * -Jamey 3/1/03
-      */
-     {
-         int i;
-         int changed = 0;
-         pkg_vec_t *available = pkg_vec_alloc();
-         pkg_hash_fetch_available(&conf->pkg_hash, available);
-         opkg_message(conf, OPKG_DEBUG, "Clearing SW_INSTALL for SS_NOT_INSTALLED packages.\n");
-         for (i = 0; i < available->len; i++) {
-              pkg_t *pkg = available->pkgs[i];
-              if (pkg->state_want == SW_INSTALL && pkg->state_status == SS_NOT_INSTALLED) {
-                   opkg_message(conf, OPKG_DEBUG, "Clearing SW_INSTALL on package %s.\n", pkg->name);
-                   pkg->state_want = SW_UNKNOWN;
-                   changed = 1;
-              }
-         }
-         pkg_vec_free(available);
-         if (changed) {
-              write_status_files_if_changed(conf);
-         }
-     }
-#endif
-
      return failures;
 }
 
@@ -443,9 +402,99 @@ int opkg_finalize_intercepts(opkg_intercept_t ctx)
     return err;
 }
 
+/* For package pkg do the following: If it is already visited, return. If not,
+   add it in visited list and recurse to its deps. Finally, add it to ordered 
+   list.
+   pkg_vec all contains all available packages in repos.
+   pkg_vec visited contains packages already visited by this function, and is 
+   used to end recursion and avoid an infinite loop on graph cycles.
+   pkg_vec ordered will finally contain the ordered set of packages.
+*/
+int opkg_recurse_pkgs_in_order(opkg_conf_t *conf, pkg_t *pkg, pkg_vec_t *all,
+                               pkg_vec_t *visited, pkg_vec_t *ordered)
+{
+    int j,k,l,m;
+    int count;
+    pkg_t *dep;
+    compound_depend_t * compound_depend;
+    depend_t ** possible_satisfiers;
+    abstract_pkg_t *abpkg;
+    abstract_pkg_t **dependents;
+
+    /* If it's just an available package, that is, not installed and not even
+       unpacked, skip it */
+    /* XXX: This is probably an overkill, since a state_status != SS_UNPACKED 
+       would do here. However, if there is an intermediate node (pkg) that is 
+       configured and installed between two unpacked packages, the latter 
+       won't be properly reordered, unless all installed/unpacked pkgs are
+       checked */
+    if (pkg->state_status == SS_NOT_INSTALLED) 
+        return 0;
+
+    /* If the  package has already been visited (by this function), skip it */
+    for(j = 0; j < visited->len; j++) 
+        if ( ! strcmp(visited->pkgs[j]->name, pkg->name)) {
+            opkg_message(conf, OPKG_INFO,
+                         "  pkg: %s already visited\n", pkg->name);
+            return 0;
+        }
+    
+    pkg_vec_insert(visited, pkg);
+
+    count = pkg->pre_depends_count + pkg->depends_count + \
+        pkg->recommends_count + pkg->suggests_count;
+
+    opkg_message(conf, OPKG_INFO,
+                 "  pkg: %s\n", pkg->name);
+
+    /* Iterate over all the dependencies of pkg. For each one, find a package 
+       that is either installed or unpacked and satisfies this dependency.
+       (there should only be one such package per dependency installed or 
+       unpacked). Then recurse to the dependency package */
+    for (j=0; j < count ; j++) {
+        compound_depend = &pkg->depends[j];
+        possible_satisfiers = compound_depend->possibilities;
+        for (k=0; k < compound_depend->possibility_count ; k++) {
+            abpkg = possible_satisfiers[k]->pkg;
+            dependents = abpkg->provided_by->pkgs;
+            l = 0;
+            if (dependents != NULL)
+                while (dependents [l] != NULL && l < abpkg->provided_by->len) {
+                    opkg_message(conf, OPKG_INFO,
+                                 "  Descending on pkg: %s\n", 
+                                 dependents [l]->name);
+    
+                    /* find whether dependent l is installed or unpacked,
+                     * and then find which package in the list satisfies it */
+                    for(m = 0; m < all->len; m++) {
+                        dep = all->pkgs[m];
+                        if ( dep->state_status != SS_NOT_INSTALLED)
+                            if ( ! strcmp(dep->name, dependents[l]->name)) {
+                                opkg_recurse_pkgs_in_order(conf, dep, all, 
+                                                           visited, ordered);
+                                /* Stop the outer loop */
+                                l = abpkg->provided_by->len;
+                                /* break from the inner loop */
+                                break;
+                            }
+                    }
+                    l++;
+                }
+        }
+    }
+
+    /* When all recursions from this node down, are over, and all 
+       dependencies have been added in proper order in the ordered array, add
+       also the package pkg to ordered array */
+    pkg_vec_insert(ordered, pkg);
+
+    return 0;
+
+}
+
 int opkg_configure_packages(opkg_conf_t *conf, char *pkg_name)
 {
-     pkg_vec_t *all;
+    pkg_vec_t *all, *ordered, *visited;
      int i;
      pkg_t *pkg;
      opkg_intercept_t ic;
@@ -456,8 +505,21 @@ int opkg_configure_packages(opkg_conf_t *conf, char *pkg_name)
      fflush( stdout );
 
      all = pkg_vec_alloc();
+
      pkg_hash_fetch_available(&conf->pkg_hash, all);
 
+     /* Reorder pkgs in order to be configured according to the Depends: tag
+        order */
+     opkg_message(conf, OPKG_INFO,
+                  "Reordering packages before configuring them...\n");
+     ordered = pkg_vec_alloc();
+     visited = pkg_vec_alloc();
+     for(i = 0; i < all->len; i++) {
+         pkg = all->pkgs[i];
+         opkg_recurse_pkgs_in_order(conf, pkg, all, visited, ordered);
+     }
+
+
      ic = opkg_prep_intercepts (conf);
     
      for(i = 0; i < all->len; i++) {
@@ -487,6 +549,9 @@ int opkg_configure_packages(opkg_conf_t *conf, char *pkg_name)
         err = r;
 
      pkg_vec_free(all);
+     pkg_vec_free(ordered);
+     pkg_vec_free(visited);
+
      return err;
 }
 
@@ -525,11 +590,7 @@ static int opkg_install_cmd(opkg_conf_t *conf, int argc, char **argv)
 
      for (i=0; i < argc; i++) {
          arg = argv[i];
-         if (conf->multiple_providers)
-              err = opkg_install_multi_by_name(conf, arg);
-         else{
-              err = opkg_install_by_name(conf, arg);
-          }
+          err = opkg_install_by_name(conf, arg);
          if (err == OPKG_PKG_HAS_NO_CANDIDATE) {
               opkg_message(conf, OPKG_ERROR,
                            "Cannot find package %s.\n"
@@ -677,9 +738,6 @@ static int opkg_list_cmd(opkg_conf_t *conf, int argc, char **argv)
          if (newline) {
               *newline = '\0';
          }
-#ifndef OPKG_LIB
-         printf("%s - %s\n", pkg->name, desc_short);
-#else
          if (opkg_cb_list) {
                version_str = pkg_version_str_alloc(pkg);
                opkg_cb_list(pkg->name,desc_short,
@@ -688,7 +746,6 @@ static int opkg_list_cmd(opkg_conf_t *conf, int argc, char **argv)
                                         p_userdata);
                free(version_str);
          }
-#endif
      }
      pkg_vec_free(available);
 
@@ -726,9 +783,6 @@ static int opkg_list_installed_cmd(opkg_conf_t *conf, int argc, char **argv)
          if (newline) {
               *newline = '\0';
          }
-#ifndef OPKG_LIB
-         printf("%s - %s\n", pkg->name, desc_short);
-#else
          if (opkg_cb_list) {
                version_str = pkg_version_str_alloc(pkg);
                opkg_cb_list(pkg->name,desc_short,
@@ -737,7 +791,6 @@ static int opkg_list_installed_cmd(opkg_conf_t *conf, int argc, char **argv)
                                         p_userdata);
                free(version_str);
          }
-#endif
      }
 
      return 0;
@@ -771,14 +824,6 @@ static int opkg_info_status_cmd(opkg_conf_t *conf, int argc, char **argv, int in
          if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) {
               continue;
          }
-#ifndef OPKG_LIB
-         if (n_fields) {
-              for (j = 0; j < n_fields; j++)
-                   pkg_print_field(pkg, stdout, pkg_fields[j]);
-         } else {
-              pkg_print_info(pkg, stdout);
-         }
-#else
 
          buff = pkg_formatted_info(pkg);
           if ( buff ) {
@@ -792,7 +837,6 @@ static int opkg_info_status_cmd(opkg_conf_t *conf, int argc, char **argv, int in
 */
                free(buff);
           }
-#endif
          if (conf->verbosity > 1) {
               conffile_list_elt_t *iter;
               for (iter = pkg->conffiles.head; iter; iter = iter->next) {
@@ -803,10 +847,6 @@ static int opkg_info_status_cmd(opkg_conf_t *conf, int argc, char **argv, int in
               }
          }
      }
-#ifndef OPKG_LIB
-     if (buff)
-         free(buff);
-#endif
      pkg_vec_free(available);
 
      return 0;
@@ -1081,13 +1121,6 @@ static int opkg_files_cmd(opkg_conf_t *conf, int argc, char **argv)
      installed_files = pkg_get_installed_files(pkg);
      pkg_version = pkg_version_str_alloc(pkg);
 
-#ifndef OPKG_LIB
-     printf("Package %s (%s) is installed on %s and has the following files:\n",
-           pkg->name, pkg_version, pkg->dest->name);
-     for (iter = installed_files->head; iter; iter = iter->next) {
-         puts(iter->data);
-     }
-#else
      if (buff) {
      try_again:
          used_len = snprintf(buff, buff_len, "Package %s (%s) is installed on %s and has the following files:\n",
@@ -1113,7 +1146,6 @@ static int opkg_files_cmd(opkg_conf_t *conf, int argc, char **argv)
                                         p_userdata);
          free(buff);
      }
-#endif
 
      free(pkg_version);
      pkg_free_installed_files(pkg);
@@ -1407,14 +1439,10 @@ static int opkg_search_cmd(opkg_conf_t *conf, int argc, char **argv)
          for (iter = installed_files->head; iter; iter = iter->next) {
               installed_file = iter->data;
               if (fnmatch(argv[0], installed_file, 0)==0)  {
-#ifndef OPKG_LIB
-                   printf("%s: %s\n", pkg->name, installed_file);
-#else
                        if (opkg_cb_list) opkg_cb_list(pkg->name, 
                                                       installed_file, 
                                                       pkg_version_str_alloc(pkg), 
                                                       pkg->state_status, p_userdata);
-#endif                    
               }                
          }