libopkg: selectively load package feeds in opkg_info_status_cmd()
[oweals/opkg-lede.git] / libopkg / opkg_cmd.c
index 0fb3c8591a716479d0ca0f295927b38864e08905..f9d519259053dc51d94837026ba6727fc7ac2051 100644 (file)
    General Public License for more details.
 */
 
+#include "config.h"
 
-#include "includes.h"
+#include <stdio.h>
 #include <dirent.h>
 #include <glob.h>
 #include <fnmatch.h>
+#include <signal.h>
+#include <unistd.h>
 
 #include "opkg_conf.h"
 #include "opkg_cmd.h"
 #include "opkg_upgrade.h"
 #include "opkg_remove.h"
 #include "opkg_configure.h"
-#include "opkg_message.h"
-#include "libopkg.h"
 #include "xsystem.h"
 
-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);
-static int opkg_list_cmd(opkg_conf_t *conf, int argc, char **argv);
-static int opkg_info_cmd(opkg_conf_t *conf, int argc, char **argv);
-static int opkg_status_cmd(opkg_conf_t *conf, int argc, char **argv);
-static int opkg_install_cmd(opkg_conf_t *conf, int argc, char **argv);
-static int opkg_list_installed_cmd(opkg_conf_t *conf, int argc, char **argv);
-static int opkg_list_upgradable_cmd(opkg_conf_t *conf, int argc, char **argv);
-static int opkg_remove_cmd(opkg_conf_t *conf, int argc, char **argv);
-static int opkg_flag_cmd(opkg_conf_t *conf, int argc, char **argv);
-static int opkg_files_cmd(opkg_conf_t *conf, int argc, char **argv);
-static int opkg_search_cmd(opkg_conf_t *conf, int argc, char **argv);
-static int opkg_download_cmd(opkg_conf_t *conf, int argc, char **argv);
-static int opkg_depends_cmd(opkg_conf_t *conf, int argc, char **argv);
-static int opkg_whatdepends_cmd(opkg_conf_t *conf, int argc, char **argv);
-static int opkg_whatdepends_recursively_cmd(opkg_conf_t *conf, int argc, char **argv);
-static int opkg_whatsuggests_cmd(opkg_conf_t *conf, int argc, char **argv);
-static int opkg_whatrecommends_cmd(opkg_conf_t *conf, int argc, char **argv);
-static int opkg_whatprovides_cmd(opkg_conf_t *conf, int argc, char **argv);
-static int opkg_whatconflicts_cmd(opkg_conf_t *conf, int argc, char **argv);
-static int opkg_whatreplaces_cmd(opkg_conf_t *conf, int argc, char **argv);
-static int opkg_compare_versions_cmd(opkg_conf_t *conf, int argc, char **argv);
-static int opkg_print_architecture_cmd(opkg_conf_t *conf, int argc, char **argv);
-static int opkg_configure_cmd(opkg_conf_t *conf, int argc, char **argv);
-static int pkg_mark_provides(pkg_t *pkg);
-
-/* XXX: CLEANUP: The usage strings should be incorporated into this
-   array for easier maintenance */
-static opkg_cmd_t cmds[] = {
-     {"update", 0, (opkg_cmd_fun_t)opkg_update_cmd}, 
-     {"upgrade", 0, (opkg_cmd_fun_t)opkg_upgrade_cmd},
-     {"list", 0, (opkg_cmd_fun_t)opkg_list_cmd},
-     {"list_installed", 0, (opkg_cmd_fun_t)opkg_list_installed_cmd},
-     {"list-installed", 0, (opkg_cmd_fun_t)opkg_list_installed_cmd},
-     {"list_upgradable", 0, (opkg_cmd_fun_t)opkg_list_upgradable_cmd},
-     {"list-upgradable", 0, (opkg_cmd_fun_t)opkg_list_upgradable_cmd},
-     {"info", 0, (opkg_cmd_fun_t)opkg_info_cmd},
-     {"flag", 1, (opkg_cmd_fun_t)opkg_flag_cmd},
-     {"status", 0, (opkg_cmd_fun_t)opkg_status_cmd},
-     {"install", 1, (opkg_cmd_fun_t)opkg_install_cmd},
-     {"remove", 1, (opkg_cmd_fun_t)opkg_remove_cmd},
-     {"configure", 0, (opkg_cmd_fun_t)opkg_configure_cmd},
-     {"files", 1, (opkg_cmd_fun_t)opkg_files_cmd},
-     {"search", 1, (opkg_cmd_fun_t)opkg_search_cmd},
-     {"download", 1, (opkg_cmd_fun_t)opkg_download_cmd},
-     {"compare_versions", 1, (opkg_cmd_fun_t)opkg_compare_versions_cmd},
-     {"compare-versions", 1, (opkg_cmd_fun_t)opkg_compare_versions_cmd},
-     {"print-architecture", 0, (opkg_cmd_fun_t)opkg_print_architecture_cmd},
-     {"print_architecture", 0, (opkg_cmd_fun_t)opkg_print_architecture_cmd},
-     {"print-installation-architecture", 0, (opkg_cmd_fun_t)opkg_print_architecture_cmd},
-     {"print_installation_architecture", 0, (opkg_cmd_fun_t)opkg_print_architecture_cmd},
-     {"depends", 1, (opkg_cmd_fun_t)opkg_depends_cmd},
-     {"whatdepends", 1, (opkg_cmd_fun_t)opkg_whatdepends_cmd},
-     {"whatdependsrec", 1, (opkg_cmd_fun_t)opkg_whatdepends_recursively_cmd},
-     {"whatrecommends", 1, (opkg_cmd_fun_t)opkg_whatrecommends_cmd},
-     {"whatsuggests", 1, (opkg_cmd_fun_t)opkg_whatsuggests_cmd},
-     {"whatprovides", 1, (opkg_cmd_fun_t)opkg_whatprovides_cmd},
-     {"whatreplaces", 1, (opkg_cmd_fun_t)opkg_whatreplaces_cmd},
-     {"whatconflicts", 1, (opkg_cmd_fun_t)opkg_whatconflicts_cmd},
-};
-
-static void print_pkg(pkg_t *pkg)
+static void print_pkg(pkg_t * pkg)
 {
        char *version = pkg_version_str_alloc(pkg);
-       if (pkg->description)
-               printf("%s - %s - %s\n", pkg->name, version, pkg->description);
-       else
-               printf("%s - %s\n", pkg->name, version);
+       char *description = pkg_get_string(pkg, PKG_DESCRIPTION);
+       printf("%s - %s", pkg->name, version);
+       if (conf->size)
+               printf(" - %lu", (unsigned long) pkg_get_int(pkg, PKG_SIZE));
+       if (description)
+               printf(" - %s", description);
+       printf("\n");
        free(version);
 }
 
 int opkg_state_changed;
-static void write_status_files_if_changed(opkg_conf_t *conf)
+
+static void write_status_files_if_changed(void)
 {
-     if (opkg_state_changed && !conf->noaction) {
-         opkg_message(conf, OPKG_INFO,
-                      "  writing status file\n");
-         opkg_conf_write_status_files(conf);
-         pkg_write_changed_filelists(conf);
-     } else { 
-         opkg_message(conf, OPKG_DEBUG, "Nothing to be done\n");
-     }
+       if (opkg_state_changed && !conf->noaction) {
+               opkg_msg(INFO, "Writing status file.\n");
+               opkg_conf_write_status_files();
+               pkg_write_changed_filelists();
+       } else {
+               opkg_msg(DEBUG, "Nothing to be done.\n");
+       }
 }
 
-
-static int num_cmds = sizeof(cmds) / sizeof(opkg_cmd_t);
-
-opkg_cmd_t *opkg_cmd_find(const char *name)
+static void sigint_handler(int sig)
 {
-     int i;
-     opkg_cmd_t *cmd;
-
-     for (i=0; i < num_cmds; i++) {
-         cmd = &cmds[i];
-         if (strcmp(name, cmd->name) == 0) {
-              return cmd;
-         }
-     }
-
-     return NULL;
+       signal(sig, SIG_DFL);
+       opkg_msg(NOTICE, "Interrupted. Writing out status database.\n");
+       write_status_files_if_changed();
+       exit(128 + sig);
 }
 
-int opkg_cmd_exec(opkg_cmd_t *cmd, opkg_conf_t *conf, int argc, const char **argv, void *userdata)
+static int opkg_update_cmd(int argc, char **argv)
 {
-       int result;
-
-       result = (cmd->fun)(conf, argc, argv);
+       char *tmp;
+       int err;
+       int failures;
+       int pkglist_dl_error;
+       char *lists_dir;
+       pkg_src_list_elt_t *iter;
+       pkg_src_t *src;
+
+       sprintf_alloc(&lists_dir, "%s",
+                     conf->restrict_to_default_dest ? conf->default_dest->
+                     lists_dir : conf->lists_dir);
+
+       if (!file_is_dir(lists_dir)) {
+               if (file_exists(lists_dir)) {
+                       opkg_msg(ERROR, "%s exists, but is not a directory.\n",
+                                lists_dir);
+                       free(lists_dir);
+                       return -1;
+               }
+               err = file_mkdir_hier(lists_dir, 0755);
+               if (err) {
+                       free(lists_dir);
+                       return -1;
+               }
+       }
 
-       print_error_list();
-       free_error_list();
+       failures = 0;
 
-       return result;
-}
+       sprintf_alloc(&tmp, "%s/update-XXXXXX", conf->tmp_dir);
+       if (mkdtemp(tmp) == NULL) {
+               opkg_perror(ERROR, "Failed to make temp dir %s", conf->tmp_dir);
+               return -1;
+       }
 
