-/* 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"
#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);
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 */
opkg_conf_write_status_files(conf);
pkg_write_changed_filelists(conf);
} else {
- opkg_message(conf, OPKG_NOTICE, "Nothing to be done\n");
+ opkg_message(conf, OPKG_DEBUG, "Nothing to be done\n");
}
}
return NULL;
}
-#ifdef OPKG_LIB
+void opkg_print_error_list (opkg_conf_t *conf)
+{
+ if ( error_list ) {
+ reverse_error_list(&error_list);
+
+ printf ("Collected errors:\n");
+ /* Here we print the errors collected and free the list */
+ while (error_list != NULL) {
+ printf (" * %s", error_list->errmsg);
+ error_list = error_list->next;
+
+ }
+ free_error_list(&error_list);
+ }
+
+}
+
int opkg_cmd_exec(opkg_cmd_t *cmd, opkg_conf_t *conf, int argc, const char **argv, void *userdata)
{
int result;
result = (cmd->fun)(conf, argc, argv);
- if ( result != 0 ) {
+ if ( result != 0 && !error_list) {
opkg_message(conf, OPKG_NOTICE, "An error ocurred, return value: %d.\n", result);
}
- if ( error_list ) {
- reverse_error_list(&error_list);
-
- opkg_message(conf, OPKG_NOTICE, "Collected errors:\n");
- /* Here we print the errors collected and free the list */
- while (error_list != NULL) {
- opkg_message(conf, OPKG_NOTICE, "%s",error_list->errmsg);
- error_list = error_list->next;
+ opkg_print_error_list (conf);
- }
- free_error_list(&error_list);
-
- }
-
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;
}
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;
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");
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 {
}
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? */
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;
}
-/* scan the args passed and cache the local filenames of the packages */
-int opkg_multiple_files_scan(opkg_conf_t *conf, int argc, char **argv)
-{
- int i;
- int err;
-
- /*
- * First scan through package names/urls
- * For any urls, download the packages and install in database.
- * For any files, install package info in database.
- */
- for (i = 0; i < argc; i ++) {
- char *filename = argv [i];
- //char *tmp = basename (tmp);
- //int tmplen = strlen (tmp);
-
- //if (strcmp (tmp + (tmplen - strlen (OPKG_PKG_EXTENSION)), OPKG_PKG_EXTENSION) != 0)
- // continue;
- //if (strcmp (tmp + (tmplen - strlen (DPKG_PKG_EXTENSION)), DPKG_PKG_EXTENSION) != 0)
- // continue;
-
- opkg_message(conf, OPKG_DEBUG2, "Debug mfs: %s \n",filename );
-
- err = opkg_prepare_url_for_install(conf, filename, &argv[i]);
- if (err)
- return err;
- }
- return 0;
-}
-
struct opkg_intercept
{
char *oldpath;
typedef struct opkg_intercept *opkg_intercept_t;
-opkg_intercept_t opkg_prep_intercepts(opkg_conf_t *conf)
+static opkg_intercept_t opkg_prep_intercepts(opkg_conf_t *conf)
{
opkg_intercept_t ctx;
char *newpath;
return ctx;
}
-int opkg_finalize_intercepts(opkg_intercept_t ctx)
+static int opkg_finalize_intercepts(opkg_intercept_t ctx)
{
char *cmd;
DIR *dir;
return err;
}
-int opkg_configure_packages(opkg_conf_t *conf, char *pkg_name)
+/* 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.
+*/
+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)
+{
+ 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;
+
+}
+
+static 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;
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++) {
err = r;
pkg_vec_free(all);
+ pkg_vec_free(ordered);
+ pkg_vec_free(visited);
+
return err;
}
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"
- "Check the spelling or perhaps run 'opkg update'\n",
+ "Cannot find package %s.\n",
arg);
}
}
for (i = 0; i < argc; i++) {
arg = argv[i];
- pkg = pkg_hash_fetch_best_installation_candidate_by_name(conf, arg);
+ 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"
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,
p_userdata);
free(version_str);
}
-#endif
}
pkg_vec_free(available);
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,
p_userdata);
free(version_str);
}
-#endif
}
return 0;
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 ) {
*/
free(buff);
}
-#endif
if (conf->verbosity > 1) {
conffile_list_elt_t *iter;
for (iter = pkg->conffiles.head; iter; iter = iter->next) {
}
}
}
-#ifndef OPKG_LIB
- if (buff)
- free(buff);
-#endif
pkg_vec_free(available);
return 0;
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",
p_userdata);
free(buff);
}
-#endif
free(pkg_version);
pkg_free_installed_files(pkg);
return 0;
}
-int pkg_mark_provides(pkg_t *pkg)
+static int pkg_mark_provides(pkg_t *pkg)
{
int provides_count = pkg->provides_count;
abstract_pkg_t **provides = pkg->provides;
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
}
}