-/* 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>
static int opkg_install_pending_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_purge_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_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 */
{"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_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},
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;
}
+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();
+ }
+
+}
+
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_print_error_list (conf);
- 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;
-
- }
- free_error_list(&error_list);
-
- }
-
p_userdata = NULL;
return result;
}
FILE *in, *out;
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");
unlink (tmp_file_name);
}
} else
- err = opkg_download(conf, url, list_file_name);
+ err = opkg_download(conf, url, list_file_name, NULL, NULL);
if (err) {
failures++;
} else {
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
free (tmp_file_name);
free (url);
#else
- opkg_message (conf, OPKG_NOTICE, "Signiture check for %s skipped "
+ opkg_message (conf, OPKG_NOTICE, "Signature check for %s skipped "
"because GPG support was not enabled in this build\n", src->name);
#endif
free(list_file_name);
}
-/* 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 *oldpath;
char *newpath;
int gen;
- ctx = malloc (sizeof (*ctx));
- ctx->oldpath = strdup (getenv ("PATH"));
+ ctx = calloc (1, sizeof (*ctx));
+ oldpath = getenv ("PATH");
+ if (oldpath) {
+ ctx->oldpath = strdup (oldpath);
+ } else {
+ ctx->oldpath = 0;
+ }
+
sprintf_alloc (&newpath, "%s/opkg/intercept:%s", DATADIR, ctx->oldpath);
setenv ("PATH", newpath, 1);
return ctx;
}
-int opkg_finalize_intercepts(opkg_intercept_t ctx)
+static int opkg_finalize_intercepts(opkg_intercept_t ctx)
{
char *cmd;
DIR *dir;
int err = 0;
- setenv ("PATH", ctx->oldpath, 1);
- free (ctx->oldpath);
+ if (ctx->oldpath) {
+ setenv ("PATH", ctx->oldpath, 1);
+ free (ctx->oldpath);
+ } else {
+ unsetenv("PATH");
+ }
dir = opendir (ctx->statedir);
if (dir) {
perror (ctx->statedir);
sprintf_alloc (&cmd, "rm -rf %s", ctx->statedir);
- system (cmd);
+ err = system (cmd);
free (cmd);
free (ctx->statedir);
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"
}
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 */
}
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 */
return 0;
}
+static int opkg_list_upgradable_cmd(opkg_conf_t *conf, 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);
+ if (opkg_cb_list)
+ opkg_cb_list(_old_pkg->name, new_v, old_v, _old_pkg->state_status, p_userdata);
+ 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)
{
int i;
char *pkg_name = NULL;
char **pkg_fields = NULL;
int n_fields = 0;
- char *buff ; // = (char *)malloc(1);
+ char *buff ;
if (argc > 0) {
pkg_name = argv[0];
done = 0;
- available = pkg_vec_alloc();
pkg_info_preinstall_check(conf);
if ( argc > 0 ) {
+ available = pkg_vec_alloc();
pkg_hash_fetch_all_installed(&conf->pkg_hash, available);
for (i=0; i < argc; i++) {
- pkg_name = malloc(strlen(argv[i])+2);
+ pkg_name = calloc(1, strlen(argv[i])+2);
strcpy(pkg_name,argv[i]);
for (a=0; a < available->len; a++) {
pkg = available->pkgs[a];
size_t used_len;
char *buff ;
- buff = (char *)malloc(buff_len);
+ buff = (char *)calloc(1, buff_len);
if ( buff == NULL ) {
fprintf( stderr,"%s: Unable to allocate memory \n",__FUNCTION__);
return ENOMEM;
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;
installed = pkg_vec_alloc();
pkg_hash_fetch_all_installed(&conf->pkg_hash, installed);
+ pkg_vec_sort(installed, pkg_compare_names);
for (i=0; i < installed->len; i++) {
pkg = installed->pkgs[i];
pkg_free_installed_files(pkg);
}
- /* XXX: CLEANUP: It's not obvious from the name of
- pkg_hash_fetch_all_installed that we need to call
- pkg_vec_free to avoid a memory leak. */
pkg_vec_free(installed);
return 0;