-static int opkg_update_cmd(opkg_conf_t *conf, int argc, char **argv)
-{
-     char *tmp;
-     int err;
-     int failures;
-     char *lists_dir;
-     pkg_src_list_elt_t *iter;
-     pkg_src_t *src;
-
-    sprintf_alloc(&lists_dir, "%s", conf->restrict_to_default_dest ? conf->default_dest->lists_dir : conf->lists_dir);
-    if (! file_is_dir(lists_dir)) {
-         if (file_exists(lists_dir)) {
-              opkg_message(conf, OPKG_ERROR,
-                           "%s: ERROR: %s exists, but is not a directory\n",
-                           __FUNCTION__, lists_dir);
-              free(lists_dir);
-              return -1;
-         }
-         err = file_mkdir_hier(lists_dir, 0755);
-         if (err) {
-              opkg_message(conf, OPKG_ERROR,
-                           "%s: ERROR: failed to make directory %s: %s\n",
-                           __FUNCTION__, lists_dir, strerror(errno));
-              free(lists_dir);
-              return -1;
-         }     
-     } 
-
-     failures = 0;
-
-     sprintf_alloc(&tmp, "%s/update-XXXXXX", conf->tmp_dir);
-     if (mkdtemp (tmp) == NULL) {
-        perror ("mkdtemp");
-        return -1;
-     }
-
-
-     for (iter = void_list_first(&conf->pkg_src_list); iter; iter = void_list_next(&conf->pkg_src_list, iter)) {
-         char *url, *list_file_name;
-
-         src = (pkg_src_t *)iter->data;
-
-         if (src->extra_data)  /* debian style? */
-             sprintf_alloc(&url, "%s/%s/%s", src->value, src->extra_data, 
-                           src->gzip ? "Packages.gz" : "Packages");
-         else
-             sprintf_alloc(&url, "%s/%s", src->value, src->gzip ? "Packages.gz" : "Packages");
-
-         sprintf_alloc(&list_file_name, "%s/%s", lists_dir, src->name);
-         if (src->gzip) {
-             char *tmp_file_name;
-             FILE *in, *out;
-             
-             sprintf_alloc (&tmp_file_name, "%s/%s.gz", tmp, src->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");
-                  out = fopen (list_file_name, "w");
-                  if (in && out)
-                       unzip (in, out);
-                  else
-                       err = 1;
-                  if (in)
-                       fclose (in);
-                  if (out)
-                       fclose (out);
-                  unlink (tmp_file_name);
-             }
-             free(tmp_file_name);
-         } else
-             err = opkg_download(conf, url, list_file_name, NULL, NULL);
-         if (err) {
-              failures++;
-         } else {
-              opkg_message(conf, OPKG_NOTICE,
-                           "Updated list of available packages in %s\n",
-                           list_file_name);
-         }
-         free(url);
-#if defined(HAVE_GPGME) || defined(HAVE_OPENSSL)
-          if (conf->check_signature) {
-              /* download detached signitures to verify the package lists */
-              /* get the url for the sig file */
-              if (src->extra_data)     /* debian style? */
-                  sprintf_alloc(&url, "%s/%s/%s", src->value, src->extra_data,
-                          "Packages.sig");
-              else
-                  sprintf_alloc(&url, "%s/%s", src->value, "Packages.sig");
-
-              /* create temporary file for it */
-              char *tmp_file_name;
-
-              /* Put the signature in the right place */
-              sprintf_alloc (&tmp_file_name, "%s/%s.sig", lists_dir, src->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 (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");
-              }
-              /* We shouldn't unlink the signature ! */
-              // unlink (tmp_file_name);
-              free (tmp_file_name);
-              free (url);
-          }
+       for (iter = void_list_first(&conf->pkg_src_list); iter;
+            iter = void_list_next(&conf->pkg_src_list, iter)) {
+               char *url, *list_file_name;
+
+               src = (pkg_src_t *) iter->data;
+
+               if (src->extra_data && strcmp(src->extra_data, "__dummy__ "))
+                       continue;
+
+               if (src->extra_data)    /* debian style? */
+                       sprintf_alloc(&url, "%s/%s/%s", src->value,
+                                     src->extra_data,
+                                     src->gzip ? "Packages.gz" : "Packages");
+               else
+                       sprintf_alloc(&url, "%s/%s", src->value,
+                                     src->gzip ? "Packages.gz" : "Packages");
+
+               sprintf_alloc(&list_file_name, "%s/%s", lists_dir, src->name);
+               pkglist_dl_error = 0;
+               if (opkg_download(url, list_file_name, NULL, NULL, 0)) {
+                       failures++;
+                       pkglist_dl_error = 1;
+                       opkg_msg(NOTICE,
+                                "*** Failed to download the package list from %s\n\n",
+                                url);
+               } else {
+                       opkg_msg(NOTICE,
+                                "Updated list of available packages in %s\n",
+                                list_file_name);
+               }
+               free(url);
+#if defined(HAVE_GPGME) || defined(HAVE_OPENSSL) || defined(HAVE_USIGN)
+               if (pkglist_dl_error == 0 && conf->check_signature) {
+                       /* download detached signitures to verify the package lists */
+                       /* get the url for the sig file */
+                       if (src->extra_data)    /* debian style? */
+                               sprintf_alloc(&url, "%s/%s/%s", src->value,
+                                             src->extra_data, "Packages.sig");
+                       else
+                               sprintf_alloc(&url, "%s/%s", src->value,
+                                             "Packages.sig");
+
+                       /* create temporary file for it */
+                       char *tmp_file_name;
+
+                       /* Put the signature in the right place */
+                       sprintf_alloc(&tmp_file_name, "%s/%s.sig", lists_dir,
+                                     src->name);
+
+                       err = opkg_download(url, tmp_file_name, NULL, NULL, 0);
+                       if (err) {
+                               failures++;
+                               opkg_msg(NOTICE,
+                                        "Signature file download failed.\n");
+                       } else {
+                               err =
+                                   opkg_verify_file(list_file_name,
+                                                    tmp_file_name);
+                               if (err == 0)
+                                       opkg_msg(NOTICE,
+                                                "Signature check passed.\n");
+                               else
+                                       opkg_msg(NOTICE,
+                                                "Signature check failed.\n");
+                       }
+                       if (err && !conf->force_signature) {
+                               /* The signature was wrong so delete it */
+                               opkg_msg(NOTICE,
+                                        "Remove wrong Signature file.\n");
+                               unlink(tmp_file_name);
+                               unlink(list_file_name);
+                       }
+                       /* We shouldn't unlink the signature ! */
+                       // unlink (tmp_file_name);
+                       free(tmp_file_name);
+                       free(url);
+               }
 #else
-          // Do nothing
+               // Do nothing
 #endif
-         free(list_file_name);
-     }
-     rmdir (tmp);
-     free (tmp);
-     free(lists_dir);
+               free(list_file_name);
+       }
+       rmdir(tmp);
+       free(tmp);
+       free(lists_dir);
 
-     return failures;
+       return failures;
 }
 
-
-struct opkg_intercept
-{
-    char *oldpath;
-    char *statedir;
+struct opkg_intercept {
+       char *oldpath;
+       char *statedir;
 };
 
 typedef struct opkg_intercept *opkg_intercept_t;
 
-static opkg_intercept_t opkg_prep_intercepts(opkg_conf_t *conf)
+static opkg_intercept_t opkg_prep_intercepts(void)
 {
-    opkg_intercept_t ctx;
-    char *newpath;
-
-    ctx = xcalloc(1, sizeof (*ctx));
-    ctx->oldpath = xstrdup(getenv("PATH"));
-    sprintf_alloc(&newpath, "%s/opkg/intercept:%s", DATADIR, ctx->oldpath);
-    sprintf_alloc(&ctx->statedir, "%s/opkg-intercept-XXXXXX", conf->tmp_dir);
-
-    if (mkdtemp(ctx->statedir) == NULL) {
-        fprintf(stderr, "%s: mkdtemp: %s\n", __FUNCTION__, strerror(errno));
-       free(ctx->oldpath);
-       free(ctx->statedir);
-        free(newpath);
-       free(ctx);
-       return NULL;
-    }
+       opkg_intercept_t ctx;
+       char *newpath;
+
+       ctx = xcalloc(1, sizeof(*ctx));
+       ctx->oldpath = xstrdup(getenv("PATH"));
+       sprintf_alloc(&newpath, "%s/opkg/intercept:%s", DATADIR, ctx->oldpath);
+       sprintf_alloc(&ctx->statedir, "%s/opkg-intercept-XXXXXX",
+                     conf->tmp_dir);
+
+       if (mkdtemp(ctx->statedir) == NULL) {
+               opkg_perror(ERROR, "Failed to make temp dir %s", ctx->statedir);
+               free(ctx->oldpath);
+               free(ctx->statedir);
+               free(newpath);
+               free(ctx);
+               return NULL;
+       }
 
-    setenv("OPKG_INTERCEPT_DIR", ctx->statedir, 1);
-    setenv("PATH", newpath, 1);
-    free(newpath);
+       setenv("OPKG_INTERCEPT_DIR", ctx->statedir, 1);
+       setenv("PATH", newpath, 1);
+       free(newpath);
 
-    return ctx;
+       return ctx;
 }
 
 static int opkg_finalize_intercepts(opkg_intercept_t ctx)
 {
-    DIR *dir;
-    int err = 0;
-
-    setenv ("PATH", ctx->oldpath, 1);
-    free (ctx->oldpath);
-
-    dir = opendir (ctx->statedir);
-    if (dir) {
-       struct dirent *de;
-       while (de = readdir (dir), de != NULL) {
-           char *path;
-
-           if (de->d_name[0] == '.')
-               continue;
-           
-           sprintf_alloc (&path, "%s/%s", ctx->statedir, de->d_name);
-           if (access (path, X_OK) == 0) {
-               const char *argv[] = {"sh", "-c", path, NULL};
-               xsystem (argv);
-           }
-           free (path);
-       }
-        closedir(dir);
-    } else
-       perror (ctx->statedir);
-       
-    rm_r(ctx->statedir);
-    free (ctx->statedir);
-    free (ctx);
-
-    return err;
+       DIR *dir;
+       int err = 0;
+
+       setenv("PATH", ctx->oldpath, 1);
+       free(ctx->oldpath);
+
+       dir = opendir(ctx->statedir);
+       if (dir) {
+               struct dirent *de;
+               while (de = readdir(dir), de != NULL) {
+                       char *path;
+
+                       if (de->d_name[0] == '.')
+                               continue;
+
+                       sprintf_alloc(&path, "%s/%s", ctx->statedir,
+                                     de->d_name);
+                       if (access(path, X_OK) == 0) {
+                               const char *argv[] = { "sh", "-c", path, NULL };
+                               xsystem(argv);
+                       }
+                       free(path);
+               }
+               closedir(dir);
+       } else
+               opkg_perror(ERROR, "Failed to open dir %s", ctx->statedir);
+
+       rm_r(ctx->statedir);
+       free(ctx->statedir);
+       free(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 
+   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 
+   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.
 */
-static 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)
+static int
+opkg_recurse_pkgs_in_order(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 (l < abpkg->provided_by->len && dependents[l] != NULL) {
-                    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 j, k, l, m;
+       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_msg(DEBUG, "pkg %s already visited, skipping.\n",
+                                pkg->name);
+                       return 0;
+               }
+
+       pkg_vec_insert(visited, pkg);
+
+       opkg_msg(DEBUG, "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 (compound_depend = pkg_get_ptr(pkg, PKG_DEPENDS); compound_depend && compound_depend->type; compound_depend++) {
+               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 (l < abpkg->provided_by->len
+                                      && dependents[l] != NULL) {
+                                       opkg_msg(DEBUG,
+                                                "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
+                                                                   (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;
 
 }
 
-static int opkg_configure_packages(opkg_conf_t *conf, char *pkg_name)
+static int opkg_configure_packages(char *pkg_name)
 {
-     pkg_vec_t *all, *ordered, *visited;
-     int i;
-     pkg_t *pkg;
-     opkg_intercept_t ic;
-     int r, err = 0;
-
-     opkg_message(conf, OPKG_INFO,
-                 "Configuring unpacked packages\n");
-     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);
-     if (ic == NULL) {
-            err = -1;
-            goto error;
-     }
-    
-     for(i = 0; i < all->len; i++) {
-         pkg = all->pkgs[i];
-
-         if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) 
-              continue;
-
-         if (pkg->state_status == SS_UNPACKED) {
-              opkg_message(conf, OPKG_NOTICE,
-                           "Configuring %s\n", pkg->name);
-              fflush( stdout );
-              r = opkg_configure(conf, pkg);
-              if (r == 0) {
-                   pkg->state_status = SS_INSTALLED;
-                   pkg->parent->state_status = SS_INSTALLED;
-                   pkg->state_flag &= ~SF_PREFER;
-              } else {
-                   if (!err)
-                       err = r;
-              }
-         }
-     }
-
-     r = opkg_finalize_intercepts (ic);
-     if (r && !err)
-        err = r;
+       pkg_vec_t *all, *ordered, *visited;
+       int i;
+       pkg_t *pkg;
+       opkg_intercept_t ic;
+       int r, err = 0;
+
+       opkg_msg(INFO, "Configuring unpacked packages.\n");
+
+       all = pkg_vec_alloc();
+
+       pkg_hash_fetch_available(all);
+
+       /* Reorder pkgs in order to be configured according to the Depends: tag
+          order */
+       opkg_msg(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(pkg, all, visited, ordered);
+       }
+
+       ic = opkg_prep_intercepts();
+       if (ic == NULL) {
+               err = -1;
+               goto error;
+       }
+
+       for (i = 0; i < ordered->len; i++) {
+               pkg = ordered->pkgs[i];
+
+               if (pkg_name && fnmatch(pkg_name, pkg->name, conf->nocase))
+                       continue;
+
+               if (pkg->state_status == SS_UNPACKED) {
+                       opkg_msg(NOTICE, "Configuring %s.\n", pkg->name);
+                       r = opkg_configure(pkg);
+                       if (r == 0) {
+                               pkg->state_status = SS_INSTALLED;
+                               pkg->parent->state_status = SS_INSTALLED;
+                               pkg->state_flag &= ~SF_PREFER;
+                               opkg_state_changed++;
+                       } else {
+                               err = -1;
+                       }
+               }
+       }
+
+       if (opkg_finalize_intercepts(ic))
+               err = -1;
 
 error:
-     pkg_vec_free(all);
-     pkg_vec_free(ordered);
-     pkg_vec_free(visited);
+       pkg_vec_free(all);
+       pkg_vec_free(ordered);
+       pkg_vec_free(visited);
 
-     return err;
+       return err;
 }
 
-static opkg_conf_t *global_conf;
+static int opkg_remove_cmd(int argc, char **argv);
 
-static void sigint_handler(int sig)
+static int opkg_install_cmd(int argc, char **argv)
 {
-     signal(sig, SIG_DFL);
-     opkg_message(NULL, OPKG_NOTICE,
-                 "opkg: interrupted. writing out status database\n");
-     write_status_files_if_changed(global_conf);
-     exit(128 + sig);
+       int i;
+       char *arg;
+       int err = 0;
+
+       signal(SIGINT, sigint_handler);
+
+       /*
+        * Now scan through package names and install
+        */
+       for (i = 0; i < argc; i++) {
+               arg = argv[i];
+
+               opkg_msg(DEBUG2, "%s\n", arg);
+               if (opkg_prepare_url_for_install(arg, &argv[i]))
+                       return -1;
+       }
+
+       pkg_hash_load_package_details();
+       pkg_hash_load_status_files();
+
+       if (conf->force_reinstall) {
+               int saved_force_depends = conf->force_depends;
+               conf->force_depends = 1;
+               (void)opkg_remove_cmd(argc, argv);
+               conf->force_depends = saved_force_depends;
+               conf->force_reinstall = 0;
+       }
+
+       pkg_info_preinstall_check();
+
+       for (i = 0; i < argc; i++) {
+               arg = argv[i];
+               if (opkg_install_by_name(arg)) {
+                       opkg_msg(ERROR, "Cannot install package %s.\n", arg);
+                       err = -1;
+               }
+       }
+
+       if (opkg_configure_packages(NULL))
+               err = -1;
+
+       write_status_files_if_changed();
+
+       return err;
 }
 
-static int opkg_install_cmd(opkg_conf_t *conf, int argc, char **argv)
+static int opkg_upgrade_cmd(int argc, char **argv)
 {
-     int i;
-     char *arg;
-     int err=0;
-
-     global_conf = conf;
-     signal(SIGINT, sigint_handler);
-
-     /*
-      * Now scan through package names and install
-      */
-     for (i=0; i < argc; i++) {
-         arg = argv[i];
-
-          opkg_message(conf, OPKG_DEBUG2, "Debug install_cmd: %s  \n",arg );
-          err = opkg_prepare_url_for_install(conf, arg, &argv[i]);
-          if (err != EINVAL && err != 0)
-              return err;
-     }
-     pkg_info_preinstall_check(conf);
-
-     for (i=0; i < argc; i++) {
-         arg = argv[i];
-          err = opkg_install_by_name(conf, arg);
-         if (err == OPKG_PKG_HAS_NO_CANDIDATE) {
-              opkg_message(conf, OPKG_ERROR,
-                           "Cannot find package %s.\n",
-                           arg);
-         }
-     }
-
-     opkg_configure_packages(conf, NULL);
-
-     write_status_files_if_changed(conf);
-
-     return err;
+       int i;
+       pkg_t *pkg;
+       int err = 0;
+
+       signal(SIGINT, sigint_handler);
+
+       if (argc) {
+               for (i = 0; i < argc; i++) {
+                       char *arg = argv[i];
+
+                       if (opkg_prepare_url_for_install(arg, &arg))
+                               return -1;
+               }
+               pkg_info_preinstall_check();
+
+               for (i = 0; i < argc; i++) {
+                       char *arg = argv[i];
+                       if (conf->restrict_to_default_dest) {
+                               pkg =
+                                   pkg_hash_fetch_installed_by_name_dest(argv
+                                                                         [i],
+                                                                         conf->
+                                                                         default_dest);
+                               if (pkg == NULL) {
+                                       opkg_msg(NOTICE,
+                                                "Package %s not installed in %s.\n",
+                                                argv[i],
+                                                conf->default_dest->name);
+                                       continue;
+                               }
+                       } else {
+                               pkg = pkg_hash_fetch_installed_by_name(argv[i]);
+                       }
+                       if (pkg) {
+                               if (opkg_upgrade_pkg(pkg))
+                                       err = -1;
+                       } else {
+                               if (opkg_install_by_name(arg))
+                                       err = -1;
+                       }
+               }
+       }
+
+       if (opkg_configure_packages(NULL))
+               err = -1;
+
+       write_status_files_if_changed();
+
+       return err;
 }
 
-static int opkg_upgrade_cmd(opkg_conf_t *conf, int argc, char **argv)
+static int opkg_download_cmd(int argc, char **argv)
 {
-     int i;
-     pkg_t *pkg;
-     int err;
-
-     global_conf = conf;
-     signal(SIGINT, sigint_handler);
-
-     if (argc) {
-         for (i=0; i < argc; i++) {
-              char *arg = argv[i];
-
-               err = opkg_prepare_url_for_install(conf, arg, &arg);
-               if (err != EINVAL && err != 0)
-                   return err;
-         }
-         pkg_info_preinstall_check(conf);
-
-         for (i=0; i < argc; i++) {
-              char *arg = argv[i];
-              if (conf->restrict_to_default_dest) {
-                   pkg = pkg_hash_fetch_installed_by_name_dest(&conf->pkg_hash,
-                                                               argv[i],
-                                                               conf->default_dest);
-                   if (pkg == NULL) {
-                        opkg_message(conf, OPKG_NOTICE,
-                                     "Package %s not installed in %s\n",
-                                     argv[i], conf->default_dest->name);
-                        continue;
-                   }
-              } else {
-                   pkg = pkg_hash_fetch_installed_by_name(&conf->pkg_hash,
-                                                          argv[i]);
-              }
-              if (pkg)
-                   opkg_upgrade_pkg(conf, pkg);
-              else {
-                   opkg_install_by_name(conf, arg);
-               }
-         }
-     } else {
-         pkg_vec_t *installed = pkg_vec_alloc();
-
-         pkg_info_preinstall_check(conf);
-
-         pkg_hash_fetch_all_installed(&conf->pkg_hash, installed);
-         for (i = 0; i < installed->len; i++) {
-              pkg = installed->pkgs[i];
-              opkg_upgrade_pkg(conf, pkg);
-         }
-         pkg_vec_free(installed);
-     }
-
-     opkg_configure_packages(conf, NULL);
-
-     write_status_files_if_changed(conf);
-
-     return 0;
+       int i, err = 0;
+       char *arg;
+       pkg_t *pkg;
+
+       pkg_info_preinstall_check();
+       for (i = 0; i < argc; i++) {
+               arg = argv[i];
+
+               pkg = pkg_hash_fetch_best_installation_candidate_by_name(arg);
+               if (pkg == NULL) {
+                       opkg_msg(ERROR, "Cannot find package %s.\n", arg);
+                       continue;
+               }
+
+               if (opkg_download_pkg(pkg, "."))
+                       err = -1;
+
+               if (err) {
+                       opkg_msg(ERROR, "Failed to download %s.\n", pkg->name);
+               } else {
+                       opkg_msg(NOTICE, "Downloaded %s as %s.\n",
+                                pkg->name, pkg_get_string(pkg, PKG_LOCAL_FILENAME));
+               }
+       }
+
+       return err;
 }
 
-static int opkg_download_cmd(opkg_conf_t *conf, int argc, char **argv)
+static int opkg_list_find_cmd(int argc, char **argv, int use_desc)
 {
-     int i, err;
-     char *arg;
-     pkg_t *pkg;
-
-     pkg_info_preinstall_check(conf);
-     for (i = 0; i < argc; i++) {
-         arg = argv[i];
-
-         pkg = pkg_hash_fetch_best_installation_candidate_by_name(conf, arg, &err);
-         if (pkg == NULL) {
-              opkg_message(conf, OPKG_ERROR,
-                           "Cannot find package %s.\n"
-                           "Check the spelling or perhaps run 'opkg update'\n",
-                           arg);
-              continue;
-         }
-
-         err = opkg_download_pkg(conf, pkg, ".");
-
-         if (err) {
-              opkg_message(conf, OPKG_ERROR,
-                           "Failed to download %s\n", pkg->name);
-         } else {
-              opkg_message(conf, OPKG_NOTICE,
-                           "Downloaded %s as %s\n",
-                           pkg->name, pkg->local_filename);
-         }
-     }
-
-     return 0;
+       int i;
+       pkg_vec_t *available;
+       pkg_t *pkg;
+       char *pkg_name = NULL;
+       char *description;
+
+       if (argc > 0) {
+               pkg_name = argv[0];
+       }
+       available = pkg_vec_alloc();
+       pkg_hash_fetch_available(available);
+       pkg_vec_sort(available, pkg_compare_names);
+       for (i = 0; i < available->len; i++) {
+               pkg = available->pkgs[i];
+               description = use_desc ? pkg_get_string(pkg, PKG_DESCRIPTION) : NULL;
+               /* if we have package name or pattern and pkg does not match, then skip it */
+               if (pkg_name && fnmatch(pkg_name, pkg->name, conf->nocase) &&
+                   (!use_desc || !description
+                    || fnmatch(pkg_name, description, conf->nocase)))
+                       continue;
+               print_pkg(pkg);
+       }
+       pkg_vec_free(available);
+
+       return 0;
 }
 
+static int opkg_list_cmd(int argc, char **argv)
+{
+       return opkg_list_find_cmd(argc, argv, 0);
+}
 
-static int opkg_list_cmd(opkg_conf_t *conf, int argc, char **argv)
+static int opkg_find_cmd(int argc, char **argv)
 {
-     int i;
-     pkg_vec_t *available;
-     pkg_t *pkg;
-     char *pkg_name = NULL;
-
-     if (argc > 0) {
-         pkg_name = argv[0];
-     }
-     available = pkg_vec_alloc();
-     pkg_hash_fetch_available(&conf->pkg_hash, available);
-     pkg_vec_sort(available, pkg_compare_names);
-     for (i=0; i < available->len; i++) {
-         pkg = available->pkgs[i];
-         /* if we have package name or pattern and pkg does not match, then skip it */
-         if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) 
-              continue;
-          print_pkg(pkg);
-     }
-     pkg_vec_free(available);
-
-     return 0;
+       return opkg_list_find_cmd(argc, argv, 1);
 }
 
+static int opkg_list_installed_cmd(int argc, char **argv)
+{
+       int i;
+       pkg_vec_t *available;
+       pkg_t *pkg;
+       char *pkg_name = NULL;
 
-static int opkg_list_installed_cmd(opkg_conf_t *conf, int argc, char **argv)
+       if (argc > 0) {
+               pkg_name = argv[0];
+       }
+       available = pkg_vec_alloc();
+       pkg_hash_fetch_all_installed(available);
+       pkg_vec_sort(available, pkg_compare_names);
+       for (i = 0; i < available->len; i++) {
+               pkg = available->pkgs[i];
+               /* if we have package name or pattern and pkg does not match, then skip it */
+               if (pkg_name && fnmatch(pkg_name, pkg->name, conf->nocase))
+                       continue;
+               print_pkg(pkg);
+       }
+
+       pkg_vec_free(available);
+
+       return 0;
+}
+
+static int opkg_list_changed_conffiles_cmd(int argc, char **argv)
 {
-     int i ;
-     pkg_vec_t *available;
-     pkg_t *pkg;
-     char *pkg_name = NULL;
-
-     if (argc > 0) {
-         pkg_name = argv[0];
-     }
-     available = pkg_vec_alloc();
-     pkg_hash_fetch_all_installed(&conf->pkg_hash, available);
-     pkg_vec_sort(available, pkg_compare_names);
-     for (i=0; i < available->len; i++) {
-         pkg = available->pkgs[i];
-         /* if we have package name or pattern and pkg does not match, then skip it */
-         if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) 
-              continue;
-          print_pkg(pkg);
-     }
-
-     pkg_vec_free(available);
-
-     return 0;
+       int i;
+       pkg_vec_t *available;
+       pkg_t *pkg;
+       char *pkg_name = NULL;
+       conffile_list_elt_t *iter;
+       conffile_list_t *cl;
+       conffile_t *cf;
+
+       if (argc > 0) {
+               pkg_name = argv[0];
+       }
+       available = pkg_vec_alloc();
+       pkg_hash_fetch_all_installed(available);
+       pkg_vec_sort(available, pkg_compare_names);
+       for (i = 0; i < available->len; i++) {
+               pkg = available->pkgs[i];
+               cl = pkg_get_ptr(pkg, PKG_CONFFILES);
+               /* if we have package name or pattern and pkg does not match, then skip it */
+               if (pkg_name && fnmatch(pkg_name, pkg->name, conf->nocase))
+                       continue;
+               if (!cl || nv_pair_list_empty(cl))
+                       continue;
+               for (iter = nv_pair_list_first(cl); iter;
+                    iter = nv_pair_list_next(cl, iter)) {
+                       cf = (conffile_t *) iter->data;
+                       if (cf->name && cf->value
+                           && conffile_has_been_modified(cf))
+                               printf("%s\n", cf->name);
+               }
+       }
+       pkg_vec_free(available);
+       return 0;
 }
 
-static int opkg_list_upgradable_cmd(opkg_conf_t *conf, int argc, char **argv) 
+static int opkg_list_upgradable_cmd(int argc, char **argv)
 {
-    struct active_list *head = prepare_upgrade_list(conf);
-    struct active_list *node=NULL;
-    pkg_t *_old_pkg, *_new_pkg;
-    char *old_v, *new_v;
-    for (node = active_list_next(head, head); node;node = active_list_next(head,node)) {
-        _old_pkg = list_entry(node, pkg_t, list);
-        _new_pkg = pkg_hash_fetch_best_installation_candidate_by_name(conf, _old_pkg->name, NULL);
-        old_v = pkg_version_str_alloc(_old_pkg);
-        new_v = pkg_version_str_alloc(_new_pkg);
-        printf("%s - %s - %s\n", _old_pkg->name, old_v, new_v);
-        free(old_v);
-        free(new_v);
-    }
-    active_list_head_delete(head);
-    return 0;
+       struct active_list *head = prepare_upgrade_list();
+       struct active_list *node = NULL;
+       pkg_t *_old_pkg, *_new_pkg;
+       char *old_v, *new_v;
+       for (node = active_list_next(head, head); node;
+            node = active_list_next(head, node)) {
+               _old_pkg = node->pkg;
+               _new_pkg =
+                   pkg_hash_fetch_best_installation_candidate_by_name
+                   (_old_pkg->name);
+               if (_new_pkg == NULL)
+                       continue;
+               old_v = pkg_version_str_alloc(_old_pkg);
+               new_v = pkg_version_str_alloc(_new_pkg);
+               printf("%s - %s - %s\n", _old_pkg->name, old_v, new_v);
+               free(old_v);
+               free(new_v);
+       }
+       active_list_head_delete(head);
+       return 0;
 }
 
-static int opkg_info_status_cmd(opkg_conf_t *conf, int argc, char **argv, int installed_only)
+static int opkg_info_status_cmd(int argc, char **argv, int installed_only)
 {
-     int i;
-     pkg_vec_t *available;
-     pkg_t *pkg;
-     char *pkg_name = NULL;
-
-     if (argc > 0) {
-         pkg_name = argv[0];
-     }
-
-     available = pkg_vec_alloc();
-     if (installed_only)
-         pkg_hash_fetch_all_installed(&conf->pkg_hash, available);
-     else
-         pkg_hash_fetch_available(&conf->pkg_hash, available);
-
-     for (i=0; i < available->len; i++) {
-         pkg = available->pkgs[i];
-         if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) {
-              continue;
-         }
-
-         pkg_formatted_info(stdout, pkg);
-
-         if (conf->verbosity >= OPKG_NOTICE) {
-              conffile_list_elt_t *iter;
-              for (iter = nv_pair_list_first(&pkg->conffiles); iter; iter = nv_pair_list_next(&pkg->conffiles, iter)) {
-                   conffile_t *cf = (conffile_t *)iter->data;
-                   int modified = conffile_has_been_modified(conf, cf);
-                   if (cf->value)
-                       opkg_message(conf, OPKG_NOTICE,
-                               "conffile=%s md5sum=%s modified=%d\n",
-                                cf->name, cf->value, modified);
-              }
-         }
-     }
-     pkg_vec_free(available);
-
-     return 0;
+       int i;
+       pkg_vec_t *available;
+       pkg_t *pkg;
+       char *pkg_name = NULL;
+       conffile_list_t *cl;
+
+       if (argc > 0) {
+               pkg_name = argv[0];
+       }
+
+       available = pkg_vec_alloc();
+       if (installed_only)
+               pkg_hash_fetch_all_installed(available);
+       else
+               pkg_hash_fetch_available(available);
+
+       for (i = 0; i < available->len; i++) {
+               pkg = available->pkgs[i];
+               if (pkg_name && fnmatch(pkg_name, pkg->name, conf->nocase)) {
+                       continue;
+               }
+
+               pkg_formatted_info(stdout, pkg);
+
+               cl = pkg_get_ptr(pkg, PKG_CONFFILES);
+
+               if (conf->verbosity >= NOTICE && cl) {
+                       conffile_list_elt_t *iter;
+                       for (iter = nv_pair_list_first(cl); iter;
+                            iter = nv_pair_list_next(cl, iter)) {
+                               conffile_t *cf = (conffile_t *) iter->data;
+                               int modified = conffile_has_been_modified(cf);
+                               if (cf->value)
+                                       opkg_msg(INFO,
+                                                "conffile=%s md5sum=%s modified=%d.\n",
+                                                cf->name, cf->value, modified);
+                       }
+               }
+       }
+       pkg_vec_free(available);
+
+       return 0;
 }
 
-static int opkg_info_cmd(opkg_conf_t *conf, int argc, char **argv)
+static int opkg_info_cmd(int argc, char **argv)
 {
-     return opkg_info_status_cmd(conf, argc, argv, 0);
+       return opkg_info_status_cmd(argc, argv, 0);
 }
 
-static int opkg_status_cmd(opkg_conf_t *conf, int argc, char **argv)
+static int opkg_status_cmd(int argc, char **argv)
 {
-     return opkg_info_status_cmd(conf, argc, argv, 1);
+       return opkg_info_status_cmd(argc, argv, 1);
 }
 
-static int opkg_configure_cmd(opkg_conf_t *conf, int argc, char **argv)
+static int opkg_configure_cmd(int argc, char **argv)
 {
-     
-     int err;
-     if (argc > 0) {
-         char *pkg_name = NULL;
+       int err;
+       char *pkg_name = NULL;
 
-         pkg_name = argv[0];
+       if (argc > 0)
+               pkg_name = argv[0];
 
-         err = opkg_configure_packages (conf, pkg_name);
-     
-     } else {
-         err = opkg_configure_packages (conf, NULL);
-     }
+       err = opkg_configure_packages(pkg_name);
 
-     write_status_files_if_changed(conf);
+       write_status_files_if_changed();
 
-     return err;
+       return err;
 }
 
-static int opkg_remove_cmd(opkg_conf_t *conf, int argc, char **argv)
+static int opkg_remove_cmd(int argc, char **argv)
 {
-     int i, a, done;
-     pkg_t *pkg;
-     pkg_t *pkg_to_remove;
-     pkg_vec_t *available;
-
-     global_conf = conf;
-     done = 0;
-
-     signal(SIGINT, sigint_handler);
-
-     pkg_info_preinstall_check(conf);
-
-     available = pkg_vec_alloc();
-     pkg_hash_fetch_all_installed(&conf->pkg_hash, available);
-
-     for (i=0; i<argc; i++) {
-        for (a=0; a<available->len; a++) {
-            pkg = available->pkgs[a];
-           if (fnmatch(argv[i], pkg->name, 0)) {
-               continue;
-            }
-            if (conf->restrict_to_default_dest) {
-                pkg_to_remove = pkg_hash_fetch_installed_by_name_dest(&conf->pkg_hash,
-                                       pkg->name,
-                                       conf->default_dest);
-            } else {
-                pkg_to_remove = pkg_hash_fetch_installed_by_name(&conf->pkg_hash, pkg->name );
-            }
-        
-            if (pkg_to_remove == NULL) {
-                opkg_message(conf, OPKG_ERROR, "Package %s is not installed.\n", pkg->name);
-                continue;
-            }
-            if (pkg->state_status == SS_NOT_INSTALLED) {    // Added the control, so every already removed package could be skipped
-                opkg_message(conf, OPKG_ERROR, "Package seems to be %s not installed (STATUS = NOT_INSTALLED).\n", pkg->name);
-                 continue;
-            }
-            opkg_remove_pkg(conf, pkg_to_remove, 0);
-            done = 1;
-        }
-     }
-
-     pkg_vec_free(available);
-
-     if (done == 0)
-        opkg_message(conf, OPKG_NOTICE, "No packages removed.\n");
-
-     write_status_files_if_changed(conf);
-     return 0;
+       int i, a, done, err = 0;
+       pkg_t *pkg;
+       pkg_t *pkg_to_remove;
+       pkg_vec_t *available;
+
+       done = 0;
+
+       signal(SIGINT, sigint_handler);
+
+       pkg_info_preinstall_check();
+
+       available = pkg_vec_alloc();
+       pkg_hash_fetch_all_installed(available);
+
+       for (i = 0; i < argc; i++) {
+               for (a = 0; a < available->len; a++) {
+                       pkg = available->pkgs[a];
+                       if (fnmatch(argv[i], pkg->name, conf->nocase)) {
+                               continue;
+                       }
+                       if (conf->restrict_to_default_dest) {
+                               pkg_to_remove =
+                                   pkg_hash_fetch_installed_by_name_dest(pkg->
+                                                                         name,
+                                                                         conf->
+                                                                         default_dest);
+                       } else {
+                               pkg_to_remove =
+                                   pkg_hash_fetch_installed_by_name(pkg->name);
+                       }
+
+                       if (pkg_to_remove == NULL) {
+                               opkg_msg(ERROR,
+                                        "Package %s is not installed.\n",
+                                        pkg->name);
+                               continue;
+                       }
+                       if (pkg->state_status == SS_NOT_INSTALLED) {
+                               opkg_msg(ERROR, "Package %s not installed.\n",
+                                        pkg->name);
+                               continue;
+                       }
+
+                       if (opkg_remove_pkg(pkg_to_remove, 0))
+                               err = -1;
+                       else
+                               done = 1;
+               }
+       }
+
+       pkg_vec_free(available);
+
+       if (done == 0)
+               opkg_msg(NOTICE, "No packages removed.\n");
+
+       write_status_files_if_changed();
+       return err;
 }
 
-static int opkg_flag_cmd(opkg_conf_t *conf, int argc, char **argv)
+static int opkg_flag_cmd(int argc, char **argv)
 {
-     int i;
-     pkg_t *pkg;
-     const char *flags = argv[0];
-    
-     global_conf = conf;
-     signal(SIGINT, sigint_handler);
-
-     for (i=1; i < argc; i++) {
-         if (conf->restrict_to_default_dest) {
-              pkg = pkg_hash_fetch_installed_by_name_dest(&conf->pkg_hash,
-                                                          argv[i],
-                                                          conf->default_dest);
-         } else {
-              pkg = pkg_hash_fetch_installed_by_name(&conf->pkg_hash, argv[i]);
-         }
-
-         if (pkg == NULL) {
-              opkg_message(conf, OPKG_ERROR,
-                           "Package %s is not installed.\n", argv[i]);
-              continue;
-         }
-          if (( strcmp(flags,"hold")==0)||( strcmp(flags,"noprune")==0)||
-              ( strcmp(flags,"user")==0)||( strcmp(flags,"ok")==0)) {
-             pkg->state_flag = pkg_state_flag_from_str(flags);
-          }
-
-         /* 
-          * Useful if a package is installed in an offline_root, and
-          * should be configured by opkg-cl configure at a later date.
-          */
-          if (( strcmp(flags,"installed")==0)||( strcmp(flags,"unpacked")==0)){
-             pkg->state_status = pkg_state_status_from_str(flags);
-          }
-
-         opkg_state_changed++;
-         opkg_message(conf, OPKG_NOTICE,
-                      "Setting flags for package %s to %s\n",
-                      pkg->name, flags);
-     }
-
-     write_status_files_if_changed(conf);
-     return 0;
+       int i;
+       pkg_t *pkg;
+       const char *flags = argv[0];
+
+       signal(SIGINT, sigint_handler);
+
+       for (i = 1; i < argc; i++) {
+               if (conf->restrict_to_default_dest) {
+                       pkg = pkg_hash_fetch_installed_by_name_dest(argv[i],
+                                                                   conf->
+                                                                   default_dest);
+               } else {
+                       pkg = pkg_hash_fetch_installed_by_name(argv[i]);
+               }
+
+               if (pkg == NULL) {
+                       opkg_msg(ERROR, "Package %s is not installed.\n",
+                                argv[i]);
+                       continue;
+               }
+               if ((strcmp(flags, "hold") == 0)
+                   || (strcmp(flags, "noprune") == 0)
+                   || (strcmp(flags, "user") == 0)
+                   || (strcmp(flags, "ok") == 0)) {
+                       pkg->state_flag = pkg_state_flag_from_str(flags);
+               }
+
+               /*
+                * Useful if a package is installed in an offline_root, and
+                * should be configured by opkg-cl configure at a later date.
+                */
+               if ((strcmp(flags, "installed") == 0)
+                   || (strcmp(flags, "unpacked") == 0)) {
+                       pkg->state_status = pkg_state_status_from_str(flags);
+               }
+
+               opkg_state_changed++;
+               opkg_msg(NOTICE, "Setting flags for package %s to %s.\n",
+                        pkg->name, flags);
+       }
+
+       write_status_files_if_changed();
+       return 0;
 }
 
-static int opkg_files_cmd(opkg_conf_t *conf, int argc, char **argv)
+static int opkg_files_cmd(int argc, char **argv)
 {
-     pkg_t *pkg;
-     str_list_t *files;
-     str_list_elt_t *iter;
-     char *pkg_version;
+       pkg_t *pkg;
+       str_list_t *files;
+       str_list_elt_t *iter;
+       char *pkg_version;
 
-     if (argc < 1) {
-         return EINVAL;
-     }
+       if (argc < 1) {
+               return -1;
+       }
 
-     pkg = pkg_hash_fetch_installed_by_name(&conf->pkg_hash,
-                                           argv[0]);
-     if (pkg == NULL) {
-         opkg_message(conf, OPKG_ERROR,
-                      "Package %s not installed.\n", argv[0]);
-         return 0;
-     }
+       pkg = pkg_hash_fetch_installed_by_name(argv[0]);
+       if (pkg == NULL) {
+               opkg_msg(ERROR, "Package %s not installed.\n", argv[0]);
+               return 0;
+       }
 
-     files = pkg_get_installed_files(conf, pkg);
-     pkg_version = pkg_version_str_alloc(pkg);
+       files = pkg_get_installed_files(pkg);
+       pkg_version = pkg_version_str_alloc(pkg);
 
-     printf("Package %s (%s) is installed on %s and has the following files:\n",
-               pkg->name, pkg_version, pkg->dest->name);
+       printf
+           ("Package %s (%s) is installed on %s and has the following files:\n",
+            pkg->name, pkg_version, pkg->dest->name);
 
-     for (iter=str_list_first(files); iter; iter=str_list_next(files, iter))
-          printf("%s\n", (char *)iter->data);
+       for (iter = str_list_first(files); iter;
+            iter = str_list_next(files, iter))
+               printf("%s\n", (char *)iter->data);
 
-     free(pkg_version);
-     pkg_free_installed_files(pkg);
+       free(pkg_version);
+       pkg_free_installed_files(pkg);
 
-     return 0;
+       return 0;
 }
 
-static int opkg_depends_cmd(opkg_conf_t *conf, int argc, char **argv)
+static int opkg_depends_cmd(int argc, char **argv)
 {
        int i, j, k;
-       int depends_count;
        pkg_vec_t *available_pkgs;
        compound_depend_t *cdep;
        pkg_t *pkg;
        char *str;
 
-       pkg_info_preinstall_check(conf);
+       pkg_info_preinstall_check();
 
        available_pkgs = pkg_vec_alloc();
        if (conf->query_all)
-              pkg_hash_fetch_available(&conf->pkg_hash, available_pkgs);
+               pkg_hash_fetch_available(available_pkgs);
        else
-              pkg_hash_fetch_all_installed(&conf->pkg_hash, available_pkgs);
+               pkg_hash_fetch_all_installed(available_pkgs);
 
-       for (i=0; i<argc; i++) {
-               for (j=0; j<available_pkgs->len; j++) {
+       for (i = 0; i < argc; i++) {
+               for (j = 0; j < available_pkgs->len; j++) {
                        pkg = available_pkgs->pkgs[j];
 
-                       if (fnmatch(argv[i], pkg->name, 0) != 0)
+                       if (fnmatch(argv[i], pkg->name, conf->nocase) != 0)
                                continue;
 
-                       depends_count = pkg->depends_count +
-                                       pkg->pre_depends_count +
-                                       pkg->recommends_count +
-                                       pkg->suggests_count;
-
-                       opkg_message(conf, OPKG_NOTICE, "%s depends on:\n",
-                                     pkg->name);
-
-                       for (k=0; k<depends_count; k++) {
-                               cdep = &pkg->depends[k];
+                       opkg_msg(NOTICE, "%s depends on:\n", pkg->name);
 
+                       for (k = 0, cdep = pkg_get_ptr(pkg, PKG_DEPENDS); cdep && cdep->type; k++, cdep++) {
                                if (cdep->type != DEPEND)
-                                     continue;
+                                       continue;
 
                                str = pkg_depend_str(pkg, k);
-                               opkg_message(conf, OPKG_NOTICE, "\t%s\n", str);
+                               opkg_msg(NOTICE, "\t%s\n", str);
                                free(str);
                        }
 
-              }
+               }
        }
 
        pkg_vec_free(available_pkgs);
        return 0;
 }
 
+static int pkg_mark_provides(pkg_t * pkg)
+{
+       abstract_pkg_t **provider = pkg_get_ptr(pkg, PKG_PROVIDES);
+
+       pkg->parent->state_flag |= SF_MARKED;
+
+       while (provider && *provider) {
+               (*provider)->state_flag |= SF_MARKED;
+               provider++;
+       }
+
+       return 0;
+}
+
 enum what_field_type {
-  WHATDEPENDS,
-  WHATCONFLICTS,
-  WHATPROVIDES,
-  WHATREPLACES,
-  WHATRECOMMENDS,
-  WHATSUGGESTS
+       WHATDEPENDS,
+       WHATCONFLICTS,
+       WHATPROVIDES,
+       WHATREPLACES,
+       WHATRECOMMENDS,
+       WHATSUGGESTS
 };
 
-static int opkg_what_depends_conflicts_cmd(opkg_conf_t *conf, enum depend_type what_field_type, int recursive, int argc, char **argv)
+static int
+opkg_what_depends_conflicts_cmd(enum depend_type what_field_type, int recursive,
+                               int argc, char **argv)
 {
        depend_t *possibility;
-       compound_depend_t *cdep;
+       compound_depend_t *cdep, *deps;
        pkg_vec_t *available_pkgs;
        pkg_t *pkg;
-       int i, j, k, l;
-       int changed, count;
+       int i, j, l;
+       int changed;
        const char *rel_str = NULL;
        char *ver;
 
        switch (what_field_type) {
-       case DEPEND: rel_str = "depends on"; break;
-       case CONFLICTS: rel_str = "conflicts with"; break;
-       case SUGGEST: rel_str = "suggests"; break;
-       case RECOMMEND: rel_str = "recommends"; break;
-       default: return -1;
+       case DEPEND:
+               rel_str = "depends on";
+               break;
+       case CONFLICTS:
+               rel_str = "conflicts with";
+               break;
+       case SUGGEST:
+               rel_str = "suggests";
+               break;
+       case RECOMMEND:
+               rel_str = "recommends";
+               break;
+       default:
+               return -1;
        }
-     
+
        available_pkgs = pkg_vec_alloc();
 
        if (conf->query_all)
-              pkg_hash_fetch_available(&conf->pkg_hash, available_pkgs);
+               pkg_hash_fetch_available(available_pkgs);
        else
-              pkg_hash_fetch_all_installed(&conf->pkg_hash, available_pkgs);
+               pkg_hash_fetch_all_installed(available_pkgs);
 
        /* mark the root set */
        pkg_vec_clear_marks(available_pkgs);
-       opkg_message(conf, OPKG_NOTICE, "Root set:\n");
+       opkg_msg(NOTICE, "Root set:\n");
        for (i = 0; i < argc; i++)
-              pkg_vec_mark_if_matches(available_pkgs, argv[i]);
+               pkg_vec_mark_if_matches(available_pkgs, argv[i]);
 
        for (i = 0; i < available_pkgs->len; i++) {
-              pkg = available_pkgs->pkgs[i];
-              if (pkg->state_flag & SF_MARKED) {
-                   /* mark the parent (abstract) package */
-                   pkg_mark_provides(pkg);
-                   opkg_message(conf, OPKG_NOTICE, "  %s\n", pkg->name);
-              }
+               pkg = available_pkgs->pkgs[i];
+               if (pkg->state_flag & SF_MARKED) {
+                       /* mark the parent (abstract) package */
+                       pkg_mark_provides(pkg);
+                       opkg_msg(NOTICE, "  %s\n", pkg->name);
+               }
        }
 
-       opkg_message(conf, OPKG_NOTICE, "What %s root set\n", rel_str);
+       opkg_msg(NOTICE, "What %s root set\n", rel_str);
        do {
                changed = 0;
 
-               for (j=0; j<available_pkgs->len; j++) {
+               for (j = 0; j < available_pkgs->len; j++) {
 
                        pkg = available_pkgs->pkgs[j];
+                       /*
                        count = ((what_field_type == CONFLICTS)
                                 ? pkg->conflicts_count
                                 : pkg->pre_depends_count +
                                 pkg->depends_count +
-                                pkg->recommends_count +
-                                pkg->suggests_count);
+                                pkg->recommends_count + pkg->suggests_count);
+                                */
 
                        /* skip this package if it is already marked */
                        if (pkg->parent->state_flag & SF_MARKED)
                                continue;
 
-                       for (k=0; k<count; k++) {
-                               cdep = (what_field_type == CONFLICTS)
-                                       ? &pkg->conflicts[k]
-                                       : &pkg->depends[k];
+                       deps = pkg_get_ptr(pkg, (what_field_type == CONFLICTS) ? PKG_CONFLICTS : PKG_DEPENDS);
 
+                       for (cdep = deps; cdep->type; cdep++) {
                                if (what_field_type != cdep->type)
                                        continue;
 
-                               for (l=0; l<cdep->possibility_count; l++) {
+                               for (l = 0; l < cdep->possibility_count; l++) {
                                        possibility = cdep->possibilities[l];
 
                                        if ((possibility->pkg->state_flag
-                                                               & SF_MARKED)
-                                                       != SF_MARKED)
+                                            & SF_MARKED)
+                                           != SF_MARKED)
                                                continue;
-                                       
+
                                        /* mark the depending package so we
-                                       * won't visit it again */
+                                        * won't visit it again */
                                        pkg->state_flag |= SF_MARKED;
                                        pkg_mark_provides(pkg);
                                        changed++;
 
-                                       ver = pkg_version_str_alloc(pkg); 
-                                       opkg_message(conf, OPKG_NOTICE,
-                                                       "\t%s %s\t%s %s",
-                                                       pkg->name,
-                                                       ver,
-                                                       rel_str,
-                                                       possibility->pkg->name);
+                                       ver = pkg_version_str_alloc(pkg);
+                                       opkg_msg(NOTICE, "\t%s %s\t%s %s",
+                                                pkg->name,
+                                                ver,
+                                                rel_str,
+                                                possibility->pkg->name);
                                        free(ver);
                                        if (possibility->version) {
-                                               opkg_message(conf, OPKG_NOTICE,
-                                                       " (%s%s)",
-                                                       constraint_to_str(possibility->constraint),
-                                                       possibility->version);
+                                               opkg_msg(NOTICE, " (%s%s)",
+                                                        constraint_to_str
+                                                        (possibility->
+                                                         constraint),
+                                                        possibility->version);
                                        }
-                                       if (!pkg_dependence_satisfiable(conf, possibility))
-                                               opkg_message(conf, OPKG_NOTICE,
-                                                       " unsatisfiable");
-                                       opkg_message(conf, OPKG_NOTICE, "\n");
+                                       if (!pkg_dependence_satisfiable
+                                           (possibility))
+                                               opkg_msg(NOTICE,
+                                                        " unsatisfiable");
+                                       opkg_message(NOTICE, "\n");
                                        goto next_package;
                                }
                        }
@@ -1103,155 +1085,241 @@ next_package:
        return 0;
 }
 
-static int pkg_mark_provides(pkg_t *pkg)
+static int opkg_whatdepends_recursively_cmd(int argc, char **argv)
 {
-     int provides_count = pkg->provides_count;
-     abstract_pkg_t **provides = pkg->provides;
-     int i;
-     pkg->parent->state_flag |= SF_MARKED;
-     for (i = 0; i < provides_count; i++) {
-         provides[i]->state_flag |= SF_MARKED;
-     }
-     return 0;
+       return opkg_what_depends_conflicts_cmd(DEPEND, 1, argc, argv);
 }
 
-static int opkg_whatdepends_recursively_cmd(opkg_conf_t *conf, int argc, char **argv)
-{
-     return opkg_what_depends_conflicts_cmd(conf, DEPEND, 1, argc, argv);
-}
-static int opkg_whatdepends_cmd(opkg_conf_t *conf, int argc, char **argv)
+static int opkg_whatdepends_cmd(int argc, char **argv)
 {
-     return opkg_what_depends_conflicts_cmd(conf, DEPEND, 0, argc, argv);
+       return opkg_what_depends_conflicts_cmd(DEPEND, 0, argc, argv);
 }
 
-static int opkg_whatsuggests_cmd(opkg_conf_t *conf, int argc, char **argv)
+static int opkg_whatsuggests_cmd(int argc, char **argv)
 {
-     return opkg_what_depends_conflicts_cmd(conf, SUGGEST, 0, argc, argv);
+       return opkg_what_depends_conflicts_cmd(SUGGEST, 0, argc, argv);
 }
 
-static int opkg_whatrecommends_cmd(opkg_conf_t *conf, int argc, char **argv)
+static int opkg_whatrecommends_cmd(int argc, char **argv)
 {
-     return opkg_what_depends_conflicts_cmd(conf, RECOMMEND, 0, argc, argv);
+       return opkg_what_depends_conflicts_cmd(RECOMMEND, 0, argc, argv);
 }
 
-static int opkg_whatconflicts_cmd(opkg_conf_t *conf, int argc, char **argv)
+static int opkg_whatconflicts_cmd(int argc, char **argv)
 {
-     return opkg_what_depends_conflicts_cmd(conf, CONFLICTS, 0, argc, argv);
+       return opkg_what_depends_conflicts_cmd(CONFLICTS, 0, argc, argv);
 }
 
-static int opkg_what_provides_replaces_cmd(opkg_conf_t *conf, enum what_field_type what_field_type, int argc, char **argv)
+static int
+opkg_what_provides_replaces_cmd(enum what_field_type what_field_type, int argc,
+                               char **argv)
 {
+       abstract_pkg_t *apkg, **abpkgs;
+
+       if (argc > 0) {
+               pkg_vec_t *available_pkgs = pkg_vec_alloc();
+               const char *rel_str =
+                   (what_field_type == WHATPROVIDES ? "provides" : "replaces");
+               int i;
+
+               pkg_info_preinstall_check();
+
+               if (conf->query_all)
+                       pkg_hash_fetch_available(available_pkgs);
+               else
+                       pkg_hash_fetch_all_installed(available_pkgs);
+               for (i = 0; i < argc; i++) {
+                       const char *target = argv[i];
+                       int j;
+
+                       opkg_msg(NOTICE, "What %s %s\n", rel_str, target);
+                       for (j = 0; j < available_pkgs->len; j++) {
+                               pkg_t *pkg = available_pkgs->pkgs[j];
+                               abpkgs = pkg_get_ptr(pkg, (what_field_type == WHATPROVIDES) ? PKG_PROVIDES : PKG_REPLACES);
+
+                               while (abpkgs && *abpkgs) {
+                                       apkg = *abpkgs;
+
+                                       if (fnmatch(target, apkg->name, conf->nocase))
+                                               continue;
+
+                                       opkg_msg(NOTICE, "    %s", pkg->name);
 
-     if (argc > 0) {
-         pkg_vec_t *available_pkgs = pkg_vec_alloc();
-         const char *rel_str = (what_field_type == WHATPROVIDES ? "provides" : "replaces");
-         int i;
-     
-         pkg_info_preinstall_check(conf);
-
-         if (conf->query_all)
-              pkg_hash_fetch_available(&conf->pkg_hash, available_pkgs);
-         else
-              pkg_hash_fetch_all_installed(&conf->pkg_hash, available_pkgs);
-         for (i = 0; i < argc; i++) {
-              const char *target = argv[i];
-              int j;
-
-              opkg_message(conf, OPKG_ERROR, "What %s %s\n",
-                           rel_str, target);
-              for (j = 0; j < available_pkgs->len; j++) {
-                   pkg_t *pkg = available_pkgs->pkgs[j];
-                   int k;
-                   int count = (what_field_type == WHATPROVIDES) ? pkg->provides_count : pkg->replaces_count;
-                   for (k = 0; k < count; k++) {
-                        abstract_pkg_t *apkg = 
-                             ((what_field_type == WHATPROVIDES) 
-                              ? pkg->provides[k]
-                              : pkg->replaces[k]);
-                        if (fnmatch(target, apkg->name, 0) == 0) {
-                             opkg_message(conf, OPKG_ERROR, "    %s", pkg->name);
-                             if (strcmp(target, apkg->name) != 0)
-                                  opkg_message(conf, OPKG_ERROR, "\t%s %s\n", rel_str, apkg->name);
-                             opkg_message(conf, OPKG_ERROR, "\n");
-                        }
-                   }
-              }
-         }
-         pkg_vec_free(available_pkgs);
-     }
-     return 0;
+                                       if ((conf->nocase ? strcasecmp(target, apkg->name)
+                                           : strcmp(target, apkg->name)))
+                                               opkg_msg(NOTICE, "\t%s %s\n", rel_str, apkg->name);
+
+                                       opkg_message(NOTICE, "\n");
+                                       abpkgs++;
+                               }
+                       }
+               }
+               pkg_vec_free(available_pkgs);
+       }
+       return 0;
 }
 
-static int opkg_whatprovides_cmd(opkg_conf_t *conf, int argc, char **argv)
+static int opkg_whatprovides_cmd(int argc, char **argv)
 {
-     return opkg_what_provides_replaces_cmd(conf, WHATPROVIDES, argc, argv);
+       return opkg_what_provides_replaces_cmd(WHATPROVIDES, argc, argv);
 }
 
-static int opkg_whatreplaces_cmd(opkg_conf_t *conf, int argc, char **argv)
+static int opkg_whatreplaces_cmd(int argc, char **argv)
 {
-     return opkg_what_provides_replaces_cmd(conf, WHATREPLACES, argc, argv);
+       return opkg_what_provides_replaces_cmd(WHATREPLACES, argc, argv);
 }
 
-static int opkg_search_cmd(opkg_conf_t *conf, int argc, char **argv)
+static int opkg_search_cmd(int argc, char **argv)
 {
-     int i;
+       int i;
 
-     pkg_vec_t *installed;
-     pkg_t *pkg;
-     str_list_t *installed_files;
-     str_list_elt_t *iter;
-     char *installed_file;
+       pkg_vec_t *installed;
+       pkg_t *pkg;
+       str_list_t *installed_files;
+       str_list_elt_t *iter;
+       char *installed_file;
 
-     if (argc < 1) {
-         return EINVAL;
-     }
-     installed = pkg_vec_alloc();
-     pkg_hash_fetch_all_installed(&conf->pkg_hash, installed);
-     pkg_vec_sort(installed, pkg_compare_names);
+       if (argc < 1) {
+               return -1;
+       }
 
-     for (i=0; i < installed->len; i++) {
-         pkg = installed->pkgs[i];
+       installed = pkg_vec_alloc();
+       pkg_hash_fetch_all_installed(installed);
+       pkg_vec_sort(installed, pkg_compare_names);
 
-         installed_files = pkg_get_installed_files(conf, pkg);
+       for (i = 0; i < installed->len; i++) {
+               pkg = installed->pkgs[i];
 
-         for (iter = str_list_first(installed_files); iter; iter = str_list_next(installed_files, iter)) {
-              installed_file = (char *)iter->data;
-              if (fnmatch(argv[0], installed_file, 0)==0)
-                   print_pkg(pkg);
-         }
+               installed_files = pkg_get_installed_files(pkg);
 
-         pkg_free_installed_files(pkg);
-     }
+               for (iter = str_list_first(installed_files); iter;
+                    iter = str_list_next(installed_files, iter)) {
+                       installed_file = (char *)iter->data;
+                       if (fnmatch(argv[0], installed_file, conf->nocase) == 0)
+                               print_pkg(pkg);
+               }
+
+               pkg_free_installed_files(pkg);
+       }
 
-     pkg_vec_free(installed);
+       pkg_vec_free(installed);
 
-     return 0;
+       return 0;
+}
+
+static int opkg_compare_versions_cmd(int argc, char **argv)
+{
+       if (argc == 3) {
+               /* this is a bit gross */
+               struct pkg p1, p2;
+               parse_version(&p1, argv[0]);
+               parse_version(&p2, argv[2]);
+               return pkg_version_satisfied(&p1, &p2, argv[1]);
+       } else {
+               opkg_msg(ERROR,
+                        "opkg compare_versions <v1> <op> <v2>\n"
+                        "<op> is one of <= >= << >> =\n");
+               return -1;
+       }
 }
 
-static int opkg_compare_versions_cmd(opkg_conf_t *conf, int argc, char **argv)
+static int opkg_print_architecture_cmd(int argc, char **argv)
 {
-     if (argc == 3) {
-         /* this is a bit gross */
-         struct pkg p1, p2;
-         parse_version(&p1, argv[0]); 
-         parse_version(&p2, argv[2]); 
-         return pkg_version_satisfied(&p1, &p2, argv[1]);
-     } else {
-         opkg_message(conf, OPKG_ERROR,
-                      "opkg compare_versions <v1> <op> <v2>\n"
-                      "<op> is one of <= >= << >> =\n");
-         return -1;
-     }
+       nv_pair_list_elt_t *l;
+
+       list_for_each_entry(l, &conf->arch_list.head, node) {
+               nv_pair_t *nv = (nv_pair_t *) l->data;
+               printf("arch %s %s\n", nv->name, nv->value);
+       }
+       return 0;
 }
 
-static int opkg_print_architecture_cmd(opkg_conf_t *conf, int argc, char **argv)
+/* XXX: CLEANUP: The usage strings should be incorporated into this
+   array for easier maintenance */
+static opkg_cmd_t cmds[] = {
+       {"update", 0, (opkg_cmd_fun_t) opkg_update_cmd,
+        PFM_DESCRIPTION | PFM_SOURCE},
+       {"upgrade", 1, (opkg_cmd_fun_t) opkg_upgrade_cmd,
+        PFM_DESCRIPTION | PFM_SOURCE},
+       {"list", 0, (opkg_cmd_fun_t) opkg_list_cmd, PFM_SOURCE},
+       {"list_installed", 0, (opkg_cmd_fun_t) opkg_list_installed_cmd,
+        PFM_SOURCE},
+       {"list-installed", 0, (opkg_cmd_fun_t) opkg_list_installed_cmd,
+        PFM_SOURCE},
+       {"list_upgradable", 0, (opkg_cmd_fun_t) opkg_list_upgradable_cmd,
+        PFM_SOURCE},
+       {"list-upgradable", 0, (opkg_cmd_fun_t) opkg_list_upgradable_cmd,
+        PFM_SOURCE},
+       {"list_changed_conffiles", 0,
+        (opkg_cmd_fun_t) opkg_list_changed_conffiles_cmd, PFM_SOURCE},
+       {"list-changed-conffiles", 0,
+        (opkg_cmd_fun_t) opkg_list_changed_conffiles_cmd, PFM_SOURCE},
+       {"info", 0, (opkg_cmd_fun_t) opkg_info_cmd, 0},
+       {"flag", 1, (opkg_cmd_fun_t) opkg_flag_cmd,
+        PFM_DESCRIPTION | PFM_SOURCE},
+       {"status", 0, (opkg_cmd_fun_t) opkg_status_cmd,
+        PFM_DESCRIPTION | PFM_SOURCE},
+       {"install", 1, (opkg_cmd_fun_t) opkg_install_cmd,
+        PFM_DESCRIPTION | PFM_SOURCE},
+       {"remove", 1, (opkg_cmd_fun_t) opkg_remove_cmd,
+        PFM_DESCRIPTION | PFM_SOURCE},
+       {"configure", 0, (opkg_cmd_fun_t) opkg_configure_cmd,
+        PFM_DESCRIPTION | PFM_SOURCE},
+       {"files", 1, (opkg_cmd_fun_t) opkg_files_cmd,
+        PFM_DESCRIPTION | PFM_SOURCE},
+       {"search", 1, (opkg_cmd_fun_t) opkg_search_cmd,
+        PFM_DESCRIPTION | PFM_SOURCE},
+       {"find", 1, (opkg_cmd_fun_t) opkg_find_cmd, PFM_SOURCE},
+       {"download", 1, (opkg_cmd_fun_t) opkg_download_cmd,
+        PFM_DESCRIPTION | PFM_SOURCE},
+       {"compare_versions", 1, (opkg_cmd_fun_t) opkg_compare_versions_cmd,
+        PFM_DESCRIPTION | PFM_SOURCE},
+       {"compare-versions", 1, (opkg_cmd_fun_t) opkg_compare_versions_cmd,
+        PFM_DESCRIPTION | PFM_SOURCE},
+       {"print-architecture", 0, (opkg_cmd_fun_t) opkg_print_architecture_cmd,
+        PFM_DESCRIPTION | PFM_SOURCE},
+       {"print_architecture", 0, (opkg_cmd_fun_t) opkg_print_architecture_cmd,
+        PFM_DESCRIPTION | PFM_SOURCE},
+       {"print-installation-architecture", 0,
+        (opkg_cmd_fun_t) opkg_print_architecture_cmd,
+        PFM_DESCRIPTION | PFM_SOURCE},
+       {"print_installation_architecture", 0,
+        (opkg_cmd_fun_t) opkg_print_architecture_cmd,
+        PFM_DESCRIPTION | PFM_SOURCE},
+       {"depends", 1, (opkg_cmd_fun_t) opkg_depends_cmd,
+        PFM_DESCRIPTION | PFM_SOURCE},
+       {"whatdepends", 1, (opkg_cmd_fun_t) opkg_whatdepends_cmd,
+        PFM_DESCRIPTION | PFM_SOURCE},
+       {"whatdependsrec", 1, (opkg_cmd_fun_t) opkg_whatdepends_recursively_cmd,
+        PFM_DESCRIPTION | PFM_SOURCE},
+       {"whatrecommends", 1, (opkg_cmd_fun_t) opkg_whatrecommends_cmd,
+        PFM_DESCRIPTION | PFM_SOURCE},
+       {"whatsuggests", 1, (opkg_cmd_fun_t) opkg_whatsuggests_cmd,
+        PFM_DESCRIPTION | PFM_SOURCE},
+       {"whatprovides", 1, (opkg_cmd_fun_t) opkg_whatprovides_cmd,
+        PFM_DESCRIPTION | PFM_SOURCE},
+       {"whatreplaces", 1, (opkg_cmd_fun_t) opkg_whatreplaces_cmd,
+        PFM_DESCRIPTION | PFM_SOURCE},
+       {"whatconflicts", 1, (opkg_cmd_fun_t) opkg_whatconflicts_cmd,
+        PFM_DESCRIPTION | PFM_SOURCE},
+};
+
+opkg_cmd_t *opkg_cmd_find(const char *name)
 {
-     nv_pair_list_elt_t *l;
+       int i;
+       opkg_cmd_t *cmd;
+       int num_cmds = sizeof(cmds) / sizeof(opkg_cmd_t);
+
+       for (i = 0; i < num_cmds; i++) {
+               cmd = &cmds[i];
+               if (strcmp(name, cmd->name) == 0)
+                       return cmd;
+       }
 
-     list_for_each_entry(l, &conf->arch_list.head, node) {
-         nv_pair_t *nv = (nv_pair_t *)l->data;
-         printf("arch %s %s\n", nv->name, nv->value);
-     }
-     return 0;
+       return NULL;
+}
+
+int opkg_cmd_exec(opkg_cmd_t * cmd, int argc, const char **argv)
+{
+       return (cmd->fun) (argc, argv);
 }