1
0
mirror of git://projects.qi-hardware.com/openwrt-xburst.git synced 2024-11-27 21:18:26 +02:00
openwrt-xburst/package/busybox/patches/911-ipkg.patch
nico 0138f12994 update ipkg patch to v1.99.154,
add a patch to suppress warnings from libipkg compilation

git-svn-id: svn://svn.openwrt.org/openwrt/trunk/openwrt@2343 3c298f89-4303-0410-b956-a3cf2f4a3e73
2005-11-06 05:18:05 +00:00

13726 lines
424 KiB
Diff
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

diff -ruN busybox-1.00-orig/Makefile busybox-1.00+ipkg-0.99.154/Makefile
--- busybox-1.00-orig/Makefile 2004-10-08 09:45:08.000000000 +0200
+++ busybox-1.00+ipkg-0.99.154/Makefile 2005-10-26 17:36:45.000000000 +0200
@@ -39,7 +39,7 @@
include $(top_builddir)/Rules.mak
-DIRS:=applets archival archival/libunarchive coreutils console-tools \
+DIRS:=applets archival archival/libipkg archival/libunarchive coreutils console-tools \
debianutils editors findutils init miscutils modutils networking \
networking/libiproute networking/udhcp procps loginutils shell \
sysklogd util-linux libpwdgrp coreutils/libcoreutils libbb
diff -ruN busybox-1.00-orig/archival/Config.in busybox-1.00+ipkg-0.99.154/archival/Config.in
--- busybox-1.00-orig/archival/Config.in 2004-03-15 09:28:16.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/Config.in 2005-10-26 17:36:45.000000000 +0200
@@ -121,6 +121,14 @@
gzip is used to compress files.
It's probably the most widely used UNIX compression program.
+config CONFIG_IPKG
+ bool "ipkg"
+ default n
+ select CONFIG_MD5SUM
+ select CONFIG_WGET
+ help
+ ipkg is the itsy package management system.
+
config CONFIG_RPM2CPIO
bool "rpm2cpio"
default n
diff -ruN busybox-1.00-orig/archival/Makefile.in busybox-1.00+ipkg-0.99.154/archival/Makefile.in
--- busybox-1.00-orig/archival/Makefile.in 2004-10-08 09:45:09.000000000 +0200
+++ busybox-1.00+ipkg-0.99.154/archival/Makefile.in 2005-10-26 17:36:45.000000000 +0200
@@ -32,6 +32,7 @@
ARCHIVAL-$(CONFIG_DPKG_DEB) += dpkg_deb.o
ARCHIVAL-$(CONFIG_GUNZIP) += gunzip.o
ARCHIVAL-$(CONFIG_GZIP) += gzip.o
+ARCHIVAL-$(CONFIG_IPKG) += ipkg.o
ARCHIVAL-$(CONFIG_RPM2CPIO) += rpm2cpio.o
ARCHIVAL-$(CONFIG_RPM) += rpm.o
ARCHIVAL-$(CONFIG_TAR) += tar.o
diff -ruN busybox-1.00-orig/archival/dpkg.c busybox-1.00+ipkg-0.99.154/archival/dpkg.c
--- busybox-1.00-orig/archival/dpkg.c 2004-04-14 19:51:08.000000000 +0200
+++ busybox-1.00+ipkg-0.99.154/archival/dpkg.c 2005-10-26 17:36:45.000000000 +0200
@@ -1527,6 +1527,10 @@
return(ar_handle->sub_archive->buffer);
}
+/*
+
+// moved to data_extract_all.c
+
static void data_extract_all_prefix(archive_handle_t *archive_handle)
{
char *name_ptr = archive_handle->file_header->name;
@@ -1541,6 +1545,8 @@
return;
}
+*/
+
static void unpack_package(deb_file_t *deb_file)
{
const char *package_name = name_hashtable[package_hashtable[deb_file->package]->name];
diff -ruN busybox-1.00-orig/archival/ipkg.c busybox-1.00+ipkg-0.99.154/archival/ipkg.c
--- busybox-1.00-orig/archival/ipkg.c 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/ipkg.c 2005-10-26 17:36:45.000000000 +0200
@@ -0,0 +1,26 @@
+/* ipkg.c - the itsy package management system
+
+ Florina Boor
+
+ Copyright (C) 2003 kernel concepts
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ ipkg command line frontend using libipkg
+
+*/
+
+#include "libipkg/libipkg.h"
+
+int ipkg_main(int argc, char **argv)
+{
+ return ipkg_op(argc, argv);
+}
diff -ruN busybox-1.00-orig/archival/libipkg/Makefile busybox-1.00+ipkg-0.99.154/archival/libipkg/Makefile
--- busybox-1.00-orig/archival/libipkg/Makefile 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/Makefile 2005-10-26 17:36:45.000000000 +0200
@@ -0,0 +1,32 @@
+# Makefile for busybox
+#
+# Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+
+top_srcdir=../..
+top_builddir=../..
+srcdir=$(top_srcdir)/archival/libipkg
+LIBIPKG_DIR:=./
+include $(top_builddir)/Rules.mak
+include $(top_builddir)/.config
+include $(srcdir)/Makefile.in
+all: $(libraries-y)
+-include $(top_builddir)/.depend
+
+clean:
+ rm -f *.o *.a $(AR_TARGET)
+
diff -ruN busybox-1.00-orig/archival/libipkg/Makefile.in busybox-1.00+ipkg-0.99.154/archival/libipkg/Makefile.in
--- busybox-1.00-orig/archival/libipkg/Makefile.in 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/Makefile.in 2005-10-26 17:36:45.000000000 +0200
@@ -0,0 +1,83 @@
+# Makefile for busybox
+#
+# Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+
+LIBIPKG_AR:=libipkg.a
+ifndef $(LIBIPKG_DIR)
+LIBIPKG_DIR:=$(top_builddir)/archival/libipkg/
+endif
+srcdir=$(top_srcdir)/archival/libipkg
+
+LIBIPKG_CORE_SOURCES:= \
+ args.c \
+ libipkg.c \
+ user.c \
+
+LIBIPKG_CMD_SOURCES:= \
+ ipkg_cmd.c \
+ ipkg_configure.c \
+ ipkg_download.c \
+ ipkg_install.c \
+ ipkg_remove.c \
+ ipkg_upgrade.c \
+
+LIBIPKG_DB_SOURCES:= \
+ hash_table.c \
+ ipkg_conf.c \
+ ipkg_utils.c \
+ pkg.c \
+ pkg_depends.c \
+ pkg_extract.c \
+ pkg_hash.c \
+ pkg_parse.c \
+ pkg_vec.c \
+
+LIBIPKG_LIST_SOURCES:= \
+ conffile.c \
+ conffile_list.c \
+ nv_pair.c \
+ nv_pair_list.c \
+ pkg_dest.c \
+ pkg_dest_list.c \
+ pkg_src.c \
+ pkg_src_list.c \
+ str_list.c \
+ void_list.c \
+
+LIBIPKG_UTIL_SOURCES:= \
+ file_util.c \
+ ipkg_message.c \
+ md5.c \
+ str_util.c \
+ xsystem.c \
+
+LIBIPKG-y += $(LIBIPKG_CORE_SOURCES)
+LIBIPKG-y += $(LIBIPKG_CMD_SOURCES)
+LIBIPKG-y += $(LIBIPKG_DB_SOURCES)
+LIBIPKG-y += $(LIBIPKG_LIST_SOURCES)
+LIBIPKG-y += $(LIBIPKG_UTIL_SOURCES)
+LIBIPKG_OBJS=$(patsubst %.c,$(LIBIPKG_DIR)%.o, $(LIBIPKG-y))
+
+libraries-y += $(LIBIPKG_DIR)$(LIBIPKG_AR)
+
+$(LIBIPKG_DIR)$(LIBIPKG_AR): $(LIBIPKG_OBJS)
+ $(AR) -ro $@ $^
+
+$(LIBIPKG_OBJS): $(LIBIPKG_DIR)%.o : $(srcdir)/%.c
+ $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -DIPKG_LIB -DIPKGLIBDIR="\"/usr/lib\"" -DHOST_CPU_STR="\"$(ARCH)\"" -c -o $@ $<
+
diff -ruN busybox-1.00-orig/archival/libipkg/args.c busybox-1.00+ipkg-0.99.154/archival/libipkg/args.c
--- busybox-1.00-orig/archival/libipkg/args.c 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/args.c 2005-10-26 17:36:45.000000000 +0200
@@ -0,0 +1,241 @@
+/* args.c - parse command-line args
+
+ Carl D. Worth
+
+ Copyright 2001 University of Southern California
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+ */
+
+#include <getopt.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "ipkg.h"
+#include "ipkg_message.h"
+
+#include "args.h"
+#include "sprintf_alloc.h"
+
+#include "libbb.h"
+
+
+static void print_version(void);
+
+enum long_args_opt
+{
+ ARGS_OPT_FORCE_DEFAULTS = 129,
+ ARGS_OPT_FORCE_DEPENDS,
+ ARGS_OPT_FORCE_OVERWRITE,
+ ARGS_OPT_FORCE_DOWNGRADE,
+ ARGS_OPT_FORCE_REINSTALL,
+ ARGS_OPT_FORCE_REMOVAL_OF_DEPENDENT_PACKAGES,
+ ARGS_OPT_FORCE_REMOVAL_OF_ESSENTIAL_PACKAGES,
+ ARGS_OPT_FORCE_SPACE,
+ ARGS_OPT_NOACTION,
+ ARGS_OPT_NODEPS,
+ ARGS_OPT_VERBOSE_WGET,
+ ARGS_OPT_VERBOSITY,
+ ARGS_OPT_MULTIPLE_PROVIDERS
+};
+
+int args_init(args_t *args)
+{
+ char *conf_file_dir;
+
+ memset(args, 0, sizeof(args_t));
+
+ args->dest = ARGS_DEFAULT_DEST;
+
+ conf_file_dir = getenv("IPKG_CONF_DIR");
+ if (conf_file_dir == NULL || conf_file_dir[0] == '\0') {
+ conf_file_dir = ARGS_DEFAULT_CONF_FILE_DIR;
+ }
+ sprintf_alloc(&args->conf_file, "%s/%s", conf_file_dir,
+ ARGS_DEFAULT_CONF_FILE_NAME);
+
+ args->force_defaults = ARGS_DEFAULT_FORCE_DEFAULTS;
+ args->force_depends = ARGS_DEFAULT_FORCE_DEPENDS;
+ args->force_overwrite = ARGS_DEFAULT_FORCE_OVERWRITE;
+ args->force_downgrade = ARGS_DEFAULT_FORCE_DOWNGRADE;
+ args->force_reinstall = ARGS_DEFAULT_FORCE_REINSTALL;
+ args->force_removal_of_dependent_packages = ARGS_DEFAULT_FORCE_REMOVAL_OF_DEPENDENT_PACKAGES;
+ args->force_removal_of_essential_packages = ARGS_DEFAULT_FORCE_REMOVAL_OF_ESSENTIAL_PACKAGES;
+ args->noaction = ARGS_DEFAULT_NOACTION;
+ args->nodeps = ARGS_DEFAULT_NODEPS;
+ args->verbose_wget = ARGS_DEFAULT_VERBOSE_WGET;
+ args->verbosity = ARGS_DEFAULT_VERBOSITY;
+ args->offline_root = ARGS_DEFAULT_OFFLINE_ROOT;
+ args->offline_root_pre_script_cmd = ARGS_DEFAULT_OFFLINE_ROOT_PRE_SCRIPT_CMD;
+ args->offline_root_post_script_cmd = ARGS_DEFAULT_OFFLINE_ROOT_POST_SCRIPT_CMD;
+ args->multiple_providers = 0;
+ args->nocheckfordirorfile = 0;
+
+ return 1;
+}
+
+void args_deinit(args_t *args)
+{
+ free(args->conf_file);
+ args->conf_file = NULL;
+}
+
+int args_parse(args_t *args, int argc, char *argv[])
+{
+ int c;
+ int option_index = 0;
+ int parse_err = 0;
+ static struct option long_options[] = {
+ {"query-all", 0, 0, 'A'},
+ {"conf-file", 1, 0, 'f'},
+ {"conf", 1, 0, 'f'},
+ {"dest", 1, 0, 'd'},
+ {"force-defaults", 0, 0, ARGS_OPT_FORCE_DEFAULTS},
+ {"force_defaults", 0, 0, ARGS_OPT_FORCE_DEFAULTS},
+ {"force-depends", 0, 0, ARGS_OPT_FORCE_DEPENDS},
+ {"force_depends", 0, 0, ARGS_OPT_FORCE_DEPENDS},
+ {"force-overwrite", 0, 0, ARGS_OPT_FORCE_OVERWRITE},
+ {"force_overwrite", 0, 0, ARGS_OPT_FORCE_OVERWRITE},
+ {"force_downgrade", 0, 0, ARGS_OPT_FORCE_DOWNGRADE},
+ {"force-downgrade", 0, 0, ARGS_OPT_FORCE_DOWNGRADE},
+ {"force-reinstall", 0, 0, ARGS_OPT_FORCE_REINSTALL},
+ {"force_reinstall", 0, 0, ARGS_OPT_FORCE_REINSTALL},
+ {"force-space", 0, 0, ARGS_OPT_FORCE_SPACE},
+ {"force_space", 0, 0, ARGS_OPT_FORCE_SPACE},
+ {"recursive", 0, 0,
+ ARGS_OPT_FORCE_REMOVAL_OF_DEPENDENT_PACKAGES},
+ {"force-removal-of-dependent-packages", 0, 0,
+ ARGS_OPT_FORCE_REMOVAL_OF_DEPENDENT_PACKAGES},
+ {"force_removal_of_dependent_packages", 0, 0,
+ ARGS_OPT_FORCE_REMOVAL_OF_DEPENDENT_PACKAGES},
+ {"force-removal-of-essential-packages", 0, 0,
+ ARGS_OPT_FORCE_REMOVAL_OF_ESSENTIAL_PACKAGES},
+ {"force_removal_of_essential_packages", 0, 0,
+ ARGS_OPT_FORCE_REMOVAL_OF_ESSENTIAL_PACKAGES},
+ {"multiple-providers", 0, 0, ARGS_OPT_MULTIPLE_PROVIDERS},
+ {"multiple_providers", 0, 0, ARGS_OPT_MULTIPLE_PROVIDERS},
+ {"noaction", 0, 0, ARGS_OPT_NOACTION},
+ {"nodeps", 0, 0, ARGS_OPT_NODEPS},
+ {"offline", 1, 0, 'o'},
+ {"offline-root", 1, 0, 'o'},
+ {"test", 0, 0, ARGS_OPT_NOACTION},
+ {"tmp-dir", 1, 0, 't'},
+ {"verbose-wget", 0, 0, ARGS_OPT_VERBOSE_WGET},
+ {"verbose_wget", 0, 0, ARGS_OPT_VERBOSE_WGET},
+ {"verbosity", 2, 0, 'V'},
+ {"version", 0, 0, 'v'},
+ {0, 0, 0, 0}
+ };
+
+ while (1) {
+ c = getopt_long_only(argc, argv, "Ad:f:no:t:vV:", long_options, &option_index);
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'A':
+ args->query_all = 1;
+ break;
+ case 'd':
+ args->dest = optarg;
+ break;
+ case 'f':
+ free(args->conf_file);
+ args->conf_file = strdup(optarg);
+ break;
+ case 'o':
+ args->offline_root = optarg;
+ break;
+ case 'n':
+ args->noaction = 1;
+ break;
+ case 't':
+ args->tmp_dir = strdup(optarg);
+ break;
+ case 'v':
+ print_version();
+ exit(0);
+ case 'V':
+ case ARGS_OPT_VERBOSITY:
+ if (optarg)
+ args->verbosity = atoi(optarg);
+ else
+ args->verbosity += 1;
+ break;
+ case ARGS_OPT_FORCE_DEFAULTS:
+ args->force_defaults = 1;
+ break;
+ case ARGS_OPT_FORCE_DEPENDS:
+ args->force_depends = 1;
+ break;
+ case ARGS_OPT_FORCE_OVERWRITE:
+ args->force_overwrite = 1;
+ break;
+ case ARGS_OPT_FORCE_DOWNGRADE:
+ args->force_downgrade = 1;
+ break;
+ case ARGS_OPT_FORCE_REINSTALL:
+ args->force_reinstall = 1;
+ break;
+ case ARGS_OPT_FORCE_REMOVAL_OF_ESSENTIAL_PACKAGES:
+ args->force_removal_of_essential_packages = 1;
+ break;
+ case ARGS_OPT_FORCE_REMOVAL_OF_DEPENDENT_PACKAGES:
+ args->force_removal_of_dependent_packages = 1;
+ break;
+ case ARGS_OPT_FORCE_SPACE:
+ args->force_space = 1;
+ break;
+ case ARGS_OPT_VERBOSE_WGET:
+ args->verbose_wget = 1;
+ break;
+ case ARGS_OPT_MULTIPLE_PROVIDERS:
+ args->multiple_providers = 1;
+ break;
+ case ARGS_OPT_NODEPS:
+ args->nodeps = 1;
+ break;
+ case ARGS_OPT_NOACTION:
+ args->noaction = 1;
+ break;
+ case ':':
+ parse_err++;
+ break;
+ case '?':
+ parse_err++;
+ break;
+ default:
+ bb_error_msg("Confusion: getopt_long returned %d\n", c);
+ }
+ }
+
+ if (parse_err) {
+ return -parse_err;
+ } else {
+ return optind;
+ }
+}
+
+void args_usage(char *complaint)
+{
+ if (complaint) {
+ bb_error_msg("%s\n", complaint);
+ }
+ print_version();
+ bb_show_usage();
+ exit(1);
+}
+
+static void print_version(void)
+{
+ bb_error_msg("version %s\n", IPKG_VERSION);
+}
diff -ruN busybox-1.00-orig/archival/libipkg/args.h busybox-1.00+ipkg-0.99.154/archival/libipkg/args.h
--- busybox-1.00-orig/archival/libipkg/args.h 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/args.h 2005-10-26 17:36:45.000000000 +0200
@@ -0,0 +1,71 @@
+/* args.h - parse command-line args
+
+ Carl D. Worth
+
+ Copyright 2001 University of Southern California
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+*/
+
+#ifndef ARGS_H
+#define ARGS_H
+
+struct args
+{
+ char *conf_file;
+ char *dest;
+ char *tmp_dir;
+ int force_defaults;
+ int force_depends;
+ int force_overwrite;
+ int force_downgrade;
+ int force_reinstall;
+ int force_removal_of_essential_packages;
+ int force_removal_of_dependent_packages;
+ int force_space;
+ int noaction;
+ int nodeps;
+ int multiple_providers;
+ int query_all;
+ int verbose_wget;
+ int verbosity;
+ int nocheckfordirorfile;
+ char *offline_root;
+ char *offline_root_pre_script_cmd;
+ char *offline_root_post_script_cmd;
+};
+typedef struct args args_t;
+
+#define ARGS_DEFAULT_CONF_FILE_DIR "/etc"
+#define ARGS_DEFAULT_CONF_FILE_NAME "ipkg.conf"
+#define ARGS_DEFAULT_DEST NULL
+#define ARGS_DEFAULT_FORCE_DEFAULTS 0
+#define ARGS_DEFAULT_FORCE_DEPENDS 0
+#define ARGS_DEFAULT_FORCE_OVERWRITE 0
+#define ARGS_DEFAULT_FORCE_DOWNGRADE 0
+#define ARGS_DEFAULT_FORCE_REINSTALL 0
+#define ARGS_DEFAULT_FORCE_REMOVAL_OF_ESSENTIAL_PACKAGES 0
+#define ARGS_DEFAULT_FORCE_REMOVAL_OF_DEPENDENT_PACKAGES 0
+#define ARGS_DEFAULT_FORCE_SPACE 0
+#define ARGS_DEFAULT_OFFLINE_ROOT NULL
+#define ARGS_DEFAULT_OFFLINE_ROOT_PRE_SCRIPT_CMD NULL
+#define ARGS_DEFAULT_OFFLINE_ROOT_POST_SCRIPT_CMD NULL
+#define ARGS_DEFAULT_NOACTION 0
+#define ARGS_DEFAULT_NODEPS 0
+#define ARGS_DEFAULT_VERBOSE_WGET 0
+#define ARGS_DEFAULT_VERBOSITY 1
+
+int args_init(args_t *args);
+void args_deinit(args_t *args);
+int args_parse(args_t *args, int argc, char *argv[]);
+void args_usage(char *complaint);
+
+#endif
diff -ruN busybox-1.00-orig/archival/libipkg/conffile.c busybox-1.00+ipkg-0.99.154/archival/libipkg/conffile.c
--- busybox-1.00-orig/archival/libipkg/conffile.c 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/conffile.c 2005-10-26 17:36:45.000000000 +0200
@@ -0,0 +1,64 @@
+/* conffile.c - the itsy package management system
+
+ Carl D. Worth
+
+ Copyright (C) 2001 University of Southern California
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "ipkg.h"
+#include "ipkg_message.h"
+
+#include "conffile.h"
+#include "file_util.h"
+#include "sprintf_alloc.h"
+
+int conffile_init(conffile_t *conffile, const char *file_name, const char *md5sum)
+{
+ return nv_pair_init(conffile, file_name, md5sum);
+}
+
+void conffile_deinit(conffile_t *conffile)
+{
+ nv_pair_deinit(conffile);
+}
+
+int conffile_has_been_modified(ipkg_conf_t *conf, conffile_t *conffile)
+{
+ char *md5sum;
+ char *filename = conffile->name;
+ char *root_filename;
+ int ret;
+
+ if (conffile->value == NULL) {
+ ipkg_message(conf, IPKG_NOTICE, "%s: conffile %s has no md5sum\n", __FUNCTION__, conffile->name);
+ return 1;
+ }
+
+ root_filename = root_filename_alloc(conf, filename);
+
+ md5sum = file_md5sum_alloc(root_filename);
+
+ ret = strcmp(md5sum, conffile->value);
+ if (ret) {
+ ipkg_message(conf, IPKG_NOTICE, "%s: conffile %s: \t\nold md5=%s \t\nnew md5=%s\n", __FUNCTION__,
+ conffile->name, md5sum, conffile->value);
+ }
+
+ free(root_filename);
+ free(md5sum);
+
+ return ret;
+}
diff -ruN busybox-1.00-orig/archival/libipkg/conffile.h busybox-1.00+ipkg-0.99.154/archival/libipkg/conffile.h
--- busybox-1.00-orig/archival/libipkg/conffile.h 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/conffile.h 2005-10-26 17:36:45.000000000 +0200
@@ -0,0 +1,30 @@
+/* conffile.h - the itsy package management system
+
+ Carl D. Worth
+
+ Copyright (C) 2001 University of Southern California
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#ifndef CONFFILE_H
+#define CONFFILE_H
+
+#include "nv_pair.h"
+
+typedef struct nv_pair conffile_t;
+
+int conffile_init(conffile_t *conffile, const char *file_name, const char *md5sum);
+void conffile_deinit(conffile_t *conffile);
+int conffile_has_been_modified(struct ipkg_conf *conf, conffile_t *conffile);
+
+#endif
+
diff -ruN busybox-1.00-orig/archival/libipkg/conffile_list.c busybox-1.00+ipkg-0.99.154/archival/libipkg/conffile_list.c
--- busybox-1.00-orig/archival/libipkg/conffile_list.c 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/conffile_list.c 2005-10-26 17:36:45.000000000 +0200
@@ -0,0 +1,47 @@
+/* conffile_list.c - the itsy package management system
+
+ Carl D. Worth
+
+ Copyright (C) 2001 University of Southern California
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#include "ipkg.h"
+
+#include "conffile_list.h"
+
+int conffile_list_init(conffile_list_t *list)
+{
+ return nv_pair_list_init(list);
+}
+
+void conffile_list_deinit(conffile_list_t *list)
+{
+ nv_pair_list_deinit(list);
+}
+
+conffile_t *conffile_list_append(conffile_list_t *list, const char *file_name,
+ const char *md5sum)
+{
+ return nv_pair_list_append(list, file_name, md5sum);
+}
+
+int conffile_list_push(conffile_list_t *list, conffile_t *data)
+{
+ return nv_pair_list_push(list, data);
+}
+
+conffile_list_elt_t *conffile_list_pop(conffile_list_t *list)
+{
+ return nv_pair_list_pop(list);
+}
+
diff -ruN busybox-1.00-orig/archival/libipkg/conffile_list.h busybox-1.00+ipkg-0.99.154/archival/libipkg/conffile_list.h
--- busybox-1.00-orig/archival/libipkg/conffile_list.h 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/conffile_list.h 2005-10-26 17:36:45.000000000 +0200
@@ -0,0 +1,36 @@
+/* conffile_list.h - the itsy package management system
+
+ Carl D. Worth
+
+ Copyright (C) 2001 University of Southern California
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#ifndef CONFFILE_LIST_H
+#define CONFFILE_LIST_H
+
+#include "conffile.h"
+#include "nv_pair_list.h"
+
+typedef struct nv_pair_list_elt conffile_list_elt_t;
+typedef struct nv_pair_list conffile_list_t;
+
+int conffile_list_init(conffile_list_t *list);
+void conffile_list_deinit(conffile_list_t *list);
+
+conffile_t *conffile_list_append(conffile_list_t *list, const char *name,
+ const char *root_dir);
+int conffile_list_push(conffile_list_t *list, conffile_t *data);
+conffile_list_elt_t *conffile_list_pop(conffile_list_t *list);
+
+#endif
+
diff -ruN busybox-1.00-orig/archival/libipkg/file_util.c busybox-1.00+ipkg-0.99.154/archival/libipkg/file_util.c
--- busybox-1.00-orig/archival/libipkg/file_util.c 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/file_util.c 2005-10-26 17:36:45.000000000 +0200
@@ -0,0 +1,177 @@
+/* file_util.c - convenience routines for common stat operations
+
+ Carl D. Worth
+
+ Copyright (C) 2001 University of Southern California
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#include "ipkg.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "sprintf_alloc.h"
+#include "file_util.h"
+#include "md5.h"
+#include "libbb.h"
+#undef strlen
+
+int file_exists(const char *file_name)
+{
+ int err;
+ struct stat stat_buf;
+
+ err = stat(file_name, &stat_buf);
+ if (err == 0) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+int file_is_dir(const char *file_name)
+{
+ int err;
+ struct stat stat_buf;
+
+ err = stat(file_name, &stat_buf);
+ if (err) {
+ return 0;
+ }
+
+ return S_ISDIR(stat_buf.st_mode);
+}
+
+/* read a single line from a file, stopping at a newline or EOF.
+ If a newline is read, it will appear in the resulting string.
+ Return value is a malloc'ed char * which should be freed at
+ some point by the caller.
+
+ Return value is NULL if the file is at EOF when called.
+*/
+#define FILE_READ_LINE_BUF_SIZE 1024
+char *file_read_line_alloc(FILE *file)
+{
+ char buf[FILE_READ_LINE_BUF_SIZE];
+ int buf_len;
+ char *line = NULL;
+ int line_size = 0;
+
+ memset(buf, 0, FILE_READ_LINE_BUF_SIZE);
+ while (fgets(buf, FILE_READ_LINE_BUF_SIZE, file)) {
+ buf_len = strlen(buf);
+ if (line) {
+ line_size += buf_len;
+ line = realloc(line, line_size);
+ if (line == NULL) {
+ fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
+ break;
+ }
+ strcat(line, buf);
+ } else {
+ line_size = buf_len + 1;
+ line = strdup(buf);
+ }
+ if (buf[buf_len - 1] == '\n') {
+ break;
+ }
+ }
+
+ return line;
+}
+
+int file_move(const char *src, const char *dest)
+{
+ int err;
+
+ err = rename(src, dest);
+
+ if (err && errno == EXDEV) {
+ err = file_copy(src, dest);
+ unlink(src);
+ } else if (err) {
+ fprintf(stderr, "%s: ERROR: failed to rename %s to %s: %s\n",
+ __FUNCTION__, src, dest, strerror(errno));
+ }
+
+ return err;
+}
+
+/* I put these here to keep libbb dependencies from creeping all over
+ the ipkg code */
+int file_copy(const char *src, const char *dest)
+{
+ int err;
+
+ err = copy_file(src, dest, FILEUTILS_FORCE | FILEUTILS_PRESERVE_STATUS);
+ if (err) {
+ fprintf(stderr, "%s: ERROR: failed to copy %s to %s\n",
+ __FUNCTION__, src, dest);
+ }
+
+ return err;
+}
+
+int file_mkdir_hier(const char *path, long mode)
+{
+ return bb_make_directory(path, mode, FILEUTILS_RECUR);
+}
+
+char *file_md5sum_alloc(const char *file_name)
+{
+ static const int md5sum_bin_len = 16;
+ static const int md5sum_hex_len = 32;
+
+ static const unsigned char bin2hex[16] = {
+ '0', '1', '2', '3',
+ '4', '5', '6', '7',
+ '8', '9', 'a', 'b',
+ 'c', 'd', 'e', 'f'
+ };
+
+ int i, err;
+ FILE *file;
+ unsigned char *md5sum_hex;
+ unsigned char md5sum_bin[md5sum_bin_len];
+
+ md5sum_hex = malloc(md5sum_hex_len + 1);
+ if (md5sum_hex == NULL) {
+ fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
+ return strdup("");
+ }
+
+ file = fopen(file_name, "r");
+ if (file == NULL) {
+ fprintf(stderr, "%s: Failed to open file %s: %s\n",
+ __FUNCTION__, file_name, strerror(errno));
+ return strdup("");
+ }
+
+ err = md5_stream(file, md5sum_bin);
+ if (err) {
+ fprintf(stderr, "%s: ERROR computing md5sum for %s: %s\n",
+ __FUNCTION__, file_name, strerror(err));
+ return strdup("");
+ }
+
+ fclose(file);
+
+ for (i=0; i < md5sum_bin_len; i++) {
+ md5sum_hex[i*2] = bin2hex[md5sum_bin[i] >> 4];
+ md5sum_hex[i*2+1] = bin2hex[md5sum_bin[i] & 0xf];
+ }
+
+ md5sum_hex[md5sum_hex_len] = '\0';
+
+ return md5sum_hex;
+}
+
diff -ruN busybox-1.00-orig/archival/libipkg/file_util.h busybox-1.00+ipkg-0.99.154/archival/libipkg/file_util.h
--- busybox-1.00-orig/archival/libipkg/file_util.h 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/file_util.h 2005-10-26 17:36:45.000000000 +0200
@@ -0,0 +1,29 @@
+/* file_util.h - convenience routines for common file operations
+
+ Carl D. Worth
+
+ Copyright (C) 2001 University of Southern California
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#ifndef FILE_UTIL_H
+#define FILE_UTIL_H
+
+int file_exists(const char *file_name);
+int file_is_dir(const char *file_name);
+char *file_read_line_alloc(FILE *file);
+int file_move(const char *src, const char *dest);
+int file_copy(const char *src, const char *dest);
+int file_mkdir_hier(const char *path, long mode);
+char *file_md5sum_alloc(const char *file_name);
+
+#endif
diff -ruN busybox-1.00-orig/archival/libipkg/hash_table.c busybox-1.00+ipkg-0.99.154/archival/libipkg/hash_table.c
--- busybox-1.00-orig/archival/libipkg/hash_table.c 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/hash_table.c 2005-10-26 17:36:45.000000000 +0200
@@ -0,0 +1,155 @@
+/* hash.c - hash tables for ipkg
+
+ Steven M. Ayer, Jamey Hicks
+
+ Copyright (C) 2002 Compaq Computer Corporation
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "hash_table.h"
+#include "ipkg_message.h"
+
+
+static int hash_index(hash_table_t *hash, const char *pkg_name);
+static int rotating(const char *key, int len, int prime);
+
+static int hash_index(hash_table_t *hash, const char *pkg_name)
+{
+ return rotating(pkg_name, strlen(pkg_name), hash->n_entries);
+}
+
+static int rotating(const char *key, int len, int prime)
+{
+ unsigned int hash, i;
+ for (hash=len, i=0; i<len; ++i)
+ hash = (hash<<4)^(hash>>28)^key[i];
+ return (hash % prime);
+}
+
+
+/*
+ * this is an open table keyed by strings
+ */
+int hash_table_init(const char *name, hash_table_t *hash, int len)
+{
+ static int primes_table[] = {
+ 379, 761, 983, 1423, 2711, 3361, 3931, 4679, 5519, 6701, 9587,
+ 19471, 23143, 33961, 46499, 49727, 99529, 0
+ };
+ int *picker;
+
+ if (hash->entries != NULL) {
+ /* we have been here already */
+ return 0;
+ }
+
+ hash->name = name;
+ hash->entries = NULL;
+ hash->n_entries = 0;
+ hash->hash_entry_key = NULL;
+
+ picker = primes_table;
+ while(*picker && (*picker++ < len));
+ if(!*picker)
+ fprintf(stderr, "%s: primes table might not be big enough (! << %d)\n", __FUNCTION__, len);
+ --picker;
+
+ hash->n_entries = *picker;
+ hash->entries = (hash_entry_t *)calloc(hash->n_entries, sizeof(hash_entry_t));
+ if (hash->entries == NULL) {
+ fprintf(stderr, "%s: Out of memory.\n", __FUNCTION__);
+ return ENOMEM;
+ }
+ return 0;
+}
+
+void hash_table_deinit(hash_table_t *hash)
+{
+ free(hash->entries);
+ hash->entries = NULL;
+ hash->n_entries = 0;
+}
+
+void *hash_table_get(hash_table_t *hash, const char *key)
+{
+ int ndx= hash_index(hash, key);
+ hash_entry_t *hash_entry = hash->entries + ndx;
+ while (hash_entry)
+ {
+ if (hash_entry->key)
+ {
+ if (strcmp(key, hash_entry->key) == 0) {
+ // ipkg_message(NULL, IPKG_DEBUG, "Function: %s. Key found for '%s' \n", __FUNCTION__, key);
+ return hash_entry->data;
+ }
+ }
+ hash_entry = hash_entry->next;
+ }
+ return NULL;
+}
+
+int hash_table_insert(hash_table_t *hash, const char *key, void *value)
+{
+ int ndx= hash_index(hash, key);
+ hash_entry_t *hash_entry = hash->entries + ndx;
+ if (0) ipkg_message(NULL, IPKG_DEBUG2, "Function: %s. Inserting in hash for '%s' \n", __FUNCTION__, key);
+ if (hash_entry->key) {
+ if (strcmp(hash_entry->key, key) == 0) {
+ /* alread in table, update the value */
+ if (0) ipkg_message(NULL, IPKG_DEBUG2, "Function: %s. Value already in hash for '%s' \n", __FUNCTION__, key);
+ hash_entry->data = value;
+ return 0;
+ } else {
+ /*
+ * if this is a collision, we have to go to the end of the ll,
+ * then add a new entry
+ * before we can hook up the value
+ */
+ if (0) ipkg_message(NULL, IPKG_DEBUG2, "Function: %s. Value already in hash by collision for '%s' \n", __FUNCTION__, key);
+ while (hash_entry->next)
+ hash_entry = hash_entry->next;
+ hash_entry->next = (hash_entry_t *)malloc(sizeof(hash_entry_t));
+ if (!hash_entry->next) {
+ return -ENOMEM;
+ }
+ hash_entry = hash_entry->next;
+ hash_entry->next = NULL;
+ }
+ }
+ hash->n_elements++;
+ hash_entry->key = strdup(key);
+ hash_entry->data = value;
+
+ return 0;
+}
+
+
+void hash_table_foreach(hash_table_t *hash, void (*f)(const char *key, void *entry, void *data), void *data)
+{
+ int i;
+ if (!hash || !f)
+ return;
+
+ for (i = 0; i < hash->n_entries; i++) {
+ hash_entry_t *hash_entry = (hash->entries + i);
+ do {
+ if(hash_entry->key) {
+ f(hash_entry->key, hash_entry->data, data);
+ }
+ } while((hash_entry = hash_entry->next));
+ }
+}
+
diff -ruN busybox-1.00-orig/archival/libipkg/hash_table.h busybox-1.00+ipkg-0.99.154/archival/libipkg/hash_table.h
--- busybox-1.00-orig/archival/libipkg/hash_table.h 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/hash_table.h 2005-10-26 17:36:45.000000000 +0200
@@ -0,0 +1,44 @@
+/* hash.h - hash tables for ipkg
+
+ Steven M. Ayer, Jamey Hicks
+
+ Copyright (C) 2002 Compaq Computer Corporation
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#ifndef _HASH_TABLE_H_
+#define _HASH_TABLE_H_
+
+typedef struct hash_entry hash_entry_t;
+typedef struct hash_table hash_table_t;
+
+struct hash_entry {
+ const char * key;
+ void * data;
+ struct hash_entry * next;
+};
+
+struct hash_table {
+ const char *name;
+ hash_entry_t * entries;
+ int n_entries; /* number of buckets */
+ int n_elements;
+ const char * (*hash_entry_key)(void * data);
+};
+
+int hash_table_init(const char *name, hash_table_t *hash, int len);
+void hash_table_deinit(hash_table_t *hash);
+void *hash_table_get(hash_table_t *hash, const char *key);
+int hash_table_insert(hash_table_t *hash, const char *key, void *value);
+void hash_table_foreach(hash_table_t *hash, void (*f)(const char *key, void *entry, void *data), void *data);
+
+#endif /* _HASH_TABLE_H_ */
diff -ruN busybox-1.00-orig/archival/libipkg/ipkg.h busybox-1.00+ipkg-0.99.154/archival/libipkg/ipkg.h
--- busybox-1.00-orig/archival/libipkg/ipkg.h 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/ipkg.h 2005-10-26 17:45:05.000000000 +0200
@@ -0,0 +1,74 @@
+/* ipkg.h - the itsy package management system
+
+ Carl D. Worth
+
+ Copyright (C) 2001 University of Southern California
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#ifndef IPKG_H
+#define IPKG_H
+
+/*
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+*/
+
+#if 0
+#define IPKG_DEBUG_NO_TMP_CLEANUP
+#endif
+
+#include "ipkg_includes.h"
+#include "ipkg_conf.h"
+#include "ipkg_message.h"
+
+#define IPKG_PKG_EXTENSION ".ipk"
+#define DPKG_PKG_EXTENSION ".deb"
+
+#define IPKG_LEGAL_PKG_NAME_CHARS "abcdefghijklmnopqrstuvwxyz0123456789.+-"
+#define IPKG_PKG_VERSION_SEP_CHAR '_'
+
+#define IPKG_STATE_DIR_PREFIX IPKGLIBDIR"/ipkg"
+#define IPKG_LISTS_DIR_SUFFIX "lists"
+#define IPKG_INFO_DIR_SUFFIX "info"
+#define IPKG_STATUS_FILE_SUFFIX "status"
+
+#define IPKG_BACKUP_SUFFIX "-ipkg.backup"
+
+#define IPKG_LIST_DESCRIPTION_LENGTH 128
+
+#define IPKG_VERSION "0.99.154"
+
+
+enum ipkg_error {
+ IPKG_SUCCESS = 0,
+ IPKG_PKG_DEPS_UNSATISFIED,
+ IPKG_PKG_IS_ESSENTIAL,
+ IPKG_PKG_HAS_DEPENDENTS,
+ IPKG_PKG_HAS_NO_CANDIDATE
+};
+typedef enum ipkg_error ipkg_error_t;
+
+extern int ipkg_state_changed;
+
+
+struct errlist {
+ char * errmsg;
+ struct errlist * next;
+} ;
+
+extern struct errlist* error_list;
+
+extern ipkg_conf_t *global_conf;
+
+#endif
diff -ruN busybox-1.00-orig/archival/libipkg/ipkg_cmd.c busybox-1.00+ipkg-0.99.154/archival/libipkg/ipkg_cmd.c
--- busybox-1.00-orig/archival/libipkg/ipkg_cmd.c 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/ipkg_cmd.c 2005-10-26 17:36:46.000000000 +0200
@@ -0,0 +1,1344 @@
+/* ipkg_cmd.c - the itsy package management system
+
+ Carl D. Worth
+
+ Copyright (C) 2001 University of Southern California
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#include <string.h>
+
+#include "ipkg.h"
+#include <libgen.h>
+#include <glob.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <stdio.h>
+
+#include "ipkg_conf.h"
+#include "ipkg_cmd.h"
+#include "ipkg_message.h"
+#include "pkg.h"
+#include "pkg_dest.h"
+#include "pkg_parse.h"
+#include "sprintf_alloc.h"
+#include "pkg.h"
+#include "file_util.h"
+#include "str_util.h"
+#include "libbb.h"
+#include "unarchive.h"
+
+#include <fnmatch.h>
+
+
+#include "ipkg_download.h"
+#include "ipkg_install.h"
+#include "ipkg_upgrade.h"
+#include "ipkg_remove.h"
+#include "ipkg_configure.h"
+#include "ipkg_message.h"
+
+#ifdef IPKG_LIB
+#include "libipkg.h"
+static void *p_userdata = NULL;
+#endif
+
+static int ipkg_update_cmd(ipkg_conf_t *conf, int argc, char **argv);
+static int ipkg_upgrade_cmd(ipkg_conf_t *conf, int argc, char **argv);
+static int ipkg_list_cmd(ipkg_conf_t *conf, int argc, char **argv);
+static int ipkg_info_cmd(ipkg_conf_t *conf, int argc, char **argv);
+static int ipkg_status_cmd(ipkg_conf_t *conf, int argc, char **argv);
+static int ipkg_install_pending_cmd(ipkg_conf_t *conf, int argc, char **argv);
+static int ipkg_install_cmd(ipkg_conf_t *conf, int argc, char **argv);
+static int ipkg_list_installed_cmd(ipkg_conf_t *conf, int argc, char **argv);
+static int ipkg_remove_cmd(ipkg_conf_t *conf, int argc, char **argv);
+static int ipkg_purge_cmd(ipkg_conf_t *conf, int argc, char **argv);
+static int ipkg_flag_cmd(ipkg_conf_t *conf, int argc, char **argv);
+static int ipkg_files_cmd(ipkg_conf_t *conf, int argc, char **argv);
+static int ipkg_search_cmd(ipkg_conf_t *conf, int argc, char **argv);
+static int ipkg_download_cmd(ipkg_conf_t *conf, int argc, char **argv);
+static int ipkg_depends_cmd(ipkg_conf_t *conf, int argc, char **argv);
+static int ipkg_whatdepends_cmd(ipkg_conf_t *conf, int argc, char **argv);
+static int ipkg_whatdepends_recursively_cmd(ipkg_conf_t *conf, int argc, char **argv);
+static int ipkg_whatsuggests_cmd(ipkg_conf_t *conf, int argc, char **argv);
+static int ipkg_whatrecommends_cmd(ipkg_conf_t *conf, int argc, char **argv);
+static int ipkg_whatprovides_cmd(ipkg_conf_t *conf, int argc, char **argv);
+static int ipkg_whatconflicts_cmd(ipkg_conf_t *conf, int argc, char **argv);
+static int ipkg_whatreplaces_cmd(ipkg_conf_t *conf, int argc, char **argv);
+static int ipkg_compare_versions_cmd(ipkg_conf_t *conf, int argc, char **argv);
+static int ipkg_print_architecture_cmd(ipkg_conf_t *conf, int argc, char **argv);
+static int ipkg_configure_cmd(ipkg_conf_t *conf, int argc, char **argv);
+
+/* XXX: CLEANUP: The usage strings should be incorporated into this
+ array for easier maintenance */
+static ipkg_cmd_t cmds[] = {
+ {"update", 0, (ipkg_cmd_fun_t)ipkg_update_cmd},
+ {"upgrade", 0, (ipkg_cmd_fun_t)ipkg_upgrade_cmd},
+ {"list", 0, (ipkg_cmd_fun_t)ipkg_list_cmd},
+ {"list_installed", 0, (ipkg_cmd_fun_t)ipkg_list_installed_cmd},
+ {"info", 0, (ipkg_cmd_fun_t)ipkg_info_cmd},
+ {"flag", 1, (ipkg_cmd_fun_t)ipkg_flag_cmd},
+ {"status", 0, (ipkg_cmd_fun_t)ipkg_status_cmd},
+ {"install_pending", 0, (ipkg_cmd_fun_t)ipkg_install_pending_cmd},
+ {"install", 1, (ipkg_cmd_fun_t)ipkg_install_cmd},
+ {"remove", 1, (ipkg_cmd_fun_t)ipkg_remove_cmd},
+ {"purge", 1, (ipkg_cmd_fun_t)ipkg_purge_cmd},
+ {"configure", 0, (ipkg_cmd_fun_t)ipkg_configure_cmd},
+ {"files", 1, (ipkg_cmd_fun_t)ipkg_files_cmd},
+ {"search", 1, (ipkg_cmd_fun_t)ipkg_search_cmd},
+ {"download", 1, (ipkg_cmd_fun_t)ipkg_download_cmd},
+ {"compare_versions", 1, (ipkg_cmd_fun_t)ipkg_compare_versions_cmd},
+ {"compare-versions", 1, (ipkg_cmd_fun_t)ipkg_compare_versions_cmd},
+ {"print-architecture", 0, (ipkg_cmd_fun_t)ipkg_print_architecture_cmd},
+ {"print_architecture", 0, (ipkg_cmd_fun_t)ipkg_print_architecture_cmd},
+ {"print-installation-architecture", 0, (ipkg_cmd_fun_t)ipkg_print_architecture_cmd},
+ {"print_installation_architecture", 0, (ipkg_cmd_fun_t)ipkg_print_architecture_cmd},
+ {"depends", 1, (ipkg_cmd_fun_t)ipkg_depends_cmd},
+ {"whatdepends", 1, (ipkg_cmd_fun_t)ipkg_whatdepends_cmd},
+ {"whatdependsrec", 1, (ipkg_cmd_fun_t)ipkg_whatdepends_recursively_cmd},
+ {"whatrecommends", 1, (ipkg_cmd_fun_t)ipkg_whatrecommends_cmd},
+ {"whatsuggests", 1, (ipkg_cmd_fun_t)ipkg_whatsuggests_cmd},
+ {"whatprovides", 1, (ipkg_cmd_fun_t)ipkg_whatprovides_cmd},
+ {"whatreplaces", 1, (ipkg_cmd_fun_t)ipkg_whatreplaces_cmd},
+ {"whatconflicts", 1, (ipkg_cmd_fun_t)ipkg_whatconflicts_cmd},
+};
+
+int ipkg_state_changed;
+static void write_status_files_if_changed(ipkg_conf_t *conf)
+{
+ if (ipkg_state_changed && !conf->noaction) {
+ ipkg_message(conf, IPKG_INFO,
+ " writing status file\n");
+ ipkg_conf_write_status_files(conf);
+ pkg_write_changed_filelists(conf);
+ } else {
+ ipkg_message(conf, IPKG_NOTICE, "Nothing to be done\n");
+ }
+}
+
+
+static int num_cmds = sizeof(cmds) / sizeof(ipkg_cmd_t);
+
+ipkg_cmd_t *ipkg_cmd_find(const char *name)
+{
+ int i;
+ ipkg_cmd_t *cmd;
+
+ for (i=0; i < num_cmds; i++) {
+ cmd = &cmds[i];
+ if (strcmp(name, cmd->name) == 0) {
+ return cmd;
+ }
+ }
+
+ return NULL;
+}
+
+#ifdef IPKG_LIB
+int ipkg_cmd_exec(ipkg_cmd_t *cmd, ipkg_conf_t *conf, int argc, const char **argv, void *userdata)
+{
+ int result;
+ p_userdata = userdata;
+
+
+ result = (cmd->fun)(conf, argc, argv);
+ if ( result == 0 ) {
+ ipkg_message(conf, IPKG_NOTICE, "Done.\n");
+ } else {
+ ipkg_message(conf, IPKG_NOTICE, "An error ocurred, return value: %d.\n", result);
+
+ }
+ if ( error_list ) {
+ reverse_error_list(&error_list);
+
+ ipkg_message(conf, IPKG_NOTICE, "Collected errors:\n");
+ /* Here we print the errors collected and free the list */
+ while (error_list != NULL) {
+ ipkg_message(conf, IPKG_NOTICE, "%s",error_list->errmsg);
+ error_list = error_list->next;
+
+ }
+ free_error_list(&error_list);
+
+ }
+
+ p_userdata = NULL;
+ return result;
+}
+#else
+int ipkg_cmd_exec(ipkg_cmd_t *cmd, ipkg_conf_t *conf, int argc, const char **argv)
+{
+ return (cmd->fun)(conf, argc, argv);
+}
+#endif
+
+static int ipkg_update_cmd(ipkg_conf_t *conf, int argc, char **argv)
+{
+ int err;
+ int failures;
+ char *lists_dir;
+ pkg_src_list_elt_t *iter;
+ pkg_src_t *src;
+
+
+ if (conf->offline_root) {
+ sprintf_alloc(&lists_dir, "%s/%s",
+ conf->offline_root,
+ conf->restrict_to_default_dest ? conf->default_dest->lists_dir : conf->lists_dir);
+ } else {
+ 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)) {
+ ipkg_message(conf, IPKG_ERROR,
+ "%s: ERROR: %s exists, but is not a directory\n",
+ __FUNCTION__, lists_dir);
+ free(lists_dir);
+ return EINVAL;
+ }
+ err = file_mkdir_hier(lists_dir, 0755);
+ if (err) {
+ ipkg_message(conf, IPKG_ERROR,
+ "%s: ERROR: failed to make directory %s: %s\n",
+ __FUNCTION__, lists_dir, strerror(errno));
+ free(lists_dir);
+ return EINVAL;
+ }
+ }
+
+ failures = 0;
+ for (iter = conf->pkg_src_list.head; iter; iter = iter->next) {
+ char *url, *list_file_name;
+
+ src = 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;
+ char *tmp_file_name;
+ FILE *in, *out;
+
+ tmp = strdup ("/tmp/ipkg.XXXXXX");
+
+ if (mkdtemp (tmp) == NULL) {
+ perror ("mkdtemp");
+ failures++;
+ continue;
+ }
+
+ sprintf_alloc (&tmp_file_name, "%s/%s.gz", tmp, src->name);
+ err = ipkg_download(conf, url, tmp_file_name);
+ if (err == 0) {
+ ipkg_message (conf, IPKG_NOTICE, "Inflating %s\n", url);
+ in = fopen (tmp_file_name, "r");
+ out = fopen (list_file_name, "w");
+ if (in && out)
+ inflate_unzip (in, out);
+ else
+ err = 1;
+ if (in)
+ fclose (in);
+ if (out)
+ fclose (out);
+ unlink (tmp_file_name);
+ rmdir (tmp);
+ free (tmp);
+ }
+ } else
+ err = ipkg_download(conf, url, list_file_name);
+ if (err) {
+ failures++;
+ } else {
+ ipkg_message(conf, IPKG_NOTICE,
+ "Updated list of available packages in %s\n",
+ list_file_name);
+ }
+ free(url);
+ free(list_file_name);
+ }
+ 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 ipkg 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);
+ ipkg_message(conf, IPKG_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) {
+ ipkg_message(conf, IPKG_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 ipkg_multiple_files_scan(ipkg_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 (IPKG_PKG_EXTENSION)), IPKG_PKG_EXTENSION) != 0)
+ // continue;
+ //if (strcmp (tmp + (tmplen - strlen (DPKG_PKG_EXTENSION)), DPKG_PKG_EXTENSION) != 0)
+ // continue;
+
+ err = ipkg_prepare_url_for_install(conf, filename, &argv[i]);
+ if (err)
+ return err;
+ }
+ return 0;
+}
+
+int ipkg_configure_packages(ipkg_conf_t *conf, char *pkg_name)
+{
+ pkg_vec_t *all;
+ int i;
+ pkg_t *pkg;
+
+ ipkg_message(conf, IPKG_INFO,
+ "Configuring unpacked packages\n");
+ fflush( stdout );
+
+ all = pkg_vec_alloc();
+ pkg_hash_fetch_available(&conf->pkg_hash, all);
+
+ 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) {
+ ipkg_message(conf, IPKG_NOTICE,
+ "Configuring %s\n", pkg->name);
+ fflush( stdout );
+ if (ipkg_configure(conf, pkg) == 0) {
+ pkg->state_status = SS_INSTALLED;
+ pkg->parent->state_status = SS_INSTALLED;
+ pkg->state_flag &= ~SF_PREFER;
+ }
+ }
+ }
+
+ pkg_vec_free(all);
+ return 0;
+}
+
+static void sigint_handler(int sig)
+{
+ signal(sig, SIG_DFL);
+ ipkg_message(NULL, IPKG_NOTICE,
+ "ipkg: interrupted. writing out status database\n");
+ write_status_files_if_changed(global_conf);
+ exit(128 + sig);
+}
+
+static int ipkg_install_cmd(ipkg_conf_t *conf, 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];
+
+ err = ipkg_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];
+ if (conf->multiple_providers)
+ err = ipkg_install_multi_by_name(conf, arg);
+ else{
+ err = ipkg_install_by_name(conf, arg);
+ }
+ if (err == IPKG_PKG_HAS_NO_CANDIDATE) {
+ ipkg_message(conf, IPKG_ERROR,
+ "Cannot find package %s.\n"
+ "Check the spelling or perhaps run 'ipkg update'\n",
+ arg);
+ }
+ }
+
+ /* recheck to verify that all dependences are satisfied */
+ if (0) ipkg_satisfy_all_dependences(conf);
+
+ ipkg_configure_packages(conf, NULL);
+
+ write_status_files_if_changed(conf);
+
+ return err;
+}
+
+static int ipkg_upgrade_cmd(ipkg_conf_t *conf, 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 = ipkg_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) {
+ ipkg_message(conf, IPKG_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)
+ ipkg_upgrade_pkg(conf, pkg);
+ else {
+ ipkg_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];
+ ipkg_upgrade_pkg(conf, pkg);
+ }
+ pkg_vec_free(installed);
+ }
+
+ /* recheck to verify that all dependences are satisfied */
+ if (0) ipkg_satisfy_all_dependences(conf);
+
+ ipkg_configure_packages(conf, NULL);
+
+ write_status_files_if_changed(conf);
+
+ return 0;
+}
+
+static int ipkg_download_cmd(ipkg_conf_t *conf, int argc, char **argv)
+{
+ 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);
+ if (pkg == NULL) {
+ ipkg_message(conf, IPKG_ERROR,
+ "Cannot find package %s.\n"
+ "Check the spelling or perhaps run 'ipkg update'\n",
+ arg);
+ continue;
+ }
+
+ err = ipkg_download_pkg(conf, pkg, ".");
+
+ if (err) {
+ ipkg_message(conf, IPKG_ERROR,
+ "Failed to download %s\n", pkg->name);
+ } else {
+ ipkg_message(conf, IPKG_NOTICE,
+ "Downloaded %s as %s\n",
+ pkg->name, pkg->local_filename);
+ }
+ }
+
+ return 0;
+}
+
+
+static int ipkg_list_cmd(ipkg_conf_t *conf, int argc, char **argv)
+{
+ int i ;
+ pkg_vec_t *available;
+ pkg_t *pkg;
+ char desc_short[IPKG_LIST_DESCRIPTION_LENGTH];
+ char *newline;
+ char *pkg_name = NULL;
+ char *version_str;
+
+ if (argc > 0) {
+ pkg_name = argv[0];
+ }
+ available = pkg_vec_alloc();
+ pkg_hash_fetch_available(&conf->pkg_hash, available);
+ 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;
+ if (pkg->description) {
+ strncpy(desc_short, pkg->description, IPKG_LIST_DESCRIPTION_LENGTH);
+ } else {
+ desc_short[0] = '\0';
+ }
+ desc_short[IPKG_LIST_DESCRIPTION_LENGTH - 1] = '\0';
+ newline = strchr(desc_short, '\n');
+ if (newline) {
+ *newline = '\0';
+ }
+#ifndef IPKG_LIB
+ printf("%s - %s\n", pkg->name, desc_short);
+#else
+ if (ipkg_cb_list) {
+ version_str = pkg_version_str_alloc(pkg);
+ ipkg_cb_list(pkg->name,desc_short,
+ version_str,
+ pkg->state_status,
+ p_userdata);
+ free(version_str);
+ }
+#endif
+ }
+ pkg_vec_free(available);
+
+ return 0;
+}
+
+
+static int ipkg_list_installed_cmd(ipkg_conf_t *conf, int argc, char **argv)
+{
+ int i ;
+ pkg_vec_t *available;
+ pkg_t *pkg;
+ char desc_short[IPKG_LIST_DESCRIPTION_LENGTH];
+ char *newline;
+ char *pkg_name = NULL;
+ char *version_str;
+
+ if (argc > 0) {
+ pkg_name = argv[0];
+ }
+ available = pkg_vec_alloc();
+ pkg_hash_fetch_all_installed(&conf->pkg_hash, available);
+ 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;
+ if (pkg->description) {
+ strncpy(desc_short, pkg->description, IPKG_LIST_DESCRIPTION_LENGTH);
+ } else {
+ desc_short[0] = '\0';
+ }
+ desc_short[IPKG_LIST_DESCRIPTION_LENGTH - 1] = '\0';
+ newline = strchr(desc_short, '\n');
+ if (newline) {
+ *newline = '\0';
+ }
+#ifndef IPKG_LIB
+ printf("%s - %s\n", pkg->name, desc_short);
+#else
+ if (ipkg_cb_list) {
+ version_str = pkg_version_str_alloc(pkg);
+ ipkg_cb_list(pkg->name,desc_short,
+ version_str,
+ pkg->state_status,
+ p_userdata);
+ free(version_str);
+ }
+#endif
+ }
+
+ return 0;
+}
+
+static int ipkg_info_status_cmd(ipkg_conf_t *conf, int argc, char **argv, int installed_only)
+{
+ int i;
+ pkg_vec_t *available;
+ pkg_t *pkg;
+ char *pkg_name = NULL;
+ char **pkg_fields = NULL;
+ int n_fields = 0;
+ char *buff ; // = (char *)malloc(1);
+
+ if (argc > 0) {
+ pkg_name = argv[0];
+ }
+ if (argc > 1) {
+ pkg_fields = &argv[1];
+ n_fields = argc - 1;
+ }
+
+ 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;
+ }
+#ifndef IPKG_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 ) {
+ if (ipkg_cb_status) ipkg_cb_status(pkg->name,
+ pkg->state_status,
+ buff,
+ p_userdata);
+/*
+ We should not forget that actually the pointer is allocated.
+ We need to free it :) ( Thanks florian for seeing the error )
+*/
+ free(buff);
+ }
+#endif
+ if (conf->verbosity > 1) {
+ conffile_list_elt_t *iter;
+ for (iter = pkg->conffiles.head; iter; iter = iter->next) {
+ conffile_t *cf = iter->data;
+ int modified = conffile_has_been_modified(conf, cf);
+ ipkg_message(conf, IPKG_NOTICE, "conffile=%s md5sum=%s modified=%d\n",
+ cf->name, cf->value, modified);
+ }
+ }
+ }
+#ifndef IPKG_LIB
+ if (buff)
+ free(buff);
+#endif
+ pkg_vec_free(available);
+
+ return 0;
+}
+
+static int ipkg_info_cmd(ipkg_conf_t *conf, int argc, char **argv)
+{
+ return ipkg_info_status_cmd(conf, argc, argv, 0);
+}
+
+static int ipkg_status_cmd(ipkg_conf_t *conf, int argc, char **argv)
+{
+ return ipkg_info_status_cmd(conf, argc, argv, 1);
+}
+
+static int ipkg_configure_cmd(ipkg_conf_t *conf, int argc, char **argv)
+{
+
+ int err;
+ if (argc > 0) {
+ char *pkg_name = NULL;
+
+ pkg_name = argv[0];
+
+ err = ipkg_configure_packages (conf, pkg_name);
+
+ } else {
+ err = ipkg_configure_packages (conf, NULL);
+ }
+
+ write_status_files_if_changed(conf);
+
+ return err;
+}
+
+static int ipkg_install_pending_cmd(ipkg_conf_t *conf, int argc, char **argv)
+{
+ int i, err;
+ char *globpattern;
+ glob_t globbuf;
+
+ sprintf_alloc(&globpattern, "%s/*" IPKG_PKG_EXTENSION, conf->pending_dir);
+ err = glob(globpattern, 0, NULL, &globbuf);
+ free(globpattern);
+ if (err) {
+ return 0;
+ }
+
+ ipkg_message(conf, IPKG_NOTICE,
+ "The following packages in %s will now be installed.\n",
+ conf->pending_dir);
+ for (i = 0; i < globbuf.gl_pathc; i++) {
+ ipkg_message(conf, IPKG_NOTICE,
+ "%s%s", i == 0 ? "" : " ", globbuf.gl_pathv[i]);
+ }
+ ipkg_message(conf, IPKG_NOTICE, "\n");
+ for (i = 0; i < globbuf.gl_pathc; i++) {
+ err = ipkg_install_from_file(conf, globbuf.gl_pathv[i]);
+ if (err == 0) {
+ err = unlink(globbuf.gl_pathv[i]);
+ if (err) {
+ ipkg_message(conf, IPKG_ERROR,
+ "%s: ERROR: failed to unlink %s: %s\n",
+ __FUNCTION__, globbuf.gl_pathv[i], strerror(err));
+ return err;
+ }
+ }
+ }
+ globfree(&globbuf);
+
+ return err;
+}
+
+static int ipkg_remove_cmd(ipkg_conf_t *conf, int argc, char **argv)
+{
+ int i,a,done;
+ pkg_t *pkg;
+ pkg_t *pkg_to_remove;
+ pkg_vec_t *available;
+ char *pkg_name = NULL;
+ global_conf = conf;
+ signal(SIGINT, sigint_handler);
+
+// ENH: Add the "no pkg removed" just in case.
+
+ done = 0;
+
+ available = pkg_vec_alloc();
+ pkg_info_preinstall_check(conf);
+ if ( argc > 0 ) {
+ pkg_hash_fetch_all_installed(&conf->pkg_hash, available);
+ for (i=0; i < argc; i++) {
+ pkg_name = malloc(strlen(argv[i])+2);
+ strcpy(pkg_name,argv[i]);
+ for (a=0; a < available->len; a++) {
+ pkg = available->pkgs[a];
+ if (pkg_name && fnmatch(pkg_name, 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 == NULL) {
+ ipkg_message(conf, IPKG_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
+ ipkg_message(conf, IPKG_ERROR, "Package seems to be %s not installed (STATUS = NOT_INSTALLED).\n", pkg->name);
+ continue;
+ }
+ ipkg_remove_pkg(conf, pkg_to_remove);
+ done = 1;
+ }
+ free (pkg_name);
+ }
+ pkg_vec_free(available);
+ } else {
+ pkg_vec_t *installed_pkgs = pkg_vec_alloc();
+ int i;
+ int flagged_pkg_count = 0;
+ int removed;
+
+ pkg_hash_fetch_all_installed(&conf->pkg_hash, installed_pkgs);
+
+ for (i = 0; i < installed_pkgs->len; i++) {
+ pkg_t *pkg = installed_pkgs->pkgs[i];
+ if (pkg->state_flag & SF_USER) {
+ flagged_pkg_count++;
+ } else {
+ if (!pkg_has_installed_dependents(conf, pkg->parent, pkg, NULL))
+ ipkg_message(conf, IPKG_NOTICE, "Non-user leaf package: %s\n", pkg->name);
+ }
+ }
+ if (!flagged_pkg_count) {
+ ipkg_message(conf, IPKG_NOTICE, "No packages flagged as installed by user, \n"
+ "so refusing to uninstall unflagged non-leaf packages\n");
+ return 0;
+ }
+
+ /* find packages not flagged SF_USER (i.e., installed to
+ * satisfy a dependence) and not having any dependents, and
+ * remove them */
+ do {
+ removed = 0;
+ for (i = 0; i < installed_pkgs->len; i++) {
+ pkg_t *pkg = installed_pkgs->pkgs[i];
+ if (!(pkg->state_flag & SF_USER)
+ && !pkg_has_installed_dependents(conf, pkg->parent, pkg, NULL)) {
+ removed++;
+ ipkg_message(conf, IPKG_NOTICE, "Removing non-user leaf package %s\n");
+ ipkg_remove_pkg(conf, pkg);
+ done = 1;
+ }
+ }
+ } while (removed);
+ pkg_vec_free(installed_pkgs);
+ }
+
+ if ( done == 0 )
+ ipkg_message(conf, IPKG_NOTICE, "No packages removed.\n");
+
+ write_status_files_if_changed(conf);
+ return 0;
+}
+
+static int ipkg_purge_cmd(ipkg_conf_t *conf, int argc, char **argv)
+{
+ int i;
+ pkg_t *pkg;
+
+ global_conf = conf;
+ signal(SIGINT, sigint_handler);
+
+ pkg_info_preinstall_check(conf);
+
+ for (i=0; 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) {
+ ipkg_message(conf, IPKG_ERROR,
+ "Package %s is not installed.\n", argv[i]);
+ continue;
+ }
+ ipkg_purge_pkg(conf, pkg);
+ }
+
+ write_status_files_if_changed(conf);
+ return 0;
+}
+
+static int ipkg_flag_cmd(ipkg_conf_t *conf, 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) {
+ ipkg_message(conf, IPKG_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);
+ }
+/* pb_ asked this feature 03292004 */
+/* Actually I will use only this two, but this is an open for various status */
+ if (( strcmp(flags,"installed")==0)||( strcmp(flags,"unpacked")==0)){
+ pkg->state_status = pkg_state_status_from_str(flags);
+ }
+ ipkg_state_changed++;
+ ipkg_message(conf, IPKG_NOTICE,
+ "Setting flags for package %s to %s\n",
+ pkg->name, flags);
+ }
+
+ write_status_files_if_changed(conf);
+ return 0;
+}
+
+static int ipkg_files_cmd(ipkg_conf_t *conf, int argc, char **argv)
+{
+ pkg_t *pkg;
+ str_list_t *installed_files;
+ str_list_elt_t *iter;
+ char *pkg_version;
+ size_t buff_len = 8192;
+ size_t used_len;
+ char *buff ;
+
+ buff = (char *)malloc(buff_len);
+ if ( buff == NULL ) {
+ fprintf( stderr,"%s: Unable to allocate memory \n",__FUNCTION__);
+ return ENOMEM;
+ }
+
+ if (argc < 1) {
+ return EINVAL;
+ }
+
+ pkg = pkg_hash_fetch_installed_by_name(&conf->pkg_hash,
+ argv[0]);
+ if (pkg == NULL) {
+ ipkg_message(conf, IPKG_ERROR,
+ "Package %s not installed.\n", argv[0]);
+ return 0;
+ }
+
+ installed_files = pkg_get_installed_files(pkg);
+ pkg_version = pkg_version_str_alloc(pkg);
+
+#ifndef IPKG_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",
+ pkg->name, pkg_version, pkg->dest->name) + 1;
+ if (used_len > buff_len) {
+ buff_len *= 2;
+ buff = realloc (buff, buff_len);
+ goto try_again;
+ }
+ for (iter = installed_files->head; iter; iter = iter->next) {
+ used_len += strlen (iter->data) + 1;
+ while (buff_len <= used_len) {
+ buff_len *= 2;
+ buff = realloc (buff, buff_len);
+ }
+ strncat(buff, iter->data, buff_len);
+ strncat(buff, "\n", buff_len);
+ }
+ if (ipkg_cb_list) ipkg_cb_list(pkg->name,
+ buff,
+ pkg_version_str_alloc(pkg),
+ pkg->state_status,
+ p_userdata);
+ free(buff);
+ }
+#endif
+
+ free(pkg_version);
+ pkg_free_installed_files(pkg);
+
+ return 0;
+}
+
+static int ipkg_depends_cmd(ipkg_conf_t *conf, int argc, char **argv)
+{
+
+ if (argc > 0) {
+ pkg_vec_t *available_pkgs = pkg_vec_alloc();
+ const char *rel_str = "depends on";
+ 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;
+
+ ipkg_message(conf, IPKG_ERROR, "target=%s\n", target);
+
+ for (j = 0; j < available_pkgs->len; j++) {
+ pkg_t *pkg = available_pkgs->pkgs[j];
+ if (fnmatch(target, pkg->name, 0) == 0) {
+ int k;
+ int count = pkg->depends_count + pkg->pre_depends_count;
+ ipkg_message(conf, IPKG_ERROR, "What %s (arch=%s) %s\n",
+ target, pkg->architecture, rel_str);
+ for (k = 0; k < count; k++) {
+ compound_depend_t *cdepend = &pkg->depends[k];
+ int l;
+ for (l = 0; l < cdepend->possibility_count; l++) {
+ depend_t *possibility = cdepend->possibilities[l];
+ ipkg_message(conf, IPKG_ERROR, " %s", possibility->pkg->name);
+ if (conf->verbosity > 0) {
+ // char *ver = abstract_pkg_version_str_alloc(possibility->pkg);
+ ipkg_message(conf, IPKG_NOTICE, " %s", possibility->version);
+ if (possibility->version) {
+ char *typestr = NULL;
+ switch (possibility->constraint) {
+ case NONE: typestr = "none"; break;
+ case EARLIER: typestr = "<"; break;
+ case EARLIER_EQUAL: typestr = "<="; break;
+ case EQUAL: typestr = "="; break;
+ case LATER_EQUAL: typestr = ">="; break;
+ case LATER: typestr = ">"; break;
+ }
+ ipkg_message(conf, IPKG_NOTICE, " (%s %s)", typestr, possibility->version);
+ }
+ // free(ver);
+ }
+ ipkg_message(conf, IPKG_ERROR, "\n");
+ }
+ }
+ }
+ }
+ }
+ pkg_vec_free(available_pkgs);
+ }
+ return 0;
+}
+
+enum what_field_type {
+ WHATDEPENDS,
+ WHATCONFLICTS,
+ WHATPROVIDES,
+ WHATREPLACES,
+ WHATRECOMMENDS,
+ WHATSUGGESTS
+};
+
+static int ipkg_what_depends_conflicts_cmd(ipkg_conf_t *conf, enum what_field_type what_field_type, int recursive, int argc, char **argv)
+{
+
+ if (argc > 0) {
+ pkg_vec_t *available_pkgs = pkg_vec_alloc();
+ const char *rel_str = NULL;
+ int i;
+ int changed;
+
+ switch (what_field_type) {
+ case WHATDEPENDS: rel_str = "depends on"; break;
+ case WHATCONFLICTS: rel_str = "conflicts with"; break;
+ case WHATSUGGESTS: rel_str = "suggests"; break;
+ case WHATRECOMMENDS: rel_str = "recommends"; break;
+ case WHATPROVIDES: rel_str = "provides"; break;
+ case WHATREPLACES: rel_str = "replaces"; break;
+ }
+
+ if (conf->query_all)
+ pkg_hash_fetch_available(&conf->pkg_hash, available_pkgs);
+ else
+ pkg_hash_fetch_all_installed(&conf->pkg_hash, available_pkgs);
+
+ /* mark the root set */
+ pkg_vec_clear_marks(available_pkgs);
+ ipkg_message(conf, IPKG_NOTICE, "Root set:\n");
+ for (i = 0; i < argc; i++) {
+ const char *dependee_pattern = argv[i];
+ pkg_vec_mark_if_matches(available_pkgs, dependee_pattern);
+ }
+ for (i = 0; i < available_pkgs->len; i++) {
+ pkg_t *pkg = available_pkgs->pkgs[i];
+ if (pkg->state_flag & SF_MARKED) {
+ /* mark the parent (abstract) package */
+ pkg_mark_provides(pkg);
+ ipkg_message(conf, IPKG_NOTICE, " %s\n", pkg->name);
+ }
+ }
+
+ ipkg_message(conf, IPKG_NOTICE, "What %s root set\n", rel_str);
+ do {
+ int j;
+ changed = 0;
+
+ for (j = 0; j < available_pkgs->len; j++) {
+ pkg_t *pkg = available_pkgs->pkgs[j];
+ int k;
+ int count = ((what_field_type == WHATCONFLICTS)
+ ? pkg->conflicts_count
+ : pkg->pre_depends_count + pkg->depends_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++) {
+ compound_depend_t *cdepend =
+ (what_field_type == WHATCONFLICTS) ? &pkg->conflicts[k] : &pkg->depends[k];
+ int l;
+ for (l = 0; l < cdepend->possibility_count; l++) {
+ depend_t *possibility = cdepend->possibilities[l];
+ if (possibility->pkg->state_flag & SF_MARKED) {
+ /* mark the depending package so we won't visit it again */
+ pkg->state_flag |= SF_MARKED;
+ pkg_mark_provides(pkg);
+ changed++;
+
+ ipkg_message(conf, IPKG_NOTICE, " %s", pkg->name);
+ if (conf->verbosity > 0) {
+ char *ver = pkg_version_str_alloc(pkg);
+ ipkg_message(conf, IPKG_NOTICE, " %s", ver);
+ ipkg_message(conf, IPKG_NOTICE, "\t%s %s", rel_str, possibility->pkg->name);
+ if (possibility->version) {
+ char *typestr = NULL;
+ switch (possibility->constraint) {
+ case NONE: typestr = "none"; break;
+ case EARLIER: typestr = "<"; break;
+ case EARLIER_EQUAL: typestr = "<="; break;
+ case EQUAL: typestr = "="; break;
+ case LATER_EQUAL: typestr = ">="; break;
+ case LATER: typestr = ">"; break;
+ }
+ ipkg_message(conf, IPKG_NOTICE, " (%s %s)", typestr, possibility->version);
+ }
+ free(ver);
+ if (!pkg_dependence_satisfiable(conf, possibility))
+ ipkg_message(conf, IPKG_NOTICE, " unsatisfiable");
+ }
+ ipkg_message(conf, IPKG_NOTICE, "\n");
+ goto next_package;
+ }
+ }
+ }
+ next_package:
+ ;
+ }
+ } while (changed && recursive);
+ pkg_vec_free(available_pkgs);
+ }
+
+ return 0;
+}
+
+int pkg_mark_provides(pkg_t *pkg)
+{
+ 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;
+}
+
+static int ipkg_whatdepends_recursively_cmd(ipkg_conf_t *conf, int argc, char **argv)
+{
+ return ipkg_what_depends_conflicts_cmd(conf, WHATDEPENDS, 1, argc, argv);
+}
+static int ipkg_whatdepends_cmd(ipkg_conf_t *conf, int argc, char **argv)
+{
+ return ipkg_what_depends_conflicts_cmd(conf, WHATDEPENDS, 0, argc, argv);
+}
+
+static int ipkg_whatsuggests_cmd(ipkg_conf_t *conf, int argc, char **argv)
+{
+ return ipkg_what_depends_conflicts_cmd(conf, WHATSUGGESTS, 0, argc, argv);
+}
+
+static int ipkg_whatrecommends_cmd(ipkg_conf_t *conf, int argc, char **argv)
+{
+ return ipkg_what_depends_conflicts_cmd(conf, WHATRECOMMENDS, 0, argc, argv);
+}
+
+static int ipkg_whatconflicts_cmd(ipkg_conf_t *conf, int argc, char **argv)
+{
+ return ipkg_what_depends_conflicts_cmd(conf, WHATCONFLICTS, 0, argc, argv);
+}
+
+static int ipkg_what_provides_replaces_cmd(ipkg_conf_t *conf, enum what_field_type what_field_type, int argc, char **argv)
+{
+
+ 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;
+
+ ipkg_message(conf, IPKG_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) {
+ ipkg_message(conf, IPKG_ERROR, " %s", pkg->name);
+ if (strcmp(target, apkg->name) != 0)
+ ipkg_message(conf, IPKG_ERROR, "\t%s %s\n", rel_str, apkg->name);
+ ipkg_message(conf, IPKG_ERROR, "\n");
+ }
+ }
+ }
+ }
+ pkg_vec_free(available_pkgs);
+ }
+ return 0;
+}
+
+static int ipkg_whatprovides_cmd(ipkg_conf_t *conf, int argc, char **argv)
+{
+ return ipkg_what_provides_replaces_cmd(conf, WHATPROVIDES, argc, argv);
+}
+
+static int ipkg_whatreplaces_cmd(ipkg_conf_t *conf, int argc, char **argv)
+{
+ return ipkg_what_provides_replaces_cmd(conf, WHATREPLACES, argc, argv);
+}
+
+static int ipkg_search_cmd(ipkg_conf_t *conf, int argc, char **argv)
+{
+ int i;
+
+ 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);
+
+ for (i=0; i < installed->len; i++) {
+ pkg = installed->pkgs[i];
+
+ installed_files = pkg_get_installed_files(pkg);
+
+ for (iter = installed_files->head; iter; iter = iter->next) {
+ installed_file = iter->data;
+ if (fnmatch(argv[0], installed_file, 0)==0) {
+#ifndef IPKG_LIB
+ printf("%s: %s\n", pkg->name, installed_file);
+#else
+ if (ipkg_cb_list) ipkg_cb_list(pkg->name,
+ installed_file,
+ pkg_version_str_alloc(pkg),
+ pkg->state_status, p_userdata);
+#endif
+ }
+ }
+
+ 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;
+}
+
+static int ipkg_compare_versions_cmd(ipkg_conf_t *conf, int argc, char **argv)
+{
+ if (argc == 3) {
+ /* this is a bit gross */
+ struct pkg p1, p2;
+ parseVersion(&p1, argv[0]);
+ parseVersion(&p2, argv[2]);
+ return pkg_version_satisfied(&p1, &p2, argv[1]);
+ } else {
+ ipkg_message(conf, IPKG_ERROR,
+ "ipkg compare_versions <v1> <op> <v2>\n"
+ "<op> is one of <= >= << >> =\n");
+ return -1;
+ }
+}
+
+#ifndef HOST_CPU_STR
+#define HOST_CPU_STR__(X) #X
+#define HOST_CPU_STR_(X) HOST_CPU_STR__(X)
+#define HOST_CPU_STR HOST_CPU_STR_(HOST_CPU_FOO)
+#endif
+
+static int ipkg_print_architecture_cmd(ipkg_conf_t *conf, int argc, char **argv)
+{
+ nv_pair_list_elt_t *l;
+
+ l = conf->arch_list.head;
+ while (l) {
+ nv_pair_t *nv = l->data;
+ printf("arch %s %s\n", nv->name, nv->value);
+ l = l->next;
+ }
+ return 0;
+}
+
+
diff -ruN busybox-1.00-orig/archival/libipkg/ipkg_cmd.h busybox-1.00+ipkg-0.99.154/archival/libipkg/ipkg_cmd.h
--- busybox-1.00-orig/archival/libipkg/ipkg_cmd.h 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/ipkg_cmd.h 2005-10-26 17:36:46.000000000 +0200
@@ -0,0 +1,46 @@
+/* ipkg_cmd.h - the itsy package management system
+
+ Carl D. Worth
+
+ Copyright (C) 2001 University of Southern California
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#ifndef IPKG_CMD_H
+#define IPKG_CMD_H
+
+typedef int (*ipkg_cmd_fun_t)(ipkg_conf_t *conf, int argc, const char **argv);
+
+struct ipkg_cmd
+{
+ char *name;
+ int requires_args;
+ ipkg_cmd_fun_t fun;
+};
+typedef struct ipkg_cmd ipkg_cmd_t;
+
+ipkg_cmd_t *ipkg_cmd_find(const char *name);
+#ifdef IPKG_LIB
+int ipkg_cmd_exec(ipkg_cmd_t *cmd, ipkg_conf_t *conf, int argc,
+ const char **argv, void *userdata);
+#else
+int ipkg_cmd_exec(ipkg_cmd_t *cmd, ipkg_conf_t *conf, int argc, const char **argv);
+#endif
+int ipkg_multiple_files_scan (ipkg_conf_t *conf, int argc, char *argv[]);
+/* install any packges with state_want == SW_INSTALL */
+int ipkg_install_wanted_packages(ipkg_conf_t *conf);
+/* ensure that all dependences are satisfied */
+int ipkg_configure_packages(ipkg_conf_t *conf, char *pkg_name);
+
+int pkg_mark_provides(pkg_t *pkg);
+
+#endif
diff -ruN busybox-1.00-orig/archival/libipkg/ipkg_conf.c busybox-1.00+ipkg-0.99.154/archival/libipkg/ipkg_conf.c
--- busybox-1.00-orig/archival/libipkg/ipkg_conf.c 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/ipkg_conf.c 2005-10-26 17:36:46.000000000 +0200
@@ -0,0 +1,709 @@
+/* ipkg_conf.c - the itsy package management system
+
+ Carl D. Worth
+
+ Copyright (C) 2001 University of Southern California
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#include <glob.h>
+
+#include "ipkg.h"
+#include "ipkg_conf.h"
+
+#include "xregex.h"
+#include "sprintf_alloc.h"
+#include "ipkg_conf.h"
+#include "ipkg_message.h"
+#include "file_util.h"
+#include "str_util.h"
+#include "xsystem.h"
+
+
+ipkg_conf_t *global_conf;
+
+static int ipkg_conf_parse_file(ipkg_conf_t *conf, const char *filename,
+ pkg_src_list_t *pkg_src_list,
+ nv_pair_list_t *tmp_dest_nv_pair_list,
+ char **tmp_lists_dir);
+static int ipkg_init_options_array(const ipkg_conf_t *conf, ipkg_option_t **options);
+static int ipkg_conf_set_option(const ipkg_option_t *options,
+ const char *name, const char *value);
+static int ipkg_conf_set_default_dest(ipkg_conf_t *conf,
+ const char *default_dest_name);
+static int set_and_load_pkg_src_list(ipkg_conf_t *conf,
+ pkg_src_list_t *nv_pair_list);
+static int set_and_load_pkg_dest_list(ipkg_conf_t *conf,
+ nv_pair_list_t *nv_pair_list, char * lists_dir);
+
+int ipkg_init_options_array(const ipkg_conf_t *conf, ipkg_option_t **options)
+{
+ ipkg_option_t tmp[] = {
+ { "force_defaults", IPKG_OPT_TYPE_BOOL, &conf->force_defaults },
+ { "force_depends", IPKG_OPT_TYPE_BOOL, &conf->force_depends },
+ { "force_overwrite", IPKG_OPT_TYPE_BOOL, &conf->force_overwrite },
+ { "force_downgrade", IPKG_OPT_TYPE_BOOL, &conf->force_downgrade },
+ { "force_reinstall", IPKG_OPT_TYPE_BOOL, &conf->force_reinstall },
+ { "force_space", IPKG_OPT_TYPE_BOOL, &conf->force_space },
+ { "ftp_proxy", IPKG_OPT_TYPE_STRING, &conf->ftp_proxy },
+ { "http_proxy", IPKG_OPT_TYPE_STRING, &conf->http_proxy },
+ { "multiple_providers", IPKG_OPT_TYPE_BOOL, &conf->multiple_providers },
+ { "no_proxy", IPKG_OPT_TYPE_STRING, &conf->no_proxy },
+ { "test", IPKG_OPT_TYPE_INT, &conf->noaction },
+ { "noaction", IPKG_OPT_TYPE_INT, &conf->noaction },
+ { "nodeps", IPKG_OPT_TYPE_BOOL, &conf->nodeps },
+ { "offline_root", IPKG_OPT_TYPE_STRING, &conf->offline_root },
+ { "offline_root_post_script_cmd", IPKG_OPT_TYPE_STRING, &conf->offline_root_post_script_cmd },
+ { "offline_root_pre_script_cmd", IPKG_OPT_TYPE_STRING, &conf->offline_root_pre_script_cmd },
+ { "proxy_passwd", IPKG_OPT_TYPE_STRING, &conf->proxy_passwd },
+ { "proxy_user", IPKG_OPT_TYPE_STRING, &conf->proxy_user },
+ { "query-all", IPKG_OPT_TYPE_BOOL, &conf->query_all },
+ { "verbose-wget", IPKG_OPT_TYPE_BOOL, &conf->verbose_wget },
+ { "verbosity", IPKG_OPT_TYPE_BOOL, &conf->verbosity },
+ { NULL }
+ };
+
+ *options = (ipkg_option_t *)malloc(sizeof(tmp));
+ if ( options == NULL ){
+ fprintf(stderr,"%s: Unable to allocate memory\n",__FUNCTION__);
+ return -1;
+ }
+
+ memcpy(*options, tmp, sizeof(tmp));
+ return 0;
+};
+
+static void ipkg_conf_override_string(char **conf_str, char *arg_str)
+{
+ if (arg_str) {
+ if (*conf_str) {
+ free(*conf_str);
+ }
+ *conf_str = strdup(arg_str);
+ }
+}
+
+static void ipkg_conf_free_string(char **conf_str)
+{
+ if (*conf_str) {
+ free(*conf_str);
+ *conf_str = NULL;
+ }
+}
+
+int ipkg_conf_init(ipkg_conf_t *conf, const args_t *args)
+{
+ int err;
+ char *tmp_dir_base;
+ nv_pair_list_t tmp_dest_nv_pair_list;
+ char * lists_dir =NULL;
+ glob_t globbuf;
+ char *etc_ipkg_conf_pattern = "/etc/ipkg/*.conf";
+ char *pending_dir =NULL;
+
+ memset(conf, 0, sizeof(ipkg_conf_t));
+
+ pkg_src_list_init(&conf->pkg_src_list);
+
+ nv_pair_list_init(&tmp_dest_nv_pair_list);
+ pkg_dest_list_init(&conf->pkg_dest_list);
+
+ nv_pair_list_init(&conf->arch_list);
+
+ conf->restrict_to_default_dest = 0;
+ conf->default_dest = NULL;
+
+
+ if (args->tmp_dir)
+ tmp_dir_base = args->tmp_dir;
+ else
+ tmp_dir_base = getenv("TMPDIR");
+ sprintf_alloc(&conf->tmp_dir, "%s/%s",
+ tmp_dir_base ? tmp_dir_base : IPKG_CONF_DEFAULT_TMP_DIR_BASE,
+ IPKG_CONF_TMP_DIR_SUFFIX);
+ conf->tmp_dir = mkdtemp(conf->tmp_dir);
+ if (conf->tmp_dir == NULL) {
+ fprintf(stderr, "%s: Failed to create temporary directory `%s': %s\n",
+ __FUNCTION__, conf->tmp_dir, strerror(errno));
+ return errno;
+ }
+
+ conf->force_depends = 0;
+ conf->force_defaults = 0;
+ conf->force_overwrite = 0;
+ conf->force_downgrade = 0;
+ conf->force_reinstall = 0;
+ conf->force_space = 0;
+ conf->force_removal_of_essential_packages = 0;
+ conf->force_removal_of_dependent_packages = 0;
+ conf->nodeps = 0;
+ conf->verbose_wget = 0;
+ conf->offline_root = NULL;
+ conf->offline_root_pre_script_cmd = NULL;
+ conf->offline_root_post_script_cmd = NULL;
+ conf->multiple_providers = 0;
+ conf->verbosity = 1;
+ conf->noaction = 0;
+
+ conf->http_proxy = NULL;
+ conf->ftp_proxy = NULL;
+ conf->no_proxy = NULL;
+ conf->proxy_user = NULL;
+ conf->proxy_passwd = NULL;
+
+ pkg_hash_init("pkg-hash", &conf->pkg_hash, IPKG_CONF_DEFAULT_HASH_LEN);
+ hash_table_init("file-hash", &conf->file_hash, IPKG_CONF_DEFAULT_HASH_LEN);
+ hash_table_init("obs-file-hash", &conf->obs_file_hash, IPKG_CONF_DEFAULT_HASH_LEN);
+ lists_dir=(char *)malloc(1);
+ lists_dir[0]='\0';
+ if (args->conf_file) {
+ struct stat stat_buf;
+ err = stat(args->conf_file, &stat_buf);
+ if (err == 0)
+ if (ipkg_conf_parse_file(conf, args->conf_file,
+ &conf->pkg_src_list, &tmp_dest_nv_pair_list,&lists_dir)<0) {
+ /* Memory leakage from ipkg_conf_parse-file */
+ return -1;
+ }
+
+ }
+
+ /* if (!lists_dir ){*/
+ if (strlen(lists_dir)<=1 ){
+ lists_dir = realloc(lists_dir,strlen(IPKG_CONF_LISTS_DIR)+2);
+ sprintf (lists_dir,"%s",IPKG_CONF_LISTS_DIR);
+ }
+
+ pending_dir = malloc(strlen(lists_dir)+strlen("/pending")+5);
+ snprintf(pending_dir,strlen(lists_dir)+strlen("/pending") ,"%s%s",lists_dir,"/pending");
+
+ conf->lists_dir = strdup(lists_dir);
+ conf->pending_dir = strdup(pending_dir);
+
+ if (args->offline_root)
+ sprintf_alloc(&etc_ipkg_conf_pattern, "%s/etc/ipkg/*.conf", args->offline_root);
+ memset(&globbuf, 0, sizeof(globbuf));
+ err = glob(etc_ipkg_conf_pattern, 0, NULL, &globbuf);
+ if (!err) {
+ int i;
+ for (i = 0; i < globbuf.gl_pathc; i++) {
+ if (globbuf.gl_pathv[i])
+ if ( ipkg_conf_parse_file(conf, globbuf.gl_pathv[i],
+ &conf->pkg_src_list, &tmp_dest_nv_pair_list,&lists_dir)<0) {
+ /* Memory leakage from ipkg_conf_parse-file */
+ return -1;
+ }
+ }
+ }
+ globfree(&globbuf);
+
+ /* if no architectures were defined, then default all, noarch, and host architecture */
+ if (nv_pair_list_empty(&conf->arch_list)) {
+ nv_pair_list_append(&conf->arch_list, "all", "1");
+ nv_pair_list_append(&conf->arch_list, "noarch", "1");
+ nv_pair_list_append(&conf->arch_list, HOST_CPU_STR, "10");
+ }
+
+ /* Even if there is no conf file, we'll need at least one dest. */
+ if (tmp_dest_nv_pair_list.head == NULL) {
+ nv_pair_list_append(&tmp_dest_nv_pair_list,
+ IPKG_CONF_DEFAULT_DEST_NAME,
+ IPKG_CONF_DEFAULT_DEST_ROOT_DIR);
+ }
+
+ /* After parsing the file, set options from command-line, (so that
+ command-line arguments take precedence) */
+ /* XXX: CLEANUP: The interaction between args.c and ipkg_conf.c
+ really needs to be cleaned up. There is so much duplication
+ right now it is ridiculous. Maybe ipkg_conf_t should just save
+ a pointer to args_t (which could then not be freed), rather
+ than duplicating every field here? */
+ if (args->force_depends) {
+ conf->force_depends = 1;
+ }
+ if (args->force_defaults) {
+ conf->force_defaults = 1;
+ }
+ if (args->force_overwrite) {
+ conf->force_overwrite = 1;
+ }
+ if (args->force_downgrade) {
+ conf->force_downgrade = 1;
+ }
+ if (args->force_reinstall) {
+ conf->force_reinstall = 1;
+ }
+ if (args->force_removal_of_dependent_packages) {
+ conf->force_removal_of_dependent_packages = 1;
+ }
+ if (args->force_removal_of_essential_packages) {
+ conf->force_removal_of_essential_packages = 1;
+ }
+ if (args->nodeps) {
+ conf->nodeps = 1;
+ }
+ if (args->noaction) {
+ conf->noaction = 1;
+ }
+ if (args->query_all) {
+ conf->query_all = 1;
+ }
+ if (args->verbose_wget) {
+ conf->verbose_wget = 1;
+ }
+ if (args->multiple_providers) {
+ conf->multiple_providers = 1;
+ }
+ if (args->verbosity != conf->verbosity) {
+ conf->verbosity = args->verbosity;
+ }
+
+ ipkg_conf_override_string(&conf->offline_root,
+ args->offline_root);
+ ipkg_conf_override_string(&conf->offline_root_pre_script_cmd,
+ args->offline_root_pre_script_cmd);
+ ipkg_conf_override_string(&conf->offline_root_post_script_cmd,
+ args->offline_root_post_script_cmd);
+
+/* Pigi: added a flag to disable the checking of structures if the command does not need to
+ read anything from there.
+*/
+ if ( !(args->nocheckfordirorfile)){
+ /* need to run load the source list before dest list -Jamey */
+ set_and_load_pkg_src_list(conf, &conf->pkg_src_list);
+
+ /* Now that we have resolved conf->offline_root, we can commit to
+ the directory names for the dests and load in all the package
+ lists. */
+ set_and_load_pkg_dest_list(conf, &tmp_dest_nv_pair_list,lists_dir);
+
+ if (args->dest) {
+ err = ipkg_conf_set_default_dest(conf, args->dest);
+ if (err) {
+ return err;
+ }
+ }
+ }
+ nv_pair_list_deinit(&tmp_dest_nv_pair_list);
+ free(lists_dir);
+ free(pending_dir);
+
+ return 0;
+}
+
+void ipkg_conf_deinit(ipkg_conf_t *conf)
+{
+#ifdef IPKG_DEBUG_NO_TMP_CLEANUP
+#error
+ fprintf(stderr, "%s: Not cleaning up %s since ipkg compiled "
+ "with IPKG_DEBUG_NO_TMP_CLEANUP\n",
+ __FUNCTION__, conf->tmp_dir);
+#else
+ int err;
+
+ err = rmdir(conf->tmp_dir);
+ if (err) {
+ if (errno == ENOTEMPTY) {
+ char *cmd;
+ sprintf_alloc(&cmd, "rm -fr %s\n", conf->tmp_dir);
+ err = xsystem(cmd);
+ free(cmd);
+ }
+ if (err)
+ fprintf(stderr, "WARNING: Unable to remove temporary directory: %s: %s\n", conf->tmp_dir, strerror(errno));
+ }
+#endif /* IPKG_DEBUG_NO_TMP_CLEANUP */
+
+ free(conf->tmp_dir); /*XXX*/
+
+ pkg_src_list_deinit(&conf->pkg_src_list);
+ pkg_dest_list_deinit(&conf->pkg_dest_list);
+ nv_pair_list_deinit(&conf->arch_list);
+ if (&conf->pkg_hash)
+ pkg_hash_deinit(&conf->pkg_hash);
+ if (&conf->file_hash)
+ hash_table_deinit(&conf->file_hash);
+ if (&conf->obs_file_hash)
+ hash_table_deinit(&conf->obs_file_hash);
+
+ ipkg_conf_free_string(&conf->offline_root);
+ ipkg_conf_free_string(&conf->offline_root_pre_script_cmd);
+ ipkg_conf_free_string(&conf->offline_root_post_script_cmd);
+
+ if (conf->verbosity > 1) {
+ int i;
+ hash_table_t *hashes[] = {
+ &conf->pkg_hash,
+ &conf->file_hash,
+ &conf->obs_file_hash };
+ for (i = 0; i < 3; i++) {
+ hash_table_t *hash = hashes[i];
+ int c = 0;
+ int n_conflicts = 0;
+ int j;
+ for (j = 0; j < hash->n_entries; j++) {
+ int len = 0;
+ hash_entry_t *e = &hash->entries[j];
+ if (e->next)
+ n_conflicts++;
+ while (e && e->key) {
+ len++;
+ e = e->next;
+ }
+ if (len > c)
+ c = len;
+ }
+ ipkg_message(conf, IPKG_DEBUG, "hash_table[%s] n_buckets=%d n_elements=%d max_conflicts=%d n_conflicts=%d\n",
+ hash->name, hash->n_entries, hash->n_elements, c, n_conflicts);
+ hash_table_deinit(hash);
+ }
+ }
+}
+
+static int ipkg_conf_set_default_dest(ipkg_conf_t *conf,
+ const char *default_dest_name)
+{
+ pkg_dest_list_elt_t *iter;
+ pkg_dest_t *dest;
+
+ for (iter = conf->pkg_dest_list.head; iter; iter = iter->next) {
+ dest = iter->data;
+ if (strcmp(dest->name, default_dest_name) == 0) {
+ conf->default_dest = dest;
+ conf->restrict_to_default_dest = 1;
+ return 0;
+ }
+ }
+
+ fprintf(stderr, "ERROR: Unknown dest name: `%s'\n", default_dest_name);
+
+ return 1;
+}
+
+static int set_and_load_pkg_src_list(ipkg_conf_t *conf, pkg_src_list_t *pkg_src_list)
+{
+ pkg_src_list_elt_t *iter;
+ pkg_src_t *src;
+ char *list_file;
+
+ for (iter = pkg_src_list->head; iter; iter = iter->next) {
+ src = iter->data;
+ if (src == NULL) {
+ continue;
+ }
+ if (conf->offline_root) {
+ sprintf_alloc(&list_file, "%s/%s/%s",
+ conf->offline_root,
+ conf->restrict_to_default_dest ? conf->default_dest->lists_dir : conf->lists_dir,
+ src->name);
+ } else {
+ sprintf_alloc(&list_file, "%s/%s",
+ conf->restrict_to_default_dest ? conf->default_dest->lists_dir : conf->lists_dir,
+ src->name);
+ }
+
+ if (file_exists(list_file)) {
+ pkg_hash_add_from_file(conf, list_file, src, NULL, 0);
+ }
+ free(list_file);
+ }
+
+ return 0;
+}
+
+static int set_and_load_pkg_dest_list(ipkg_conf_t *conf, nv_pair_list_t *nv_pair_list, char *lists_dir )
+{
+ nv_pair_list_elt_t *iter;
+ nv_pair_t *nv_pair;
+ pkg_dest_t *dest;
+ char *root_dir;
+
+ for (iter = nv_pair_list->head; iter; iter = iter->next) {
+ nv_pair = iter->data;
+
+ if (conf->offline_root) {
+ sprintf_alloc(&root_dir, "%s%s", conf->offline_root, nv_pair->value);
+ } else {
+ root_dir = strdup(nv_pair->value);
+ }
+ dest = pkg_dest_list_append(&conf->pkg_dest_list, nv_pair->name, root_dir, lists_dir);
+ free(root_dir);
+ if (dest == NULL) {
+ continue;
+ }
+ if (conf->default_dest == NULL) {
+ conf->default_dest = dest;
+ }
+ if (file_exists(dest->status_file_name)) {
+ pkg_hash_add_from_file(conf, dest->status_file_name,
+ NULL, dest, 1);
+ }
+ }
+
+ return 0;
+}
+
+static int ipkg_conf_parse_file(ipkg_conf_t *conf, const char *filename,
+ pkg_src_list_t *pkg_src_list,
+ nv_pair_list_t *tmp_dest_nv_pair_list,
+ char **lists_dir)
+{
+ ipkg_option_t * options;
+ FILE *file = fopen(filename, "r");
+ regex_t valid_line_re, comment_re;
+#define regmatch_size 12
+ regmatch_t regmatch[regmatch_size];
+
+ if (ipkg_init_options_array(conf, &options)<0)
+ return ENOMEM;
+
+ if (file == NULL) {
+ fprintf(stderr, "%s: failed to open %s: %s\n",
+ __FUNCTION__, filename, strerror(errno));
+ free(options);
+ return errno;
+ }
+ ipkg_message(conf, IPKG_NOTICE, "loading conf file %s\n", filename);
+
+ xregcomp(&comment_re,
+ "^[[:space:]]*(#.*|[[:space:]]*)$",
+ REG_EXTENDED);
+ xregcomp(&valid_line_re, "^[[:space:]]*(\"([^\"]*)\"|([^[:space:]]*))[[:space:]]*(\"([^\"]*)\"|([^[:space:]]*))[[:space:]]*(\"([^\"]*)\"|([^[:space:]]*))([[:space:]]+([^[:space:]]+))?[[:space:]]*$", REG_EXTENDED);
+
+ while(1) {
+ int line_num = 0;
+ char *line;
+ char *type, *name, *value, *extra;
+
+ line = file_read_line_alloc(file);
+ line_num++;
+ if (line == NULL) {
+ break;
+ }
+
+ str_chomp(line);
+
+ if (regexec(&comment_re, line, 0, 0, 0) == 0) {
+ goto NEXT_LINE;
+ }
+
+ if (regexec(&valid_line_re, line, regmatch_size, regmatch, 0) == REG_NOMATCH) {
+ str_chomp(line);
+ fprintf(stderr, "%s:%d: Ignoring invalid line: `%s'\n",
+ filename, line_num, line);
+ goto NEXT_LINE;
+ }
+
+ /* This has to be so ugly to deal with optional quotation marks */
+ if (regmatch[2].rm_so > 0) {
+ type = strndup(line + regmatch[2].rm_so,
+ regmatch[2].rm_eo - regmatch[2].rm_so);
+ } else {
+ type = strndup(line + regmatch[3].rm_so,
+ regmatch[3].rm_eo - regmatch[3].rm_so);
+ }
+ if (regmatch[5].rm_so > 0) {
+ name = strndup(line + regmatch[5].rm_so,
+ regmatch[5].rm_eo - regmatch[5].rm_so);
+ } else {
+ name = strndup(line + regmatch[6].rm_so,
+ regmatch[6].rm_eo - regmatch[6].rm_so);
+ }
+ if (regmatch[8].rm_so > 0) {
+ value = strndup(line + regmatch[8].rm_so,
+ regmatch[8].rm_eo - regmatch[8].rm_so);
+ } else {
+ value = strndup(line + regmatch[9].rm_so,
+ regmatch[9].rm_eo - regmatch[9].rm_so);
+ }
+ extra = NULL;
+ if (regmatch[11].rm_so > 0) {
+ extra = strndup (line + regmatch[11].rm_so,
+ regmatch[11].rm_eo - regmatch[11].rm_so);
+ }
+
+ /* We use the tmp_dest_nv_pair_list below instead of
+ conf->pkg_dest_list because we might encounter an
+ offline_root option later and that would invalidate the
+ directories we would have computed in
+ pkg_dest_list_init. (We do a similar thing with
+ tmp_src_nv_pair_list for sake of symmetry.) */
+ if (strcmp(type, "option") == 0) {
+ ipkg_conf_set_option(options, name, value);
+ } else if (strcmp(type, "src") == 0) {
+ if (!nv_pair_list_find(pkg_src_list, name)) {
+ pkg_src_list_append (pkg_src_list, name, value, extra, 0);
+ } else {
+ ipkg_message(conf, IPKG_ERROR, "ERROR: duplicate src declaration. Skipping:\n\t src %s %s\n",
+ name, value);
+ }
+ } else if (strcmp(type, "src/gz") == 0) {
+ if (!nv_pair_list_find(pkg_src_list, name)) {
+ pkg_src_list_append (pkg_src_list, name, value, extra, 1);
+ } else {
+ ipkg_message(conf, IPKG_ERROR, "ERROR: duplicate src declaration. Skipping:\n\t src %s %s\n",
+ name, value);
+ }
+ } else if (strcmp(type, "dest") == 0) {
+ nv_pair_list_append(tmp_dest_nv_pair_list, name, value);
+ } else if (strcmp(type, "lists_dir") == 0) {
+ *lists_dir = realloc(*lists_dir,strlen(value)+1);
+ if (*lists_dir == NULL) {
+ ipkg_message(conf, IPKG_ERROR, "ERROR: Not enough memory\n");
+ free(options);
+ return EINVAL;
+ }
+ sprintf (*lists_dir,"%s",value);
+ } else if (strcmp(type, "arch") == 0) {
+ ipkg_message(conf, IPKG_INFO, "supported arch %s priority (%s)\n", name, value);
+ if (!value) {
+ ipkg_message(conf, IPKG_NOTICE, "defaulting architecture %s priority to 10\n", name);
+ value = strdup("10");
+ }
+ nv_pair_list_append(&conf->arch_list, strdup(name), strdup(value));
+ } else {
+ fprintf(stderr, "WARNING: Ignoring unknown configuration "
+ "parameter: %s %s %s\n", type, name, value);
+ free(options);
+ return EINVAL;
+ }
+
+ free(type);
+ free(name);
+ free(value);
+ if (extra)
+ free (extra);
+
+ NEXT_LINE:
+ free(line);
+ }
+
+ free(options);
+ regfree(&comment_re);
+ regfree(&valid_line_re);
+ fclose(file);
+
+ return 0;
+}
+
+static int ipkg_conf_set_option(const ipkg_option_t *options,
+ const char *name, const char *value)
+{
+ int i = 0;
+ while (options[i].name) {
+ if (strcmp(options[i].name, name) == 0) {
+ switch (options[i].type) {
+ case IPKG_OPT_TYPE_BOOL:
+ *((int *)options[i].value) = 1;
+ return 0;
+ case IPKG_OPT_TYPE_INT:
+ if (value) {
+ *((int *)options[i].value) = atoi(value);
+ return 0;
+ } else {
+ printf("%s: Option %s need an argument\n",
+ __FUNCTION__, name);
+ return EINVAL;
+ }
+ case IPKG_OPT_TYPE_STRING:
+ if (value) {
+ *((char **)options[i].value) = strdup(value);
+ return 0;
+ } else {
+ printf("%s: Option %s need an argument\n",
+ __FUNCTION__, name);
+ return EINVAL;
+ }
+ }
+ }
+ i++;
+ }
+
+ fprintf(stderr, "%s: Unrecognized option: %s=%s\n",
+ __FUNCTION__, name, value);
+ return EINVAL;
+}
+
+int ipkg_conf_write_status_files(ipkg_conf_t *conf)
+{
+ pkg_dest_list_elt_t *iter;
+ pkg_dest_t *dest;
+ pkg_vec_t *all;
+ pkg_t *pkg;
+ register int i;
+ int err;
+
+ if (conf->noaction)
+ return 0;
+ for (iter = conf->pkg_dest_list.head; iter; iter = iter->next) {
+ dest = iter->data;
+ dest->status_file = fopen(dest->status_file_tmp_name, "w");
+ if (dest->status_file == NULL) {
+ fprintf(stderr, "%s: Can't open status file: %s for writing: %s\n",
+ __FUNCTION__, dest->status_file_name, strerror(errno));
+ }
+ }
+
+ all = pkg_vec_alloc();
+ pkg_hash_fetch_available(&conf->pkg_hash, all);
+
+ for(i = 0; i < all->len; i++) {
+ pkg = all->pkgs[i];
+ /* We don't need most uninstalled packages in the status file */
+ if (pkg->state_status == SS_NOT_INSTALLED
+ && (pkg->state_want == SW_UNKNOWN
+ || pkg->state_want == SW_DEINSTALL
+ || pkg->state_want == SW_PURGE)) {
+ continue;
+ }
+ if (!pkg) {
+ fprintf(stderr, "Null package\n");
+ }
+ if (pkg->dest == NULL) {
+ fprintf(stderr, "%s: ERROR: Can't write status for "
+ "package %s since it has a NULL dest\n",
+ __FUNCTION__, pkg->name);
+ continue;
+ }
+ if (pkg->dest->status_file) {
+ pkg_print_status(pkg, pkg->dest->status_file);
+ }
+ }
+
+ pkg_vec_free(all);
+
+ for (iter = conf->pkg_dest_list.head; iter; iter = iter->next) {
+ dest = iter->data;
+ if (dest->status_file) {
+ err = ferror(dest->status_file);
+ fclose(dest->status_file);
+ dest->status_file = NULL;
+ if (!err) {
+ file_move(dest->status_file_tmp_name, dest->status_file_name);
+ } else {
+ fprintf(stderr, "%s: ERROR: An error has occurred writing %s, "
+ "retaining old %s\n", __FUNCTION__,
+ dest->status_file_tmp_name, dest->status_file_name);
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+char *root_filename_alloc(ipkg_conf_t *conf, char *filename)
+{
+ char *root_filename;
+ sprintf_alloc(&root_filename, "%s%s", (conf->offline_root ? conf->offline_root : ""), filename);
+ return root_filename;
+}
diff -ruN busybox-1.00-orig/archival/libipkg/ipkg_conf.h busybox-1.00+ipkg-0.99.154/archival/libipkg/ipkg_conf.h
--- busybox-1.00-orig/archival/libipkg/ipkg_conf.h 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/ipkg_conf.h 2005-10-26 17:36:46.000000000 +0200
@@ -0,0 +1,107 @@
+/* ipkg_conf.h - the itsy package management system
+
+ Carl D. Worth
+
+ Copyright (C) 2001 University of Southern California
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#ifndef IPKG_CONF_H
+#define IPKG_CONF_H
+
+typedef struct ipkg_conf ipkg_conf_t;
+
+#include "hash_table.h"
+#include "ipkg.h"
+#include "args.h"
+#include "pkg.h"
+#include "pkg_hash.h"
+#include "pkg_src_list.h"
+#include "pkg_dest_list.h"
+#include "nv_pair_list.h"
+
+#define IPKG_CONF_DEFAULT_TMP_DIR_BASE "/tmp"
+#define IPKG_CONF_TMP_DIR_SUFFIX "ipkg-XXXXXX"
+#define IPKG_CONF_LISTS_DIR IPKG_STATE_DIR_PREFIX "/lists"
+#define IPKG_CONF_PENDING_DIR IPKG_STATE_DIR_PREFIX "/pending"
+
+/* In case the config file defines no dest */
+#define IPKG_CONF_DEFAULT_DEST_NAME "root"
+#define IPKG_CONF_DEFAULT_DEST_ROOT_DIR "/"
+
+#define IPKG_CONF_DEFAULT_HASH_LEN 1024
+
+struct ipkg_conf
+{
+ pkg_src_list_t pkg_src_list;
+ pkg_dest_list_t pkg_dest_list;
+ nv_pair_list_t arch_list;
+
+ int restrict_to_default_dest;
+ pkg_dest_t *default_dest;
+
+ char *tmp_dir;
+ const char *lists_dir;
+ const char *pending_dir;
+
+ /* options */
+ int force_depends;
+ int force_defaults;
+ int force_overwrite;
+ int force_downgrade;
+ int force_reinstall;
+ int force_space;
+ int force_removal_of_dependent_packages;
+ int force_removal_of_essential_packages;
+ int nodeps; /* do not follow dependences */
+ int verbose_wget;
+ int multiple_providers;
+ char *offline_root;
+ char *offline_root_pre_script_cmd;
+ char *offline_root_post_script_cmd;
+ int query_all;
+ int verbosity;
+ int noaction;
+
+ /* proxy options */
+ char *http_proxy;
+ char *ftp_proxy;
+ char *no_proxy;
+ char *proxy_user;
+ char *proxy_passwd;
+
+ hash_table_t pkg_hash;
+ hash_table_t file_hash;
+ hash_table_t obs_file_hash;
+};
+
+enum ipkg_option_type {
+ IPKG_OPT_TYPE_BOOL,
+ IPKG_OPT_TYPE_INT,
+ IPKG_OPT_TYPE_STRING
+};
+typedef enum ipkg_option_type ipkg_option_type_t;
+
+typedef struct ipkg_option ipkg_option_t;
+struct ipkg_option {
+ const char *name;
+ const ipkg_option_type_t type;
+ const void *value;
+};
+
+int ipkg_conf_init(ipkg_conf_t *conf, const args_t *args);
+void ipkg_conf_deinit(ipkg_conf_t *conf);
+
+int ipkg_conf_write_status_files(ipkg_conf_t *conf);
+char *root_filename_alloc(ipkg_conf_t *conf, char *filename);
+
+#endif
diff -ruN busybox-1.00-orig/archival/libipkg/ipkg_configure.c busybox-1.00+ipkg-0.99.154/archival/libipkg/ipkg_configure.c
--- busybox-1.00-orig/archival/libipkg/ipkg_configure.c 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/ipkg_configure.c 2005-10-26 17:36:46.000000000 +0200
@@ -0,0 +1,40 @@
+/* ipkg_configure.c - the itsy package management system
+
+ Carl D. Worth
+
+ Copyright (C) 2001 University of Southern California
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#include "ipkg.h"
+
+#include "ipkg_configure.h"
+
+int ipkg_configure(ipkg_conf_t *conf, pkg_t *pkg)
+{
+ int err;
+
+ /* DPKG_INCOMPATIBILITY:
+ dpkg actually does some conffile handling here, rather than at the
+ end of ipkg_install(). Do we care? */
+ /* DPKG_INCOMPATIBILITY:
+ dpkg actually includes a version number to this script call */
+ err = pkg_run_script(conf, pkg, "postinst", "configure");
+ if (err) {
+ printf("ERROR: %s.postinst returned %d\n", pkg->name, err);
+ return err;
+ }
+
+ ipkg_state_changed++;
+ return 0;
+}
+
diff -ruN busybox-1.00-orig/archival/libipkg/ipkg_configure.h busybox-1.00+ipkg-0.99.154/archival/libipkg/ipkg_configure.h
--- busybox-1.00-orig/archival/libipkg/ipkg_configure.h 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/ipkg_configure.h 2005-10-26 17:36:46.000000000 +0200
@@ -0,0 +1,25 @@
+/* ipkg_configure.h - the itsy package management system
+
+ Carl D. Worth
+
+ Copyright (C) 2001 University of Southern California
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#ifndef IPKG_CONFIGURE_H
+#define IPKG_CONFIGURE_H
+
+#include "ipkg_conf.h"
+
+int ipkg_configure(ipkg_conf_t *ipkg_conf, pkg_t *pkg);
+
+#endif
diff -ruN busybox-1.00-orig/archival/libipkg/ipkg_download.c busybox-1.00+ipkg-0.99.154/archival/libipkg/ipkg_download.c
--- busybox-1.00-orig/archival/libipkg/ipkg_download.c 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/ipkg_download.c 2005-10-26 17:36:46.000000000 +0200
@@ -0,0 +1,191 @@
+/* ipkg_download.c - the itsy package management system
+
+ Carl D. Worth
+
+ Copyright (C) 2001 University of Southern California
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#include "ipkg.h"
+#include "ipkg_download.h"
+#include "ipkg_message.h"
+
+#include "sprintf_alloc.h"
+#include "xsystem.h"
+#include "file_util.h"
+#include "str_util.h"
+
+int ipkg_download(ipkg_conf_t *conf, const char *src, const char *dest_file_name)
+{
+ int err = 0;
+
+ char *src_basec = strdup(src);
+ char *src_base = basename(src_basec);
+ char *tmp_file_location;
+ char *cmd;
+
+ ipkg_message(conf,IPKG_NOTICE,"Downloading %s\n", src);
+
+ fflush(stdout);
+
+ if (str_starts_with(src, "file:")) {
+ int ret;
+ const char *file_src = src + 5;
+ ipkg_message(conf,IPKG_INFO,"Copying %s to %s...", file_src, dest_file_name);
+ ret = file_copy(src + 5, dest_file_name);
+ ipkg_message(conf,IPKG_INFO,"Done.\n");
+ return ret;
+ }
+
+ sprintf_alloc(&tmp_file_location, "%s/%s", conf->tmp_dir, src_base);
+ err = unlink(tmp_file_location);
+ if (err && errno != ENOENT) {
+ ipkg_message(conf,IPKG_ERROR, "%s: ERROR: failed to unlink %s: %s\n",
+ __FUNCTION__, tmp_file_location, strerror(errno));
+ free(tmp_file_location);
+ return errno;
+ }
+
+ if (conf->http_proxy) {
+ ipkg_message(conf,IPKG_DEBUG,"Setting environment variable: http_proxy = %s\n", conf->http_proxy);
+ setenv("http_proxy", conf->http_proxy, 1);
+ }
+ if (conf->ftp_proxy) {
+ ipkg_message(conf,IPKG_DEBUG,"Setting environment variable: ftp_proxy = %s\n", conf->ftp_proxy);
+ setenv("ftp_proxy", conf->ftp_proxy, 1);
+ }
+ if (conf->no_proxy) {
+ ipkg_message(conf,IPKG_DEBUG,"Setting environment variable: no_proxy = %s\n", conf->no_proxy);
+ setenv("no_proxy", conf->no_proxy, 1);
+ }
+
+ /* XXX: BUG rewrite to use execvp or else busybox's internal wget -Jamey 7/23/2002 */
+ sprintf_alloc(&cmd, "wget --passive-ftp %s %s%s %s%s %s -P %s %s",
+ (conf->http_proxy || conf->ftp_proxy) ? "--proxy=on" : "",
+ conf->proxy_user ? "--proxy-user=" : "",
+ conf->proxy_user ? conf->proxy_user : "",
+ conf->proxy_passwd ? "--proxy-passwd=" : "",
+ conf->proxy_passwd ? conf->proxy_passwd : "",
+ conf->verbose_wget ? "" : "-q",
+ conf->tmp_dir,
+ src);
+ err = xsystem(cmd);
+ if (err) {
+ if (err != -1) {
+ ipkg_message(conf,IPKG_ERROR, "%s: ERROR: Command failed with return value %d: `%s'\n",
+ __FUNCTION__, err, cmd);
+ }
+ unlink(tmp_file_location);
+ free(tmp_file_location);
+ free(src_basec);
+ free(cmd);
+ return EINVAL;
+ }
+ free(cmd);
+
+ err = file_move(tmp_file_location, dest_file_name);
+
+ free(tmp_file_location);
+ free(src_basec);
+
+ if (err) {
+ return err;
+ }
+
+ return 0;
+}
+
+int ipkg_download_pkg(ipkg_conf_t *conf, pkg_t *pkg, const char *dir)
+{
+ int err;
+ char *url;
+
+ if (pkg->src == NULL) {
+ ipkg_message(conf,IPKG_ERROR, "ERROR: Package %s (parent %s) is not available from any configured src.\n",
+ pkg->name, pkg->parent->name);
+ return -1;
+ }
+
+ sprintf_alloc(&url, "%s/%s", pkg->src->value, pkg->filename);
+
+ /* XXX: BUG: The pkg->filename might be something like
+ "../../foo.ipk". While this is correct, and exactly what we
+ want to use to construct url above, here we actually need to
+ use just the filename part, without any directory. */
+ sprintf_alloc(&pkg->local_filename, "%s/%s", dir, pkg->filename);
+
+ err = ipkg_download(conf, url, pkg->local_filename);
+ free(url);
+
+ return err;
+}
+
+/*
+ * Downloads file from url, installs in package database, return package name.
+ */
+int ipkg_prepare_url_for_install(ipkg_conf_t *conf, const char *url, char **namep)
+{
+ int err = 0;
+ pkg_t *pkg;
+ pkg = pkg_new();
+ if (pkg == NULL)
+ return ENOMEM;
+
+ if (str_starts_with(url, "http://")
+ || str_starts_with(url, "ftp://")) {
+ char *tmp_file;
+ char *file_basec = strdup(url);
+ char *file_base = basename(file_basec);
+
+ sprintf_alloc(&tmp_file, "%s/%s", conf->tmp_dir, file_base);
+ err = ipkg_download(conf, url, tmp_file);
+ if (err)
+ return err;
+
+ err = pkg_init_from_file(pkg, tmp_file);
+ if (err)
+ return err;
+ pkg->local_filename = strdup(tmp_file);
+
+ free(tmp_file);
+ free(file_basec);
+
+ } else if (strcmp(&url[strlen(url) - 4], IPKG_PKG_EXTENSION) == 0
+ || strcmp(&url[strlen(url) - 4], DPKG_PKG_EXTENSION) == 0) {
+
+ err = pkg_init_from_file(pkg, url);
+ if (err)
+ return err;
+ pkg->local_filename = strdup(url);
+
+ } else {
+ return 0;
+ }
+
+ if (!pkg->architecture) {
+ ipkg_message(conf, IPKG_ERROR, "Package %s has no Architecture defined.\n", pkg->name);
+ return -EINVAL;
+ }
+
+ pkg->dest = conf->default_dest;
+ pkg->state_want = SW_INSTALL;
+ pkg->state_flag |= SF_PREFER;
+ pkg = hash_insert_pkg(&conf->pkg_hash, pkg, 1,conf);
+ if ( pkg == NULL ){
+ fprintf(stderr, "%s : This should never happen. Report this Bug in bugzilla please \n ",__FUNCTION__);
+ return 0;
+ }
+ if (namep) {
+ *namep = pkg->name;
+ }
+ return 0;
+}
diff -ruN busybox-1.00-orig/archival/libipkg/ipkg_download.h busybox-1.00+ipkg-0.99.154/archival/libipkg/ipkg_download.h
--- busybox-1.00-orig/archival/libipkg/ipkg_download.h 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/ipkg_download.h 2005-10-26 17:36:46.000000000 +0200
@@ -0,0 +1,30 @@
+/* ipkg_download.h - the itsy package management system
+
+ Carl D. Worth
+
+ Copyright (C) 2001 University of Southern California
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#ifndef IPKG_DOWNLOAD_H
+#define IPKG_DOWNLOAD_H
+
+#include "ipkg_conf.h"
+
+int ipkg_download(ipkg_conf_t *conf, const char *src, const char *dest_file_name);
+int ipkg_download_pkg(ipkg_conf_t *conf, pkg_t *pkg, const char *dir);
+/*
+ * Downloads file from url, installs in package database, return package name.
+ */
+int ipkg_prepare_url_for_install(ipkg_conf_t *conf, const char *url, char **namep);
+
+#endif
diff -ruN busybox-1.00-orig/archival/libipkg/ipkg_includes.h busybox-1.00+ipkg-0.99.154/archival/libipkg/ipkg_includes.h
--- busybox-1.00-orig/archival/libipkg/ipkg_includes.h 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/ipkg_includes.h 2005-10-26 17:36:46.000000000 +0200
@@ -0,0 +1,79 @@
+#ifndef IPKG_INCLUDES_H
+#define IPKG_INCLUDES_H
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the <regex.h> header file. */
+#define HAVE_REGEX_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
+#define HAVE_SYS_WAIT_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+
+#include <stdio.h>
+
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stdarg.h>
+# include <stddef.h>
+# include <ctype.h>
+# include <errno.h>
+#else
+# if HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+
+#if HAVE_REGEX_H
+# include <regex.h>
+#endif
+
+#if HAVE_STRING_H
+# if !STDC_HEADERS && HAVE_MEMORY_H
+# include <memory.h>
+# endif
+/* XXX: What's the right way to pick up GNU's strndup declaration? */
+# if __GNUC__
+# define __USE_GNU 1
+# endif
+# include <string.h>
+# undef __USE_GNU
+#endif
+
+#if HAVE_STRINGS_H
+# include <strings.h>
+#endif
+
+#if HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+
+#if HAVE_SYS_WAIT_H
+# include <sys/wait.h>
+#endif
+
+#if HAVE_UNISTD_H
+# include <sys/types.h>
+# include <unistd.h>
+#endif
+
+#endif /* IPKG_INCLUDES_H */
diff -ruN busybox-1.00-orig/archival/libipkg/ipkg_install.c busybox-1.00+ipkg-0.99.154/archival/libipkg/ipkg_install.c
--- busybox-1.00-orig/archival/libipkg/ipkg_install.c 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/ipkg_install.c 2005-10-26 17:36:46.000000000 +0200
@@ -0,0 +1,1823 @@
+/* ipkg_install.c - the itsy package management system
+
+ Carl D. Worth
+
+ Copyright (C) 2001 University of Southern California
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#include "ipkg.h"
+#include <errno.h>
+#include <dirent.h>
+#include <glob.h>
+#include <time.h>
+#include <signal.h>
+typedef void (*sighandler_t)(int);
+
+#include "pkg.h"
+#include "pkg_hash.h"
+#include "pkg_extract.h"
+
+#include "ipkg_install.h"
+#include "ipkg_configure.h"
+#include "ipkg_download.h"
+#include "ipkg_remove.h"
+
+#include "ipkg_utils.h"
+#include "ipkg_message.h"
+
+#include "sprintf_alloc.h"
+#include "file_util.h"
+#include "str_util.h"
+#include "xsystem.h"
+#include "user.h"
+
+int satisfy_dependencies_for(ipkg_conf_t *conf, pkg_t *pkg);
+static int verify_pkg_installable(ipkg_conf_t *conf, pkg_t *pkg);
+static int unpack_pkg_control_files(ipkg_conf_t *conf, pkg_t *pkg);
+
+static int prerm_upgrade_old_pkg(ipkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg);
+static int prerm_upgrade_old_pkg_unwind(ipkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg);
+static int prerm_deconfigure_conflictors(ipkg_conf_t *conf, pkg_t *pkg, pkg_vec_t *conflictors);
+static int prerm_deconfigure_conflictors_unwind(ipkg_conf_t *conf, pkg_t *pkg, pkg_vec_t *conflictors);
+static int preinst_configure(ipkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg);
+static int preinst_configure_unwind(ipkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg);
+static int check_data_file_clashes(ipkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg);
+static int check_data_file_clashes_unwind(ipkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg);
+static int backup_modified_conffiles(ipkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg);
+static int backup_modified_conffiles_unwind(ipkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg);
+static int postrm_upgrade_old_pkg(ipkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg);
+static int postrm_upgrade_old_pkg_unwind(ipkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg);
+
+static int remove_obsolesced_files(ipkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg);
+static int install_maintainer_scripts(ipkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg);
+static int remove_disappeared(ipkg_conf_t *conf, pkg_t *pkg);
+static int install_data_files(ipkg_conf_t *conf, pkg_t *pkg);
+static int resolve_conffiles(ipkg_conf_t *conf, pkg_t *pkg);
+
+static int cleanup_temporary_files(ipkg_conf_t *conf, pkg_t *pkg);
+
+static int user_prefers_old_conffile(const char *file, const char *backup);
+
+static char *backup_filename_alloc(const char *file_name);
+static int backup_make_backup(ipkg_conf_t *conf, const char *file_name);
+static int backup_exists_for(const char *file_name);
+static int backup_remove(const char *file_name);
+
+
+int ipkg_install_from_file(ipkg_conf_t *conf, const char *filename)
+{
+ int err, cmp;
+ pkg_t *pkg, *old;
+ char *old_version, *new_version;
+
+ pkg = pkg_new();
+ if (pkg == NULL) {
+ return ENOMEM;
+ }
+
+ err = pkg_init_from_file(pkg, filename);
+ if (err) {
+ return err;
+ }
+
+ if (!pkg->architecture) {
+ ipkg_message(conf, IPKG_ERROR, "Package %s has no Architecture defined.\n", pkg->name);
+ return -EINVAL;
+ }
+
+ /* XXX: CLEANUP: hash_insert_pkg has a nasty side effect of possibly
+ freeing the pkg that we pass in. It might be nice to clean this up
+ if possible. */
+ pkg = hash_insert_pkg(&conf->pkg_hash, pkg, 1,conf);
+ old = pkg_hash_fetch_installed_by_name(&conf->pkg_hash, pkg->name);
+
+ pkg->local_filename = strdup(filename);
+
+ if (old) {
+ old_version = pkg_version_str_alloc(old);
+ new_version = pkg_version_str_alloc(pkg);
+
+ cmp = pkg_compare_versions(old, pkg);
+ if ( (conf->force_downgrade==1) && (cmp > 0) ){ /* We've been asked to allow downgrade and version is precedent */
+ cmp = -1 ; /* then we force ipkg to downgrade */
+ /* We need to use a value < 0 because in the 0 case we are asking to */
+ /* reinstall, and some check could fail asking the "force-reinstall" option */
+ }
+ if (cmp > 0) {
+ ipkg_message(conf, IPKG_NOTICE,
+ "Not downgrading package %s on %s from %s to %s.\n",
+ old->name, old->dest->name, old_version, new_version);
+ pkg->state_want = SW_DEINSTALL;
+ pkg->state_flag |= SF_OBSOLETE;
+ free(old_version);
+ free(new_version);
+ return 0;
+ } else {
+ free(old_version);
+ free(new_version);
+ }
+ }
+
+ ipkg_message(conf, IPKG_DEBUG2,"Function: %s calling ipkg_install_pkg \n",__FUNCTION__);
+ return ipkg_install_pkg(conf, pkg);
+}
+
+ipkg_error_t ipkg_install_by_name(ipkg_conf_t *conf, const char *pkg_name)
+{
+ int cmp;
+ pkg_t *old, *new;
+ char *old_version, *new_version;
+
+ old = pkg_hash_fetch_installed_by_name(&conf->pkg_hash, pkg_name);
+
+ new = pkg_hash_fetch_best_installation_candidate_by_name(conf, pkg_name);
+ if (new == NULL) {
+ return IPKG_PKG_HAS_NO_CANDIDATE;
+ }
+
+ new->state_flag |= SF_USER;
+ if (old) {
+ old_version = pkg_version_str_alloc(old);
+ new_version = pkg_version_str_alloc(new);
+
+ cmp = pkg_compare_versions(old, new);
+ if ( (conf->force_downgrade==1) && (cmp > 0) ){ /* We've been asked to allow downgrade and version is precedent */
+ ipkg_message(conf, IPKG_DEBUG, " Forcing downgrade \n");
+ cmp = -1 ; /* then we force ipkg to downgrade */
+ /* We need to use a value < 0 because in the 0 case we are asking to */
+ /* reinstall, and some check could fail asking the "force-reinstall" option */
+ }
+ ipkg_message(conf, IPKG_DEBUG,
+ "comparing visible versions of pkg %s:"
+ "\n\t%s is installed "
+ "\n\t%s is available "
+ "\n\t%d was comparison result\n",
+ pkg_name, old_version, new_version, cmp);
+ if (cmp == 0 && !conf->force_reinstall) {
+ ipkg_message(conf, IPKG_NOTICE,
+ "Package %s (%s) installed in %s is up to date.\n",
+ old->name, old_version, old->dest->name);
+ free(old_version);
+ free(new_version);
+ return 0;
+ } else if (cmp > 0) {
+ ipkg_message(conf, IPKG_NOTICE,
+ "Not downgrading package %s on %s from %s to %s.\n",
+ old->name, old->dest->name, old_version, new_version);
+ free(old_version);
+ free(new_version);
+ return 0;
+ } else if (cmp < 0) {
+ new->dest = old->dest;
+ old->state_want = SW_DEINSTALL; /* Here probably the problem for bug 1277 */
+ }
+ }
+
+ /* XXX: CLEANUP: The error code of ipkg_install_by_name is really
+ supposed to be an ipkg_error_t, but ipkg_install_pkg could
+ return any kind of integer, (might be errno from a syscall,
+ etc.). This is a real mess and will need to be cleaned up if
+ anyone ever wants to make a nice libipkg. */
+
+ ipkg_message(conf, IPKG_DEBUG2,"Function: %s calling ipkg_install_pkg \n",__FUNCTION__);
+ return ipkg_install_pkg(conf, new);
+}
+
+ipkg_error_t ipkg_install_multi_by_name(ipkg_conf_t *conf, const char *pkg_name)
+{
+ abstract_pkg_vec_t *providers = pkg_hash_fetch_all_installation_candidates (&conf->pkg_hash, pkg_name);
+ int i;
+ ipkg_error_t err;
+ abstract_pkg_t *ppkg ;
+
+ if (providers == NULL)
+ return IPKG_PKG_HAS_NO_CANDIDATE;
+
+ for (i = 0; i < providers->len; i++) {
+ ppkg = abstract_pkg_vec_get(providers, i);
+ ipkg_message(conf, IPKG_DEBUG2,"Function: %s calling ipkg_install_by_name %d \n",__FUNCTION__, i);
+ err = ipkg_install_by_name(conf, ppkg->name);
+ if (err)
+ return err;
+/* XXX Maybe ppkg should be freed ? */
+ }
+ return 0;
+}
+
+/*
+ * Walk dependence graph starting with pkg, collect packages to be
+ * installed into pkgs_needed, in dependence order.
+ */
+int pkg_mark_dependencies_for_installation(ipkg_conf_t *conf, pkg_t *pkg, pkg_vec_t *pkgs_needed)
+{
+ int i, err;
+ pkg_vec_t *depends = pkg_vec_alloc();
+ char **unresolved = NULL;
+ int ndepends;
+
+ ndepends = pkg_hash_fetch_unsatisfied_dependencies(conf,
+ pkg, depends,
+ &unresolved);
+
+ if (unresolved) {
+ ipkg_message(conf, IPKG_ERROR,
+ "%s: Cannot satisfy the following dependencies for %s:\n\t",
+ conf->force_depends ? "Warning" : "ERROR", pkg->name);
+ while (*unresolved) {
+ ipkg_message(conf, IPKG_ERROR, " %s", *unresolved);
+ unresolved++;
+ }
+ ipkg_message(conf, IPKG_ERROR, "\n");
+ if (! conf->force_depends) {
+ ipkg_message(conf, IPKG_INFO,
+ "This could mean that your package list is out of date or that the packages\n"
+ "mentioned above do not yet exist (try 'ipkg update'). To proceed in spite\n"
+ "of this problem try again with the '-force-depends' option.\n");
+ pkg_vec_free(depends);
+ return IPKG_PKG_DEPS_UNSATISFIED;
+ }
+ }
+
+ if (ndepends <= 0) {
+ pkg_vec_free(depends);
+ return 0;
+ }
+
+ for (i = 0; i < depends->len; i++) {
+ pkg_t *dep = depends->pkgs[i];
+ /* The package was uninstalled when we started, but another
+ dep earlier in this loop may have depended on it and pulled
+ it in, so check first. */
+ if ((dep->state_status != SS_INSTALLED)
+ && (dep->state_status != SS_UNPACKED)
+ && (dep->state_want != SW_INSTALL)) {
+
+ /* Mark packages as to-be-installed */
+ dep->state_want = SW_INSTALL;
+
+ /* Dependencies should be installed the same place as pkg */
+ if (dep->dest == NULL) {
+ dep->dest = pkg->dest;
+ }
+
+ err = pkg_mark_dependencies_for_installation(conf, dep, pkgs_needed);
+ if (err) {
+ pkg_vec_free(depends);
+ return err;
+ }
+ }
+ }
+ if (pkgs_needed)
+ pkg_vec_insert(pkgs_needed, pkg);
+
+ pkg_vec_free(depends);
+
+ return 0;
+}
+
+int name_mark_dependencies_for_installation(ipkg_conf_t *conf, const char *pkg_name, pkg_vec_t *pkgs_needed)
+{
+ int cmp;
+ pkg_t *old, *new;
+ char *old_version, *new_version;
+
+ old = pkg_hash_fetch_installed_by_name(&conf->pkg_hash, pkg_name);
+
+ new = pkg_hash_fetch_best_installation_candidate_by_name(conf, pkg_name);
+ if (new == NULL) {
+ return IPKG_PKG_HAS_NO_CANDIDATE;
+ }
+ if (old) {
+ old_version = pkg_version_str_alloc(old);
+ new_version = pkg_version_str_alloc(new);
+
+ cmp = pkg_compare_versions(old, new);
+ if ( (conf->force_downgrade==1) && (cmp > 0) ){ /* We've been asked to allow downgrade and version is precedent */
+ ipkg_message(conf, IPKG_DEBUG, " Forcing downgrade ");
+ cmp = -1 ; /* then we force ipkg to downgrade */
+ /* We need to use a value < 0 because in the 0 case we are asking to */
+ /* reinstall, and some check could fail asking the "force-reinstall" option */
+ }
+ ipkg_message(conf, IPKG_DEBUG,
+ "comparing visible versions of pkg %s:"
+ "\n\t%s is installed "
+ "\n\t%s is available "
+ "\n\t%d was comparison result\n",
+ pkg_name, old_version, new_version, cmp);
+ if (cmp == 0 && !conf->force_reinstall) {
+ ipkg_message(conf, IPKG_NOTICE,
+ "Package %s (%s) installed in %s is up to date.\n",
+ old->name, old_version, old->dest->name);
+ free(old_version);
+ free(new_version);
+ return 0;
+ } else if (cmp > 0) {
+ ipkg_message(conf, IPKG_NOTICE,
+ "Not downgrading package %s on %s from %s to %s.\n",
+ old->name, old->dest->name, old_version, new_version);
+ free(old_version);
+ free(new_version);
+ return 0;
+ } else if (cmp < 0) {
+ new->dest = old->dest;
+ old->state_want = SW_DEINSTALL;
+ old->state_flag |= SF_OBSOLETE;
+ }
+ }
+ return pkg_mark_dependencies_for_installation(conf, new, pkgs_needed);
+}
+
+
+
+int satisfy_dependencies_for(ipkg_conf_t *conf, pkg_t *pkg)
+{
+ int i, err;
+ pkg_vec_t *depends = pkg_vec_alloc();
+ pkg_t *dep;
+ char **unresolved = NULL;
+ int ndepends;
+
+ ndepends = pkg_hash_fetch_unsatisfied_dependencies(conf,
+ pkg, depends,
+ &unresolved);
+
+ if (unresolved) {
+ ipkg_message(conf, IPKG_ERROR,
+ "%s: Cannot satisfy the following dependencies for %s:\n\t",
+ conf->force_depends ? "Warning" : "ERROR", pkg->name);
+ while (*unresolved) {
+ ipkg_message(conf, IPKG_ERROR, " %s", *unresolved);
+ unresolved++;
+ }
+ ipkg_message(conf, IPKG_ERROR, "\n");
+ if (! conf->force_depends) {
+ ipkg_message(conf, IPKG_INFO,
+ "This could mean that your package list is out of date or that the packages\n"
+ "mentioned above do not yet exist (try 'ipkg update'). To proceed in spite\n"
+ "of this problem try again with the '-force-depends' option.\n");
+ pkg_vec_free(depends);
+ return IPKG_PKG_DEPS_UNSATISFIED;
+ }
+ }
+
+ if (ndepends <= 0) {
+ return 0;
+ }
+
+ /* Mark packages as to-be-installed */
+ for (i=0; i < depends->len; i++) {
+ /* Dependencies should be installed the same place as pkg */
+ if (depends->pkgs[i]->dest == NULL) {
+ depends->pkgs[i]->dest = pkg->dest;
+ }
+ depends->pkgs[i]->state_want = SW_INSTALL;
+ }
+
+ for (i = 0; i < depends->len; i++) {
+ dep = depends->pkgs[i];
+ /* The package was uninstalled when we started, but another
+ dep earlier in this loop may have depended on it and pulled
+ it in, so check first. */
+ if ((dep->state_status != SS_INSTALLED)
+ && (dep->state_status != SS_UNPACKED)) {
+ ipkg_message(conf, IPKG_DEBUG2,"Function: %s calling ipkg_install_pkg \n",__FUNCTION__);
+ err = ipkg_install_pkg(conf, dep);
+ if (err) {
+ pkg_vec_free(depends);
+ return err;
+ }
+ }
+ }
+
+ pkg_vec_free(depends);
+
+ return 0;
+}
+
+
+/* check all packages have their dependences satisfied, e.g., in case an upgraded package split */
+int ipkg_satisfy_all_dependences(ipkg_conf_t *conf)
+{
+ if (conf->nodeps == 0) {
+ int i;
+ pkg_vec_t *installed = pkg_vec_alloc();
+ pkg_hash_fetch_all_installed(&conf->pkg_hash, installed);
+ for (i = 0; i < installed->len; i++) {
+ pkg_t *pkg = installed->pkgs[i];
+ satisfy_dependencies_for(conf, pkg);
+ }
+ pkg_vec_free(installed);
+ }
+ return 0;
+}
+
+
+
+static int check_conflicts_for(ipkg_conf_t *conf, pkg_t *pkg)
+{
+ int i;
+ pkg_vec_t *conflicts = NULL;
+ int level;
+ const char *prefix;
+ if (conf->force_depends) {
+ level = IPKG_NOTICE;
+ prefix = "Warning";
+ } else {
+ level = IPKG_ERROR;
+ prefix = "ERROR";
+ }
+
+ if (!conf->force_depends)
+ conflicts = (pkg_vec_t *)pkg_hash_fetch_conflicts(&conf->pkg_hash, pkg);
+
+ if (conflicts) {
+ ipkg_message(conf, level,
+ "%s: The following packages conflict with %s:\n\t", prefix, pkg->name);
+ i = 0;
+ while (i < conflicts->len)
+ ipkg_message(conf, level, " %s", conflicts->pkgs[i++]->name);
+ ipkg_message(conf, level, "\n");
+ pkg_vec_free(conflicts);
+ return IPKG_PKG_DEPS_UNSATISFIED;
+ }
+ return 0;
+}
+
+static int update_file_ownership(ipkg_conf_t *conf, pkg_t *new_pkg, pkg_t *old_pkg)
+{
+ str_list_t *new_list = pkg_get_installed_files(new_pkg);
+ str_list_elt_t *iter;
+
+ for (iter = new_list->head; iter; iter = iter->next) {
+ char *new_file = iter->data;
+ pkg_t *owner = file_hash_get_file_owner(conf, new_file);
+ if (!new_file)
+ ipkg_message(conf, IPKG_ERROR, "Null new_file for new_pkg=%s\n", new_pkg->name);
+ if (!owner || (owner == old_pkg))
+ file_hash_set_file_owner(conf, new_file, new_pkg);
+ }
+ if (old_pkg) {
+ str_list_t *old_list = pkg_get_installed_files(old_pkg);
+ for (iter = old_list->head; iter; iter = iter->next) {
+ char *old_file = iter->data;
+ pkg_t *owner = file_hash_get_file_owner(conf, old_file);
+ if (owner == old_pkg) {
+ /* obsolete */
+ hash_table_insert(&conf->obs_file_hash, old_file, old_pkg);
+ }
+ }
+ }
+ return 0;
+}
+
+static int verify_pkg_installable(ipkg_conf_t *conf, pkg_t *pkg)
+{
+ /* XXX: FEATURE: Anything else needed here? Maybe a check on free space? */
+
+ /* sma 6.20.02: yup; here's the first bit */
+ /*
+ * XXX: BUG easy for cworth
+ * 1) please point the call below to the correct current root destination
+ * 2) we need to resolve how to check the required space for a pending pkg,
+ * my diddling with the .ipk file size below isn't going to cut it.
+ * 3) return a proper error code instead of 1
+ */
+ int comp_size, blocks_available;
+
+ if (!conf->force_space && pkg->installed_size != NULL) {
+ blocks_available = get_available_blocks(conf->default_dest->root_dir);
+
+ comp_size = strtoul(pkg->installed_size, NULL, 0);
+ /* round up a blocks count without doing fancy-but-slow casting jazz */
+ comp_size = (int)((comp_size + 1023) / 1024);
+
+ if (comp_size >= blocks_available) {
+ ipkg_message(conf, IPKG_ERROR,
+ "Only have %d available blocks on filesystem %s, pkg %s needs %d\n",
+ blocks_available, conf->default_dest->root_dir, pkg->name, comp_size);
+ return ENOSPC;
+ }
+ }
+ return 0;
+}
+
+static int unpack_pkg_control_files(ipkg_conf_t *conf, pkg_t *pkg)
+{
+ int err;
+ char *conffiles_file_name;
+ char *root_dir;
+ FILE *conffiles_file;
+
+ sprintf_alloc(&pkg->tmp_unpack_dir, "%s/%s-XXXXXX", conf->tmp_dir, pkg->name);
+
+ pkg->tmp_unpack_dir = mkdtemp(pkg->tmp_unpack_dir);
+ if (pkg->tmp_unpack_dir == NULL) {
+ ipkg_message(conf, IPKG_ERROR,
+ "%s: Failed to create temporary directory '%s': %s\n",
+ __FUNCTION__, pkg->tmp_unpack_dir, strerror(errno));
+ return errno;
+ }
+
+ err = pkg_extract_control_files_to_dir(pkg, pkg->tmp_unpack_dir);
+ if (err) {
+ return err;
+ }
+
+ /* XXX: CLEANUP: There might be a cleaner place to read in the
+ conffiles. Seems like I should be able to get everything to go
+ through pkg_init_from_file. If so, maybe it would make sense to
+ move all of unpack_pkg_control_files to that function. */
+
+ /* Don't need to re-read conffiles if we already have it */
+ if (pkg->conffiles.head) {
+ return 0;
+ }
+
+ sprintf_alloc(&conffiles_file_name, "%s/conffiles", pkg->tmp_unpack_dir);
+ if (! file_exists(conffiles_file_name)) {
+ free(conffiles_file_name);
+ return 0;
+ }
+
+ conffiles_file = fopen(conffiles_file_name, "r");
+ if (conffiles_file == NULL) {
+ fprintf(stderr, "%s: failed to open %s: %s\n",
+ __FUNCTION__, conffiles_file_name, strerror(errno));
+ free(conffiles_file_name);
+ return errno;
+ }
+ free(conffiles_file_name);
+
+ while (1) {
+ char *cf_name;
+ char *cf_name_in_dest;
+
+ cf_name = file_read_line_alloc(conffiles_file);
+ if (cf_name == NULL) {
+ break;
+ }
+ str_chomp(cf_name);
+ if (cf_name[0] == '\0') {
+ continue;
+ }
+
+ /* Prepend dest->root_dir to conffile name.
+ Take pains to avoid multiple slashes. */
+ root_dir = pkg->dest->root_dir;
+ if (conf->offline_root)
+ /* skip the offline_root prefix */
+ root_dir = pkg->dest->root_dir + strlen(conf->offline_root);
+ sprintf_alloc(&cf_name_in_dest, "%s%s", root_dir,
+ cf_name[0] == '/' ? (cf_name + 1) : cf_name);
+
+ /* Can't get an md5sum now, (file isn't extracted yet).
+ We'll wait until resolve_conffiles */
+ conffile_list_append(&pkg->conffiles, cf_name_in_dest, NULL);
+
+ free(cf_name);
+ free(cf_name_in_dest);
+ }
+
+ fclose(conffiles_file);
+
+ return 0;
+}
+
+/* returns number of installed replacees */
+int pkg_get_installed_replacees(ipkg_conf_t *conf, pkg_t *pkg, pkg_vec_t *installed_replacees)
+{
+ abstract_pkg_t **replaces = pkg->replaces;
+ int replaces_count = pkg->replaces_count;
+ int i, j;
+ for (i = 0; i < replaces_count; i++) {
+ abstract_pkg_t *ab_pkg = replaces[i];
+ pkg_vec_t *pkg_vec = ab_pkg->pkgs;
+ if (pkg_vec) {
+ for (j = 0; j < pkg_vec->len; j++) {
+ pkg_t *replacee = pkg_vec->pkgs[j];
+ if (!pkg_conflicts(pkg, replacee))
+ continue;
+ if (replacee->state_status == SS_INSTALLED) {
+ pkg_vec_insert(installed_replacees, replacee);
+ }
+ }
+ }
+ }
+ return installed_replacees->len;
+}
+
+int pkg_remove_installed_replacees(ipkg_conf_t *conf, pkg_vec_t *replacees)
+{
+ int i;
+ int replaces_count = replacees->len;
+ for (i = 0; i < replaces_count; i++) {
+ pkg_t *replacee = replacees->pkgs[i];
+ int err;
+ replacee->state_flag |= SF_REPLACE; /* flag it so remove won't complain */
+ err = ipkg_remove_pkg(conf, replacee);
+ if (err)
+ return err;
+ }
+ return 0;
+}
+
+/* to unwind the removal: make sure they are installed */
+int pkg_remove_installed_replacees_unwind(ipkg_conf_t *conf, pkg_vec_t *replacees)
+{
+ int i, err;
+ int replaces_count = replacees->len;
+ for (i = 0; i < replaces_count; i++) {
+ pkg_t *replacee = replacees->pkgs[i];
+ if (replacee->state_status != SS_INSTALLED) {
+ ipkg_message(conf, IPKG_DEBUG2,"Function: %s calling ipkg_install_pkg \n",__FUNCTION__);
+ err = ipkg_install_pkg(conf, replacee);
+ if (err)
+ return err;
+ }
+ }
+ return 0;
+}
+
+int caught_sigint = 0;
+static void ipkg_install_pkg_sigint_handler(int sig)
+{
+ caught_sigint = sig;
+}
+
+/* compares versions of pkg and old_pkg, returns 0 if OK to proceed with installation of pkg, 1 otherwise */
+static int ipkg_install_check_downgrade(ipkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg)
+{
+ if (old_pkg) {
+ char message_out[15];
+ char *old_version = pkg_version_str_alloc(old_pkg);
+ char *new_version = pkg_version_str_alloc(pkg);
+ int cmp = pkg_compare_versions(old_pkg, pkg);
+ int rc = 0;
+
+ strncpy (message_out,"Upgrading ",13);
+ if ( (conf->force_downgrade==1) && (cmp > 0) ){ /* We've been asked to allow downgrade and version is precedent */
+ cmp = -1 ; /* then we force ipkg to downgrade */
+ strncpy (message_out,"Downgrading ",13); /* We need to use a value < 0 because in the 0 case we are asking to */
+ /* reinstall, and some check could fail asking the "force-reinstall" option */
+ }
+
+ if (cmp > 0) {
+ ipkg_message(conf, IPKG_NOTICE,
+ "Not downgrading package %s on %s from %s to %s.\n",
+ old_pkg->name, old_pkg->dest->name, old_version, new_version);
+ rc = 1;
+ } else if (cmp < 0) {
+ ipkg_message(conf, IPKG_NOTICE,
+ "%s %s on %s from %s to %s...\n",
+ message_out, pkg->name, old_pkg->dest->name, old_version, new_version);
+ pkg->dest = old_pkg->dest;
+ rc = 0;
+ } else /* cmp == 0 */ {
+ if (conf->force_reinstall) {
+ ipkg_message(conf, IPKG_NOTICE,
+ "Reinstalling %s (%s) on %s...\n",
+ pkg->name, new_version, old_pkg->dest->name);
+ pkg->dest = old_pkg->dest;
+ rc = 0;
+ } else {
+ ipkg_message(conf, IPKG_NOTICE,
+ "Not installing %s (%s) on %s -- already installed.\n",
+ pkg->name, new_version, old_pkg->dest->name);
+ rc = 1;
+ }
+ }
+ free(old_version);
+ free(new_version);
+ return rc;
+ } else {
+ char *version = pkg_version_str_alloc(pkg);
+ ipkg_message(conf, IPKG_NOTICE,
+ "Installing %s (%s) to %s...\n",
+ pkg->name, version, pkg->dest->name);
+ free(version);
+ return 0;
+ }
+}
+
+/* and now the meat... */
+int ipkg_install_pkg(ipkg_conf_t *conf, pkg_t *pkg)
+{
+ int err = 0;
+ pkg_t *old_pkg = NULL;
+ pkg_vec_t *replacees;
+ abstract_pkg_t *ab_pkg = NULL;
+ int old_state_flag;
+
+ if (!pkg) {
+ ipkg_message(conf, IPKG_ERROR,
+ "INTERNAL ERROR: null pkg passed to ipkg_install_pkg\n");
+ return -EINVAL;
+ }
+
+ ipkg_message(conf, IPKG_DEBUG2, "Function: %s calling pkg_arch_supported %s \n", __FUNCTION__, __FUNCTION__);
+
+ if (!pkg_arch_supported(conf, pkg)) {
+ ipkg_message(conf, IPKG_ERROR, "INTERNAL ERROR: architecture %s for pkg %s is unsupported.\n",
+ pkg->architecture, pkg->name);
+ return -EINVAL;
+ }
+ if (pkg->state_status == SS_INSTALLED && conf->force_reinstall == 0 && conf->nodeps == 0) {
+ err = satisfy_dependencies_for(conf, pkg);
+ if (err) { return err; }
+
+ ipkg_message(conf, IPKG_NOTICE,
+ "Package %s is already installed in %s.\n",
+ pkg->name, pkg->dest->name);
+ return 0;
+ }
+
+ if (pkg->dest == NULL) {
+ pkg->dest = conf->default_dest;
+ }
+
+ old_pkg = pkg_hash_fetch_installed_by_name(&conf->pkg_hash, pkg->name);
+
+ err = ipkg_install_check_downgrade(conf, pkg, old_pkg);
+ if (err) { return err; }
+
+ pkg->state_want = SW_INSTALL;
+ if (old_pkg) old_pkg->state_want = SW_DEINSTALL; /* needed for check_data_file_clashes of dependences */
+
+ /* Abhaya: conflicts check */
+ err = check_conflicts_for(conf, pkg);
+ if (err) { return err; }
+
+ /* this setup is to remove the upgrade scenario in the end when
+ installing pkg A, A deps B & B deps on A. So both B and A are
+ installed. Then A's installation is started resulting in an
+ uncecessary upgrade */
+ if (pkg->state_status == SS_INSTALLED
+ && conf->force_reinstall == 0) return 0;
+
+ err = verify_pkg_installable(conf, pkg);
+ if (err) { return err; }
+
+ if (pkg->local_filename == NULL) {
+ err = ipkg_download_pkg(conf, pkg, conf->tmp_dir);
+ if (err) {
+ ipkg_message(conf, IPKG_ERROR,
+ "Failed to download %s. Perhaps you need to run 'ipkg update'?\n",
+ pkg->name);
+ return err;
+ }
+ }
+ if (pkg->tmp_unpack_dir == NULL) {
+ unpack_pkg_control_files(conf, pkg);
+ }
+
+ /* We should update the filelist here, so that upgrades of packages that split will not fail. -Jamey 27-MAR-03 */
+ err = update_file_ownership(conf, pkg, old_pkg);
+ if (err) { return err; }
+
+ if (conf->nodeps == 0) {
+ err = satisfy_dependencies_for(conf, pkg);
+ if (err) { return err; }
+ }
+
+ replacees = pkg_vec_alloc();
+ pkg_get_installed_replacees(conf, pkg, replacees);
+
+ /* this next section we do with SIGINT blocked to prevent inconsistency between ipkg database and filesystem */
+ {
+ sigset_t newset, oldset;
+ sighandler_t old_handler = NULL;
+ int use_signal = 0;
+ caught_sigint = 0;
+ if (use_signal) {
+ old_handler = signal(SIGINT, ipkg_install_pkg_sigint_handler);
+ } else {
+ sigemptyset(&newset);
+ sigaddset(&newset, SIGINT);
+ sigprocmask(SIG_BLOCK, &newset, &oldset);
+ }
+
+ ipkg_state_changed++;
+ pkg->state_flag |= SF_FILELIST_CHANGED;
+
+ /* XXX: BUG: we really should treat replacement more like an upgrade
+ * Instead, we're going to remove the replacees
+ */
+ err = pkg_remove_installed_replacees(conf, replacees);
+ if (err) goto UNWIND_REMOVE_INSTALLED_REPLACEES;
+
+ err = prerm_upgrade_old_pkg(conf, pkg, old_pkg);
+ if (err) goto UNWIND_PRERM_UPGRADE_OLD_PKG;
+
+ err = prerm_deconfigure_conflictors(conf, pkg, replacees);
+ if (err) goto UNWIND_PRERM_DECONFIGURE_CONFLICTORS;
+
+ err = preinst_configure(conf, pkg, old_pkg);
+ if (err) goto UNWIND_PREINST_CONFIGURE;
+
+ err = backup_modified_conffiles(conf, pkg, old_pkg);
+ if (err) goto UNWIND_BACKUP_MODIFIED_CONFFILES;
+
+ err = check_data_file_clashes(conf, pkg, old_pkg);
+ if (err) goto UNWIND_CHECK_DATA_FILE_CLASHES;
+
+ err = postrm_upgrade_old_pkg(conf, pkg, old_pkg);
+ if (err) goto UNWIND_POSTRM_UPGRADE_OLD_PKG;
+
+ if (conf->noaction) return 0;
+
+ /* point of no return: no unwinding after this */
+ if (old_pkg && !conf->force_reinstall) {
+ old_pkg->state_want = SW_DEINSTALL;
+
+ if (old_pkg->state_flag & SF_NOPRUNE) {
+ ipkg_message(conf, IPKG_INFO,
+ " not removing obsolesced files because package marked noprune\n");
+ } else {
+ ipkg_message(conf, IPKG_INFO,
+ " removing obsolesced files\n");
+ remove_obsolesced_files(conf, pkg, old_pkg);
+ }
+ }
+ ipkg_message(conf, IPKG_INFO,
+ " installing maintainer scripts\n");
+ install_maintainer_scripts(conf, pkg, old_pkg);
+
+ /* the following just returns 0 */
+ remove_disappeared(conf, pkg);
+
+ ipkg_message(conf, IPKG_INFO,
+ " installing data files\n");
+ install_data_files(conf, pkg);
+
+ ipkg_message(conf, IPKG_INFO,
+ " resolving conf files\n");
+ resolve_conffiles(conf, pkg);
+
+ pkg->state_status = SS_UNPACKED;
+ old_state_flag = pkg->state_flag;
+ pkg->state_flag &= ~SF_PREFER;
+ ipkg_message(conf, IPKG_DEBUG, " pkg=%s old_state_flag=%x state_flag=%x\n", pkg->name, old_state_flag, pkg->state_flag);
+
+ if (old_pkg && !conf->force_reinstall) {
+ old_pkg->state_status = SS_NOT_INSTALLED;
+ }
+
+ time(&pkg->installed_time);
+
+ ipkg_message(conf, IPKG_INFO,
+ " cleanup temp files\n");
+ cleanup_temporary_files(conf, pkg);
+
+ ab_pkg = pkg->parent;
+ if (ab_pkg)
+ ab_pkg->state_status = pkg->state_status;
+
+ ipkg_message(conf, IPKG_INFO, "Done.\n");
+
+ if (use_signal)
+ signal(SIGINT, old_handler);
+ else
+ sigprocmask(SIG_UNBLOCK, &newset, &oldset);
+
+ return 0;
+
+
+ UNWIND_POSTRM_UPGRADE_OLD_PKG:
+ postrm_upgrade_old_pkg_unwind(conf, pkg, old_pkg);
+ UNWIND_CHECK_DATA_FILE_CLASHES:
+ check_data_file_clashes_unwind(conf, pkg, old_pkg);
+ UNWIND_BACKUP_MODIFIED_CONFFILES:
+ backup_modified_conffiles_unwind(conf, pkg, old_pkg);
+ UNWIND_PREINST_CONFIGURE:
+ preinst_configure_unwind(conf, pkg, old_pkg);
+ UNWIND_PRERM_DECONFIGURE_CONFLICTORS:
+ prerm_deconfigure_conflictors_unwind(conf, pkg, replacees);
+ UNWIND_PRERM_UPGRADE_OLD_PKG:
+ prerm_upgrade_old_pkg_unwind(conf, pkg, old_pkg);
+ UNWIND_REMOVE_INSTALLED_REPLACEES:
+ pkg_remove_installed_replacees_unwind(conf, replacees);
+
+ ipkg_message(conf, IPKG_INFO,
+ " cleanup temp files\n");
+ cleanup_temporary_files(conf, pkg);
+
+ ipkg_message(conf, IPKG_INFO,
+ "Failed.\n");
+ if (use_signal)
+ signal(SIGINT, old_handler);
+ else
+ sigprocmask(SIG_UNBLOCK, &newset, &oldset);
+
+ return err;
+ }
+}
+
+static int prerm_upgrade_old_pkg(ipkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg)
+{
+ /* DPKG_INCOMPATIBILITY:
+ dpkg does some things here that we don't do yet. Do we care?
+
+ 1. If a version of the package is already installed, call
+ old-prerm upgrade new-version
+ 2. If the script runs but exits with a non-zero exit status
+ new-prerm failed-upgrade old-version
+ Error unwind, for both the above cases:
+ old-postinst abort-upgrade new-version
+ */
+ return 0;
+}
+
+static int prerm_upgrade_old_pkg_unwind(ipkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg)
+{
+ /* DPKG_INCOMPATIBILITY:
+ dpkg does some things here that we don't do yet. Do we care?
+ (See prerm_upgrade_old_package for details)
+ */
+ return 0;
+}
+
+static int prerm_deconfigure_conflictors(ipkg_conf_t *conf, pkg_t *pkg, pkg_vec_t *conflictors)
+{
+ /* DPKG_INCOMPATIBILITY:
+ dpkg does some things here that we don't do yet. Do we care?
+ 2. If a 'conflicting' package is being removed at the same time:
+ 1. If any packages depended on that conflicting package and
+ --auto-deconfigure is specified, call, for each such package:
+ deconfigured's-prerm deconfigure \
+ in-favour package-being-installed version \
+ removing conflicting-package version
+ Error unwind:
+ deconfigured's-postinst abort-deconfigure \
+ in-favour package-being-installed-but-failed version \
+ removing conflicting-package version
+
+ The deconfigured packages are marked as requiring
+ configuration, so that if --install is used they will be
+ configured again if possible.
+ 2. To prepare for removal of the conflicting package, call:
+ conflictor's-prerm remove in-favour package new-version
+ Error unwind:
+ conflictor's-postinst abort-remove in-favour package new-version
+ */
+ return 0;
+}
+
+static int prerm_deconfigure_conflictors_unwind(ipkg_conf_t *conf, pkg_t *pkg, pkg_vec_t *conflictors)
+{
+ /* DPKG_INCOMPATIBILITY: dpkg does some things here that we don't
+ do yet. Do we care? (See prerm_deconfigure_conflictors for
+ details) */
+ return 0;
+}
+
+static int preinst_configure(ipkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg)
+{
+ int err;
+ char *preinst_args;
+
+ if (old_pkg) {
+ char *old_version = pkg_version_str_alloc(old_pkg);
+ sprintf_alloc(&preinst_args, "upgrade %s", old_version);
+ free(old_version);
+ } else if (pkg->state_status == SS_CONFIG_FILES) {
+ char *pkg_version = pkg_version_str_alloc(pkg);
+ sprintf_alloc(&preinst_args, "install %s", pkg_version);
+ free(pkg_version);
+ } else {
+ preinst_args = strdup("install");
+ }
+
+ err = pkg_run_script(conf, pkg, "preinst", preinst_args);
+ if (err) {
+ ipkg_message(conf, IPKG_ERROR,
+ "Aborting installation of %s\n", pkg->name);
+ return 1;
+ }
+
+ free(preinst_args);
+
+ return 0;
+}
+
+static int preinst_configure_unwind(ipkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg)
+{
+ /* DPKG_INCOMPATIBILITY:
+ dpkg does the following error unwind, should we?
+ pkg->postrm abort-upgrade old-version
+ OR pkg->postrm abort-install old-version
+ OR pkg->postrm abort-install
+ */
+ return 0;
+}
+
+static int backup_modified_conffiles(ipkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg)
+{
+ int err;
+ conffile_list_elt_t *iter;
+ conffile_t *cf;
+
+ if (conf->noaction) return 0;
+
+ /* Backup all modified conffiles */
+ if (old_pkg) {
+ for (iter = old_pkg->conffiles.head; iter; iter = iter->next) {
+ char *cf_name;
+
+ cf = iter->data;
+ cf_name = root_filename_alloc(conf, cf->name);
+
+ /* Don't worry if the conffile is just plain gone */
+ if (file_exists(cf_name) && conffile_has_been_modified(conf, cf)) {
+ err = backup_make_backup(conf, cf_name);
+ if (err) {
+ return err;
+ }
+ }
+ free(cf_name);
+ }
+ }
+
+ /* Backup all conffiles that were not conffiles in old_pkg */
+ for (iter = pkg->conffiles.head; iter; iter = iter->next) {
+ char *cf_name;
+ cf = iter->data;
+ cf_name = root_filename_alloc(conf, cf->name);
+ /* Ignore if this was a conffile in old_pkg as well */
+ if (pkg_get_conffile(old_pkg, cf->name)) {
+ continue;
+ }
+
+ if (file_exists(cf_name) && (! backup_exists_for(cf_name))) {
+ err = backup_make_backup(conf, cf_name);
+ if (err) {
+ return err;
+ }
+ }
+ free(cf_name);
+ }
+
+ return 0;
+}
+
+static int backup_modified_conffiles_unwind(ipkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg)
+{
+ conffile_list_elt_t *iter;
+
+ if (old_pkg) {
+ for (iter = old_pkg->conffiles.head; iter; iter = iter->next) {
+ backup_remove(iter->data->name);
+ }
+ }
+
+ for (iter = pkg->conffiles.head; iter; iter = iter->next) {
+ backup_remove(iter->data->name);
+ }
+
+ return 0;
+}
+
+static int check_data_file_clashes(ipkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg)
+{
+ /* DPKG_INCOMPATIBILITY:
+ ipkg takes a slightly different approach than dpkg at this
+ point. dpkg installs each file in the new package while
+ creating a backup for any file that is replaced, (so that it
+ can unwind if necessary). To avoid complexity and redundant
+ storage, ipkg doesn't do any installation until later, (at the
+ point at which dpkg removes the backups.
+
+ But, we do have to check for data file clashes, since after
+ installing a package with a file clash, removing either of the
+ packages involved in the clash has the potential to break the
+ other package.
+ */
+ str_list_t *files_list;
+ str_list_elt_t *iter;
+
+ int clashes = 0;
+
+ files_list = pkg_get_installed_files(pkg);
+ for (iter = files_list->head; iter; iter = iter->next) {
+ char *root_filename;
+ char *filename = iter->data;
+ root_filename = root_filename_alloc(conf, filename);
+ if (file_exists(root_filename) && (! file_is_dir(root_filename))) {
+ pkg_t *owner;
+ pkg_t *obs;
+ /* Pre-existing conffiles are OK */
+ /* @@@@ should have way to check that it is a conffile -Jamey */
+ if (backup_exists_for(root_filename)) {
+ continue;
+ }
+
+ /* Pre-existing files are OK if force-overwrite was asserted. */
+ if (conf->force_overwrite) {
+ /* but we need to change who owns this file */
+ file_hash_set_file_owner(conf, filename, pkg);
+ continue;
+ }
+
+ owner = file_hash_get_file_owner(conf, filename);
+
+ /* Pre-existing files are OK if owned by the pkg being upgraded. */
+ if (owner && old_pkg) {
+ if (strcmp(owner->name, old_pkg->name) == 0) {
+ continue;
+ }
+ }
+
+ /* Pre-existing files are OK if owned by a package replaced by new pkg. */
+ if (owner) {
+ if (pkg_replaces(pkg, owner)) {
+ ipkg_message(conf, IPKG_INFO, "Replacing pre-existing file %s owned by package %s\n", filename, owner->name);
+ continue;
+ }
+/* If the file that would be installed is owned by the same package, ( as per a reinstall or similar )
+ then it's ok to overwrite. */
+ if (strcmp(owner->name,pkg->name)==0){
+ ipkg_message(conf, IPKG_INFO, "Replacing pre-existing file %s owned by package %s\n", filename, owner->name);
+ continue;
+ }
+ }
+
+ /* Pre-existing files are OK if they are obsolete */
+ obs = hash_table_get(&conf->obs_file_hash, filename);
+ if (obs) {
+ ipkg_message(conf, IPKG_INFO, "Pre-exiting file %s is obsolete. obs_pkg=%s\n", filename, obs->name);
+ continue;
+ }
+
+ /* We have found a clash. */
+ ipkg_message(conf, IPKG_ERROR,
+ "Package %s wants to install file %s\n"
+ "\tBut that file is already provided by package ",
+ pkg->name, filename);
+ if (owner) {
+ ipkg_message(conf, IPKG_ERROR,
+ "%s\n", owner->name);
+ } else {
+ ipkg_message(conf, IPKG_ERROR,
+ "<no package>\nPlease move this file out of the way and try again.\n");
+ }
+ clashes++;
+ }
+ free(root_filename);
+ }
+ pkg_free_installed_files(pkg);
+
+ return clashes;
+}
+
+static int check_data_file_clashes_unwind(ipkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg)
+{
+ /* Nothing to do since check_data_file_clashes doesn't change state */
+ return 0;
+}
+
+static int postrm_upgrade_old_pkg(ipkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg)
+{
+ /* DPKG_INCOMPATIBILITY: dpkg does the following here, should we?
+ 1. If the package is being upgraded, call
+ old-postrm upgrade new-version
+ 2. If this fails, attempt:
+ new-postrm failed-upgrade old-version
+ Error unwind, for both cases:
+ old-preinst abort-upgrade new-version */
+ return 0;
+}
+
+static int postrm_upgrade_old_pkg_unwind(ipkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg)
+{
+ /* DPKG_INCOMPATIBILITY:
+ dpkg does some things here that we don't do yet. Do we care?
+ (See postrm_upgrade_old_pkg for details)
+ */
+ return 0;
+}
+
+static int remove_obsolesced_files(ipkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg)
+{
+ int err;
+ str_list_t *old_files;
+ str_list_elt_t *of;
+ str_list_t *new_files;
+ str_list_elt_t *nf;
+
+ if (old_pkg == NULL) {
+ return 0;
+ }
+
+ old_files = pkg_get_installed_files(old_pkg);
+ new_files = pkg_get_installed_files(pkg);
+
+ for (of = old_files->head; of; of = of->next) {
+ pkg_t *owner;
+ char *old, *new;
+ old = of->data;
+ for (nf = new_files->head; nf; nf = nf->next) {
+ new = nf->data;
+ if (strcmp(old, new) == 0) {
+ goto NOT_OBSOLETE;
+ }
+ }
+ if (file_is_dir(old)) {
+ continue;
+ }
+ owner = file_hash_get_file_owner(conf, old);
+ if (owner != old_pkg) {
+ /* in case obsolete file no longer belongs to old_pkg */
+ continue;
+ }
+
+ /* old file is obsolete */
+ ipkg_message(conf, IPKG_INFO,
+ " removing obsolete file %s\n", old);
+ if (!conf->noaction) {
+ err = unlink(old);
+ if (err) {
+ ipkg_message(conf, IPKG_ERROR, " Warning: remove %s failed: %s\n", old,
+ strerror(errno));
+ }
+ }
+
+ NOT_OBSOLETE:
+ ;
+ }
+
+ pkg_free_installed_files(old_pkg);
+ pkg_free_installed_files(pkg);
+
+ return 0;
+}
+
+static int remove_obsolete_maintainer_scripts(ipkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg)
+{
+ int i;
+ int err = 0;
+ char *globpattern;
+ glob_t globbuf;
+ if (0) {
+ if (!pkg->dest) {
+ ipkg_message(conf, IPKG_ERROR, "%s: no dest for package %s\n", __FUNCTION__, pkg->name);
+ return -1;
+ }
+ sprintf_alloc(&globpattern, "%s/%s.*", pkg->dest->info_dir, pkg->name);
+ err = glob(globpattern, 0, NULL, &globbuf);
+ free(globpattern);
+ if (err) {
+ return err;
+ }
+ /* XXXX this should perhaps only remove the ones that are not overwritten in new package. Jamey 11/11/2003 */
+ for (i = 0; i < globbuf.gl_pathc; i++) {
+ ipkg_message(conf, IPKG_DEBUG, "Removing control file %s from old_pkg %s\n",
+ globbuf.gl_pathv[i], old_pkg->name);
+ if (!conf->noaction)
+ unlink(globbuf.gl_pathv[i]);
+ }
+ globfree(&globbuf);
+ }
+ return err;
+}
+
+static int install_maintainer_scripts(ipkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg)
+{
+ int ret;
+ char *prefix;
+
+ if (old_pkg)
+ remove_obsolete_maintainer_scripts(conf, pkg, old_pkg);
+ sprintf_alloc(&prefix, "%s.", pkg->name);
+ ret = pkg_extract_control_files_to_dir_with_prefix(pkg,
+ pkg->dest->info_dir,
+ prefix);
+ free(prefix);
+ return ret;
+}
+
+static int remove_disappeared(ipkg_conf_t *conf, pkg_t *pkg)
+{
+ /* DPKG_INCOMPATIBILITY:
+ This is a fairly sophisticated dpkg operation. Shall we
+ skip it? */
+
+ /* Any packages all of whose files have been overwritten during the
+ installation, and which aren't required for dependencies, are
+ considered to have been removed. For each such package
+ 1. disappearer's-postrm disappear overwriter overwriter-version
+ 2. The package's maintainer scripts are removed
+ 3. It is noted in the status database as being in a sane state,
+ namely not installed (any conffiles it may have are ignored,
+ rather than being removed by dpkg). Note that disappearing
+ packages do not have their prerm called, because dpkg doesn't
+ know in advance that the package is going to vanish.
+ */
+ return 0;
+}
+
+static int install_data_files(ipkg_conf_t *conf, pkg_t *pkg)
+{
+ int err;
+
+ /* ipkg takes a slightly different approach to data file backups
+ than dpkg. Rather than removing backups at this point, we
+ actually do the data file installation now. See comments in
+ check_data_file_clashes() for more details. */
+
+ ipkg_message(conf, IPKG_INFO,
+ " extracting data files to %s\n", pkg->dest->root_dir);
+ err = pkg_extract_data_files_to_dir(pkg, pkg->dest->root_dir);
+ if (err) {
+ return err;
+ }
+
+ /* XXX: BUG or FEATURE : We are actually loosing the Essential flag,
+ so we can't save ourself from removing important packages
+ At this point we (should) have extracted the .control file, so it
+ would be a good idea to reload the data in it, and set the Essential
+ state in *pkg. From now on the Essential is back in status file and
+ we can protect again.
+ We should operate this way:
+ fopen the file ( pkg->dest->root_dir/pkg->name.control )
+ check for "Essential" in it
+ set the value in pkg->essential.
+ This new routine could be useful also for every other flag
+ Pigi: 16/03/2004 */
+ set_flags_from_control(conf, pkg) ;
+
+ ipkg_message(conf, IPKG_DEBUG, " Calling pkg_write_filelist from %s\n", __FUNCTION__);
+ err = pkg_write_filelist(conf, pkg);
+ if (err)
+ return err;
+
+ /* XXX: FEATURE: ipkg should identify any files which existed
+ before installation and which were overwritten, (see
+ check_data_file_clashes()). What it must do is remove any such
+ files from the filelist of the old package which provided the
+ file. Otherwise, if the old package were removed at some point
+ it would break the new package. Removing the new package will
+ also break the old one, but this cannot be helped since the old
+ package's file has already been deleted. This is the importance
+ of check_data_file_clashes(), and only allowing ipkg to install
+ a clashing package with a user force. */
+
+ return 0;
+}
+
+static int resolve_conffiles(ipkg_conf_t *conf, pkg_t *pkg)
+{
+ conffile_list_elt_t *iter;
+ conffile_t *cf;
+ char *cf_backup;
+
+ char *md5sum;
+
+
+ if (conf->noaction) return 0;
+
+ for (iter = pkg->conffiles.head; iter; iter = iter->next) {
+ char *root_filename;
+ cf = iter->data;
+ root_filename = root_filename_alloc(conf, cf->name);
+
+ /* Might need to initialize the md5sum for each conffile */
+ if (cf->value == NULL) {
+ cf->value = file_md5sum_alloc(root_filename);
+ }
+
+ if (!file_exists(root_filename)) {
+ free(root_filename);
+ continue;
+ }
+
+ cf_backup = backup_filename_alloc(root_filename);
+
+
+ if (file_exists(cf_backup)) {
+ /* Let's compute md5 to test if files are changed */
+ md5sum = file_md5sum_alloc(cf_backup);
+ if (strcmp( cf->value,md5sum) != 0 ) {
+ if (conf->force_defaults
+ || user_prefers_old_conffile(cf->name, cf_backup) ) {
+ rename(cf_backup, root_filename);
+ }
+ }
+ unlink(cf_backup);
+ free(md5sum);
+ }
+
+ free(cf_backup);
+ free(root_filename);
+ }
+
+ return 0;
+}
+
+static int user_prefers_old_conffile(const char *file_name, const char *backup)
+{
+ char *response;
+ const char *short_file_name;
+
+ short_file_name = strrchr(file_name, '/');
+ if (short_file_name) {
+ short_file_name++;
+ } else {
+ short_file_name = file_name;
+ }
+
+ while (1) {
+ response = get_user_response(" Configuration file '%s'\n"
+ " ==> File on system created by you or by a script.\n"
+ " ==> File also in package provided by package maintainer.\n"
+ " What would you like to do about it ? Your options are:\n"
+ " Y or I : install the package maintainer's version\n"
+ " N or O : keep your currently-installed version\n"
+ " D : show the differences between the versions (if diff is installed)\n"
+ " The default action is to keep your current version.\n"
+ " *** %s (Y/I/N/O/D) [default=N] ? ", file_name, short_file_name);
+ if (strcmp(response, "y") == 0
+ || strcmp(response, "i") == 0
+ || strcmp(response, "yes") == 0) {
+ free(response);
+ return 0;
+ }
+
+ if (strcmp(response, "d") == 0) {
+ char *cmd;
+
+ free(response);
+ /* XXX: BUG rewrite to use exec or busybox's internal diff */
+ sprintf_alloc(&cmd, "diff -u %s %s", backup, file_name);
+ xsystem(cmd);
+ free(cmd);
+ printf(" [Press ENTER to continue]\n");
+ response = file_read_line_alloc(stdin);
+ free(response);
+ continue;
+ }
+
+ free(response);
+ return 1;
+ }
+}
+
+/* XXX: CLEANUP: I'd like to move all of the code for
+ creating/cleaning pkg->tmp_unpack_dir directly into pkg.c. (Then,
+ it would make sense to cleanup pkg->tmp_unpack_dir directly from
+ pkg_deinit for example). */
+static int cleanup_temporary_files(ipkg_conf_t *conf, pkg_t *pkg)
+{
+ DIR *tmp_dir;
+ struct dirent *dirent;
+ char *tmp_file;
+
+#ifdef IPKG_DEBUG_NO_TMP_CLEANUP
+#error
+ ipkg_message(conf, IPKG_DEBUG,
+ "%s: Not cleaning up %s since ipkg compiled with IPKG_DEBUG_NO_TMP_CLEANUP\n",
+ __FUNCTION__, pkg->tmp_unpack_dir);
+ return 0;
+#endif
+
+ if (pkg->tmp_unpack_dir && file_is_dir(pkg->tmp_unpack_dir)) {
+ tmp_dir = opendir(pkg->tmp_unpack_dir);
+ if (tmp_dir) {
+ while (1) {
+ dirent = readdir(tmp_dir);
+ if (dirent == NULL) {
+ break;
+ }
+ sprintf_alloc(&tmp_file, "%s/%s",
+ pkg->tmp_unpack_dir, dirent->d_name);
+ if (! file_is_dir(tmp_file)) {
+ unlink(tmp_file);
+ }
+ free(tmp_file);
+ }
+ closedir(tmp_dir);
+ rmdir(pkg->tmp_unpack_dir);
+ free(pkg->tmp_unpack_dir);
+ pkg->tmp_unpack_dir = NULL;
+ }
+ }
+
+ ipkg_message(conf, IPKG_INFO, "cleanup_temporary_files: pkg=%s local_filename=%s tmp_dir=%s\n",
+ pkg->name, pkg->local_filename, conf->tmp_dir);
+ if (pkg->local_filename && strncmp(pkg->local_filename, conf->tmp_dir, strlen(conf->tmp_dir)) == 0) {
+ unlink(pkg->local_filename);
+ free(pkg->local_filename);
+ pkg->local_filename = NULL;
+ }
+
+ return 0;
+}
+
+static char *backup_filename_alloc(const char *file_name)
+{
+ char *backup;
+
+ sprintf_alloc(&backup, "%s%s", file_name, IPKG_BACKUP_SUFFIX);
+
+ return backup;
+}
+
+int backup_make_backup(ipkg_conf_t *conf, const char *file_name)
+{
+ int err;
+ char *backup;
+
+ backup = backup_filename_alloc(file_name);
+ err = file_copy(file_name, backup);
+ if (err) {
+ ipkg_message(conf, IPKG_ERROR,
+ "%s: Failed to copy %s to %s\n",
+ __FUNCTION__, file_name, backup);
+ }
+
+ free(backup);
+
+ return err;
+}
+
+static int backup_exists_for(const char *file_name)
+{
+ int ret;
+ char *backup;
+
+ backup = backup_filename_alloc(file_name);
+
+ ret = file_exists(backup);
+
+ free(backup);
+
+ return ret;
+}
+
+static int backup_remove(const char *file_name)
+{
+ char *backup;
+
+ backup = backup_filename_alloc(file_name);
+ unlink(backup);
+ free(backup);
+
+ return 0;
+}
+
+
+
+#ifdef CONFIG_IPKG_PROCESS_ACTIONS
+
+int ipkg_remove_packages(ipkg_conf_t *conf, pkg_vec_t *pkgs_to_remove)
+{
+ /* first, remove the packages that need removing */
+ for (i = 0 ; i < pkgs_to_remove->len; i++ ) {
+ pkg_t *pkg = pkgs_to_remove->pkgs[i];
+ err = ipkg_remove_pkg(conf, pkg);
+ if (err) return err;
+ }
+ return 0;
+}
+
+int ipkg_process_actions_sanity_check(ipkg_conf_t *conf, pkg_vec_t *pkgs_to_remove, pkg_vec_t *pkgs_superseded, pkg_vec_t *pkgs_to_install)
+{
+ int i;
+ /* now one more pass checking on the ones that need to be installed */
+ for (i = 0 ; i < pkgs_to_install->len; i++ ) {
+ pkg_t *pkg = pkgs_to_install->pkgs[i];
+ if (pkg->dest == NULL)
+ pkg->dest = conf->default_dest;
+
+ pkg->state_want = SW_INSTALL;
+
+ /* Abhaya: conflicts check */
+ err = check_conflicts_for(conf, pkg);
+ if (err) { return err; }
+ }
+ return 0;
+}
+
+int ipkg_process_actions_unpack_packages(ipkg_conf_t *conf, pkg_vec_t *pkgs_to_remove, pkg_vec_t *pkgs_to_install)
+{
+ int i;
+ /* now one more pass checking on the ones that need to be installed */
+ for (i = 0 ; i < pkgs_to_install->len; i++ ) {
+ pkg_t *pkg = pkgs_to_install->pkgs[i];
+
+ /* XXX: FEATURE: Need to really support Provides/Replaces: here at some point */
+ pkg_vec_t *replacees = pkg_vec_alloc();
+ pkg_get_installed_replacees(conf, pkg, replacees);
+
+ /* XXX: BUG: we really should treat replacement more like an upgrade
+ * Instead, we're going to remove the replacees
+ */
+ err = pkg_remove_installed_replacees(conf, replacees);
+ if (err) return err;
+ pkg->state_flag |= SF_REMOVED_REPLACEES;
+ }
+ return 0;
+}
+
+int ipkg_process_actions_unpack_packages(ipkg_conf_t *conf, pkg_vec_t *pkgs_to_remove, pkg_vec_t *pkgs_to_install)
+{
+ int i;
+ /* now one more pass checking on the ones that need to be installed */
+ for (i = 0 ; i < pkgs_to_install->len; i++ ) {
+ pkg_t *pkg = pkgs_to_install->pkgs[i];
+ if (pkg->local_filename == NULL) {
+ err = ipkg_download_pkg(conf, pkg, conf->tmp_dir);
+ if (err) {
+ ipkg_message(conf, IPKG_ERROR,
+ "Failed to download %s. Perhaps you need to run 'ipkg update'?\n",
+ pkg->name);
+ return err;
+ }
+ }
+ if (pkg->tmp_unpack_dir == NULL) {
+ err = unpack_pkg_control_files(conf, pkg);
+ if (err) return err;
+ }
+ }
+ return 0;
+}
+
+int ipkg_process_actions_prerm(ipkg_conf_t *conf, pkg_vec_t *pkgs_to_install)
+{
+ int i;
+ /* now one more pass checking on the ones that need to be installed */
+ for (i = 0 ; i < pkgs_to_install->len; i++ ) {
+ pkg_t *pkg = pkgs_to_install->pkgs[i];
+ pkg_t *old_pkg = pkg->old_pkg;
+
+ err = prerm_upgrade_old_pkg(conf, pkg, old_pkg);
+ if (err) return err;
+
+ err = prerm_deconfigure_conflictors(conf, pkg, replacees);
+ if (err) return err;
+
+ err = preinst_configure(conf, pkg, old_pkg);
+ if (err) return err;
+
+ err = backup_modified_conffiles(conf, pkg, old_pkg);
+ if (err) return err;
+
+ err = postrm_upgrade_old_pkg(conf, pkg, old_pkg);
+ if (err) return err;
+ }
+ return 0;
+}
+
+int ipkg_process_actions_install(ipkg_conf_t *conf, pkg_vec_t *pkgs_to_install)
+{
+ int i;
+ /* now one more pass checking on the ones that need to be installed */
+ for (i = 0 ; i < pkgs_to_install->len; i++ ) {
+ pkg_t *pkg = pkgs_to_install->pkgs[i];
+ pkg_t *old_pkg = pkg->old_pkg;
+
+ if (old_pkg) {
+ old_pkg->state_want = SW_DEINSTALL;
+
+ if (old_pkg->state_flag & SF_NOPRUNE) {
+ ipkg_message(conf, IPKG_INFO,
+ " not removing obsolesced files because package marked noprune\n");
+ } else {
+ ipkg_message(conf, IPKG_INFO,
+ " removing obsolesced files\n");
+ remove_obsolesced_files(conf, pkg, old_pkg);
+ }
+ }
+
+ ipkg_message(conf, IPKG_INFO,
+ " installing maintainer scripts\n");
+ install_maintainer_scripts(conf, pkg, old_pkg);
+
+ /* the following just returns 0 */
+ remove_disappeared(conf, pkg);
+
+ ipkg_message(conf, IPKG_INFO,
+ " installing data files\n");
+ install_data_files(conf, pkg);
+
+ ipkg_message(conf, IPKG_INFO,
+ " resolving conf files\n");
+ resolve_conffiles(conf, pkg);
+
+ pkg->state_status = SS_UNPACKED;
+
+ if (old_pkg) {
+ old_pkg->state_status = SS_NOT_INSTALLED;
+ }
+
+ time(&pkg->installed_time);
+
+ ipkg_message(conf, IPKG_INFO,
+ " cleanup temp files\n");
+ cleanup_temporary_files(conf, pkg);
+
+ if (pkg->parent)
+ pkg->parent->state_status = pkg->state_status;
+ }
+ return 0;
+}
+
+int ipkg_process_actions_unwind_prerm(ipkg_conf_t *conf, pkg_vec_t *pkgs_to_install)
+{
+ int i;
+ /* now one more pass checking on the ones that need to be installed */
+ for (i = 0 ; i < pkgs_to_install->len; i++ ) {
+ pkg_t *pkg = pkgs_to_install->pkgs[i];
+ pkg_t *old_pkg = pkg->old_pkg;
+
+ if (old_pkg) {
+ if (old_pkg->state_flags & SF_POSTRM_UPGRADE)
+ postrm_upgrade_old_pkg_unwind(conf, pkg, old_pkg);
+ if (old_pkg->state_flags & SF_CHECK_DATA_FILE_CLASHES)
+ check_data_file_clashes_unwind(conf, pkg, old_pkg);
+ if (old_pkg->state_flags & SF_BACKUP_MODIFIED_CONFFILES)
+ backup_modified_conffiles_unwind(conf, pkg, old_pkg);
+ if (old_pkg->state_flags & SF_PREINST_CONFIGURE)
+ preinst_configure_unwind(conf, pkg, old_pkg);
+ if (old_pkg->state_flags & SF_DECONFIGURE_CONFLICTORS)
+ prerm_deconfigure_conflictors_unwind(conf, pkg, replacees);
+ if (old_pkg->state_flags & SF_PRERM_UPGRADE)
+ prerm_upgrade_old_pkg_unwind(conf, pkg, old_pkg);
+
+ if (old_pkg->state_flags & SF_REMOVED_REPLACEES)
+ remove_installed_replacees_unwind(conf, pkg, old_pkg);
+
+ }
+ }
+ return 0;
+}
+
+/*
+ * Perform all the actions.
+ *
+ * pkgs_to_remove are packages marked for removal.
+ * pkgs_superseded are the old packages being replaced by upgrades.
+ *
+ * Assumes pkgs_to_install includes all dependences, recursively, sorted in installable order.
+ */
+int ipkg_process_actions(ipkg_conf_t *conf, pkg_vec_t *pkgs_to_remove, pkg_vec_t *pkgs_superseded, pkg_vec_t *pkgs_to_install)
+{
+ int err;
+ int i;
+
+ err = ipkg_remove_packages(conf, pkgs_to_remove);
+ if (err) return err;
+
+ err = ipkg_process_actions_sanity_check(conf, pkgs_superseded, pkgs_to_install);
+ if (err) return err;
+
+ err = ipkg_process_actions_remove_replacees(conf, pkgs_to_install);
+ if (err) goto UNWIND;
+
+ /* @@@@ look at ipkg_install_pkg for handling replacements */
+ err = ipkg_process_actions_unpack_packages(conf, pkgs_to_install);
+ if (err) goto UNWIND;
+
+ /*
+ * Now that we have the packages unpacked, we can look for data
+ * file clashes. First, we mark the files from the superseded
+ * packages as obsolete. Then we scan the files in
+ * pkgs_to_install, and only complain about clashes with
+ * non-obsolete files.
+ */
+
+ err = ipkg_process_actions_check_data_file_clashes(conf, pkgs_superseded, pkgs_to_install);
+ if (err) goto UNWIND;
+
+ /* this was before checking data file clashes */
+ err = ipkg_process_actions_prerm(conf, pkgs_superseded, pkgs_to_install);
+ if (err) goto UNWIND;
+
+ /* point of no return: no unwinding after this */
+ err = ipkg_process_actions_install(conf, pkgs_to_install);
+ if (err) return err;
+
+ ipkg_message(conf, IPKG_INFO, "Done.\n");
+ return 0;
+
+ UNWIND:
+ ipkg_process_actions_unwind(conf, pkgs_to_install);
+
+ ipkg_message(conf, IPKG_INFO,
+ " cleanup temp files\n");
+ cleanup_temporary_files(conf, pkg);
+
+ ipkg_message(conf, IPKG_INFO,
+ "Failed.\n");
+ return err;
+}
+
+#endif
diff -ruN busybox-1.00-orig/archival/libipkg/ipkg_install.h busybox-1.00+ipkg-0.99.154/archival/libipkg/ipkg_install.h
--- busybox-1.00-orig/archival/libipkg/ipkg_install.h 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/ipkg_install.h 2005-10-26 17:36:46.000000000 +0200
@@ -0,0 +1,35 @@
+/* ipkg_install.h - the itsy package management system
+
+ Carl D. Worth
+
+ Copyright (C) 2001 University of Southern California
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#ifndef IPKG_INSTALL_H
+#define IPKG_INSTALL_H
+
+#include "pkg.h"
+#include "ipkg_conf.h"
+
+ipkg_error_t ipkg_install_by_name(ipkg_conf_t *conf, const char *pkg_name);
+ipkg_error_t ipkg_install_multi_by_name(ipkg_conf_t *conf, const char *pkg_name);
+int ipkg_install_from_file(ipkg_conf_t *conf, const char *filename);
+int ipkg_install_pkg(ipkg_conf_t *conf, pkg_t *pkg);
+int satisfy_dependencies_for(ipkg_conf_t *conf, pkg_t *pkg);
+
+int ipkg_satisfy_all_dependences(ipkg_conf_t *conf);
+
+int pkg_mark_dependencies_for_installation(ipkg_conf_t *conf, pkg_t *pkg_name, pkg_vec_t *pkgs_needed);
+int name_mark_dependencies_for_installation(ipkg_conf_t *conf, const char *pkg_name, pkg_vec_t *pkgs_needed);
+
+#endif
diff -ruN busybox-1.00-orig/archival/libipkg/ipkg_message.c busybox-1.00+ipkg-0.99.154/archival/libipkg/ipkg_message.c
--- busybox-1.00-orig/archival/libipkg/ipkg_message.c 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/ipkg_message.c 2005-10-26 17:36:46.000000000 +0200
@@ -0,0 +1,61 @@
+/* ipkg_message.c - the itsy package management system
+
+ Copyright (C) 2003 Daniele Nicolodi <daniele@grinta.net>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+
+#include "ipkg.h"
+#include "ipkg_conf.h"
+#include "ipkg_message.h"
+
+#ifndef IPKG_LIB
+
+void
+ipkg_message (ipkg_conf_t * conf, message_level_t level, char *fmt, ...)
+{
+ va_list ap;
+
+ if (conf && (conf->verbosity < level))
+ {
+ return;
+ }
+ else
+ {
+
+ va_start (ap, fmt);
+ vprintf (fmt, ap);
+ va_end (ap);
+ }
+}
+
+#else
+
+#include "libipkg.h"
+
+//#define ipkg_message(conf, level, fmt, arg...) ipkg_cb_message(conf, level, fmt, ## arg)
+
+void
+ipkg_message (ipkg_conf_t * conf, message_level_t level, char *fmt, ...)
+{
+ va_list ap;
+ char ts[256];
+
+ if (ipkg_cb_message)
+ {
+ va_start (ap, fmt);
+ vsnprintf (ts,256,fmt, ap);
+ va_end (ap);
+ ipkg_cb_message(conf,level,ts);
+ }
+}
+#endif
diff -ruN busybox-1.00-orig/archival/libipkg/ipkg_message.h busybox-1.00+ipkg-0.99.154/archival/libipkg/ipkg_message.h
--- busybox-1.00-orig/archival/libipkg/ipkg_message.h 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/ipkg_message.h 2005-10-26 17:36:46.000000000 +0200
@@ -0,0 +1,32 @@
+/* ipkg_message.h - the itsy package management system
+
+ Copyright (C) 2003 Daniele Nicolodi <daniele@grinta.net>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#ifndef _IPKG_MESSAGE_H_
+#define _IPKG_MESSAGE_H_
+
+#include "ipkg.h"
+#include "ipkg_conf.h"
+
+typedef enum {
+ IPKG_ERROR, /* error conditions */
+ IPKG_NOTICE, /* normal but significant condition */
+ IPKG_INFO, /* informational message */
+ IPKG_DEBUG, /* debug level message */
+ IPKG_DEBUG2, /* more debug level message */
+} message_level_t;
+
+extern void ipkg_message(ipkg_conf_t *conf, message_level_t level, char *fmt, ...);
+
+#endif /* _IPKG_MESSAGE_H_ */
diff -ruN busybox-1.00-orig/archival/libipkg/ipkg_remove.c busybox-1.00+ipkg-0.99.154/archival/libipkg/ipkg_remove.c
--- busybox-1.00-orig/archival/libipkg/ipkg_remove.c 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/ipkg_remove.c 2005-10-26 17:45:58.000000000 +0200
@@ -0,0 +1,381 @@
+/* ipkg_remove.c - the itsy package management system
+
+ Carl D. Worth
+
+ Copyright (C) 2001 University of Southern California
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#include "ipkg.h"
+#include "ipkg_message.h"
+
+#include <glob.h>
+
+#include "ipkg_remove.h"
+
+#include "file_util.h"
+#include "sprintf_alloc.h"
+#include "str_util.h"
+
+#include "ipkg_cmd.h"
+
+static int remove_data_files_and_list(ipkg_conf_t *conf, pkg_t *pkg);
+static int remove_maintainer_scripts_except_postrm(ipkg_conf_t *conf, pkg_t *pkg);
+static int remove_postrm(ipkg_conf_t *conf, pkg_t *pkg);
+
+/*
+ * Returns number of the number of packages depending on the packages provided by this package.
+ * Every package implicitly provides itself.
+ */
+int pkg_has_installed_dependents(ipkg_conf_t *conf, abstract_pkg_t *parent_apkg, pkg_t *pkg, abstract_pkg_t *** pdependents)
+{
+ int nprovides = pkg->provides_count;
+ abstract_pkg_t **provides = pkg->provides;
+ int n_installed_dependents = 0;
+ int i;
+ for (i = 0; i <= nprovides; i++) {
+ abstract_pkg_t *providee = provides[i];
+ abstract_pkg_t **dependers = providee->depended_upon_by;
+ abstract_pkg_t *dep_ab_pkg;
+ if (dependers == NULL)
+ continue;
+ while ((dep_ab_pkg = *dependers++) != NULL) {
+ if (dep_ab_pkg->state_status == SS_INSTALLED){
+ n_installed_dependents++;
+ }
+ }
+
+ }
+ /* if caller requested the set of installed dependents */
+ if (pdependents) {
+ int p = 0;
+ abstract_pkg_t **dependents = (abstract_pkg_t **)malloc((n_installed_dependents+1)*sizeof(abstract_pkg_t *));
+
+ if ( dependents == NULL ){
+ fprintf(stderr,"%s Unable to allocate memory. REPORT THIS BUG IN BUGZILLA PLEASE\n", __FUNCTION__);
+ return -1;
+ }
+
+ *pdependents = dependents;
+ for (i = 0; i <= nprovides; i++) {
+ abstract_pkg_t *providee = provides[i];
+ abstract_pkg_t **dependers = providee->depended_upon_by;
+ abstract_pkg_t *dep_ab_pkg;
+ if (dependers == NULL)
+ continue;
+ while ((dep_ab_pkg = *dependers++) != NULL) {
+ if (dep_ab_pkg->state_status == SS_INSTALLED && !(dep_ab_pkg->state_flag & SF_MARKED)) {
+ dependents[p++] = dep_ab_pkg;
+ dep_ab_pkg->state_flag |= SF_MARKED;
+ }
+ }
+ }
+ dependents[p] = NULL;
+ /* now clear the marks */
+ for (i = 0; i < p; i++) {
+ abstract_pkg_t *dep_ab_pkg = dependents[i];
+ dep_ab_pkg->state_flag &= ~SF_MARKED;
+ }
+ }
+ return n_installed_dependents;
+}
+
+int ipkg_remove_dependent_pkgs (ipkg_conf_t *conf, pkg_t *pkg, abstract_pkg_t **dependents)
+{
+ int i;
+ int a;
+ int count;
+ pkg_vec_t *dependent_pkgs = pkg_vec_alloc();
+ abstract_pkg_t * ab_pkg;
+
+ if((ab_pkg = pkg->parent) == NULL){
+ fprintf(stderr, "%s: unable to get dependent pkgs. pkg %s isn't in hash table\n",
+ __FUNCTION__, pkg->name);
+ return 0;
+ }
+
+ if (dependents == NULL)
+ return 0;
+
+ // here i am using the dependencies_checked
+ if (ab_pkg->dependencies_checked == 2) // variable to make out whether this package
+ return 0; // has already been encountered in the process
+ // of marking packages for removal - Karthik
+ ab_pkg->dependencies_checked = 2;
+
+ i = 0;
+ count = 1;
+ while (dependents [i] != NULL) {
+ abstract_pkg_t *dep_ab_pkg = dependents[i];
+
+ if (dep_ab_pkg->dependencies_checked == 2){
+ i++;
+ continue;
+ }
+ if (dep_ab_pkg->state_status == SS_INSTALLED) {
+ for (a = 0; a < dep_ab_pkg->pkgs->len; a++) {
+ pkg_t *dep_pkg = dep_ab_pkg->pkgs->pkgs[a];
+ if (dep_pkg->state_status == SS_INSTALLED) {
+ pkg_vec_insert(dependent_pkgs, dep_pkg);
+ count++;
+ }
+ }
+ }
+ i++;
+ /* 1 - to keep track of visited ab_pkgs when checking for possiblility of a broken removal of pkgs.
+ * 2 - to keep track of pkgs whose deps have been checked alrdy - Karthik */
+ }
+
+ if (count == 1)
+ return 0;
+
+
+ for (i = 0; i < dependent_pkgs->len; i++) {
+ int err = ipkg_remove_pkg(conf, dependent_pkgs->pkgs[i]);
+ if (err)
+ return err;
+ }
+ return 0;
+}
+
+static int user_prefers_removing_dependents(ipkg_conf_t *conf, abstract_pkg_t *abpkg, pkg_t *pkg, abstract_pkg_t **dependents)
+{
+ abstract_pkg_t *dep_ab_pkg;
+ ipkg_message(conf, IPKG_ERROR, "Package %s is depended upon by packages:\n", pkg->name);
+ while ((dep_ab_pkg = *dependents++) != NULL) {
+ if (dep_ab_pkg->state_status == SS_INSTALLED)
+ ipkg_message(conf, IPKG_ERROR, "\t%s\n", dep_ab_pkg->name);
+ }
+ ipkg_message(conf, IPKG_ERROR, "These might cease to work if package %s is removed.\n\n", pkg->name);
+ ipkg_message(conf, IPKG_ERROR, "");
+ ipkg_message(conf, IPKG_ERROR, "You can force removal of this package with -force-depends.\n");
+ ipkg_message(conf, IPKG_ERROR, "You can force removal of this package and its dependents\n");
+ ipkg_message(conf, IPKG_ERROR, "with -force-removal-of-dependent-packages or -recursive\n");
+ ipkg_message(conf, IPKG_ERROR, "or by setting option force_removal_of_dependent_packages\n");
+ ipkg_message(conf, IPKG_ERROR, "in ipkg.conf.\n");
+ return 0;
+}
+
+int ipkg_remove_pkg(ipkg_conf_t *conf, pkg_t *pkg)
+{
+ int err;
+ abstract_pkg_t *parent_pkg = NULL;
+
+ if (pkg->essential) {
+ if (conf->force_removal_of_essential_packages) {
+ fprintf(stderr, "WARNING: Removing essential package %s under your coercion.\n"
+ "\tIf your system breaks, you get to keep both pieces\n",
+ pkg->name);
+ } else {
+ fprintf(stderr, "ERROR: Refusing to remove essential package %s.\n"
+ "\tRemoving an essential package may lead to an unusable system, but if\n"
+ "\tyou enjoy that kind of pain, you can force ipkg to proceed against\n"
+ "\tits will with the option: -force-removal-of-essential-packages\n",
+ pkg->name);
+ return IPKG_PKG_IS_ESSENTIAL;
+ }
+ }
+
+ if ((parent_pkg = pkg->parent) == NULL)
+ return 0;
+
+ /* only attempt to remove dependent installed packages if
+ * force_depends is not specified or the package is being
+ * replaced.
+ */
+ if (!conf->force_depends
+ && !(pkg->state_flag & SF_REPLACE)) {
+ abstract_pkg_t **dependents;
+ int has_installed_dependents =
+ pkg_has_installed_dependents(conf, parent_pkg, pkg, &dependents);
+
+ if (has_installed_dependents) {
+ /*
+ * if this package is depended up by others, then either we should
+ * not remove it or we should remove it and all of its dependents
+ */
+
+ if (!conf->force_removal_of_dependent_packages
+ && !user_prefers_removing_dependents(conf, parent_pkg, pkg, dependents)) {
+ return IPKG_PKG_HAS_DEPENDENTS;
+ }
+
+ /* remove packages depending on this package - Karthik */
+ err = ipkg_remove_dependent_pkgs (conf, pkg, dependents);
+ free(dependents);
+ if (err) return err;
+ }
+ }
+
+ printf("Removing package %s from %s...\n", pkg->name, pkg->dest->name);
+ fflush(stdout);
+
+ pkg->state_flag |= SF_FILELIST_CHANGED;
+
+ pkg->state_want = SW_DEINSTALL;
+ ipkg_state_changed++;
+
+ pkg_run_script(conf, pkg, "prerm", "remove");
+
+ /* DPKG_INCOMPATIBILITY: dpkg is slightly different here. It
+ maintains an empty filelist rather than deleting it. That seems
+ like a big pain, and I don't see that that should make a big
+ difference, but for anyone who wants tighter compatibility,
+ feel free to fix this. */
+ remove_data_files_and_list(conf, pkg);
+
+ pkg_run_script(conf, pkg, "postrm", "remove");
+
+ remove_maintainer_scripts_except_postrm(conf, pkg);
+
+ /* Aman Gupta - Since ipkg is made for handheld devices with limited
+ * space, it doesn't make sense to leave extra configurations, files,
+ * and maintainer scripts left around. So, we make remove like purge,
+ * and take out all the crap :) */
+
+ remove_postrm(conf, pkg);
+ pkg->state_status = SS_NOT_INSTALLED;
+
+ if (parent_pkg)
+ parent_pkg->state_status = SS_NOT_INSTALLED;
+
+ return 0;
+}
+
+int ipkg_purge_pkg(ipkg_conf_t *conf, pkg_t *pkg)
+{
+ ipkg_remove_pkg(conf, pkg);
+ return 0;
+}
+
+static int remove_data_files_and_list(ipkg_conf_t *conf, pkg_t *pkg)
+{
+ str_list_t installed_dirs;
+ str_list_t *installed_files;
+ str_list_elt_t *iter;
+ char *file_name;
+ conffile_t *conffile;
+ int removed_a_dir;
+ pkg_t *owner;
+
+ str_list_init(&installed_dirs);
+ installed_files = pkg_get_installed_files(pkg);
+
+ for (iter = installed_files->head; iter; iter = iter->next) {
+ file_name = iter->data;
+
+ if (file_is_dir(file_name)) {
+ str_list_append(&installed_dirs, strdup(file_name));
+ continue;
+ }
+
+ conffile = pkg_get_conffile(pkg, file_name);
+ if (conffile) {
+ /* XXX: QUESTION: Is this right? I figure we only need to
+ save the conffile if it has been modified. Is that what
+ dpkg does? Or does dpkg preserve all conffiles? If so,
+ this seems like a better thing to do to conserve
+ space. */
+ if (conffile_has_been_modified(conf, conffile)) {
+ printf(" not deleting modified conffile %s\n", file_name);
+ fflush(stdout);
+ continue;
+ }
+ }
+
+ ipkg_message(conf, IPKG_INFO, " deleting %s (noaction=%d)\n", file_name, conf->noaction);
+ if (!conf->noaction)
+ unlink(file_name);
+ }
+
+ if (!conf->noaction) {
+ do {
+ removed_a_dir = 0;
+ for (iter = installed_dirs.head; iter; iter = iter->next) {
+ file_name = iter->data;
+
+ if (rmdir(file_name) == 0) {
+ ipkg_message(conf, IPKG_INFO, " deleting %s\n", file_name);
+ removed_a_dir = 1;
+ str_list_remove(&installed_dirs, &iter);
+ }
+ }
+ } while (removed_a_dir);
+ }
+
+ pkg_free_installed_files(pkg);
+ /* We have to remove the file list now, so that
+ find_pkg_owning_file does not always just report this package */
+ pkg_remove_installed_files_list(conf, pkg);
+
+ /* Don't print warning for dirs that are provided by other packages */
+ for (iter = installed_dirs.head; iter; iter = iter->next) {
+ file_name = iter->data;
+
+ owner = file_hash_get_file_owner(conf, file_name);
+ if (owner) {
+ free(iter->data);
+ iter->data = NULL;
+ str_list_remove(&installed_dirs, &iter);
+ }
+ }
+
+ /* cleanup */
+ for (iter = installed_dirs.head; iter; iter = iter->next) {
+ free(iter->data);
+ iter->data = NULL;
+ }
+ str_list_deinit(&installed_dirs);
+
+ return 0;
+}
+
+static int remove_maintainer_scripts_except_postrm(ipkg_conf_t *conf, pkg_t *pkg)
+{
+ int i, err;
+ char *globpattern;
+ glob_t globbuf;
+
+ if (conf->noaction) return 0;
+
+ sprintf_alloc(&globpattern, "%s/%s.*",
+ pkg->dest->info_dir, pkg->name);
+ err = glob(globpattern, 0, NULL, &globbuf);
+ free(globpattern);
+ if (err) {
+ return 0;
+ }
+
+ for (i = 0; i < globbuf.gl_pathc; i++) {
+ if (str_ends_with(globbuf.gl_pathv[i], ".postrm")) {
+ continue;
+ }
+ unlink(globbuf.gl_pathv[i]);
+ }
+ globfree(&globbuf);
+
+ return 0;
+}
+
+static int remove_postrm(ipkg_conf_t *conf, pkg_t *pkg)
+{
+ char *postrm_file_name;
+
+ if (conf->noaction) return 0;
+
+ sprintf_alloc(&postrm_file_name, "%s/%s.postrm",
+ pkg->dest->info_dir, pkg->name);
+ unlink(postrm_file_name);
+ free(postrm_file_name);
+
+ return 0;
+}
diff -ruN busybox-1.00-orig/archival/libipkg/ipkg_remove.h busybox-1.00+ipkg-0.99.154/archival/libipkg/ipkg_remove.h
--- busybox-1.00-orig/archival/libipkg/ipkg_remove.h 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/ipkg_remove.h 2005-10-26 17:36:46.000000000 +0200
@@ -0,0 +1,29 @@
+/* ipkg_remove.h - the itsy package management system
+
+ Carl D. Worth
+
+ Copyright (C) 2001 University of Southern California
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#ifndef IPKG_REMOVE_H
+#define IPKG_REMOVE_H
+
+#include "pkg.h"
+#include "ipkg_conf.h"
+
+int ipkg_remove_pkg(ipkg_conf_t *conf, pkg_t *pkg);
+int ipkg_purge_pkg(ipkg_conf_t *conf, pkg_t *pkg);
+int possible_broken_removal_of_packages (ipkg_conf_t *conf, pkg_t *pkg);
+int pkg_has_installed_dependents(ipkg_conf_t *conf, abstract_pkg_t *parent_apkg, pkg_t *pkg, abstract_pkg_t *** pdependents);
+
+#endif
diff -ruN busybox-1.00-orig/archival/libipkg/ipkg_upgrade.c busybox-1.00+ipkg-0.99.154/archival/libipkg/ipkg_upgrade.c
--- busybox-1.00-orig/archival/libipkg/ipkg_upgrade.c 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/ipkg_upgrade.c 2005-10-26 17:36:46.000000000 +0200
@@ -0,0 +1,77 @@
+/* ipkg_upgrade.c - the itsy package management system
+
+ Carl D. Worth
+ Copyright (C) 2001 University of Southern California
+
+ Copyright (C) 2003 Daniele Nicolodi <daniele@grinta.net>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#include "ipkg.h"
+#include "ipkg_install.h"
+#include "ipkg_message.h"
+
+int ipkg_upgrade_pkg(ipkg_conf_t *conf, pkg_t *old)
+{
+ pkg_t *new;
+ int cmp;
+ char *old_version, *new_version;
+
+ if (old->state_flag & SF_HOLD) {
+ ipkg_message(conf, IPKG_NOTICE,
+ "Not upgrading package %s which is marked "
+ "hold (flags=%#x)\n", old->name, old->state_flag);
+ return 0;
+ }
+
+ new = pkg_hash_fetch_best_installation_candidate_by_name(conf, old->name);
+ if (new == NULL) {
+ old_version = pkg_version_str_alloc(old);
+ ipkg_message(conf, IPKG_NOTICE,
+ "Assuming locally installed package %s (%s) "
+ "is up to date.\n", old->name, old_version);
+ free(old_version);
+ return 0;
+ }
+
+ old_version = pkg_version_str_alloc(old);
+ new_version = pkg_version_str_alloc(new);
+
+ cmp = pkg_compare_versions(old, new);
+ ipkg_message(conf, IPKG_DEBUG,
+ "comparing visible versions of pkg %s:"
+ "\n\t%s is installed "
+ "\n\t%s is available "
+ "\n\t%d was comparison result\n",
+ old->name, old_version, new_version, cmp);
+ if (cmp == 0) {
+ ipkg_message(conf, IPKG_INFO,
+ "Package %s (%s) installed in %s is up to date.\n",
+ old->name, old_version, old->dest->name);
+ free(old_version);
+ free(new_version);
+ return 0;
+ } else if (cmp > 0) {
+ ipkg_message(conf, IPKG_NOTICE,
+ "Not downgrading package %s on %s from %s to %s.\n",
+ old->name, old->dest->name, old_version, new_version);
+ free(old_version);
+ free(new_version);
+ return 0;
+ } else if (cmp < 0) {
+ new->dest = old->dest;
+ old->state_want = SW_DEINSTALL;
+ }
+
+ new->state_flag |= SF_USER;
+ return ipkg_install_pkg(conf, new);
+}
diff -ruN busybox-1.00-orig/archival/libipkg/ipkg_upgrade.h busybox-1.00+ipkg-0.99.154/archival/libipkg/ipkg_upgrade.h
--- busybox-1.00-orig/archival/libipkg/ipkg_upgrade.h 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/ipkg_upgrade.h 2005-10-26 17:36:46.000000000 +0200
@@ -0,0 +1,18 @@
+/* ipkg_upgrade.c - the itsy package management system
+
+ Copyright (C) 2003 Daniele Nicolodi <daniele@grinta.net>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#include "ipkg.h"
+
+int ipkg_upgrade_pkg(ipkg_conf_t *conf, pkg_t *old);
diff -ruN busybox-1.00-orig/archival/libipkg/ipkg_utils.c busybox-1.00+ipkg-0.99.154/archival/libipkg/ipkg_utils.c
--- busybox-1.00-orig/archival/libipkg/ipkg_utils.c 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/ipkg_utils.c 2005-10-26 17:36:46.000000000 +0200
@@ -0,0 +1,181 @@
+/* ipkg_utils.c - the itsy package management system
+
+ Steven M. Ayer
+
+ Copyright (C) 2002 Compaq Computer Corporation
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#include "ipkg.h"
+#include <errno.h>
+#include <ctype.h>
+#include <sys/vfs.h>
+
+#include "ipkg_utils.h"
+#include "pkg.h"
+#include "pkg_hash.h"
+
+struct errlist* error_list;
+
+int get_available_blocks(char * filesystem)
+{
+ struct statfs sfs;
+
+ if(statfs(filesystem, &sfs)){
+ fprintf(stderr, "bad statfs\n");
+ return 0;
+ }
+ /* fprintf(stderr, "reported fs type %x\n", sfs.f_type); */
+ return ((sfs.f_bavail * sfs.f_bsize) / 1024);
+}
+
+char **read_raw_pkgs_from_file(const char *file_name)
+{
+ FILE *fp;
+ char **ret;
+
+ if(!(fp = fopen(file_name, "r"))){
+ fprintf(stderr, "can't get %s open for read\n", file_name);
+ return NULL;
+ }
+
+ ret = read_raw_pkgs_from_stream(fp);
+
+ fclose(fp);
+
+ return ret;
+}
+
+char **read_raw_pkgs_from_stream(FILE *fp)
+{
+ char **raw = NULL, *buf, *scout;
+ int count = 0;
+ size_t size = 512;
+
+ buf = malloc (size);
+
+ while (fgets(buf, size, fp)) {
+ while (strlen (buf) == (size - 1)
+ && buf[size-2] != '\n') {
+ size_t o = size - 1;
+ size *= 2;
+ buf = realloc (buf, size);
+ if (fgets (buf + o, size - o, fp) == NULL)
+ break;
+ }
+
+ if(!(count % 50))
+ raw = realloc(raw, (count + 50) * sizeof(char *));
+
+ if((scout = strchr(buf, '\n')))
+ *scout = '\0';
+
+ raw[count++] = strdup(buf);
+ }
+
+ raw = realloc(raw, (count + 1) * sizeof(char *));
+ raw[count] = NULL;
+
+ free (buf);
+
+ return raw;
+}
+
+/* something to remove whitespace, a hash pooper */
+char *trim_alloc(char *line)
+{
+ char *new;
+ char *dest, *src, *end;
+
+ new = malloc(strlen(line) + 1);
+ if ( new == NULL ){
+ fprintf(stderr,"%s: Unable to allocate memory\n",__FUNCTION__);
+ return NULL;
+ }
+ dest = new, src = line, end = line + (strlen(line) - 1);
+
+ /* remove it from the front */
+ while(src &&
+ isspace(*src) &&
+ *src)
+ src++;
+ /* and now from the back */
+ while((end > src) &&
+ isspace(*end))
+ end--;
+ end++;
+ *end = '\0';
+ strcpy(new, src);
+ /* this does from the first space
+ * blasting away any versions stuff in depends
+ while(src &&
+ !isspace(*src) &&
+ *src)
+ *dest++ = *src++;
+ *dest = '\0';
+ */
+
+ return new;
+}
+
+int line_is_blank(const char *line)
+{
+ const char *s;
+
+ for (s = line; *s; s++) {
+ if (!isspace(*s))
+ return 0;
+ }
+ return 1;
+}
+
+void push_error_list(struct errlist ** errors, char * msg){
+ struct errlist *err_lst_tmp;
+
+
+ err_lst_tmp = malloc ( sizeof (err_lst_tmp) );
+ err_lst_tmp->errmsg=strdup(msg) ;
+ err_lst_tmp->next = *errors;
+ *errors = err_lst_tmp;
+}
+
+
+void reverse_error_list(struct errlist **errors){
+ struct errlist *result=NULL;
+ struct errlist *current= *errors;
+ struct errlist *next;
+
+ while ( current != NULL ) {
+ next = current->next;
+ current->next=result;
+ result=current;
+ current=next;
+ }
+ *errors=result;
+
+}
+
+
+void free_error_list(struct errlist **errors){
+ struct errlist *current = *errors;
+
+ while (current != NULL) {
+ free(current->errmsg);
+ current = (*errors)->next;
+ free(*errors);
+ *errors = current;
+ }
+
+
+}
+
+
diff -ruN busybox-1.00-orig/archival/libipkg/ipkg_utils.h busybox-1.00+ipkg-0.99.154/archival/libipkg/ipkg_utils.h
--- busybox-1.00-orig/archival/libipkg/ipkg_utils.h 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/ipkg_utils.h 2005-10-26 17:36:46.000000000 +0200
@@ -0,0 +1,29 @@
+/* ipkg_utils.h - the itsy package management system
+
+ Steven M. Ayer
+
+ Copyright (C) 2002 Compaq Computer Corporation
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#ifndef IPKG_UTILS_H
+#define IPKG_UTILS_H
+
+#include "pkg.h"
+
+int get_available_blocks(char * filesystem);
+char **read_raw_pkgs_from_file(const char *file_name);
+char **read_raw_pkgs_from_stream(FILE *fp);
+char *trim_alloc(char * line);
+int line_is_blank(const char *line);
+
+#endif
diff -ruN busybox-1.00-orig/archival/libipkg/libipkg.c busybox-1.00+ipkg-0.99.154/archival/libipkg/libipkg.c
--- busybox-1.00-orig/archival/libipkg/libipkg.c 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/libipkg.c 2005-10-26 17:36:46.000000000 +0200
@@ -0,0 +1,512 @@
+/* ipkglib.c - the itsy package management system
+
+ Florina Boor
+
+ Copyright (C) 2003 kernel concepts
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#ifdef IPKG_LIB
+
+#include "ipkg.h"
+#include "ipkg_includes.h"
+#include "libipkg.h"
+
+#include "args.h"
+#include "ipkg_conf.h"
+#include "ipkg_cmd.h"
+#include "file_util.h"
+
+
+
+ipkg_message_callback ipkg_cb_message = NULL;
+ipkg_response_callback ipkg_cb_response = NULL;
+ipkg_status_callback ipkg_cb_status = NULL;
+ipkg_list_callback ipkg_cb_list = NULL;
+
+
+int
+ipkg_init (ipkg_message_callback mcall,
+ ipkg_response_callback rcall,
+ args_t * args)
+{
+ ipkg_cb_message = mcall;
+ ipkg_cb_response = rcall;
+
+ args_init (args);
+
+ return 0;
+}
+
+
+int
+ipkg_deinit (args_t * args)
+{
+ args_deinit (args);
+ ipkg_cb_message = NULL;
+ ipkg_cb_response = NULL;
+
+ /* place other cleanup stuff here */
+
+ return 0;
+}
+
+
+int
+ipkg_packages_list(args_t *args,
+ const char *packages,
+ ipkg_list_callback cblist,
+ void *userdata)
+{
+ ipkg_cmd_t *cmd;
+ ipkg_conf_t ipkg_conf;
+ int err;
+
+ err = ipkg_conf_init (&ipkg_conf, args);
+ if (err)
+ {
+ return err;
+ }
+
+ ipkg_cb_list = cblist;
+ /* we need to do this because of static declarations,
+ * maybe a good idea to change */
+ cmd = ipkg_cmd_find ("list");
+ if (packages)
+ err = ipkg_cmd_exec (cmd, &ipkg_conf, 1, &packages, userdata);
+ else
+ err = ipkg_cmd_exec (cmd, &ipkg_conf, 0, NULL, userdata);
+ ipkg_cb_list = NULL;
+ ipkg_conf_deinit (&ipkg_conf);
+ return (err);
+}
+
+
+int
+ipkg_packages_status(args_t *args,
+ const char *packages,
+ ipkg_status_callback cbstatus,
+ void *userdata)
+{
+ ipkg_cmd_t *cmd;
+ ipkg_conf_t ipkg_conf;
+ int err;
+
+ err = ipkg_conf_init (&ipkg_conf, args);
+ if (err)
+ {
+ return err;
+ }
+
+ ipkg_cb_status = cbstatus;
+
+ /* we need to do this because of static declarations,
+ * maybe a good idea to change */
+ cmd = ipkg_cmd_find ("status");
+ if (packages)
+ err = ipkg_cmd_exec (cmd, &ipkg_conf, 1, &packages, userdata);
+ else
+ err = ipkg_cmd_exec (cmd, &ipkg_conf, 0, NULL, userdata);
+
+ ipkg_cb_status = NULL;
+ ipkg_conf_deinit (&ipkg_conf);
+ return (err);
+}
+
+
+int
+ipkg_packages_info(args_t *args,
+ const char *packages,
+ ipkg_status_callback cbstatus,
+ void *userdata)
+{
+ ipkg_cmd_t *cmd;
+ ipkg_conf_t ipkg_conf;
+ int err;
+
+ err = ipkg_conf_init (&ipkg_conf, args);
+ if (err)
+ {
+ return err;
+ }
+
+ ipkg_cb_status = cbstatus;
+
+ /* we need to do this because of static declarations,
+ * maybe a good idea to change */
+ cmd = ipkg_cmd_find ("info");
+ if (packages)
+ err = ipkg_cmd_exec (cmd, &ipkg_conf, 1, &packages, userdata);
+ else
+ err = ipkg_cmd_exec (cmd, &ipkg_conf, 0, NULL, userdata);
+
+ ipkg_cb_status = NULL;
+ ipkg_conf_deinit (&ipkg_conf);
+ return (err);
+}
+
+
+int
+ipkg_packages_install (args_t * args, const char *name)
+{
+ ipkg_cmd_t *cmd;
+ ipkg_conf_t ipkg_conf;
+ int err;
+
+ /* this error should be handled in application */
+ if (!name || !strlen (name))
+ return (-1);
+
+ err = ipkg_conf_init (&ipkg_conf, args);
+ if (err)
+ {
+ return err;
+ }
+
+ /* we need to do this because of static declarations,
+ * maybe a good idea to change */
+ cmd = ipkg_cmd_find ("install");
+ err = ipkg_cmd_exec (cmd, &ipkg_conf, 1, &name, NULL);
+
+ ipkg_conf_deinit(&ipkg_conf);
+ return (err);
+}
+
+
+int
+ipkg_packages_remove(args_t *args, const char *name, int purge)
+{
+ ipkg_cmd_t *cmd;
+ ipkg_conf_t ipkg_conf;
+ int err;
+
+ /* this error should be handled in application */
+ if (!name || !strlen (name))
+ return (-1);
+
+ err = ipkg_conf_init (&ipkg_conf, args);
+ if (err)
+ {
+ return err;
+ }
+
+ /* we need to do this because of static declarations,
+ * maybe a good idea to change */
+ if (purge)
+ cmd = ipkg_cmd_find ("purge");
+ else
+ cmd = ipkg_cmd_find ("remove");
+
+ err = ipkg_cmd_exec (cmd, &ipkg_conf, 1, &name, NULL);
+
+ ipkg_conf_deinit(&ipkg_conf);
+ return (err);
+}
+
+
+int
+ipkg_lists_update(args_t *args)
+{
+ ipkg_cmd_t *cmd;
+ ipkg_conf_t ipkg_conf;
+ int err;
+
+ err = ipkg_conf_init (&ipkg_conf, args);
+ if (err)
+ {
+ return err;
+ }
+
+ /* we need to do this because of static declarations,
+ * maybe a good idea to change */
+ cmd = ipkg_cmd_find ("update");
+
+ err = ipkg_cmd_exec (cmd, &ipkg_conf, 0, NULL, NULL);
+
+ ipkg_conf_deinit(&ipkg_conf);
+ return (err);
+}
+
+
+int
+ipkg_packages_upgrade(args_t *args)
+{
+ ipkg_cmd_t *cmd;
+ ipkg_conf_t ipkg_conf;
+ int err;
+
+ err = ipkg_conf_init (&ipkg_conf, args);
+ if (err)
+ {
+ return err;
+ }
+
+ /* we need to do this because of static declarations,
+ * maybe a good idea to change */
+ cmd = ipkg_cmd_find ("upgrade");
+
+ err = ipkg_cmd_exec (cmd, &ipkg_conf, 0, NULL, NULL);
+
+ ipkg_conf_deinit(&ipkg_conf);
+ return (err);
+}
+
+
+int
+ipkg_packages_download (args_t * args, const char *name)
+{
+ ipkg_cmd_t *cmd;
+ ipkg_conf_t ipkg_conf;
+ int err;
+
+ /* this error should be handled in application */
+ if (!name || !strlen (name))
+ return (-1);
+
+ err = ipkg_conf_init (&ipkg_conf, args);
+ if (err)
+ {
+ return err;
+ }
+
+ /* we need to do this because of static declarations,
+ * maybe a good idea to change */
+ cmd = ipkg_cmd_find ("download");
+ err = ipkg_cmd_exec (cmd, &ipkg_conf, 1, &name, NULL);
+
+ ipkg_conf_deinit(&ipkg_conf);
+ return (err);
+}
+
+
+int
+ipkg_package_files(args_t *args,
+ const char *name,
+ ipkg_list_callback cblist,
+ void *userdata)
+{
+ ipkg_cmd_t *cmd;
+ ipkg_conf_t ipkg_conf;
+ int err;
+
+ /* this error should be handled in application */
+ if (!name || !strlen (name))
+ return (-1);
+
+ err = ipkg_conf_init (&ipkg_conf, args);
+ if (err)
+ {
+ return err;
+ }
+
+ ipkg_cb_list = cblist;
+
+ /* we need to do this because of static declarations,
+ * maybe a good idea to change */
+ cmd = ipkg_cmd_find ("files");
+
+ err = ipkg_cmd_exec (cmd, &ipkg_conf, 1, &name, userdata);
+
+ ipkg_cb_list = NULL;
+ ipkg_conf_deinit(&ipkg_conf);
+ return (err);
+}
+
+
+int
+ipkg_file_search(args_t *args,
+ const char *file,
+ ipkg_list_callback cblist,
+ void *userdata)
+{
+ ipkg_cmd_t *cmd;
+ ipkg_conf_t ipkg_conf;
+ int err;
+
+ /* this error should be handled in application */
+ if (!file || !strlen (file))
+ return (-1);
+
+ err = ipkg_conf_init (&ipkg_conf, args);
+ if (err)
+ {
+ return err;
+ }
+
+ ipkg_cb_list = cblist;
+
+ /* we need to do this because of static declarations,
+ * maybe a good idea to change */
+ cmd = ipkg_cmd_find ("search");
+ err = ipkg_cmd_exec (cmd, &ipkg_conf, 1, &file, userdata);
+
+ ipkg_cb_list = NULL;
+ ipkg_conf_deinit(&ipkg_conf);
+ return(err);
+}
+
+
+int
+ipkg_file_what(args_t *args, const char *file, const char* command)
+{
+ ipkg_cmd_t *cmd;
+ ipkg_conf_t ipkg_conf;
+ int err;
+
+ /* this error should be handled in application */
+ if (!file || !strlen (file))
+ return (-1);
+
+ err = ipkg_conf_init (&ipkg_conf, args);
+ if (err)
+ {
+ return err;
+ }
+
+ /* we need to do this because of static declarations,
+ * maybe a good idea to change */
+ cmd = ipkg_cmd_find (command);
+ err = ipkg_cmd_exec (cmd, &ipkg_conf, 1, &file, NULL);
+
+ ipkg_conf_deinit(&ipkg_conf);
+ return(err);
+}
+
+#define ipkg_package_whatdepends(args,file) ipkg_file_what(args,file,"whatdepends")
+#define ipkg_package_whatrecommends(args, file) ipkg_file_what(args,file,"whatrecommends")
+#define ipkg_package_whatprovides(args, file) ipkg_file_what(args,file,"whatprovides")
+#define ipkg_package_whatconflicts(args, file) ipkg_file_what(args,file,"whatconflicts")
+#define ipkg_package_whatreplaces(args, file) ipkg_file_what(args,file,"whatreplaces")
+
+
+int default_ipkg_message_callback(ipkg_conf_t *conf, message_level_t level,
+ char *msg)
+{
+ if (conf && (conf->verbosity < level)) {
+ return 0;
+ } else {
+#ifdef IPKG_LIB
+ if ( level == IPKG_ERROR ){
+ push_error_list(&error_list, msg);
+// printf(msg);
+ } else
+#endif
+ printf(msg);
+ }
+ return 0;
+}
+
+int default_ipkg_list_callback(char *name, char *desc, char *version,
+ pkg_state_status_t status, void *userdata)
+{
+ if (desc)
+ printf("%s - %s - %s\n", name, version, desc);
+ else
+ printf("%s - %s\n", name, version);
+ return 0;
+}
+
+int default_ipkg_files_callback(char *name, char *desc, char *version,
+ pkg_state_status_t status, void *userdata)
+{
+ if (desc)
+ printf("%s\n", desc);
+ return 0;
+}
+
+int default_ipkg_status_callback(char *name, int istatus, char *desc,
+ void *userdata)
+{
+ printf("%s\n", desc);
+ return 0;
+}
+
+char* default_ipkg_response_callback(char *question)
+{
+ char *response = NULL;
+ printf(question);
+ fflush(stdout);
+ do {
+ response = (char *)file_read_line_alloc(stdin);
+ } while (response == NULL);
+ return response;
+}
+
+/* This is used for backward compatibility */
+int
+ipkg_op (int argc, char *argv[])
+{
+ int err, optind;
+ args_t args;
+ char *cmd_name;
+ ipkg_cmd_t *cmd;
+ ipkg_conf_t ipkg_conf;
+
+ args_init (&args);
+
+ optind = args_parse (&args, argc, argv);
+ if (optind == argc || optind < 0)
+ {
+ args_usage ("ipkg must have one sub-command argument");
+ }
+
+ cmd_name = argv[optind++];
+/* Pigi: added a flag to disable the checking of structures if the command does not need to
+ read anything from there.
+*/
+ if ( !strcmp(cmd_name,"print-architecture") ||
+ !strcmp(cmd_name,"print_architecture") ||
+ !strcmp(cmd_name,"print-installation-architecture") ||
+ !strcmp(cmd_name,"print_installation_architecture") )
+ args.nocheckfordirorfile = 1;
+
+
+ err = ipkg_conf_init (&ipkg_conf, &args);
+ if (err)
+ {
+ return err;
+ }
+
+ args_deinit (&args);
+
+ ipkg_cb_message = default_ipkg_message_callback;
+ ipkg_cb_response = default_ipkg_response_callback;
+ ipkg_cb_status = default_ipkg_status_callback;
+ if ( strcmp(cmd_name, "files")==0)
+ ipkg_cb_list = default_ipkg_files_callback;
+ else
+ ipkg_cb_list = default_ipkg_list_callback;
+
+ cmd = ipkg_cmd_find (cmd_name);
+ if (cmd == NULL)
+ {
+ fprintf (stderr, "%s: unknown sub-command %s\n", argv[0],
+ cmd_name);
+ args_usage (NULL);
+ }
+
+ if (cmd->requires_args && optind == argc)
+ {
+ fprintf (stderr,
+ "%s: the ``%s'' command requires at least one argument\n",
+ __FUNCTION__, cmd_name);
+ args_usage (NULL);
+ }
+
+ err = ipkg_cmd_exec (cmd, &ipkg_conf, argc - optind, (const char **) (argv + optind), NULL);
+
+ ipkg_conf_deinit (&ipkg_conf);
+
+ return err;
+}
+
+#endif /* IPKG_LIB */
diff -ruN busybox-1.00-orig/archival/libipkg/libipkg.h busybox-1.00+ipkg-0.99.154/archival/libipkg/libipkg.h
--- busybox-1.00-orig/archival/libipkg/libipkg.h 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/libipkg.h 2005-10-26 17:36:46.000000000 +0200
@@ -0,0 +1,87 @@
+/* ipkglib.h - the itsy package management system
+
+ Florian Boor <florian.boor@kernelconcepts.de>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#ifndef IPKGLIB_H
+#define IPKGLIB_H
+
+#ifdef IPKG_LIB
+
+#include "ipkg_conf.h"
+#include "ipkg_message.h"
+
+#include "args.h"
+#include "pkg.h"
+
+typedef int (*ipkg_message_callback)(ipkg_conf_t *conf, message_level_t level,
+ char *msg);
+typedef int (*ipkg_list_callback)(char *name, char *desc, char *version,
+ pkg_state_status_t status, void *userdata);
+typedef int (*ipkg_status_callback)(char *name, int istatus, char *desc,
+ void *userdata);
+typedef char* (*ipkg_response_callback)(char *question);
+
+extern int ipkg_op(int argc, char *argv[]); /* ipkglib.c */
+extern int ipkg_init (ipkg_message_callback mcall,
+ ipkg_response_callback rcall,
+ args_t * args);
+
+extern int ipkg_deinit (args_t *args);
+extern int ipkg_packages_list(args_t *args,
+ const char *packages,
+ ipkg_list_callback cblist,
+ void *userdata);
+extern int ipkg_packages_status(args_t *args,
+ const char *packages,
+ ipkg_status_callback cbstatus,
+ void *userdata);
+extern int ipkg_packages_info(args_t *args,
+ const char *packages,
+ ipkg_status_callback cbstatus,
+ void *userdata);
+extern int ipkg_packages_install(args_t *args, const char *name);
+extern int ipkg_packages_remove(args_t *args, const char *name, int purge);
+extern int ipkg_lists_update(args_t *args);
+extern int ipkg_packages_upgrade(args_t *args);
+extern int ipkg_packages_download(args_t *args, const char *name);
+extern int ipkg_package_files(args_t *args,
+ const char *name,
+ ipkg_list_callback cblist,
+ void *userdata);
+extern int ipkg_file_search(args_t *args,
+ const char *file,
+ ipkg_list_callback cblist,
+ void *userdata);
+extern int ipkg_package_whatdepends(args_t *args, const char *file);
+extern int ipkg_package_whatrecommends(args_t *args, const char *file);
+extern int ipkg_package_whatprovides(args_t *args, const char *file);
+extern int ipkg_package_whatconflicts(args_t *args, const char *file);
+extern int ipkg_package_whatreplaces(args_t *args, const char *file);
+
+extern ipkg_message_callback ipkg_cb_message; /* ipkglib.c */
+extern ipkg_response_callback ipkg_cb_response;
+extern ipkg_status_callback ipkg_cb_status;
+extern ipkg_list_callback ipkg_cb_list;
+extern void push_error_list(struct errlist **errors,char * msg);
+extern void reverse_error_list(struct errlist **errors);
+extern void free_error_list(struct errlist **errors);
+
+#else
+
+extern int ipkg_op(int argc, char *argv[]);
+
+#endif
+
+
+#endif
diff -ruN busybox-1.00-orig/archival/libipkg/md5.c busybox-1.00+ipkg-0.99.154/archival/libipkg/md5.c
--- busybox-1.00-orig/archival/libipkg/md5.c 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/md5.c 2005-10-26 17:36:46.000000000 +0200
@@ -0,0 +1,48 @@
+/* md5.c - wrappers to busybox md5 functions
+ *
+ * Copyright (C) 1995-1999 Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include "libbb.h"
+
+#include "md5.h"
+
+int md5_stream(FILE *stream, void *resblock)
+{
+ int fd;
+ int sum;
+
+ if( (fd = fileno(stream)) == -1 ) {
+ bb_error_msg("bad file descriptor");
+ return 1;
+ }
+
+ hash_fd(fd, -1, HASH_MD5, (uint8_t *)resblock);
+
+ return 0;
+}
+
+void *md5_buffer(const char *buffer, size_t len, void *resblock)
+{
+ struct md5_ctx_t md5_cx;
+
+ md5_begin(&md5_cx);
+ md5_hash(buffer, len, &md5_cx);
+ return md5_end(resblock, &md5_cx);
+}
+
diff -ruN busybox-1.00-orig/archival/libipkg/md5.h busybox-1.00+ipkg-0.99.154/archival/libipkg/md5.h
--- busybox-1.00-orig/archival/libipkg/md5.h 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/md5.h 2005-10-26 17:36:46.000000000 +0200
@@ -0,0 +1,35 @@
+/* md5.h - Compute MD5 checksum of files or strings according to the
+ * definition of MD5 in RFC 1321 from April 1992.
+ * Copyright (C) 1995-1999 Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef MD5_H
+#define MD5_H
+
+/* Compute MD5 message digest for bytes read from STREAM. The
+ resulting message digest number will be written into the 16 bytes
+ beginning at RESBLOCK. */
+int md5_stream(FILE *stream, void *resblock);
+
+/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The
+ result is always in little endian byte order, so that a byte-wise
+ output yields to the wanted ASCII representation of the message
+ digest. */
+void *md5_buffer(const char *buffer, size_t len, void *resblock);
+
+#endif
+
diff -ruN busybox-1.00-orig/archival/libipkg/nv_pair.c busybox-1.00+ipkg-0.99.154/archival/libipkg/nv_pair.c
--- busybox-1.00-orig/archival/libipkg/nv_pair.c 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/nv_pair.c 2005-10-26 17:36:46.000000000 +0200
@@ -0,0 +1,40 @@
+/* nv_pair.c - the itsy package management system
+
+ Carl D. Worth
+
+ Copyright (C) 2001 University of Southern California
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#include "ipkg.h"
+
+#include "nv_pair.h"
+#include "str_util.h"
+
+int nv_pair_init(nv_pair_t *nv_pair, const char *name, const char *value)
+{
+ nv_pair->name = str_dup_safe(name);
+ nv_pair->value = str_dup_safe(value);
+
+ return 0;
+}
+
+void nv_pair_deinit(nv_pair_t *nv_pair)
+{
+ free(nv_pair->name);
+ nv_pair->name = NULL;
+
+ free(nv_pair->value);
+ nv_pair->value = NULL;
+}
+
+
diff -ruN busybox-1.00-orig/archival/libipkg/nv_pair.h busybox-1.00+ipkg-0.99.154/archival/libipkg/nv_pair.h
--- busybox-1.00-orig/archival/libipkg/nv_pair.h 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/nv_pair.h 2005-10-26 17:36:46.000000000 +0200
@@ -0,0 +1,32 @@
+/* nv_pair.h - the itsy package management system
+
+ Carl D. Worth
+
+ Copyright (C) 2001 University of Southern California
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#ifndef NV_PAIR_H
+#define NV_PAIR_H
+
+typedef struct nv_pair nv_pair_t;
+struct nv_pair
+{
+ char *name;
+ char *value;
+};
+
+int nv_pair_init(nv_pair_t *nv_pair, const char *name, const char *value);
+void nv_pair_deinit(nv_pair_t *nv_pair);
+
+#endif
+
diff -ruN busybox-1.00-orig/archival/libipkg/nv_pair_list.c busybox-1.00+ipkg-0.99.154/archival/libipkg/nv_pair_list.c
--- busybox-1.00-orig/archival/libipkg/nv_pair_list.c 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/nv_pair_list.c 2005-10-26 17:36:46.000000000 +0200
@@ -0,0 +1,98 @@
+/* nv_pair_list.c - the itsy package management system
+
+ Carl D. Worth
+
+ Copyright (C) 2001 University of Southern California
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#include "ipkg.h"
+
+#include "nv_pair.h"
+#include "void_list.h"
+#include "nv_pair_list.h"
+
+int nv_pair_list_elt_init(nv_pair_list_elt_t *elt, nv_pair_t *data)
+{
+ return void_list_elt_init((void_list_elt_t *) elt, data);
+}
+
+void nv_pair_list_elt_deinit(nv_pair_list_elt_t *elt)
+{
+ void_list_elt_deinit((void_list_elt_t *) elt);
+}
+
+int nv_pair_list_init(nv_pair_list_t *list)
+{
+ return void_list_init((void_list_t *) list);
+}
+
+void nv_pair_list_deinit(nv_pair_list_t *list)
+{
+ nv_pair_list_elt_t *iter;
+ nv_pair_t *nv_pair;
+
+ for (iter = list->head; iter; iter = iter->next) {
+ nv_pair = iter->data;
+ nv_pair_deinit(nv_pair);
+
+ /* malloced in nv_pair_list_append */
+ free(nv_pair);
+ iter->data = NULL;
+ }
+ void_list_deinit((void_list_t *) list);
+}
+
+nv_pair_t *nv_pair_list_append(nv_pair_list_t *list, const char *name, const char *value)
+{
+ int err;
+
+ /* freed in nv_pair_list_deinit */
+ nv_pair_t *nv_pair = malloc(sizeof(nv_pair_t));
+
+ if (nv_pair == NULL) {
+ fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
+ return NULL;
+ }
+ nv_pair_init(nv_pair, name, value);
+
+ err = void_list_append((void_list_t *) list, nv_pair);
+ if (err) {
+ return NULL;
+ }
+
+ return nv_pair;
+}
+
+int nv_pair_list_push(nv_pair_list_t *list, nv_pair_t *data)
+{
+ return void_list_push((void_list_t *) list, data);
+}
+
+nv_pair_list_elt_t *nv_pair_list_pop(nv_pair_list_t *list)
+{
+ return (nv_pair_list_elt_t *) void_list_pop((void_list_t *) list);
+}
+
+char *nv_pair_list_find(nv_pair_list_t *list, char *name)
+{
+ nv_pair_list_elt_t *iter;
+ nv_pair_t *nv_pair;
+
+ for (iter = list->head; iter; iter = iter->next) {
+ nv_pair = iter->data;
+ if (strcmp(nv_pair->name, name) == 0) {
+ return nv_pair->value;
+ }
+ }
+ return NULL;
+}
diff -ruN busybox-1.00-orig/archival/libipkg/nv_pair_list.h busybox-1.00+ipkg-0.99.154/archival/libipkg/nv_pair_list.h
--- busybox-1.00-orig/archival/libipkg/nv_pair_list.h 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/nv_pair_list.h 2005-10-26 17:36:46.000000000 +0200
@@ -0,0 +1,60 @@
+/* nv_pair_list.h - the itsy package management system
+
+ Carl D. Worth
+
+ Copyright (C) 2001 University of Southern California
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#ifndef NV_PAIR_LIST_H
+#define NV_PAIR_LIST_H
+
+#include "nv_pair.h"
+#include "void_list.h"
+
+typedef struct nv_pair_list_elt nv_pair_list_elt_t;
+struct nv_pair_list_elt
+{
+ nv_pair_list_elt_t *next;
+ nv_pair_t *data;
+};
+
+typedef struct nv_pair_list nv_pair_list_t;
+struct nv_pair_list
+{
+ nv_pair_list_elt_t pre_head;
+ nv_pair_list_elt_t *head;
+ nv_pair_list_elt_t *tail;
+};
+
+static inline int nv_pair_list_empty(nv_pair_list_t *list)
+{
+ if (list->head == NULL)
+ return 1;
+ else
+ return 0;
+}
+
+int nv_pair_list_elt_init(nv_pair_list_elt_t *elt, nv_pair_t *data);
+void nv_pair_list_elt_deinit(nv_pair_list_elt_t *elt);
+
+int nv_pair_list_init(nv_pair_list_t *list);
+void nv_pair_list_deinit(nv_pair_list_t *list);
+
+nv_pair_t *nv_pair_list_append(nv_pair_list_t *list,
+ const char *name, const char *value);
+int nv_pair_list_push(nv_pair_list_t *list, nv_pair_t *data);
+nv_pair_list_elt_t *nv_pair_list_pop(nv_pair_list_t *list);
+char *nv_pair_list_find(nv_pair_list_t *list, char *name);
+
+#endif
+
diff -ruN busybox-1.00-orig/archival/libipkg/pkg.c busybox-1.00+ipkg-0.99.154/archival/libipkg/pkg.c
--- busybox-1.00-orig/archival/libipkg/pkg.c 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/pkg.c 2005-10-26 17:36:46.000000000 +0200
@@ -0,0 +1,1753 @@
+/* pkg.c - the itsy package management system
+
+ Carl D. Worth
+
+ Copyright (C) 2001 University of Southern California
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#include "ipkg.h"
+#include <ctype.h>
+#include <string.h>
+#include <errno.h>
+
+#include "pkg.h"
+
+#include "pkg_parse.h"
+#include "pkg_extract.h"
+#include "ipkg_message.h"
+#include "ipkg_utils.h"
+
+#include "sprintf_alloc.h"
+#include "file_util.h"
+#include "str_util.h"
+#include "xsystem.h"
+#include "ipkg_conf.h"
+
+typedef struct enum_map enum_map_t;
+struct enum_map
+{
+ int value;
+ char *str;
+};
+
+static const enum_map_t pkg_state_want_map[] = {
+ { SW_UNKNOWN, "unknown"},
+ { SW_INSTALL, "install"},
+ { SW_DEINSTALL, "deinstall"},
+ { SW_PURGE, "purge"}
+};
+
+static const enum_map_t pkg_state_flag_map[] = {
+ { SF_OK, "ok"},
+ { SF_REINSTREQ, "reinstreq"},
+ { SF_HOLD, "hold"},
+ { SF_REPLACE, "replace"},
+ { SF_NOPRUNE, "noprune"},
+ { SF_PREFER, "prefer"},
+ { SF_OBSOLETE, "obsolete"},
+ { SF_USER, "user"},
+};
+
+static const enum_map_t pkg_state_status_map[] = {
+ { SS_NOT_INSTALLED, "not-installed" },
+ { SS_UNPACKED, "unpacked" },
+ { SS_HALF_CONFIGURED, "half-configured" },
+ { SS_INSTALLED, "installed" },
+ { SS_HALF_INSTALLED, "half-installed" },
+ { SS_CONFIG_FILES, "config-files" },
+ { SS_POST_INST_FAILED, "post-inst-failed" },
+ { SS_REMOVAL_FAILED, "removal-failed" }
+};
+
+static int verrevcmp(const char *val, const char *ref);
+
+
+pkg_t *pkg_new(void)
+{
+ pkg_t *pkg;
+
+ pkg = malloc(sizeof(pkg_t));
+ if (pkg == NULL) {
+ fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
+ return NULL;
+ }
+
+ pkg_init(pkg);
+
+ return pkg;
+}
+
+int pkg_init(pkg_t *pkg)
+{
+ memset(pkg, 0, sizeof(pkg_t));
+ pkg->name = NULL;
+ pkg->epoch = 0;
+ pkg->version = NULL;
+ pkg->revision = NULL;
+ pkg->familiar_revision = NULL;
+ pkg->dest = NULL;
+ pkg->src = NULL;
+ pkg->architecture = NULL;
+ pkg->maintainer = NULL;
+ pkg->section = NULL;
+ pkg->description = NULL;
+ pkg->state_want = SW_UNKNOWN;
+ pkg->state_flag = SF_OK;
+ pkg->state_status = SS_NOT_INSTALLED;
+ pkg->depends_str = NULL;
+ pkg->provides_str = NULL;
+ pkg->depends_count = 0;
+ pkg->depends = NULL;
+ pkg->suggests_str = NULL;
+ pkg->recommends_str = NULL;
+ pkg->suggests_count = 0;
+ pkg->recommends_count = 0;
+
+ /* Abhaya: added init for conflicts fields */
+ pkg->conflicts = NULL;
+ pkg->conflicts_count = 0;
+
+ /* added for replaces. Jamey 7/23/2002 */
+ pkg->replaces = NULL;
+ pkg->replaces_count = 0;
+
+ pkg->pre_depends_count = 0;
+ pkg->pre_depends_str = NULL;
+ pkg->provides_count = 0;
+ pkg->provides = NULL;
+ pkg->filename = NULL;
+ pkg->local_filename = NULL;
+ pkg->tmp_unpack_dir = NULL;
+ pkg->md5sum = NULL;
+ pkg->size = NULL;
+ pkg->installed_size = NULL;
+ pkg->priority = NULL;
+ pkg->source = NULL;
+ conffile_list_init(&pkg->conffiles);
+ pkg->installed_files = NULL;
+ pkg->installed_files_ref_cnt = 0;
+ pkg->essential = 0;
+
+ return 0;
+}
+
+void pkg_deinit(pkg_t *pkg)
+{
+ free(pkg->name);
+ pkg->name = NULL;
+ pkg->epoch = 0;
+ free(pkg->version);
+ pkg->version = NULL;
+ /* revision and familiar_revision share storage with version, so
+ don't free */
+ pkg->revision = NULL;
+ pkg->familiar_revision = NULL;
+ /* owned by ipkg_conf_t */
+ pkg->dest = NULL;
+ /* owned by ipkg_conf_t */
+ pkg->src = NULL;
+ free(pkg->architecture);
+ pkg->architecture = NULL;
+ free(pkg->maintainer);
+ pkg->maintainer = NULL;
+ free(pkg->section);
+ pkg->section = NULL;
+ free(pkg->description);
+ pkg->description = NULL;
+ pkg->state_want = SW_UNKNOWN;
+ pkg->state_flag = SF_OK;
+ pkg->state_status = SS_NOT_INSTALLED;
+ free(pkg->depends_str);
+ pkg->depends_str = NULL;
+ free(pkg->provides_str);
+ pkg->provides_str = NULL;
+ pkg->depends_count = 0;
+ /* XXX: CLEANUP: MEMORY_LEAK: how to free up pkg->depends ? */
+ pkg->pre_depends_count = 0;
+ free(pkg->pre_depends_str);
+ pkg->pre_depends_str = NULL;
+ pkg->provides_count = 0;
+ /* XXX: CLEANUP: MEMORY_LEAK: how to free up pkg->provides ? */
+ /* XXX: CLEANUP: MEMORY_LEAK: how to free up pkg->suggests ? */
+ free(pkg->filename);
+ pkg->filename = NULL;
+ free(pkg->local_filename);
+ pkg->local_filename = NULL;
+ /* CLEANUP: It'd be nice to pullin the cleanup function from
+ ipkg_install.c here. See comment in
+ ipkg_install.c:cleanup_temporary_files */
+ free(pkg->tmp_unpack_dir);
+ pkg->tmp_unpack_dir = NULL;
+ free(pkg->md5sum);
+ pkg->md5sum = NULL;
+ free(pkg->size);
+ pkg->size = NULL;
+ free(pkg->installed_size);
+ pkg->installed_size = NULL;
+ free(pkg->priority);
+ pkg->priority = NULL;
+ free(pkg->source);
+ pkg->source = NULL;
+ conffile_list_deinit(&pkg->conffiles);
+ /* XXX: QUESTION: Is forcing this to 1 correct? I suppose so,
+ since if they are calling deinit, they should know. Maybe do an
+ assertion here instead? */
+ pkg->installed_files_ref_cnt = 1;
+ pkg_free_installed_files(pkg);
+ pkg->essential = 0;
+}
+
+int pkg_init_from_file(pkg_t *pkg, const char *filename)
+{
+ int err;
+ char **raw;
+ FILE *control_file;
+
+ err = pkg_init(pkg);
+ if (err) { return err; }
+
+ pkg->local_filename = strdup(filename);
+
+ control_file = tmpfile();
+ err = pkg_extract_control_file_to_stream(pkg, control_file);
+ if (err) { return err; }
+
+ rewind(control_file);
+ raw = read_raw_pkgs_from_stream(control_file);
+ pkg_parse_raw(pkg, &raw, NULL, NULL);
+
+ fclose(control_file);
+
+ return 0;
+}
+
+/* Merge any new information in newpkg into oldpkg */
+/* XXX: CLEANUP: This function shouldn't actually modify anything in
+ newpkg, but should leave it usable. This rework is so that
+ pkg_hash_insert doesn't clobber the pkg that you pass into it. */
+/*
+ * uh, i thought that i had originally written this so that it took
+ * two pkgs and returned a new one? we can do that again... -sma
+ */
+int pkg_merge(pkg_t *oldpkg, pkg_t *newpkg, int set_status)
+{
+ if (oldpkg == newpkg) {
+ return 0;
+ }
+
+ if (!oldpkg->src)
+ oldpkg->src = newpkg->src;
+ if (!oldpkg->dest)
+ oldpkg->dest = newpkg->dest;
+ if (!oldpkg->architecture)
+ oldpkg->architecture = str_dup_safe(newpkg->architecture);
+ if (!oldpkg->arch_priority)
+ oldpkg->arch_priority = newpkg->arch_priority;
+ if (!oldpkg->section)
+ oldpkg->section = str_dup_safe(newpkg->section);
+ if(!oldpkg->maintainer)
+ oldpkg->maintainer = str_dup_safe(newpkg->maintainer);
+ if(!oldpkg->description)
+ oldpkg->description = str_dup_safe(newpkg->description);
+ if (set_status) {
+ /* merge the state_flags from the new package */
+ oldpkg->state_want = newpkg->state_want;
+ oldpkg->state_status = newpkg->state_status;
+ oldpkg->state_flag = newpkg->state_flag;
+ } else {
+ if (oldpkg->state_want == SW_UNKNOWN)
+ oldpkg->state_want = newpkg->state_want;
+ if (oldpkg->state_status == SS_NOT_INSTALLED)
+ oldpkg->state_status = newpkg->state_status;
+ oldpkg->state_flag |= newpkg->state_flag;
+ }
+
+ if (!oldpkg->depends_str && !oldpkg->pre_depends_str && !oldpkg->recommends_str && !oldpkg->suggests_str) {
+ oldpkg->depends_str = newpkg->depends_str;
+ newpkg->depends_str = NULL;
+ oldpkg->depends_count = newpkg->depends_count;
+ newpkg->depends_count = 0;
+
+ oldpkg->depends = newpkg->depends;
+ newpkg->depends = NULL;
+
+ oldpkg->pre_depends_str = newpkg->pre_depends_str;
+ newpkg->pre_depends_str = NULL;
+ oldpkg->pre_depends_count = newpkg->pre_depends_count;
+ newpkg->pre_depends_count = 0;
+
+ oldpkg->recommends_str = newpkg->recommends_str;
+ newpkg->recommends_str = NULL;
+ oldpkg->recommends_count = newpkg->recommends_count;
+ newpkg->recommends_count = 0;
+
+ oldpkg->suggests_str = newpkg->suggests_str;
+ newpkg->suggests_str = NULL;
+ oldpkg->suggests_count = newpkg->suggests_count;
+ newpkg->suggests_count = 0;
+ }
+
+ if (!oldpkg->provides_str) {
+ oldpkg->provides_str = newpkg->provides_str;
+ newpkg->provides_str = NULL;
+ oldpkg->provides_count = newpkg->provides_count;
+ newpkg->provides_count = 0;
+
+ oldpkg->provides = newpkg->provides;
+ newpkg->provides = NULL;
+ }
+
+ if (!oldpkg->conflicts_str) {
+ oldpkg->conflicts_str = newpkg->conflicts_str;
+ newpkg->conflicts_str = NULL;
+ oldpkg->conflicts_count = newpkg->conflicts_count;
+ newpkg->conflicts_count = 0;
+
+ oldpkg->conflicts = newpkg->conflicts;
+ newpkg->conflicts = NULL;
+ }
+
+ if (!oldpkg->replaces_str) {
+ oldpkg->replaces_str = newpkg->replaces_str;
+ newpkg->replaces_str = NULL;
+ oldpkg->replaces_count = newpkg->replaces_count;
+ newpkg->replaces_count = 0;
+
+ oldpkg->replaces = newpkg->replaces;
+ newpkg->replaces = NULL;
+ }
+
+ if (!oldpkg->filename)
+ oldpkg->filename = str_dup_safe(newpkg->filename);
+ if (0)
+ fprintf(stdout, "pkg=%s old local_filename=%s new local_filename=%s\n",
+ oldpkg->name, oldpkg->local_filename, newpkg->local_filename);
+ if (!oldpkg->local_filename)
+ oldpkg->local_filename = str_dup_safe(newpkg->local_filename);
+ if (!oldpkg->tmp_unpack_dir)
+ oldpkg->tmp_unpack_dir = str_dup_safe(newpkg->tmp_unpack_dir);
+ if (!oldpkg->md5sum)
+ oldpkg->md5sum = str_dup_safe(newpkg->md5sum);
+ if (!oldpkg->size)
+ oldpkg->size = str_dup_safe(newpkg->size);
+ if (!oldpkg->installed_size)
+ oldpkg->installed_size = str_dup_safe(newpkg->installed_size);
+ if (!oldpkg->priority)
+ oldpkg->priority = str_dup_safe(newpkg->priority);
+ if (!oldpkg->source)
+ oldpkg->source = str_dup_safe(newpkg->source);
+ if (oldpkg->conffiles.head == NULL){
+ oldpkg->conffiles = newpkg->conffiles;
+ conffile_list_init(&newpkg->conffiles);
+ }
+ if (!oldpkg->installed_files){
+ oldpkg->installed_files = newpkg->installed_files;
+ oldpkg->installed_files_ref_cnt = newpkg->installed_files_ref_cnt;
+ newpkg->installed_files = NULL;
+ }
+ if (!oldpkg->essential)
+ oldpkg->essential = newpkg->essential;
+
+ return 0;
+}
+
+abstract_pkg_t *abstract_pkg_new(void)
+{
+ abstract_pkg_t * ab_pkg;
+
+ ab_pkg = malloc(sizeof(abstract_pkg_t));
+
+ if (ab_pkg == NULL) {
+ fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
+ return NULL;
+ }
+
+ if ( abstract_pkg_init(ab_pkg) < 0 )
+ return NULL;
+
+ return ab_pkg;
+}
+
+int abstract_pkg_init(abstract_pkg_t *ab_pkg)
+{
+ memset(ab_pkg, 0, sizeof(abstract_pkg_t));
+
+ ab_pkg->provided_by = abstract_pkg_vec_alloc();
+ if (ab_pkg->provided_by==NULL){
+ return -1;
+ }
+ ab_pkg->dependencies_checked = 0;
+ ab_pkg->state_status = SS_NOT_INSTALLED;
+
+ return 0;
+}
+
+void set_flags_from_control(ipkg_conf_t *conf, pkg_t *pkg){
+ char * temp_str;
+ char **raw =NULL;
+ char **raw_start=NULL;
+
+ temp_str = (char *) malloc (strlen(pkg->dest->info_dir)+strlen(pkg->name)+12);
+ if (temp_str == NULL ){
+ ipkg_message(conf, IPKG_INFO, "Out of memory in %s\n", __FUNCTION__);
+ return;
+ }
+ sprintf( temp_str,"%s/%s.control",pkg->dest->info_dir,pkg->name);
+
+ raw = raw_start = read_raw_pkgs_from_file(temp_str);
+ if (raw == NULL ){
+ ipkg_message(conf, IPKG_ERROR, "Unable to open the control file in %s\n", __FUNCTION__);
+ return;
+ }
+
+ while(*raw){
+ if (!pkg_valorize_other_field(pkg, &raw ) == 0) {
+ ipkg_message(conf, IPKG_DEBUG, "unable to read control file for %s. May be empty\n", pkg->name);
+ }
+ }
+ raw = raw_start;
+ while (*raw) {
+ if (raw!=NULL)
+ free(*raw++);
+ }
+
+ free(raw_start);
+ free(temp_str);
+
+ return ;
+
+}
+
+char * pkg_formatted_info(pkg_t *pkg )
+{
+ char *line;
+ char * buff;
+
+ buff = malloc(8192);
+ if (buff == NULL) {
+ fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
+ return NULL;
+ }
+
+ buff[0] = '\0';
+
+ line = pkg_formatted_field(pkg, "Package");
+ strncat(buff ,line, strlen(line));
+ free(line);
+
+ line = pkg_formatted_field(pkg, "Version");
+ strncat(buff ,line, strlen(line));
+ free(line);
+
+ line = pkg_formatted_field(pkg, "Depends");
+ strncat(buff ,line, strlen(line));
+ free(line);
+
+ line = pkg_formatted_field(pkg, "Recommends");
+ strncat(buff ,line, strlen(line));
+ free(line);
+
+ line = pkg_formatted_field(pkg, "Suggests");
+ strncat(buff ,line, strlen(line));
+ free(line);
+
+ line = pkg_formatted_field(pkg, "Provides");
+ strncat(buff ,line, strlen(line));
+ free(line);
+
+ line = pkg_formatted_field(pkg, "Replaces");
+ strncat(buff ,line, strlen(line));
+ free(line);
+
+ line = pkg_formatted_field(pkg, "Conflicts");
+ strncat(buff ,line, strlen(line));
+ free(line);
+
+ line = pkg_formatted_field(pkg, "Status");
+ strncat(buff ,line, strlen(line));
+ free(line);
+
+ line = pkg_formatted_field(pkg, "Section");
+ strncat(buff ,line, strlen(line));
+ free(line);
+
+ line = pkg_formatted_field(pkg, "Essential"); /* @@@@ should be removed in future release. *//* I do not agree with this Pigi*/
+ strncat(buff ,line, strlen(line));
+ free(line);
+
+ line = pkg_formatted_field(pkg, "Architecture");
+ strncat(buff ,line, strlen(line));
+ free(line);
+
+ line = pkg_formatted_field(pkg, "Maintainer");
+ strncat(buff ,line, strlen(line));
+ free(line);
+
+ line = pkg_formatted_field(pkg, "MD5sum");
+ strncat(buff ,line, strlen(line));
+ free(line);
+
+ line = pkg_formatted_field(pkg, "Size");
+ strncat(buff ,line, strlen(line));
+ free(line);
+
+ line = pkg_formatted_field(pkg, "Filename");
+ strncat(buff ,line, strlen(line));
+ free(line);
+
+ line = pkg_formatted_field(pkg, "Conffiles");
+ strncat(buff ,line, strlen(line));
+ free(line);
+
+ line = pkg_formatted_field(pkg, "Source");
+ strncat(buff ,line, strlen(line));
+ free(line);
+
+ line = pkg_formatted_field(pkg, "Description");
+ strncat(buff ,line, strlen(line));
+ free(line);
+
+ line = pkg_formatted_field(pkg, "Installed-Time");
+ strncat(buff ,line, strlen(line));
+ free(line);
+
+ return buff;
+}
+
+char * pkg_formatted_field(pkg_t *pkg, const char *field )
+{
+ static size_t LINE_LEN = 128;
+ char * temp = (char *)malloc(1);
+ int len = 0;
+ int flag_provide_false = 0;
+
+/*
+ Pigi: After some discussion with Florian we decided to modify the full procedure in
+ dynamic memory allocation. This should avoid any other segv in this area ( except for bugs )
+*/
+
+ if (strlen(field) < PKG_MINIMUM_FIELD_NAME_LEN) {
+ goto UNKNOWN_FMT_FIELD;
+ }
+
+ temp[0]='\0';
+
+ switch (field[0])
+ {
+ case 'a':
+ case 'A':
+ if (strcasecmp(field, "Architecture") == 0) {
+ /* Architecture */
+ if (pkg->architecture) {
+ temp = (char *)realloc(temp,strlen(pkg->architecture)+17);
+ if ( temp == NULL ){
+ fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
+ return NULL;
+ }
+ temp[0]='\0';
+ snprintf(temp, (strlen(pkg->architecture)+17), "Architecture: %s\n", pkg->architecture);
+ }
+ } else {
+ goto UNKNOWN_FMT_FIELD;
+ }
+ break;
+ case 'c':
+ case 'C':
+ if (strcasecmp(field, "Conffiles") == 0) {
+ /* Conffiles */
+ conffile_list_elt_t *iter;
+ char confstr[LINE_LEN];
+
+ if (pkg->conffiles.head == NULL) {
+ return temp;
+ }
+
+ len = 14 ;
+ for (iter = pkg->conffiles.head; iter; iter = iter->next) {
+ if (iter->data->name && iter->data->value) {
+ len = len + (strlen(iter->data->name)+strlen(iter->data->value)+5);
+ }
+ }
+ temp = (char *)realloc(temp,len);
+ if ( temp == NULL ){
+ fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
+ return NULL;
+ }
+ temp[0]='\0';
+ strncpy(temp, "Conffiles:\n", 12);
+ for (iter = pkg->conffiles.head; iter; iter = iter->next) {
+ if (iter->data->name && iter->data->value) {
+ snprintf(confstr, LINE_LEN, "%s %s\n", iter->data->name, iter->data->value);
+ strncat(temp, confstr, strlen(confstr));
+ }
+ }
+ } else if (strcasecmp(field, "Conflicts") == 0) {
+ int i;
+
+ if (pkg->conflicts_count) {
+ char conflictstr[LINE_LEN];
+ len = 14 ;
+ for(i = 0; i < pkg->conflicts_count; i++) {
+ len = len + (strlen(pkg->conflicts_str[i])+5);
+ }
+ temp = (char *)realloc(temp,len);
+ if ( temp == NULL ){
+ fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
+ return NULL;
+ }
+ temp[0]='\0';
+ strncpy(temp, "Conflicts:", 11);
+ for(i = 0; i < pkg->conflicts_count; i++) {
+ snprintf(conflictstr, LINE_LEN, "%s %s", i == 0 ? "" : ",", pkg->conflicts_str[i]);
+ strncat(temp, conflictstr, strlen(conflictstr));
+ }
+ strncat(temp, "\n", strlen("\n"));
+ }
+ } else {
+ goto UNKNOWN_FMT_FIELD;
+ }
+ break;
+ case 'd':
+ case 'D':
+ if (strcasecmp(field, "Depends") == 0) {
+ /* Depends */
+ int i;
+
+ if (pkg->depends_count) {
+ char depstr[LINE_LEN];
+ len = 14 ;
+ for(i = 0; i < pkg->depends_count; i++) {
+ len = len + (strlen(pkg->depends_str[i])+4);
+ }
+ temp = (char *)realloc(temp,len);
+ if ( temp == NULL ){
+ fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
+ return NULL;
+ }
+ temp[0]='\0';
+ strncpy(temp, "Depends:", 10);
+ for(i = 0; i < pkg->depends_count; i++) {
+ snprintf(depstr, LINE_LEN, "%s %s", i == 0 ? "" : ",", pkg->depends_str[i]);
+ strncat(temp, depstr, strlen(depstr));
+ }
+ strncat(temp, "\n", strlen("\n"));
+ }
+ } else if (strcasecmp(field, "Description") == 0) {
+ /* Description */
+ if (pkg->description) {
+ temp = (char *)realloc(temp,strlen(pkg->description)+16);
+ if ( temp == NULL ){
+ fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
+ return NULL;
+ }
+ temp[0]='\0';
+ snprintf(temp, (strlen(pkg->description)+16), "Description: %s\n", pkg->description);
+ }
+ } else {
+ goto UNKNOWN_FMT_FIELD;
+ }
+ break;
+ case 'e':
+ case 'E': {
+ /* Essential */
+ if (pkg->essential) {
+ temp = (char *)realloc(temp,16);
+ if ( temp == NULL ){
+ fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
+ return NULL;
+ }
+ temp[0]='\0';
+ snprintf(temp, (16), "Essential: yes\n");
+ }
+ }
+ break;
+ case 'f':
+ case 'F': {
+ /* Filename */
+ if (pkg->filename) {
+ temp = (char *)realloc(temp,strlen(pkg->filename)+12);
+ if ( temp == NULL ){
+ fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
+ return NULL;
+ }
+ temp[0]='\0';
+ snprintf(temp, (strlen(pkg->filename)+12), "Filename: %s\n", pkg->filename);
+ }
+ }
+ break;
+ case 'i':
+ case 'I': {
+ if (strcasecmp(field, "Installed-Size") == 0) {
+ /* Installed-Size */
+ temp = (char *)realloc(temp,strlen(pkg->installed_size)+17);
+ if ( temp == NULL ){
+ fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
+ return NULL;
+ }
+ temp[0]='\0';
+ snprintf(temp, (strlen(pkg->installed_size)+17), "Installed-Size: %s\n", pkg->installed_size);
+ } else if (strcasecmp(field, "Installed-Time") == 0 && pkg->installed_time) {
+ temp = (char *)realloc(temp,29);
+ if ( temp == NULL ){
+ fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
+ return NULL;
+ }
+ temp[0]='\0';
+ snprintf(temp, 29, "Installed-Time: %lu\n", pkg->installed_time);
+ }
+ }
+ break;
+ case 'm':
+ case 'M': {
+ /* Maintainer | MD5sum */
+ if (strcasecmp(field, "Maintainer") == 0) {
+ /* Maintainer */
+ if (pkg->maintainer) {
+ temp = (char *)realloc(temp,strlen(pkg->maintainer)+14);
+ if ( temp == NULL ){
+ fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
+ return NULL;
+ }
+ temp[0]='\0';
+ snprintf(temp, (strlen(pkg->maintainer)+14), "maintainer: %s\n", pkg->maintainer);
+ }
+ } else if (strcasecmp(field, "MD5sum") == 0) {
+ /* MD5sum */
+ if (pkg->md5sum) {
+ temp = (char *)realloc(temp,strlen(pkg->md5sum)+11);
+ if ( temp == NULL ){
+ fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
+ return NULL;
+ }
+ temp[0]='\0';
+ snprintf(temp, (strlen(pkg->md5sum)+11), "MD5Sum: %s\n", pkg->md5sum);
+ }
+ } else {
+ goto UNKNOWN_FMT_FIELD;
+ }
+ }
+ break;
+ case 'p':
+ case 'P': {
+ if (strcasecmp(field, "Package") == 0) {
+ /* Package */
+ temp = (char *)realloc(temp,strlen(pkg->name)+11);
+ if ( temp == NULL ){
+ fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
+ return NULL;
+ }
+ temp[0]='\0';
+ snprintf(temp, (strlen(pkg->name)+11), "Package: %s\n", pkg->name);
+ } else if (strcasecmp(field, "Priority") == 0) {
+ /* Priority */
+ temp = (char *)realloc(temp,strlen(pkg->priority)+12);
+ if ( temp == NULL ){
+ fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
+ return NULL;
+ }
+ temp[0]='\0';
+ snprintf(temp, (strlen(pkg->priority)+12), "Priority: %s\n", pkg->priority);
+ } else if (strcasecmp(field, "Provides") == 0) {
+ /* Provides */
+ int i;
+
+ if (pkg->provides_count) {
+ /* Here we check if the ipkg_internal_use_only is used, and we discard it.*/
+ for ( i=0; i < pkg->provides_count; i++ ){
+ if (strstr(pkg->provides_str[i],"ipkg_internal_use_only")!=NULL) {
+ memset (pkg->provides_str[i],'\x0',strlen(pkg->provides_str[i])); /* Pigi clear my trick flag, just in case */
+ flag_provide_false = 1;
+ }
+ }
+ if ( !flag_provide_false || /* Pigi there is not my trick flag */
+ ((flag_provide_false) && (pkg->provides_count > 1))){ /* Pigi There is, but we also have others Provides */
+ char provstr[LINE_LEN];
+ len = 15;
+ for(i = 0; i < pkg->provides_count; i++) {
+ len = len + (strlen(pkg->provides_str[i])+5);
+ }
+ temp = (char *)realloc(temp,len);
+ if ( temp == NULL ){
+ fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
+ return NULL;
+ }
+ temp[0]='\0';
+ strncpy(temp, "Provides:", 12);
+ for(i = 0; i < pkg->provides_count; i++) {
+ if (strlen(pkg->provides_str[i])>0){;
+ snprintf(provstr, LINE_LEN, "%s %s", i == 1 ? "" : ",", pkg->provides_str[i]);
+ strncat(temp, provstr, strlen(provstr));
+ }
+ }
+ strncat(temp, "\n", strlen("\n"));
+ }
+ }
+ } else {
+ goto UNKNOWN_FMT_FIELD;
+ }
+ }
+ break;
+ case 'r':
+ case 'R': {
+ int i;
+ /* Replaces | Recommends*/
+ if (strcasecmp (field, "Replaces") == 0) {
+ if (pkg->replaces_count) {
+ char replstr[LINE_LEN];
+ len = 14;
+ for (i = 0; i < pkg->replaces_count; i++) {
+ len = len + (strlen(pkg->replaces_str[i])+5);
+ }
+ temp = (char *)realloc(temp,len);
+ if ( temp == NULL ){
+ fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
+ return NULL;
+ }
+ temp[0]='\0';
+ strncpy(temp, "Replaces:", 12);
+ for (i = 0; i < pkg->replaces_count; i++) {
+ snprintf(replstr, LINE_LEN, "%s %s", i == 0 ? "" : ",", pkg->replaces_str[i]);
+ strncat(temp, replstr, strlen(replstr));
+ }
+ strncat(temp, "\n", strlen("\n"));
+ }
+ } else if (strcasecmp (field, "Recommends") == 0) {
+ if (pkg->recommends_count) {
+ char recstr[LINE_LEN];
+ len = 15;
+ for(i = 0; i < pkg->recommends_count; i++) {
+ len = len + (strlen( pkg->recommends_str[i])+5);
+ }
+ temp = (char *)realloc(temp,len);
+ if ( temp == NULL ){
+ fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
+ return NULL;
+ }
+ temp[0]='\0';
+ strncpy(temp, "Recommends:", 13);
+ for(i = 0; i < pkg->recommends_count; i++) {
+ snprintf(recstr, LINE_LEN, "%s %s", i == 0 ? "" : ",", pkg->recommends_str[i]);
+ strncat(temp, recstr, strlen(recstr));
+ }
+ strncat(temp, "\n", strlen("\n"));
+ }
+ } else {
+ goto UNKNOWN_FMT_FIELD;
+ }
+ }
+ break;
+ case 's':
+ case 'S': {
+ /* Section | Size | Source | Status | Suggests */
+ if (strcasecmp(field, "Section") == 0) {
+ /* Section */
+ if (pkg->section) {
+ temp = (char *)realloc(temp,strlen(pkg->section)+11);
+ if ( temp == NULL ){
+ fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
+ return NULL;
+ }
+ temp[0]='\0';
+ snprintf(temp, (strlen(pkg->section)+11), "Section: %s\n", pkg->section);
+ }
+ } else if (strcasecmp(field, "Size") == 0) {
+ /* Size */
+ if (pkg->size) {
+ temp = (char *)realloc(temp,strlen(pkg->size)+8);
+ if ( temp == NULL ){
+ fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
+ return NULL;
+ }
+ temp[0]='\0';
+ snprintf(temp, (strlen(pkg->size)+8), "Size: %s\n", pkg->size);
+ }
+ } else if (strcasecmp(field, "Source") == 0) {
+ /* Source */
+ if (pkg->source) {
+ temp = (char *)realloc(temp,strlen(pkg->source)+10);
+ if ( temp == NULL ){
+ fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
+ return NULL;
+ }
+ temp[0]='\0';
+ snprintf(temp, (strlen(pkg->source)+10), "Source: %s\n", pkg->source);
+ }
+ } else if (strcasecmp(field, "Status") == 0) {
+ /* Status */
+ /* Benjamin Pineau note: we should avoid direct usage of
+ * strlen(arg) without keeping "arg" for later free()
+ */
+ char *pflag=pkg_state_flag_to_str(pkg->state_flag);
+ char *pstat=pkg_state_status_to_str(pkg->state_status);
+ char *pwant=pkg_state_want_to_str(pkg->state_want);
+
+ size_t sum_of_sizes = (size_t) ( strlen(pwant)+ strlen(pflag)+ strlen(pstat) + 12 );
+ temp = (char *)realloc(temp,sum_of_sizes);
+ if ( temp == NULL ){
+ fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
+ return NULL;
+ }
+ temp[0]='\0';
+ snprintf(temp, sum_of_sizes , "Status: %s %s %s\n", pwant, pflag, pstat);
+ free(pflag);
+ free(pwant);
+ if(pstat) /* pfstat can be NULL if ENOMEM */
+ free(pstat);
+ } else if (strcasecmp(field, "Suggests") == 0) {
+ if (pkg->suggests_count) {
+ int i;
+ char sugstr[LINE_LEN];
+ len = 13;
+ for(i = 0; i < pkg->suggests_count; i++) {
+ len = len + (strlen(pkg->suggests_str[i])+5);
+ }
+ temp = (char *)realloc(temp,len);
+ if ( temp == NULL ){
+ fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
+ return NULL;
+ }
+ temp[0]='\0';
+ strncpy(temp, "Suggests:", 10);
+ for(i = 0; i < pkg->suggests_count; i++) {
+ snprintf(sugstr, LINE_LEN, "%s %s", i == 0 ? "" : ",", pkg->suggests_str[i]);
+ strncat(temp, sugstr, strlen(sugstr));
+ }
+ strncat(temp, "\n", strlen("\n"));
+ }
+ } else {
+ goto UNKNOWN_FMT_FIELD;
+ }
+ }
+ break;
+ case 'v':
+ case 'V': {
+ /* Version */
+ char *version = pkg_version_str_alloc(pkg);
+ temp = (char *)realloc(temp,strlen(version)+14);
+ if ( temp == NULL ){
+ fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
+ return NULL;
+ }
+ temp[0]='\0';
+ snprintf(temp, (strlen(version)+12), "Version: %s\n", version);
+ free(version);
+ }
+ break;
+ default:
+ goto UNKNOWN_FMT_FIELD;
+ }
+
+ if ( strlen(temp)<2 ) {
+ temp[0]='\0';
+ }
+ return temp;
+
+ UNKNOWN_FMT_FIELD:
+ fprintf(stderr, "%s: ERROR: Unknown field name: %s\n", __FUNCTION__, field);
+ if ( strlen(temp)<2 ) {
+ temp[0]='\0';
+ }
+
+ return temp;
+}
+
+void pkg_print_info(pkg_t *pkg, FILE *file)
+{
+ char * buff;
+ if (pkg == NULL) {
+ return;
+ }
+
+ buff = pkg_formatted_info(pkg);
+ if ( buff == NULL )
+ return;
+ if (strlen(buff)>2){
+ fwrite(buff, 1, strlen(buff), file);
+ }
+ free(buff);
+}
+
+void pkg_print_status(pkg_t * pkg, FILE * file)
+{
+ if (pkg == NULL) {
+ return;
+ }
+
+ /* XXX: QUESTION: Do we actually want more fields here? The
+ original idea was to save space by installing only what was
+ needed for actual computation, (package, version, status,
+ essential, conffiles). The assumption is that all other fields
+ can be found in th available file.
+
+ But, someone proposed the idea to make it possible to
+ reconstruct a .ipk from an installed package, (ie. for beaming
+ from one handheld to another). So, maybe we actually want a few
+ more fields here, (depends, suggests, etc.), so that that would
+ be guaranteed to work even in the absence of more information
+ from the available file.
+
+ 28-MAR-03: kergoth and I discussed this yesterday. We think
+ the essential info needs to be here for all installed packages
+ because they may not appear in the Packages files on various
+ feeds. Furthermore, one should be able to install from URL or
+ local storage without requiring a Packages file from any feed.
+ -Jamey
+ */
+ pkg_print_field(pkg, file, "Package");
+ pkg_print_field(pkg, file, "Version");
+ pkg_print_field(pkg, file, "Depends");
+ pkg_print_field(pkg, file, "Recommends");
+ pkg_print_field(pkg, file, "Suggests");
+ pkg_print_field(pkg, file, "Provides");
+ pkg_print_field(pkg, file, "Replaces");
+ pkg_print_field(pkg, file, "Conflicts");
+ pkg_print_field(pkg, file, "Status");
+ pkg_print_field(pkg, file, "Essential"); /* @@@@ should be removed in future release. */
+ pkg_print_field(pkg, file, "Architecture");
+ pkg_print_field(pkg, file, "Conffiles");
+ pkg_print_field(pkg, file, "Installed-Time");
+ fputs("\n", file);
+}
+
+void pkg_print_field(pkg_t *pkg, FILE *file, const char *field)
+{
+ char *buff;
+ if (strlen(field) < PKG_MINIMUM_FIELD_NAME_LEN) {
+ fprintf(stderr, "%s: ERROR: Unknown field name: %s\n",
+ __FUNCTION__, field);
+ }
+ buff = pkg_formatted_field(pkg, field);
+ if (strlen(buff)>2) {
+ fprintf(file, "%s", buff);
+ fflush(file);
+ }
+ free(buff);
+ return;
+}
+
+/*
+ * libdpkg - Debian packaging suite library routines
+ * vercmp.c - comparison of version numbers
+ *
+ * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ */
+int pkg_compare_versions(const pkg_t *pkg, const pkg_t *ref_pkg)
+{
+ int r;
+
+ if (pkg->epoch > ref_pkg->epoch) {
+ return 1;
+ }
+
+ if (pkg->epoch < ref_pkg->epoch) {
+ return -1;
+ }
+
+ r = verrevcmp(pkg->version, ref_pkg->version);
+ if (r) {
+ return r;
+ }
+
+#ifdef USE_DEBVERSION
+ r = verrevcmp(pkg->revision, ref_pkg->revision);
+ if (r) {
+ return r;
+ }
+
+ r = verrevcmp(pkg->familiar_revision, ref_pkg->familiar_revision);
+#endif
+
+ return r;
+}
+
+int verrevcmp(const char *val, const char *ref)
+{
+ int vc, rc;
+ long vl, rl;
+ const char *vp, *rp;
+ const char *vsep, *rsep;
+
+ if (!val) val= "";
+ if (!ref) ref= "";
+ for (;;) {
+ vp= val; while (*vp && !isdigit(*vp)) vp++;
+ rp= ref; while (*rp && !isdigit(*rp)) rp++;
+ for (;;) {
+ vc= (val == vp) ? 0 : *val++;
+ rc= (ref == rp) ? 0 : *ref++;
+ if (!rc && !vc) break;
+ if (vc && !isalpha(vc)) vc += 256; /* assumes ASCII character set */
+ if (rc && !isalpha(rc)) rc += 256;
+ if (vc != rc) return vc - rc;
+ }
+ val= vp;
+ ref= rp;
+ vl=0; if (isdigit(*vp)) vl= strtol(val,(char**)&val,10);
+ rl=0; if (isdigit(*rp)) rl= strtol(ref,(char**)&ref,10);
+ if (vl != rl) return vl - rl;
+
+ vc = *val;
+ rc = *ref;
+ vsep = strchr(".-", vc);
+ rsep = strchr(".-", rc);
+ if (vsep && !rsep) return -1;
+ if (!vsep && rsep) return +1;
+
+ if (!*val && !*ref) return 0;
+ if (!*val) return -1;
+ if (!*ref) return +1;
+ }
+}
+
+int pkg_version_satisfied(pkg_t *it, pkg_t *ref, const char *op)
+{
+ int r;
+
+ r = pkg_compare_versions(it, ref);
+
+ if (strcmp(op, "<=") == 0 || strcmp(op, "<") == 0) {
+ return r <= 0;
+ }
+
+ if (strcmp(op, ">=") == 0 || strcmp(op, ">") == 0) {
+ return r >= 0;
+ }
+
+ if (strcmp(op, "<<") == 0) {
+ return r < 0;
+ }
+
+ if (strcmp(op, ">>") == 0) {
+ return r > 0;
+ }
+
+ if (strcmp(op, "=") == 0) {
+ return r == 0;
+ }
+
+ fprintf(stderr, "unknown operator: %s", op);
+ return 0;
+}
+
+int pkg_name_version_and_architecture_compare(void *p1, void *p2)
+{
+ const pkg_t *a = *(const pkg_t **)p1;
+ const pkg_t *b = *(const pkg_t **)p2;
+ int namecmp;
+ int vercmp;
+ if (!a->name || !b->name) {
+ fprintf(stderr, "pkg_name_version_and_architecture_compare: a=%p a->name=%p b=%p b->name=%p\n",
+ a, a->name, b, b->name);
+ return 0;
+ }
+
+ namecmp = strcmp(a->name, b->name);
+ if (namecmp)
+ return namecmp;
+ vercmp = pkg_compare_versions(a, b);
+ if (vercmp)
+ return vercmp;
+ if (!a->arch_priority || !b->arch_priority) {
+ fprintf(stderr, "pkg_name_version_and_architecture_compare: a=%p a->arch_priority=%i b=%p b->arch_priority=%i\n",
+ a, a->arch_priority, b, b->arch_priority);
+ return 0;
+ }
+ if (a->arch_priority > b->arch_priority)
+ return 1;
+ if (a->arch_priority < b->arch_priority)
+ return -1;
+ return 0;
+}
+
+int abstract_pkg_name_compare(void *p1, void *p2)
+{
+ const abstract_pkg_t *a = *(const abstract_pkg_t **)p1;
+ const abstract_pkg_t *b = *(const abstract_pkg_t **)p2;
+ if (!a->name || !b->name) {
+ fprintf(stderr, "abstract_pkg_name_compare: a=%p a->name=%p b=%p b->name=%p\n",
+ a, a->name, b, b->name);
+ return 0;
+ }
+ return strcmp(a->name, b->name);
+}
+
+
+char *pkg_version_str_alloc(pkg_t *pkg)
+{
+ char *complete_version;
+ char *epoch_str;
+#ifdef USE_DEBVERSION
+ char *revision_str;
+ char *familiar_revision_str;
+#endif
+
+ if (pkg->epoch) {
+ sprintf_alloc(&epoch_str, "%d:", pkg->epoch);
+ } else {
+ epoch_str = strdup("");
+ }
+
+#ifdef USE_DEBVERSION
+ if (pkg->revision && strlen(pkg->revision)) {
+ sprintf_alloc(&revision_str, "-%s", pkg->revision);
+ } else {
+ revision_str = strdup("");
+ }
+
+ if (pkg->familiar_revision && strlen(pkg->familiar_revision)) {
+ sprintf_alloc(&familiar_revision_str, "-fam%s", pkg->familiar_revision);
+ } else {
+ familiar_revision_str = strdup("");
+ }
+#endif
+
+#ifdef USE_DEBVERSION
+ sprintf_alloc(&complete_version, "%s%s%s%s",
+ epoch_str, pkg->version, revision_str, familiar_revision_str);
+#else
+ sprintf_alloc(&complete_version, "%s%s",
+ epoch_str, pkg->version);
+#endif
+
+ free(epoch_str);
+#ifdef USE_DEBVERSION
+ free(revision_str);
+ free(familiar_revision_str);
+#endif
+
+ return complete_version;
+}
+
+str_list_t *pkg_get_installed_files(pkg_t *pkg)
+{
+ int err;
+ char *list_file_name = NULL;
+ FILE *list_file = NULL;
+ char *line;
+ char *installed_file_name;
+ int rootdirlen;
+
+ pkg->installed_files_ref_cnt++;
+
+ if (pkg->installed_files) {
+ return pkg->installed_files;
+ }
+
+ pkg->installed_files = str_list_alloc();
+ if (pkg->installed_files == NULL) {
+ fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
+ return NULL;
+ }
+
+ /* For uninstalled packages, get the file list firectly from the package.
+ For installed packages, look at the package.list file in the database.
+ */
+ if (pkg->state_status == SS_NOT_INSTALLED || pkg->dest == NULL) {
+ if (pkg->local_filename == NULL) {
+ return pkg->installed_files;
+ }
+ /* XXX: CLEANUP: Maybe rewrite this to avoid using a temporary
+ file. In other words, change deb_extract so that it can
+ simply return the file list as a char *[] rather than
+ insisting on writing in to a FILE * as it does now. */
+ list_file = tmpfile();
+ err = pkg_extract_data_file_names_to_stream(pkg, list_file);
+ if (err) {
+ fclose(list_file);
+ fprintf(stderr, "%s: Error extracting file list from %s: %s\n",
+ __FUNCTION__, pkg->local_filename, strerror(err));
+ return pkg->installed_files;
+ }
+ rewind(list_file);
+ } else {
+ sprintf_alloc(&list_file_name, "%s/%s.list",
+ pkg->dest->info_dir, pkg->name);
+ if (! file_exists(list_file_name)) {
+ free(list_file_name);
+ return pkg->installed_files;
+ }
+
+ list_file = fopen(list_file_name, "r");
+ if (list_file == NULL) {
+ fprintf(stderr, "WARNING: Cannot open %s: %s\n",
+ list_file_name, strerror(errno));
+ free(list_file_name);
+ return pkg->installed_files;
+ }
+ free(list_file_name);
+ }
+
+ rootdirlen = strlen( pkg->dest->root_dir );
+ while (1) {
+ char *file_name;
+
+ line = file_read_line_alloc(list_file);
+ if (line == NULL) {
+ break;
+ }
+ str_chomp(line);
+ file_name = line;
+
+ /* Take pains to avoid uglies like "/./" in the middle of file_name. */
+ if( strncmp( pkg->dest->root_dir,
+ file_name,
+ rootdirlen ) ) {
+ if (*file_name == '.') {
+ file_name++;
+ }
+ if (*file_name == '/') {
+ file_name++;
+ }
+
+ /* Freed in pkg_free_installed_files */
+ sprintf_alloc(&installed_file_name, "%s%s", pkg->dest->root_dir, file_name);
+ } else {
+ // already contains root_dir as header -> ABSOLUTE
+ sprintf_alloc(&installed_file_name, "%s", file_name);
+ }
+ str_list_append(pkg->installed_files, installed_file_name);
+ free(line);
+ }
+
+ fclose(list_file);
+
+ return pkg->installed_files;
+}
+
+/* XXX: CLEANUP: This function and it's counterpart,
+ (pkg_get_installed_files), do not match our init/deinit naming
+ convention. Nor the alloc/free convention. But, then again, neither
+ of these conventions currrently fit the way these two functions
+ work. */
+int pkg_free_installed_files(pkg_t *pkg)
+{
+ str_list_elt_t *iter;
+
+ pkg->installed_files_ref_cnt--;
+ if (pkg->installed_files_ref_cnt > 0) {
+ return 0;
+ }
+
+ if (pkg->installed_files) {
+
+ for (iter = pkg->installed_files->head; iter; iter = iter->next) {
+ /* malloced in pkg_get_installed_files */
+ free (iter->data);
+ iter->data = NULL;
+ }
+
+ str_list_deinit(pkg->installed_files);
+ }
+
+ pkg->installed_files = NULL;
+
+ return 0;
+}
+
+int pkg_remove_installed_files_list(ipkg_conf_t *conf, pkg_t *pkg)
+{
+ int err;
+ char *list_file_name;
+
+ //I don't think pkg_free_installed_files should be called here. Jamey
+ //pkg_free_installed_files(pkg);
+
+ sprintf_alloc(&list_file_name, "%s/%s.list",
+ pkg->dest->info_dir, pkg->name);
+ if (!conf->noaction) {
+ err = unlink(list_file_name);
+ free(list_file_name);
+
+ if (err) {
+ return errno;
+ }
+ }
+ return 0;
+}
+
+conffile_t *pkg_get_conffile(pkg_t *pkg, const char *file_name)
+{
+ conffile_list_elt_t *iter;
+ conffile_t *conffile;
+
+ if (pkg == NULL) {
+ return NULL;
+ }
+
+ for (iter = pkg->conffiles.head; iter; iter = iter->next) {
+ conffile = iter->data;
+
+ if (strcmp(conffile->name, file_name) == 0) {
+ return conffile;
+ }
+ }
+
+ return NULL;
+}
+
+int pkg_run_script(ipkg_conf_t *conf, pkg_t *pkg,
+ const char *script, const char *args)
+{
+ int err;
+ char *path;
+ char *cmd;
+
+ /* XXX: FEATURE: When conf->offline_root is set, we should run the
+ maintainer script within a chroot environment. */
+
+ /* Installed packages have scripts in pkg->dest->info_dir, uninstalled packages
+ have scripts in pkg->tmp_unpack_dir. */
+ if (pkg->state_status == SS_INSTALLED || pkg->state_status == SS_UNPACKED) {
+ if (pkg->dest == NULL) {
+ fprintf(stderr, "%s: ERROR: installed package %s has a NULL dest\n",
+ __FUNCTION__, pkg->name);
+ return EINVAL;
+ }
+ sprintf_alloc(&path, "%s/%s.%s", pkg->dest->info_dir, pkg->name, script);
+ } else {
+ if (pkg->tmp_unpack_dir == NULL) {
+ fprintf(stderr, "%s: ERROR: uninstalled package %s has a NULL tmp_unpack_dir\n",
+ __FUNCTION__, pkg->name);
+ return EINVAL;
+ }
+ sprintf_alloc(&path, "%s/%s", pkg->tmp_unpack_dir, script);
+ }
+
+ ipkg_message(conf, IPKG_INFO, "Running script %s\n", path);
+ if (conf->noaction) return 0;
+
+ /* XXX: CLEANUP: There must be a better way to handle maintainer
+ scripts when running with offline_root mode and/or a dest other
+ than '/'. I've been playing around with some clever chroot
+ tricks and I might come up with something workable. */
+ if (conf->offline_root) {
+ setenv("IPKG_OFFLINE_ROOT", conf->offline_root, 1);
+ }
+
+ setenv("PKG_ROOT",
+ pkg->dest ? pkg->dest->root_dir : conf->default_dest->root_dir, 1);
+
+ if (! file_exists(path)) {
+ free(path);
+ return 0;
+ }
+
+ if (conf->offline_root) {
+ fprintf(stderr, "(offline root mode: not running %s.%s)\n", pkg->name, script);
+ free(path);
+ return 0;
+ }
+
+ sprintf_alloc(&cmd, "%s %s", path, args);
+ free(path);
+
+ err = xsystem(cmd);
+ free(cmd);
+
+ if (err) {
+ fprintf(stderr, "%s script returned status %d\n", script, err);
+ return err;
+ }
+
+ return 0;
+}
+
+char *pkg_state_want_to_str(pkg_state_want_t sw)
+{
+ int i;
+
+ for (i=0; i < ARRAY_SIZE(pkg_state_want_map); i++) {
+ if (pkg_state_want_map[i].value == sw) {
+ return strdup(pkg_state_want_map[i].str);
+ }
+ }
+
+ fprintf(stderr, "%s: ERROR: Illegal value for state_want: %d\n",
+ __FUNCTION__, sw);
+ return strdup("<STATE_WANT_UNKNOWN>");
+}
+
+pkg_state_want_t pkg_state_want_from_str(char *str)
+{
+ int i;
+
+ for (i=0; i < ARRAY_SIZE(pkg_state_want_map); i++) {
+ if (strcmp(str, pkg_state_want_map[i].str) == 0) {
+ return pkg_state_want_map[i].value;
+ }
+ }
+
+ fprintf(stderr, "%s: ERROR: Illegal value for state_want string: %s\n",
+ __FUNCTION__, str);
+ return SW_UNKNOWN;
+}
+
+char *pkg_state_flag_to_str(pkg_state_flag_t sf)
+{
+ int i;
+ int len = 3; /* ok\000 is minimum */
+ char *str = NULL;
+
+ /* clear the temporary flags before converting to string */
+ sf &= SF_NONVOLATILE_FLAGS;
+
+ if (sf == 0) {
+ return strdup("ok");
+ } else {
+
+ for (i=0; i < ARRAY_SIZE(pkg_state_flag_map); i++) {
+ if (sf & pkg_state_flag_map[i].value) {
+ len += strlen(pkg_state_flag_map[i].str) + 1;
+ }
+ }
+ str = malloc(len);
+ if ( str == NULL ) {
+ fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
+ return NULL;
+ }
+ str[0] = 0;
+ for (i=0; i < ARRAY_SIZE(pkg_state_flag_map); i++) {
+ if (sf & pkg_state_flag_map[i].value) {
+ strcat(str, pkg_state_flag_map[i].str);
+ strcat(str, ",");
+ }
+ }
+ len = strlen(str);
+ str[len-1] = 0; /* squash last comma */
+ return str;
+ }
+}
+
+pkg_state_flag_t pkg_state_flag_from_str(char *str)
+{
+ int i;
+ int sf = SF_OK;
+
+ if (strcmp(str, "ok") == 0) {
+ return SF_OK;
+ }
+ for (i=0; i < ARRAY_SIZE(pkg_state_flag_map); i++) {
+ const char *sfname = pkg_state_flag_map[i].str;
+ int sfname_len = strlen(sfname);
+ if (strncmp(str, sfname, sfname_len) == 0) {
+ sf |= pkg_state_flag_map[i].value;
+ str += sfname_len;
+ if (str[0] == ',') {
+ str++;
+ } else {
+ break;
+ }
+ }
+ }
+
+ return sf;
+}
+
+char *pkg_state_status_to_str(pkg_state_status_t ss)
+{
+ int i;
+
+ for (i=0; i < ARRAY_SIZE(pkg_state_status_map); i++) {
+ if (pkg_state_status_map[i].value == ss) {
+ return strdup(pkg_state_status_map[i].str);
+ }
+ }
+
+ fprintf(stderr, "%s: ERROR: Illegal value for state_status: %d\n",
+ __FUNCTION__, ss);
+ return strdup("<STATE_STATUS_UNKNOWN>");
+}
+
+pkg_state_status_t pkg_state_status_from_str(char *str)
+{
+ int i;
+
+ for (i=0; i < ARRAY_SIZE(pkg_state_status_map); i++) {
+ if (strcmp(str, pkg_state_status_map[i].str) == 0) {
+ return pkg_state_status_map[i].value;
+ }
+ }
+
+ fprintf(stderr, "%s: ERROR: Illegal value for state_status string: %s\n",
+ __FUNCTION__, str);
+ return SS_NOT_INSTALLED;
+}
+
+int pkg_arch_supported(ipkg_conf_t *conf, pkg_t *pkg)
+{
+ nv_pair_list_elt_t *l;
+
+ if (!pkg->architecture)
+ return 1;
+
+ l = conf->arch_list.head;
+
+ while (l) {
+ nv_pair_t *nv = l->data;
+ if (strcmp(nv->name, pkg->architecture) == 0) {
+ ipkg_message(conf, IPKG_DEBUG, "arch %s (priority %s) supported for pkg %s\n", nv->name, nv->value, pkg->name);
+ return 1;
+ }
+ l = l->next;
+ }
+
+ ipkg_message(conf, IPKG_DEBUG, "arch %s unsupported for pkg %s\n", pkg->architecture, pkg->name);
+ return 0;
+}
+
+int pkg_get_arch_priority(ipkg_conf_t *conf, const char *archname)
+{
+ nv_pair_list_elt_t *l;
+
+ l = conf->arch_list.head;
+
+ while (l) {
+ nv_pair_t *nv = l->data;
+ if (strcmp(nv->name, archname) == 0) {
+ int priority = strtol(nv->value, NULL, 0);
+ return priority;
+ }
+ l = l->next;
+ }
+ return 0;
+}
+
+int pkg_info_preinstall_check(ipkg_conf_t *conf)
+{
+ int i;
+ hash_table_t *pkg_hash = &conf->pkg_hash;
+ pkg_vec_t *available_pkgs = pkg_vec_alloc();
+ pkg_vec_t *installed_pkgs = pkg_vec_alloc();
+
+ ipkg_message(conf, IPKG_INFO, "pkg_info_preinstall_check: updating arch priority for each package\n");
+ pkg_hash_fetch_available(pkg_hash, available_pkgs);
+ /* update arch_priority for each package */
+ for (i = 0; i < available_pkgs->len; i++) {
+ pkg_t *pkg = available_pkgs->pkgs[i];
+ int arch_priority = 1;
+ if (!pkg)
+ continue;
+ // ipkg_message(conf, IPKG_DEBUG2, " package %s version=%s arch=%p:", pkg->name, pkg->version, pkg->architecture);
+ if (pkg->architecture)
+ arch_priority = pkg_get_arch_priority(conf, pkg->architecture);
+ else
+ ipkg_message(conf, IPKG_ERROR, "pkg_info_preinstall_check: no architecture for package %s\n", pkg->name);
+ // ipkg_message(conf, IPKG_DEBUG2, "%s arch_priority=%d\n", pkg->architecture, arch_priority);
+ pkg->arch_priority = arch_priority;
+ }
+
+ for (i = 0; i < available_pkgs->len; i++) {
+ pkg_t *pkg = available_pkgs->pkgs[i];
+ if (!pkg->arch_priority && (pkg->state_flag || (pkg->state_want != SW_UNKNOWN))) {
+ /* clear flags and want for any uninstallable package */
+ ipkg_message(conf, IPKG_NOTICE, "Clearing state_want and state_flag for pkg=%s (arch_priority=%d flag=%d want=%d)\n",
+ pkg->name, pkg->arch_priority, pkg->state_flag, pkg->state_want);
+ pkg->state_want = SW_UNKNOWN;
+ pkg->state_flag = 0;
+ }
+ }
+ pkg_vec_free(available_pkgs);
+
+ /* update the file owner data structure */
+ ipkg_message(conf, IPKG_INFO, "pkg_info_preinstall_check: update file owner list\n");
+ pkg_hash_fetch_all_installed(pkg_hash, installed_pkgs);
+ for (i = 0; i < installed_pkgs->len; i++) {
+ pkg_t *pkg = installed_pkgs->pkgs[i];
+ str_list_t *installed_files = pkg_get_installed_files(pkg); /* this causes installed_files to be cached */
+ str_list_elt_t *iter;
+ if (installed_files == NULL) {
+ ipkg_message(conf, IPKG_ERROR, "No installed files for pkg %s\n", pkg->name);
+ break;
+ }
+ for (iter = installed_files->head; iter; iter = iter->next) {
+ char *installed_file = iter->data;
+ // ipkg_message(conf, IPKG_DEBUG2, "pkg %s: file=%s\n", pkg->name, installed_file);
+ file_hash_set_file_owner(conf, installed_file, pkg);
+ }
+ }
+ pkg_vec_free(installed_pkgs);
+
+ return 0;
+}
+
+struct pkg_write_filelist_data {
+ ipkg_conf_t *conf;
+ pkg_t *pkg;
+ FILE *stream;
+};
+
+void pkg_write_filelist_helper(const char *key, void *entry_, void *data_)
+{
+ struct pkg_write_filelist_data *data = data_;
+ pkg_t *entry = entry_;
+ if (entry == data->pkg) {
+ fprintf(data->stream, "%s\n", key);
+ }
+}
+
+int pkg_write_filelist(ipkg_conf_t *conf, pkg_t *pkg)
+{
+ struct pkg_write_filelist_data data;
+ char *list_file_name = NULL;
+ int err = 0;
+
+ if (!pkg) {
+ ipkg_message(conf, IPKG_ERROR, "Null pkg\n");
+ return -EINVAL;
+ }
+ ipkg_message(conf, IPKG_INFO,
+ " creating %s.list file\n", pkg->name);
+ sprintf_alloc(&list_file_name, "%s/%s.list", pkg->dest->info_dir, pkg->name);
+ if (!list_file_name) {
+ ipkg_message(conf, IPKG_ERROR, "Failed to alloc list_file_name\n");
+ return -ENOMEM;
+ }
+ ipkg_message(conf, IPKG_INFO,
+ " creating %s file for pkg %s\n", list_file_name, pkg->name);
+ data.stream = fopen(list_file_name, "w");
+ if (!data.stream) {
+ ipkg_message(conf, IPKG_ERROR, "Could not open %s for writing: %s\n",
+ list_file_name, strerror(errno));
+ return errno;
+ }
+ data.pkg = pkg;
+ data.conf = conf;
+ hash_table_foreach(&conf->file_hash, pkg_write_filelist_helper, &data);
+ fclose(data.stream);
+ free(list_file_name);
+
+ return err;
+}
+
+int pkg_write_changed_filelists(ipkg_conf_t *conf)
+{
+ pkg_vec_t *installed_pkgs = pkg_vec_alloc();
+ hash_table_t *pkg_hash = &conf->pkg_hash;
+ int i;
+ int err;
+ if (conf->noaction)
+ return 0;
+
+ ipkg_message(conf, IPKG_INFO, "%s: saving changed filelists\n", __FUNCTION__);
+ pkg_hash_fetch_all_installed(pkg_hash, installed_pkgs);
+ for (i = 0; i < installed_pkgs->len; i++) {
+ pkg_t *pkg = installed_pkgs->pkgs[i];
+ if (pkg->state_flag & SF_FILELIST_CHANGED) {
+ ipkg_message(conf, IPKG_DEBUG, "Calling pkg_write_filelist for pkg=%s from %s\n", pkg->name, __FUNCTION__);
+ err = pkg_write_filelist(conf, pkg);
+ if (err)
+ ipkg_message(conf, IPKG_NOTICE, "pkg_write_filelist pkg=%s returned %d\n", pkg->name, err);
+ }
+ }
+ return 0;
+}
diff -ruN busybox-1.00-orig/archival/libipkg/pkg.h busybox-1.00+ipkg-0.99.154/archival/libipkg/pkg.h
--- busybox-1.00-orig/archival/libipkg/pkg.h 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/pkg.h 2005-10-26 17:36:46.000000000 +0200
@@ -0,0 +1,230 @@
+/* pkg.h - the itsy package management system
+
+ Carl D. Worth
+
+ Copyright (C) 2001 University of Southern California
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#ifndef PKG_H
+#define PKG_H
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "pkg_vec.h"
+#include "str_list.h"
+#include "pkg_src.h"
+#include "pkg_dest.h"
+#include "ipkg_conf.h"
+#include "conffile_list.h"
+
+struct ipkg_conf;
+
+
+#define ARRAY_SIZE(array) sizeof(array) / sizeof((array)[0])
+
+/* I think "Size" is currently the shortest field name */
+#define PKG_MINIMUM_FIELD_NAME_LEN 4
+
+enum pkg_state_want
+{
+ SW_UNKNOWN = 1,
+ SW_INSTALL,
+ SW_DEINSTALL,
+ SW_PURGE,
+ SW_LAST_STATE_WANT
+};
+typedef enum pkg_state_want pkg_state_want_t;
+
+enum pkg_state_flag
+{
+ SF_OK = 0,
+ SF_REINSTREQ = 1,
+ SF_HOLD = 2, /* do not upgrade version */
+ SF_REPLACE = 4, /* replace this package */
+ SF_NOPRUNE = 8, /* do not remove obsolete files */
+ SF_PREFER = 16, /* prefer this version */
+ SF_OBSOLETE = 32, /* old package in upgrade pair */
+ SF_MARKED = 64, /* temporary mark */
+ SF_FILELIST_CHANGED = 128, /* needs filelist written */
+ SF_USER = 256,
+ SF_LAST_STATE_FLAG
+};
+typedef enum pkg_state_flag pkg_state_flag_t;
+#define SF_NONVOLATILE_FLAGS (SF_HOLD|SF_NOPRUNE|SF_PREFER|SF_OBSOLETE|SF_USER)
+
+enum pkg_state_status
+{
+ SS_NOT_INSTALLED = 1,
+ SS_UNPACKED,
+ SS_HALF_CONFIGURED,
+ SS_INSTALLED,
+ SS_HALF_INSTALLED,
+ SS_CONFIG_FILES,
+ SS_POST_INST_FAILED,
+ SS_REMOVAL_FAILED,
+ SS_LAST_STATE_STATUS
+};
+typedef enum pkg_state_status pkg_state_status_t;
+
+struct abstract_pkg{
+ char * name;
+ int dependencies_checked;
+ pkg_vec_t * pkgs;
+ pkg_state_status_t state_status;
+ pkg_state_flag_t state_flag;
+ struct abstract_pkg ** depended_upon_by; /* @@@@ this should be abstract_pkg_vec_t -Jamey */
+ abstract_pkg_vec_t * provided_by;
+ abstract_pkg_vec_t * replaced_by;
+};
+
+#include "pkg_depends.h"
+
+/* XXX: CLEANUP: I'd like to clean up pkg_t in several ways:
+
+ The 3 version fields should go into a single version struct. (This
+ is especially important since, currently, pkg->version can easily
+ be mistaken for pkg_verson_str_alloc(pkg) although they are very
+ distinct. This has been the source of multiple bugs.
+
+ The 3 state fields could possibly also go into their own struct.
+
+ All fields which deal with lists of packages, (Depends,
+ Pre-Depends, Provides, Suggests, Recommends, Enhances), should each
+ be handled by a single struct in pkg_t
+
+ All string fields for which there is a small set of possible
+ values, (section, maintainer, architecture, maybe version?), that
+ are reused among different packages -- for all such packages we
+ should move from "char *"s to some atom datatype to share data
+ storage and use less memory. We might even do reference counting,
+ but probably not since most often we only create new pkg_t structs,
+ we don't often free them. */
+struct pkg
+{
+ char *name;
+ unsigned long epoch;
+ char *version;
+ char *revision;
+ char *familiar_revision;
+ pkg_src_t *src;
+ pkg_dest_t *dest;
+ char *architecture;
+ char *section;
+ char *maintainer;
+ char *description;
+ pkg_state_want_t state_want;
+ pkg_state_flag_t state_flag;
+ pkg_state_status_t state_status;
+ char **depends_str;
+ int depends_count;
+ char **pre_depends_str;
+ int pre_depends_count;
+ char **recommends_str;
+ int recommends_count;
+ char **suggests_str;
+ int suggests_count;
+ compound_depend_t * depends;
+
+ /* Abhaya: new conflicts */
+ char **conflicts_str;
+ compound_depend_t * conflicts;
+ int conflicts_count;
+
+ char **replaces_str;
+ int replaces_count;
+ abstract_pkg_t ** replaces;
+
+ char **provides_str;
+ int provides_count;
+ abstract_pkg_t ** provides;
+
+ abstract_pkg_t *parent;
+
+ pkg_t *old_pkg; /* during upgrade, points from installee to previously installed */
+
+ char *filename;
+ char *local_filename;
+ char *url;
+ char *tmp_unpack_dir;
+ char *md5sum;
+ char *size;
+ char *installed_size;
+ char *priority;
+ char *source;
+ conffile_list_t conffiles;
+ time_t installed_time;
+ /* As pointer for lazy evaluation */
+ str_list_t *installed_files;
+ /* XXX: CLEANUP: I'd like to perhaps come up with a better
+ mechanism to avoid the problem here, (which is that the
+ installed_files list was being freed from an inner loop while
+ still being used within an outer loop. */
+ int installed_files_ref_cnt;
+ int essential;
+ int arch_priority;
+};
+
+pkg_t *pkg_new(void);
+int pkg_init(pkg_t *pkg);
+void pkg_deinit(pkg_t *pkg);
+int pkg_init_from_file(pkg_t *pkg, const char *filename);
+abstract_pkg_t *abstract_pkg_new(void);
+int abstract_pkg_init(abstract_pkg_t *ab_pkg);
+
+/*
+ * merges fields from newpkg into oldpkg.
+ * Forcibly sets oldpkg state_status, state_want and state_flags if set_status is nonzero
+ */
+int pkg_merge(pkg_t *oldpkg, pkg_t *newpkg, int set_status);
+
+char *pkg_version_str_alloc(pkg_t *pkg);
+
+int pkg_compare_versions(const pkg_t *pkg, const pkg_t *ref_pkg);
+int pkg_name_version_and_architecture_compare(void *a, void *b);
+int abstract_pkg_name_compare(void *a, void *b);
+
+char * pkg_formatted_info(pkg_t *pkg );
+char * pkg_formatted_field(pkg_t *pkg, const char *field );
+
+void set_flags_from_control(ipkg_conf_t *conf, pkg_t *pkg);
+
+void pkg_print_info(pkg_t *pkg, FILE *file);
+void pkg_print_status(pkg_t * pkg, FILE * file);
+void pkg_print_field(pkg_t *pkg, FILE *file, const char *field);
+str_list_t *pkg_get_installed_files(pkg_t *pkg);
+int pkg_free_installed_files(pkg_t *pkg);
+int pkg_remove_installed_files_list(ipkg_conf_t *conf, pkg_t *pkg);
+conffile_t *pkg_get_conffile(pkg_t *pkg, const char *file_name);
+int pkg_run_script(struct ipkg_conf *conf, pkg_t *pkg,
+ const char *script, const char *args);
+
+/* enum mappings */
+char *pkg_state_want_to_str(pkg_state_want_t sw);
+pkg_state_want_t pkg_state_want_from_str(char *str);
+char *pkg_state_flag_to_str(pkg_state_flag_t sf);
+pkg_state_flag_t pkg_state_flag_from_str(char *str);
+char *pkg_state_status_to_str(pkg_state_status_t ss);
+pkg_state_status_t pkg_state_status_from_str(char *str);
+
+int pkg_version_satisfied(pkg_t *it, pkg_t *ref, const char *op);
+
+int pkg_arch_supported(ipkg_conf_t *conf, pkg_t *pkg);
+int pkg_info_preinstall_check(ipkg_conf_t *conf);
+int pkg_free_installed_files(pkg_t *pkg);
+
+int pkg_write_filelist(ipkg_conf_t *conf, pkg_t *pkg);
+int pkg_write_changed_filelists(ipkg_conf_t *conf);
+
+#endif
diff -ruN busybox-1.00-orig/archival/libipkg/pkg_depends.c busybox-1.00+ipkg-0.99.154/archival/libipkg/pkg_depends.c
--- busybox-1.00-orig/archival/libipkg/pkg_depends.c 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/pkg_depends.c 2005-10-26 17:45:58.000000000 +0200
@@ -0,0 +1,1029 @@
+/* pkg_depends.c - the itsy package management system
+
+ Steven M. Ayer
+
+ Copyright (C) 2002 Compaq Computer Corporation
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#include "ipkg.h"
+#include <errno.h>
+#include <ctype.h>
+
+#include "pkg.h"
+#include "ipkg_utils.h"
+#include "pkg_hash.h"
+#include "ipkg_message.h"
+#include "pkg_parse.h"
+#include "hash_table.h"
+
+static int parseDepends(compound_depend_t *compound_depend, hash_table_t * hash, char * depend_str);
+static depend_t * depend_init(void);
+static void depend_deinit(depend_t *d);
+static char ** add_unresolved_dep(pkg_t * pkg, char ** the_lost, int ref_ndx);
+static char ** merge_unresolved(char ** oldstuff, char ** newstuff);
+static int is_pkg_in_pkg_vec(pkg_vec_t * vec, pkg_t * pkg);
+
+static int pkg_installed_and_constraint_satisfied(pkg_t *pkg, void *cdata)
+{
+ depend_t *depend = (depend_t *)cdata;
+ if ((pkg->state_status == SS_INSTALLED || pkg->state_status == SS_UNPACKED) && version_constraints_satisfied(depend, pkg))
+ return 1;
+ else
+ return 0;
+}
+
+static int pkg_constraint_satisfied(pkg_t *pkg, void *cdata)
+{
+ depend_t *depend = (depend_t *)cdata;
+#if 0
+ pkg_t * temp = pkg_new();
+ int comparison;
+ parseVersion(temp, depend->version);
+ comparison = pkg_compare_versions(pkg, temp);
+ free(temp);
+
+ fprintf(stderr, "%s: pkg=%s pkg->version=%s constraint=%p type=%d version=%s comparison=%d satisfied=%d\n",
+ __FUNCTION__, pkg->name, pkg->version,
+ depend, depend->constraint, depend->version,
+ comparison, version_constraints_satisfied(depend, pkg));
+#endif
+ if (version_constraints_satisfied(depend, pkg))
+ return 1;
+ else
+ return 0;
+}
+
+/* returns ndependences or negative error value */
+int pkg_hash_fetch_unsatisfied_dependencies(ipkg_conf_t *conf, pkg_t * pkg,
+ pkg_vec_t *unsatisfied, char *** unresolved)
+{
+ pkg_t * satisfier_entry_pkg;
+ register int i, j, k;
+ int count, found;
+ char ** the_lost;
+ abstract_pkg_t * ab_pkg;
+
+ /*
+ * this is a setup to check for redundant/cyclic dependency checks,
+ * which are marked at the abstract_pkg level
+ */
+ if (!(ab_pkg = pkg->parent)) {
+ fprintf(stderr, "%s:%d: something terribly wrong with pkg %s\n", __FUNCTION__, __LINE__, pkg->name);
+ *unresolved = NULL;
+ return 0;
+ }
+ if (ab_pkg->dependencies_checked) { /* avoid duplicate or cyclic checks */
+ *unresolved = NULL;
+ return 0;
+ } else {
+ ab_pkg->dependencies_checked = 1; /* mark it for subsequent visits */
+ }
+ /**/
+
+ count = pkg->pre_depends_count + pkg->depends_count + pkg->recommends_count + pkg->suggests_count;
+ if (!count){
+ *unresolved = NULL;
+ return 0;
+ }
+
+ the_lost = NULL;
+
+ /* foreach dependency */
+ for (i = 0; i < count; i++) {
+ compound_depend_t * compound_depend = &pkg->depends[i];
+ depend_t ** possible_satisfiers = compound_depend->possibilities;;
+ found = 0;
+ satisfier_entry_pkg = NULL;
+
+ if (compound_depend->type == GREEDY_DEPEND) {
+ /* foreach possible satisfier */
+ for (j = 0; j < compound_depend->possibility_count; j++) {
+ /* foreach provided_by, which includes the abstract_pkg itself */
+ abstract_pkg_t *abpkg = possible_satisfiers[j]->pkg;
+ abstract_pkg_vec_t *ab_provider_vec = abpkg->provided_by;
+ int nposs = ab_provider_vec->len;
+ abstract_pkg_t **ab_providers = ab_provider_vec->pkgs;
+ int l;
+ for (l = 0; l < nposs; l++) {
+ pkg_vec_t *test_vec = ab_providers[l]->pkgs;
+ /* if no depends on this one, try the first package that Provides this one */
+ if (!test_vec){ /* no pkg_vec hooked up to the abstract_pkg! (need another feed?) */
+ continue;
+ }
+
+ /* cruise this possiblity's pkg_vec looking for an installed version */
+ for (k = 0; k < test_vec->len; k++) {
+ pkg_t *pkg_scout = test_vec->pkgs[k];
+ /* not installed, and not already known about? */
+ if ((pkg_scout->state_want != SW_INSTALL)
+ && !pkg_scout->parent->dependencies_checked
+ && !is_pkg_in_pkg_vec(unsatisfied, pkg_scout)) {
+ char ** newstuff = NULL;
+ int rc;
+ pkg_vec_t *tmp_vec = pkg_vec_alloc ();
+ /* check for not-already-installed dependencies */
+ rc = pkg_hash_fetch_unsatisfied_dependencies(conf,
+ pkg_scout,
+ tmp_vec,
+ &newstuff);
+ if (newstuff == NULL) {
+ int i;
+ int ok = 1;
+ for (i = 0; i < rc; i++) {
+ pkg_t *p = tmp_vec->pkgs[i];
+ if (p->state_want == SW_INSTALL)
+ continue;
+ ipkg_message(conf, IPKG_DEBUG, "not installing %s due to requirement for %s\n", pkg_scout->name, p->name);
+ ok = 0;
+ break;
+ }
+ pkg_vec_free (tmp_vec);
+ if (ok) {
+ /* mark this one for installation */
+ ipkg_message(conf, IPKG_NOTICE, "Adding satisfier for greedy dependence: %s\n", pkg_scout->name);
+ pkg_vec_insert(unsatisfied, pkg_scout);
+ }
+ } else {
+ ipkg_message(conf, IPKG_DEBUG, "not installing %s due to broken depends \n", pkg_scout->name);
+ free (newstuff);
+ }
+ }
+ }
+ }
+ }
+
+ continue;
+ }
+
+ /* foreach possible satisfier, look for installed package */
+ for (j = 0; j < compound_depend->possibility_count; j++) {
+ /* foreach provided_by, which includes the abstract_pkg itself */
+ depend_t *dependence_to_satisfy = possible_satisfiers[j];
+ abstract_pkg_t *satisfying_apkg = possible_satisfiers[j]->pkg;
+ pkg_t *satisfying_pkg =
+ pkg_hash_fetch_best_installation_candidate(conf, satisfying_apkg,
+ pkg_installed_and_constraint_satisfied,
+ dependence_to_satisfy, 1);
+ /* Being that I can't test constraing in pkg_hash, I will test it here */
+ if (satisfying_pkg != NULL) {
+ if (!pkg_installed_and_constraint_satisfied ( satisfying_pkg,dependence_to_satisfy)) {
+ satisfying_pkg = NULL;
+ }
+ }
+ ipkg_message(conf, IPKG_DEBUG, "%s:%d: satisfying_pkg=%p \n", __FILE__, __LINE__, satisfying_pkg);
+ if (satisfying_pkg != NULL) {
+ found = 1;
+ break;
+ }
+
+ }
+ /* if nothing installed matches, then look for uninstalled satisfier */
+ if (!found) {
+ /* foreach possible satisfier, look for installed package */
+ for (j = 0; j < compound_depend->possibility_count; j++) {
+ /* foreach provided_by, which includes the abstract_pkg itself */
+ depend_t *dependence_to_satisfy = possible_satisfiers[j];
+ abstract_pkg_t *satisfying_apkg = possible_satisfiers[j]->pkg;
+ pkg_t *satisfying_pkg =
+ pkg_hash_fetch_best_installation_candidate(conf, satisfying_apkg,
+ pkg_constraint_satisfied,
+ dependence_to_satisfy, 1);
+ /* Being that I can't test constraing in pkg_hash, I will test it here too */
+ if (satisfying_pkg != NULL) {
+ if (!pkg_constraint_satisfied ( satisfying_pkg,dependence_to_satisfy)) {
+ satisfying_pkg = NULL;
+ }
+ }
+
+ /* user request overrides package recommendation */
+ if (satisfying_pkg != NULL
+ && (compound_depend->type == RECOMMEND || compound_depend->type == SUGGEST)
+ && (satisfying_pkg->state_want == SW_DEINSTALL || satisfying_pkg->state_want == SW_PURGE)) {
+ ipkg_message (conf, IPKG_NOTICE, "%s: ignoring recommendation for %s at user request\n",
+ pkg->name, satisfying_pkg->name);
+ continue;
+ }
+
+ ipkg_message(conf, IPKG_DEBUG, "%s:%d: satisfying_pkg=%p\n", __FILE__, __LINE__, satisfying_pkg);
+ if (satisfying_pkg != NULL) {
+ satisfier_entry_pkg = satisfying_pkg;
+ break;
+ }
+ }
+ }
+
+ /* we didn't find one, add something to the unsatisfied vector */
+ if (!found) {
+ if (!satisfier_entry_pkg) {
+ /* failure to meet recommendations is not an error */
+ if (compound_depend->type != RECOMMEND && compound_depend->type != SUGGEST)
+ the_lost = add_unresolved_dep(pkg, the_lost, i);
+ else
+ ipkg_message (conf, IPKG_NOTICE, "%s: unsatisfied recommendation for %s\n",
+ pkg->name, compound_depend->possibilities[0]->pkg->name);
+ }
+ else {
+ if (compound_depend->type == SUGGEST) {
+ /* just mention it politely */
+ ipkg_message (conf, IPKG_NOTICE, "package %s suggests installing %s\n",
+ pkg->name, satisfier_entry_pkg->name);
+ } else {
+ char ** newstuff = NULL;
+
+ if (satisfier_entry_pkg != pkg &&
+ !is_pkg_in_pkg_vec(unsatisfied, satisfier_entry_pkg)) {
+ pkg_vec_insert(unsatisfied, satisfier_entry_pkg);
+ pkg_hash_fetch_unsatisfied_dependencies(conf,
+ satisfier_entry_pkg,
+ unsatisfied,
+ &newstuff);
+ the_lost = merge_unresolved(the_lost, newstuff);
+ }
+ }
+ }
+ }
+ }
+ *unresolved = the_lost;
+
+ return unsatisfied->len;
+}
+
+/*checking for conflicts !in replaces
+ If a packages conflicts with another but is also replacing it, I should not consider it a
+ really conflicts
+ returns 0 if conflicts <> replaces or 1 if conflicts == replaces
+*/
+int is_pkg_a_replaces(pkg_t *pkg_scout,pkg_t *pkg)
+{
+ int i ;
+ int replaces_count = pkg->replaces_count;
+ abstract_pkg_t **replaces;
+
+ if (pkg->replaces_count==0) // No replaces, it's surely a conflict
+ return 0;
+
+ replaces = pkg->replaces;
+
+ for (i = 0; i < replaces_count; i++) {
+ if (strcmp(pkg_scout->name,pkg->replaces[i]->name)==0) // Found
+ return 1;
+ }
+ return 0;
+
+}
+
+
+/* Abhaya: added support for conflicts */
+pkg_vec_t * pkg_hash_fetch_conflicts(hash_table_t * hash, pkg_t * pkg)
+{
+ pkg_vec_t * installed_conflicts, * test_vec;
+ compound_depend_t * conflicts;
+ depend_t ** possible_satisfiers;
+ depend_t * possible_satisfier;
+ register int i, j, k;
+ int count;
+ abstract_pkg_t * ab_pkg;
+ pkg_t **pkg_scouts;
+ pkg_t *pkg_scout;
+
+ /*
+ * this is a setup to check for redundant/cyclic dependency checks,
+ * which are marked at the abstract_pkg level
+ */
+ if(!(ab_pkg = pkg->parent)){
+ fprintf(stderr, "dependency check error. pkg %s isn't in hash table\n", pkg->name);
+ return (pkg_vec_t *)NULL;
+ }
+
+ conflicts = pkg->conflicts;
+ if(!conflicts){
+ return (pkg_vec_t *)NULL;
+ }
+ installed_conflicts = pkg_vec_alloc();
+
+ count = pkg->conflicts_count;
+
+
+
+ /* foreach conflict */
+ for(i = 0; i < pkg->conflicts_count; i++){
+
+ possible_satisfiers = conflicts->possibilities;
+
+ /* foreach possible satisfier */
+ for(j = 0; j < conflicts->possibility_count; j++){
+ possible_satisfier = possible_satisfiers[j];
+ if (!possible_satisfier)
+ fprintf(stderr, "%s:%d: possible_satisfier is null\n", __FUNCTION__, __LINE__);
+ if (!possible_satisfier->pkg)
+ fprintf(stderr, "%s:%d: possible_satisfier->pkg is null\n", __FUNCTION__, __LINE__);
+ test_vec = possible_satisfier->pkg->pkgs;
+ if (test_vec) {
+ /* pkg_vec found, it is an actual package conflict
+ * cruise this possiblity's pkg_vec looking for an installed version */
+ pkg_scouts = test_vec->pkgs;
+ for(k = 0; k < test_vec->len; k++){
+ pkg_scout = pkg_scouts[k];
+ if (!pkg_scout) {
+ fprintf(stderr, "%s: null pkg scout\n", __FUNCTION__);
+ continue;
+ }
+ if ((pkg_scout->state_status == SS_INSTALLED || pkg_scout->state_want == SW_INSTALL) &&
+ version_constraints_satisfied(possible_satisfier, pkg_scout) && !is_pkg_a_replaces(pkg_scout,pkg)){
+ if (!is_pkg_in_pkg_vec(installed_conflicts, pkg_scout)){
+ pkg_vec_insert(installed_conflicts, pkg_scout);
+ }
+ }
+ }
+ }
+ }
+ conflicts++;
+ }
+
+ if (installed_conflicts->len)
+ return installed_conflicts;
+ pkg_vec_free(installed_conflicts);
+ return (pkg_vec_t *)NULL;
+}
+
+int version_constraints_satisfied(depend_t * depends, pkg_t * pkg)
+{
+ pkg_t * temp;
+ int comparison;
+
+ if(depends->constraint == NONE)
+ return 1;
+
+ temp = pkg_new();
+
+ parseVersion(temp, depends->version);
+
+ comparison = pkg_compare_versions(pkg, temp);
+
+ free(temp);
+
+ if((depends->constraint == EARLIER) &&
+ (comparison < 0))
+ return 1;
+ else if((depends->constraint == LATER) &&
+ (comparison > 0))
+ return 1;
+ else if(comparison == 0)
+ return 1;
+ else if((depends->constraint == LATER_EQUAL) &&
+ (comparison >= 0))
+ return 1;
+ else if((depends->constraint == EARLIER_EQUAL) &&
+ (comparison <= 0))
+ return 1;
+
+ return 0;
+}
+
+int pkg_dependence_satisfiable(ipkg_conf_t *conf, depend_t *depend)
+{
+ abstract_pkg_t *apkg = depend->pkg;
+ abstract_pkg_vec_t *provider_apkgs = apkg->provided_by;
+ int n_providers = provider_apkgs->len;
+ abstract_pkg_t **apkgs = provider_apkgs->pkgs;
+ pkg_vec_t *pkg_vec;
+ int n_pkgs ;
+ int i;
+ int j;
+
+ for (i = 0; i < n_providers; i++) {
+ abstract_pkg_t *papkg = apkgs[i];
+ pkg_vec = papkg->pkgs;
+ if (pkg_vec) {
+ n_pkgs = pkg_vec->len;
+ for (j = 0; j < n_pkgs; j++) {
+ pkg_t *pkg = pkg_vec->pkgs[j];
+ if (version_constraints_satisfied(depend, pkg)) {
+ return 1;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+int pkg_dependence_satisfied(ipkg_conf_t *conf, depend_t *depend)
+{
+ abstract_pkg_t *apkg = depend->pkg;
+ abstract_pkg_vec_t *provider_apkgs = apkg->provided_by;
+ int n_providers = provider_apkgs->len;
+ abstract_pkg_t **apkgs = provider_apkgs->pkgs;
+ int i;
+ int n_pkgs;
+ int j;
+
+ for (i = 0; i < n_providers; i++) {
+ abstract_pkg_t *papkg = apkgs[i];
+ pkg_vec_t *pkg_vec = papkg->pkgs;
+ if (pkg_vec) {
+ n_pkgs = pkg_vec->len;
+ for (j = 0; j < n_pkgs; j++) {
+ pkg_t *pkg = pkg_vec->pkgs[j];
+ if (version_constraints_satisfied(depend, pkg)) {
+ if (pkg->state_status == SS_INSTALLED || pkg->state_status == SS_UNPACKED)
+ return 1;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+static int is_pkg_in_pkg_vec(pkg_vec_t * vec, pkg_t * pkg)
+{
+ register int i;
+ pkg_t ** pkgs = vec->pkgs;
+
+ for(i = 0; i < vec->len; i++)
+ if((strcmp(pkg->name, (*(pkgs + i))->name) == 0)
+ && (pkg_compare_versions(pkg, *(pkgs + i)) == 0)
+ && (strcmp(pkg->architecture, (*(pkgs + i))->architecture) == 0))
+ return 1;
+ return 0;
+}
+
+
+#ifdef DeadCode
+/**
+ * pkg_has_common_provides returns 1 if pkg and replacee both provide
+ * the same abstract package and 0 otherwise.
+ */
+int pkg_has_common_provides(pkg_t *pkg, pkg_t *replacee)
+{
+ abstract_pkg_t **provides = pkg->provides;
+ int provides_count = pkg->provides_count;
+ abstract_pkg_t **replacee_provides = replacee->provides;
+ int replacee_provides_count = replacee->provides_count;
+ int i, j;
+ for (i = 0; i < provides_count; i++) {
+ abstract_pkg_t *apkg = provides[i];
+ for (j = 0; j < replacee_provides_count; j++) {
+ abstract_pkg_t *replacee_apkg = replacee_provides[i];
+ if (apkg == replacee_apkg)
+ return 1;
+ }
+ }
+ return 0;
+}
+#endif
+
+/**
+ * pkg_provides_abstract returns 1 if pkg->provides contains providee
+ * and 0 otherwise.
+ */
+int pkg_provides_abstract(pkg_t *pkg, abstract_pkg_t *providee)
+{
+ abstract_pkg_t **provides = pkg->provides;
+ int provides_count = pkg->provides_count;
+ int i;
+ for (i = 0; i < provides_count; i++) {
+ if (provides[i] == providee)
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * pkg_replaces returns 1 if pkg->replaces contains one of replacee's provides and 0
+ * otherwise.
+ */
+int pkg_replaces(pkg_t *pkg, pkg_t *replacee)
+{
+ abstract_pkg_t **replaces = pkg->replaces;
+ int replaces_count = pkg->replaces_count;
+ abstract_pkg_t **replacee_provides = pkg->provides;
+ int replacee_provides_count = pkg->provides_count;
+ int i, j;
+ for (i = 0; i < replaces_count; i++) {
+ abstract_pkg_t *abstract_replacee = replaces[i];
+ for (j = 0; j < replacee_provides_count; j++) {
+ if (replacee_provides[j] == abstract_replacee)
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+/**
+ * pkg_conflicts_abstract returns 1 if pkg->conflicts contains conflictee and 0
+ * otherwise.
+ */
+int pkg_conflicts_abstract(pkg_t *pkg, abstract_pkg_t *conflictee)
+{
+ compound_depend_t *conflicts = pkg->conflicts;
+ int conflicts_count = pkg->conflicts_count;
+ int i, j;
+ for (i = 0; i < conflicts_count; i++) {
+ int possibility_count = conflicts[i].possibility_count;
+ struct depend **possibilities = conflicts[i].possibilities;
+ for (j = 0; j < possibility_count; j++) {
+ if (possibilities[j]->pkg == conflictee) {
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+/**
+ * pkg_conflicts returns 1 if pkg->conflicts contains one of
+ * conflictee's provides and 0 otherwise.
+ */
+int pkg_conflicts(pkg_t *pkg, pkg_t *conflictee)
+{
+ compound_depend_t *conflicts = pkg->conflicts;
+ int conflicts_count = pkg->conflicts_count;
+ abstract_pkg_t **conflictee_provides = conflictee->provides;
+ int conflictee_provides_count = conflictee->provides_count;
+ int i, j, k;
+ int possibility_count;
+ struct depend **possibilities;
+ abstract_pkg_t *possibility ;
+
+ for (i = 0; i < conflicts_count; i++) {
+ possibility_count = conflicts[i].possibility_count;
+ possibilities = conflicts[i].possibilities;
+ for (j = 0; j < possibility_count; j++) {
+ possibility = possibilities[j]->pkg;
+ for (k = 0; k < conflictee_provides_count; k++) {
+ if (possibility == conflictee_provides[k]) {
+ return 1;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+static char ** merge_unresolved(char ** oldstuff, char ** newstuff)
+{
+ int oldlen = 0, newlen = 0;
+ char ** result;
+ register int i, j;
+
+ if(!newstuff)
+ return oldstuff;
+
+ while(oldstuff && oldstuff[oldlen]) oldlen++;
+ while(newstuff && newstuff[newlen]) newlen++;
+
+ result = (char **)realloc(oldstuff, sizeof(char *) * (oldlen + newlen + 1));
+ if (result == NULL) {
+ fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
+ return NULL;
+ }
+
+ for(i = oldlen, j = 0; i < (oldlen + newlen); i++, j++)
+ *(result + i) = *(newstuff + j);
+
+ *(result + i) = NULL;
+
+ return result;
+}
+
+/*
+ * a kinda kludgy way to back out depends str from two different arrays (reg'l'r 'n pre)
+ * this is null terminated, no count is carried around
+ */
+char ** add_unresolved_dep(pkg_t * pkg, char ** the_lost, int ref_ndx)
+{
+ int count;
+ char ** resized;
+ char *depend_str = pkg_depend_str(pkg, ref_ndx);
+
+ count = 0;
+ while(the_lost && the_lost[count]) count++;
+
+ count++; /* need one to hold the null */
+ resized = (char **)realloc(the_lost, sizeof(char *) * (count + 1));
+ if (resized == NULL) {
+ fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
+ return NULL;
+ }
+ resized[count - 1] = strdup(depend_str);
+ resized[count] = NULL;
+
+ return resized;
+}
+
+void printDepends(pkg_t * pkg)
+{
+ register int i, j;
+ compound_depend_t * depend;
+ int count;
+
+ count = pkg->pre_depends_count + pkg->depends_count;
+
+ depend = pkg->depends;
+ if(!depend){
+ fprintf(stderr, "Depends pointer is NULL\n");
+ return;
+ }
+ for(i = 0; i < count; i++){
+ fprintf(stderr, "%s has %d possibilities:\n",
+ (depend->type == GREEDY_DEPEND) ? "Greedy-Depend" : ((depend->type == DEPEND) ? "Depend" : "Pre-Depend"),
+ depend->possibility_count);
+ for(j = 0; j < depend->possibility_count; j++)
+ fprintf(stderr, "\t%s version %s (%d)\n",
+ depend->possibilities[j]->pkg->name,
+ depend->possibilities[j]->version,
+ depend->possibilities[j]->constraint);
+ depend++;
+ }
+}
+
+int buildProvides(hash_table_t * hash, abstract_pkg_t * ab_pkg, pkg_t * pkg)
+{
+ register int i, j;
+
+ /* every pkg provides itself */
+ abstract_pkg_vec_insert(ab_pkg->provided_by, ab_pkg);
+
+ if (!pkg->provides_count)
+ return 0;
+
+ pkg->provides = (abstract_pkg_t **)malloc(sizeof(abstract_pkg_t *) * (pkg->provides_count + 1));
+ if (pkg->provides == NULL) {
+ fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
+ return -1 ;
+ }
+ pkg->provides[0] = ab_pkg;
+
+ // if (strcmp(ab_pkg->name, pkg->name))
+ // fprintf(stderr, __FUNCTION__ ": ab_pkg=%s pkg=%s\n", ab_pkg->name, pkg->name);
+
+ for(i = 0; i < pkg->provides_count; i++){
+ abstract_pkg_t *provided_abpkg = ensure_abstract_pkg_by_name(hash, pkg->provides_str[i]);
+
+ pkg->provides[i+1] = provided_abpkg;
+
+ j = 0;
+ abstract_pkg_vec_insert(provided_abpkg->provided_by, ab_pkg);
+ }
+ return 0;
+}
+
+/* Abhaya: added conflicts support */
+int buildConflicts(hash_table_t * hash, abstract_pkg_t * ab_pkg, pkg_t * pkg)
+{
+ register int i;
+ compound_depend_t * conflicts;
+
+ if (!pkg->conflicts_count)
+ return 0;
+
+ conflicts = pkg->conflicts = malloc(sizeof(compound_depend_t) *
+ pkg->conflicts_count);
+ if (conflicts == NULL) {
+ fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
+ return -1;
+ }
+ for (i = 0; i < pkg->conflicts_count; i++) {
+ conflicts->type = CONFLICTS;
+ parseDepends(conflicts, hash,
+ pkg->conflicts_str[i]);
+#if 0
+ for (j = 0; j < conflicts->possibility_count; j++) {
+ depend_t *possibility = conflicts->possibilities[j];
+ abstract_pkg_t *conflicting_apkg = possibility->pkg;
+ pkg_add_conflict_pair(ab_pkg, conflicting_apkg);
+ }
+#endif
+ conflicts++;
+ }
+ return 0;
+}
+
+int buildReplaces(hash_table_t * hash, abstract_pkg_t * ab_pkg, pkg_t * pkg)
+{
+ register int i, j;
+
+ if (!pkg->replaces_count)
+ return 0;
+
+ pkg->replaces = (abstract_pkg_t **)malloc(sizeof(abstract_pkg_t *) * pkg->replaces_count);
+ if (pkg->replaces == NULL) {
+ fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
+ return -1;
+ }
+
+ // if (strcmp(ab_pkg->name, pkg->name))
+ // fprintf(stderr, __FUNCTION__ ": ab_pkg=%s pkg=%s\n", ab_pkg->name, pkg->name);
+
+ for(i = 0; i < pkg->replaces_count; i++){
+ abstract_pkg_t *old_abpkg = ensure_abstract_pkg_by_name(hash, pkg->replaces_str[i]);
+
+ pkg->replaces[i] = old_abpkg;
+
+ j = 0;
+ if (!old_abpkg->replaced_by)
+ old_abpkg->replaced_by = abstract_pkg_vec_alloc();
+ if ( old_abpkg->replaced_by == NULL ){
+ return -1;
+ }
+ /* if a package pkg both replaces and conflicts old_abpkg,
+ * then add it to the replaced_by vector so that old_abpkg
+ * will be upgraded to ab_pkg automatically */
+ if (pkg_conflicts_abstract(pkg, old_abpkg))
+ abstract_pkg_vec_insert(old_abpkg->replaced_by, ab_pkg);
+ }
+ return 0;
+}
+
+int buildDepends(hash_table_t * hash, pkg_t * pkg)
+{
+ int count;
+ register int i;
+ compound_depend_t * depends;
+
+ if(!(count = pkg->pre_depends_count + pkg->depends_count + pkg->recommends_count + pkg->suggests_count))
+ return 0;
+
+ if (0 && pkg->pre_depends_count)
+ fprintf(stderr, "pkg=%s pre_depends_count=%d depends_count=%d\n",
+ pkg->name, pkg->pre_depends_count, pkg->depends_count);
+ depends = pkg->depends = malloc(sizeof(compound_depend_t) * count);
+ if (depends == NULL) {
+ fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
+ return -1;
+ }
+
+
+ for(i = 0; i < pkg->pre_depends_count; i++){
+ parseDepends(depends, hash, pkg->pre_depends_str[i]);
+ if (0 && pkg->pre_depends_count)
+ fprintf(stderr, " pre_depends_str=%s depends=%p possibility_count=%x\n",
+ pkg->pre_depends_str[i], depends, depends->possibility_count);
+ depends->type = PREDEPEND;
+ depends++;
+ }
+
+ for(i = 0; i < pkg->recommends_count; i++){
+ parseDepends(depends, hash, pkg->recommends_str[i]);
+ if (0 && pkg->recommends_count)
+ fprintf(stderr, " recommends_str=%s depends=%p possibility_count=%x\n",
+ pkg->recommends_str[i], depends, depends->possibility_count);
+ depends->type = RECOMMEND;
+ depends++;
+ }
+
+ for(i = 0; i < pkg->suggests_count; i++){
+ parseDepends(depends, hash, pkg->suggests_str[i]);
+ if (0 && pkg->suggests_count)
+ fprintf(stderr, " suggests_str=%s depends=%p possibility_count=%x\n",
+ pkg->suggests_str[i], depends, depends->possibility_count);
+ depends->type = SUGGEST;
+ depends++;
+ }
+
+ for(i = 0; i < pkg->depends_count; i++){
+ parseDepends(depends, hash, pkg->depends_str[i]);
+ if (0 && pkg->depends_count)
+ fprintf(stderr, " depends_str=%s depends=%p possibility_count=%x\n",
+ pkg->depends_str[i], depends, depends->possibility_count);
+ depends++;
+ }
+ return 0;
+}
+
+/*
+ * pkg_depend_string: returns the depends string specified by index.
+ * All 4 kinds of dependences: dependence, pre-dependence, recommend, and suggest are number starting from 0.
+ * [0,npredepends) -> returns pre_depends_str[index]
+ * [npredepends,npredepends+nrecommends) -> returns recommends_str[index]
+ * [npredepends+nrecommends,npredepends+nrecommends+nsuggests) -> returns recommends_str[index]
+ * [npredepends+nrecommends+nsuggests,npredepends+nrecommends+nsuggests+ndepends) -> returns depends_str[index]
+ */
+char *pkg_depend_str(pkg_t *pkg, int index)
+{
+ if (index < pkg->pre_depends_count) {
+ return pkg->pre_depends_str[index];
+ }
+ index -= pkg->pre_depends_count;
+
+ if (index < pkg->recommends_count) {
+ return pkg->recommends_str[index];
+ }
+ index -= pkg->recommends_count;
+
+ if (index < pkg->suggests_count) {
+ return pkg->suggests_str[index];
+ }
+ index -= pkg->suggests_count;
+
+ if (index < pkg->depends_count) {
+ return pkg->depends_str[index];
+ }
+ fprintf(stderr, "pkg_depend_str: index %d out of range for pkg=%s\n", index, pkg->name);
+ return NULL;
+}
+
+void freeDepends(pkg_t *pkg)
+{
+ int i;
+
+ if (pkg == NULL || pkg->depends == NULL) {
+ return;
+ }
+
+ fprintf(stderr, "Freeing depends=%p\n", pkg->depends);
+ for (i=0; i < pkg->depends->possibility_count; i++) {
+ depend_deinit(pkg->depends->possibilities[i]);
+ }
+ free(pkg->depends->possibilities);
+ free(pkg->depends);
+ pkg->depends = NULL;
+}
+
+void buildDependedUponBy(pkg_t * pkg, abstract_pkg_t * ab_pkg)
+{
+ compound_depend_t * depends;
+ int count, othercount;
+ register int i, j;
+ abstract_pkg_t * ab_depend;
+ abstract_pkg_t ** temp;
+
+ count = pkg->pre_depends_count + pkg->depends_count;
+ depends = pkg->depends;
+
+ if (0 && pkg->pre_depends_count)
+ fprintf(stderr, "pkg=%s pre_depends_count=%d depends_count=%d\n",
+ pkg->name, pkg->pre_depends_count, pkg->depends_count);
+ for (i = 0; i < count; i++) {
+ if (0 && pkg->pre_depends_count)
+ fprintf(stderr, " i=%d possibility_count=%x depends=%p\n", i, depends->possibility_count, depends);
+ for (j = 0; j < depends->possibility_count; j++){
+ ab_depend = depends->possibilities[j]->pkg;
+ if(!ab_depend->depended_upon_by)
+ ab_depend->depended_upon_by = (abstract_pkg_t **)calloc(1, sizeof(abstract_pkg_t *));
+
+ temp = ab_depend->depended_upon_by;
+ othercount = 1;
+ while(*temp){
+ temp++;
+ othercount++;
+ }
+ *temp = ab_pkg;
+
+ ab_depend->depended_upon_by = (abstract_pkg_t **)realloc(ab_depend->depended_upon_by,
+ (othercount + 1) * sizeof(abstract_pkg_t *));
+ /* the array may have moved */
+ temp = ab_depend->depended_upon_by + othercount;
+ *temp = NULL;
+ }
+ depends++;
+ }
+}
+
+static depend_t * depend_init(void)
+{
+ depend_t * d = (depend_t *)malloc(sizeof(depend_t));
+ if ( d==NULL ){
+ fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
+ return NULL;
+ }
+ d->constraint = NONE;
+ d->version = NULL;
+ d->pkg = NULL;
+
+ return d;
+}
+
+static void depend_deinit(depend_t *d)
+{
+ free(d);
+}
+
+static int parseDepends(compound_depend_t *compound_depend,
+ hash_table_t * hash, char * depend_str)
+{
+ char * pkg_name, buffer[2048];
+ int num_of_ors = 0;
+ register int i;
+ register char * src, * dest;
+ depend_t ** possibilities;
+
+ /* first count the number of ored possibilities for satisfying dependency */
+ src = depend_str;
+ while(*src)
+ if(*src++ == '|')
+ num_of_ors++;
+
+ compound_depend->type = DEPEND;
+
+ compound_depend->possibility_count = num_of_ors + 1;
+ possibilities = (depend_t **)malloc(sizeof(depend_t *) * (num_of_ors + 1));
+ if (!possibilities)
+ return -ENOMEM;
+ compound_depend->possibilities = possibilities;
+
+ src = depend_str;
+ for(i = 0; i < num_of_ors + 1; i++){
+ possibilities[i] = depend_init();
+ if (!possibilities[i])
+ return -ENOMEM;
+ /* gobble up just the name first */
+ dest = buffer;
+ while(*src &&
+ !isspace(*src) &&
+ (*src != '(') &&
+ (*src != '*') &&
+ (*src != '|'))
+ *dest++ = *src++;
+ *dest = '\0';
+ pkg_name = trim_alloc(buffer);
+ if (pkg_name == NULL )
+ return -ENOMEM;
+
+ /* now look at possible version info */
+
+ /* skip to next chars */
+ if(isspace(*src))
+ while(*src && isspace(*src)) src++;
+
+ /* extract constraint and version */
+ if(*src == '('){
+ src++;
+ if(!strncmp(src, "<<", 2)){
+ possibilities[i]->constraint = EARLIER;
+ src += 2;
+ }
+ else if(!strncmp(src, "<=", 2)){
+ possibilities[i]->constraint = EARLIER_EQUAL;
+ src += 2;
+ }
+ else if(!strncmp(src, ">=", 2)){
+ possibilities[i]->constraint = LATER_EQUAL;
+ src += 2;
+ }
+ else if(!strncmp(src, ">>", 2)){
+ possibilities[i]->constraint = LATER;
+ src += 2;
+ }
+ else if(!strncmp(src, "=", 1)){
+ possibilities[i]->constraint = EQUAL;
+ src++;
+ }
+ /* should these be here to support deprecated designations; dpkg does */
+ else if(!strncmp(src, "<", 1)){
+ possibilities[i]->constraint = EARLIER_EQUAL;
+ src++;
+ }
+ else if(!strncmp(src, ">", 1)){
+ possibilities[i]->constraint = LATER_EQUAL;
+ src++;
+ }
+
+ /* now we have any constraint, pass space to version string */
+ while(isspace(*src)) src++;
+
+ /* this would be the version string */
+ dest = buffer;
+ while(*src && *src != ')')
+ *dest++ = *src++;
+ *dest = '\0';
+
+ possibilities[i]->version = trim_alloc(buffer);
+ /* fprintf(stderr, "let's print the depends version string:");
+ fprintf(stderr, "version %s\n", possibilities[i]->version);*/
+ if (possibilities[i]->version == NULL )
+ return -ENOMEM;
+
+
+ }
+ /* hook up the dependency to its abstract pkg */
+ possibilities[i]->pkg = ensure_abstract_pkg_by_name(hash, pkg_name);
+
+ free(pkg_name);
+
+ /* now get past the ) and any possible | chars */
+ while(*src &&
+ (isspace(*src) ||
+ (*src == ')') ||
+ (*src == '|')))
+ src++;
+ if (*src == '*')
+ {
+ compound_depend->type = GREEDY_DEPEND;
+ src++;
+ }
+ }
+
+ return 0;
+}
diff -ruN busybox-1.00-orig/archival/libipkg/pkg_depends.h busybox-1.00+ipkg-0.99.154/archival/libipkg/pkg_depends.h
--- busybox-1.00-orig/archival/libipkg/pkg_depends.h 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/pkg_depends.h 2005-10-26 17:36:46.000000000 +0200
@@ -0,0 +1,105 @@
+/* pkg_depends.h - the itsy package management system
+
+ Steven M. Ayer
+
+ Copyright (C) 2002 Compaq Computer Corporation
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#ifndef PKG_DEPENDS_H
+#define PKG_DEPENDS_H
+
+#include "pkg.h"
+#include "pkg_hash.h"
+
+enum depend_type {
+ PREDEPEND,
+ DEPEND,
+ CONFLICTS,
+ GREEDY_DEPEND,
+ RECOMMEND,
+ SUGGEST
+};
+typedef enum depend_type depend_type_t;
+
+enum version_constraint {
+ NONE,
+ EARLIER,
+ EARLIER_EQUAL,
+ EQUAL,
+ LATER_EQUAL,
+ LATER
+};
+typedef enum version_constraint version_constraint_t;
+
+struct depend{
+ version_constraint_t constraint;
+ char * version;
+ abstract_pkg_t * pkg;
+};
+typedef struct depend depend_t;
+
+struct compound_depend{
+ depend_type_t type;
+ int possibility_count;
+ struct depend ** possibilities;
+};
+typedef struct compound_depend compound_depend_t;
+
+#include "hash_table.h"
+
+int buildProvides(hash_table_t * hash, abstract_pkg_t * ab_pkg, pkg_t * pkg);
+int buildConflicts(hash_table_t * hash, abstract_pkg_t * ab_pkg, pkg_t * pkg);
+int buildReplaces(hash_table_t * hash, abstract_pkg_t * ab_pkg, pkg_t * pkg);
+int buildDepends(hash_table_t * hash, pkg_t * pkg);
+
+/**
+ * pkg_has_common_provides returns 1 if pkg and replacee both provide
+ * the same abstract package and 0 otherwise.
+ */
+int pkg_has_common_provides(pkg_t *pkg, pkg_t *replacee);
+
+/**
+ * pkg_provides returns 1 if pkg->provides contains providee and 0
+ * otherwise.
+ */
+int pkg_provides_abstract(pkg_t *pkg, abstract_pkg_t *providee);
+
+/**
+ * pkg_replaces returns 1 if pkg->replaces contains one of replacee's provides and 0
+ * otherwise.
+ */
+int pkg_replaces(pkg_t *pkg, pkg_t *replacee);
+
+/**
+ * pkg_conflicts_abstract returns 1 if pkg->conflicts contains conflictee provides and 0
+ * otherwise.
+ */
+int pkg_conflicts_abstract(pkg_t *pkg, abstract_pkg_t *conflicts);
+
+/**
+ * pkg_conflicts returns 1 if pkg->conflicts contains one of conflictee's provides and 0
+ * otherwise.
+ */
+int pkg_conflicts(pkg_t *pkg, pkg_t *conflicts);
+
+char *pkg_depend_str(pkg_t *pkg, int index);
+void buildDependedUponBy(pkg_t * pkg, abstract_pkg_t * ab_pkg);
+void freeDepends(pkg_t *pkg);
+void printDepends(pkg_t * pkg);
+int version_constraints_satisfied(depend_t * depends, pkg_t * pkg);
+int pkg_hash_fetch_unsatisfied_dependencies(ipkg_conf_t *conf, pkg_t * pkg, pkg_vec_t *depends, char *** unresolved);
+pkg_vec_t * pkg_hash_fetch_conflicts(hash_table_t * hash, pkg_t * pkg);
+int pkg_dependence_satisfiable(ipkg_conf_t *conf, depend_t *depend);
+int pkg_dependence_satisfied(ipkg_conf_t *conf, depend_t *depend);
+
+#endif
diff -ruN busybox-1.00-orig/archival/libipkg/pkg_dest.c busybox-1.00+ipkg-0.99.154/archival/libipkg/pkg_dest.c
--- busybox-1.00-orig/archival/libipkg/pkg_dest.c 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/pkg_dest.c 2005-10-26 17:36:46.000000000 +0200
@@ -0,0 +1,92 @@
+/* pkg_dest.c - the itsy package management system
+
+ Carl D. Worth
+
+ Copyright (C) 2001 University of Southern California
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#include "ipkg.h"
+
+#include "pkg_dest.h"
+#include "file_util.h"
+#include "str_util.h"
+#include "sprintf_alloc.h"
+
+int pkg_dest_init(pkg_dest_t *dest, const char *name, const char *root_dir,const char * lists_dir)
+{
+ dest->name = strdup(name);
+
+ /* Guarantee that dest->root_dir ends with a '/' */
+ if (str_ends_with(root_dir, "/")) {
+ dest->root_dir = strdup(root_dir);
+ } else {
+ sprintf_alloc(&dest->root_dir, "%s/", root_dir);
+ }
+ file_mkdir_hier(dest->root_dir, 0755);
+
+ sprintf_alloc(&dest->ipkg_dir, "%s%s",
+ dest->root_dir, IPKG_STATE_DIR_PREFIX);
+ file_mkdir_hier(dest->ipkg_dir, 0755);
+
+ if (str_starts_with (lists_dir, "/"))
+ sprintf_alloc(&dest->lists_dir, "%s", lists_dir);
+ else
+ sprintf_alloc(&dest->lists_dir, "/%s", lists_dir);
+
+ file_mkdir_hier(dest->lists_dir, 0755);
+
+ sprintf_alloc(&dest->info_dir, "%s/%s",
+ dest->ipkg_dir, IPKG_INFO_DIR_SUFFIX);
+ file_mkdir_hier(dest->info_dir, 0755);
+
+ sprintf_alloc(&dest->status_file_name, "%s/%s",
+ dest->ipkg_dir, IPKG_STATUS_FILE_SUFFIX);
+
+ sprintf_alloc(&dest->status_file_tmp_name, "%s/%s.tmp",
+ dest->ipkg_dir, IPKG_STATUS_FILE_SUFFIX);
+
+ dest->status_file = NULL;
+
+ return 0;
+}
+
+void pkg_dest_deinit(pkg_dest_t *dest)
+{
+ free(dest->name);
+ dest->name = NULL;
+
+ free(dest->root_dir);
+ dest->root_dir = NULL;
+
+ free(dest->ipkg_dir);
+ dest->ipkg_dir = NULL;
+
+ free(dest->lists_dir);
+ dest->lists_dir = NULL;
+
+ free(dest->info_dir);
+ dest->info_dir = NULL;
+
+ free(dest->status_file_name);
+ dest->status_file_name = NULL;
+
+ free(dest->status_file_tmp_name);
+ dest->status_file_tmp_name = NULL;
+
+ if (dest->status_file) {
+ fclose(dest->status_file);
+ }
+ dest->status_file = NULL;
+
+ dest->root_dir = NULL;
+}
diff -ruN busybox-1.00-orig/archival/libipkg/pkg_dest.h busybox-1.00+ipkg-0.99.154/archival/libipkg/pkg_dest.h
--- busybox-1.00-orig/archival/libipkg/pkg_dest.h 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/pkg_dest.h 2005-10-26 17:36:46.000000000 +0200
@@ -0,0 +1,38 @@
+/* pkg_dest.h - the itsy package management system
+
+ Carl D. Worth
+
+ Copyright (C) 2001 University of Southern California
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#ifndef PKG_DEST_H
+#define PKG_DEST_H
+
+typedef struct pkg_dest pkg_dest_t;
+struct pkg_dest
+{
+ char *name;
+ char *root_dir;
+ char *ipkg_dir;
+ char *lists_dir;
+ char *info_dir;
+ char *status_file_name;
+ char *status_file_tmp_name;
+ FILE *status_file;
+};
+
+int pkg_dest_init(pkg_dest_t *dest, const char *name, const char *root_dir,const char *lists_dir);
+void pkg_dest_deinit(pkg_dest_t *dest);
+
+#endif
+
diff -ruN busybox-1.00-orig/archival/libipkg/pkg_dest_list.c busybox-1.00+ipkg-0.99.154/archival/libipkg/pkg_dest_list.c
--- busybox-1.00-orig/archival/libipkg/pkg_dest_list.c 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/pkg_dest_list.c 2005-10-26 17:36:46.000000000 +0200
@@ -0,0 +1,85 @@
+/* pkg_dest_list.c - the itsy package management system
+
+ Carl D. Worth
+
+ Copyright (C) 2001 University of Southern California
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#include "ipkg.h"
+
+#include "pkg_dest.h"
+#include "void_list.h"
+#include "pkg_dest_list.h"
+
+int pkg_dest_list_elt_init(pkg_dest_list_elt_t *elt, pkg_dest_t *data)
+{
+ return void_list_elt_init((void_list_elt_t *) elt, data);
+}
+
+void pkg_dest_list_elt_deinit(pkg_dest_list_elt_t *elt)
+{
+ void_list_elt_deinit((void_list_elt_t *) elt);
+}
+
+int pkg_dest_list_init(pkg_dest_list_t *list)
+{
+ return void_list_init((void_list_t *) list);
+}
+
+void pkg_dest_list_deinit(pkg_dest_list_t *list)
+{
+ pkg_dest_list_elt_t *iter;
+ pkg_dest_t *pkg_dest;
+
+ for (iter = list->head; iter; iter = iter->next) {
+ pkg_dest = iter->data;
+ pkg_dest_deinit(pkg_dest);
+
+ /* malloced in pkg_dest_list_append */
+ free(pkg_dest);
+ iter->data = NULL;
+ }
+ void_list_deinit((void_list_t *) list);
+}
+
+pkg_dest_t *pkg_dest_list_append(pkg_dest_list_t *list, const char *name,
+ const char *root_dir,const char *lists_dir)
+{
+ int err;
+ pkg_dest_t *pkg_dest;
+
+ /* freed in plg_dest_list_deinit */
+ pkg_dest = malloc(sizeof(pkg_dest_t));
+ if (pkg_dest == NULL) {
+ fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
+ return NULL;
+ }
+
+ pkg_dest_init(pkg_dest, name, root_dir,lists_dir);
+ err = void_list_append((void_list_t *) list, pkg_dest);
+ if (err) {
+ return NULL;
+ }
+
+ return pkg_dest;
+}
+
+int pkg_dest_list_push(pkg_dest_list_t *list, pkg_dest_t *data)
+{
+ return void_list_push((void_list_t *) list, data);
+}
+
+pkg_dest_list_elt_t *pkg_dest_list_pop(pkg_dest_list_t *list)
+{
+ return (pkg_dest_list_elt_t *) void_list_pop((void_list_t *) list);
+}
diff -ruN busybox-1.00-orig/archival/libipkg/pkg_dest_list.h busybox-1.00+ipkg-0.99.154/archival/libipkg/pkg_dest_list.h
--- busybox-1.00-orig/archival/libipkg/pkg_dest_list.h 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/pkg_dest_list.h 2005-10-26 17:36:46.000000000 +0200
@@ -0,0 +1,50 @@
+/* pkg_dest_list.h - the itsy package management system
+
+ Carl D. Worth
+
+ Copyright (C) 2001 University of Southern California
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#ifndef PKG_DEST_LIST_H
+#define PKG_DEST_LIST_H
+
+#include "pkg_dest.h"
+
+typedef struct pkg_dest_list_elt pkg_dest_list_elt_t;
+struct pkg_dest_list_elt
+{
+ pkg_dest_list_elt_t *next;
+ pkg_dest_t *data;
+};
+
+typedef struct pkg_dest_list pkg_dest_list_t;
+struct pkg_dest_list
+{
+ pkg_dest_list_elt_t pre_head;
+ pkg_dest_list_elt_t *head;
+ pkg_dest_list_elt_t *tail;
+};
+
+int pkg_dest_list_elt_init(pkg_dest_list_elt_t *elt, pkg_dest_t *data);
+void pkg_dest_list_elt_deinit(pkg_dest_list_elt_t *elt);
+
+int pkg_dest_list_init(pkg_dest_list_t *list);
+void pkg_dest_list_deinit(pkg_dest_list_t *list);
+
+pkg_dest_t *pkg_dest_list_append(pkg_dest_list_t *list, const char *name,
+ const char *root_dir,const char* lists_dir);
+int pkg_dest_list_push(pkg_dest_list_t *list, pkg_dest_t *data);
+pkg_dest_list_elt_t *pkg_dest_list_pop(pkg_dest_list_t *list);
+
+#endif
+
diff -ruN busybox-1.00-orig/archival/libipkg/pkg_extract.c busybox-1.00+ipkg-0.99.154/archival/libipkg/pkg_extract.c
--- busybox-1.00-orig/archival/libipkg/pkg_extract.c 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/pkg_extract.c 2005-10-26 17:36:46.000000000 +0200
@@ -0,0 +1,224 @@
+/* pkg_extract.c - the itsy package management system
+
+ Carl D. Worth
+
+ Copyright (C) 2001 University of Southern California
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#include "ipkg.h"
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+#include "pkg_extract.h"
+
+#include "libbb.h"
+#include "file_util.h"
+#include "sprintf_alloc.h"
+#include "unarchive.h"
+
+#define IPKG_CONTROL_ARCHIVE "control.tar.gz"
+#define IPKG_DATA_ARCHIVE "data.tar.gz"
+#define IPKG_CONTROL_FILE "control"
+
+static void extract_ipkg_file_to_dir(pkg_t *pkg, const char *dir, const char *filename)
+{
+ archive_handle_t *archive;
+ char *path;
+
+ sprintf_alloc(&path, "%s/", dir);
+ archive = init_handle();
+ archive->src_fd = bb_xopen(pkg->local_filename, O_RDONLY);
+ archive->filter = filter_accept_list;
+ archive->accept = llist_add_to(NULL, (char *)filename);
+ archive->buffer = path;
+ archive->action_data = data_extract_all_prefix;
+ archive->flags |= ARCHIVE_EXTRACT_UNCONDITIONAL;
+ while( get_header_tar_gz(archive) == EXIT_SUCCESS );
+ close(archive->src_fd);
+ free(archive->accept);
+ free(archive);
+ free(path);
+}
+
+static void data_extract_file_name_to_buffer(archive_handle_t *archive)
+{
+ unsigned int size = strlen(archive->file_header->name) + 2;
+
+ if (archive->buffer == NULL) {
+ archive->buffer = xmalloc(size);
+ strcpy(archive->buffer, archive->file_header->name);
+ } else {
+ size += strlen(archive->buffer);
+ archive->buffer = xrealloc(archive->buffer, size);
+ strcat(archive->buffer, archive->file_header->name);
+ }
+ strcat(archive->buffer, "\n");
+ data_skip(archive);
+}
+
+int pkg_extract_control_file_to_stream(pkg_t *pkg, FILE *stream)
+{
+ archive_handle_t *archive;
+ char *name;
+
+ extract_ipkg_file_to_dir(pkg, global_conf->tmp_dir, "./" IPKG_CONTROL_ARCHIVE);
+ sprintf_alloc(&name, "%s/%s", global_conf->tmp_dir, IPKG_CONTROL_ARCHIVE);
+ archive = init_handle();
+ archive->src_fd = bb_xopen(name, O_RDONLY);
+ archive->filter = filter_accept_list;
+ archive->accept = llist_add_to(NULL, "./" IPKG_CONTROL_FILE);
+ archive->action_data = data_extract_to_buffer;
+ while( get_header_tar_gz(archive) == EXIT_SUCCESS );
+ close(archive->src_fd);
+ fputs(archive->buffer, stream);
+ free(archive->buffer);
+ free(archive->accept);
+ free(archive);
+ free(name);
+
+ return 0;
+}
+
+int pkg_extract_control_files_to_dir(pkg_t *pkg, const char *dir)
+{
+ return pkg_extract_control_files_to_dir_with_prefix(pkg, dir, "");
+}
+
+int pkg_extract_control_files_to_dir_with_prefix(pkg_t *pkg, const char *dir, const char *prefix)
+{
+ archive_handle_t *archive;
+ char *name;
+ char *path;
+
+ extract_ipkg_file_to_dir(pkg, global_conf->tmp_dir, "./" IPKG_CONTROL_ARCHIVE);
+ sprintf_alloc(&name, "%s/%s", global_conf->tmp_dir, IPKG_CONTROL_ARCHIVE);
+ sprintf_alloc(&path, "%s/%s", dir, prefix);
+ archive = init_handle();
+ archive->src_fd = bb_xopen(name, O_RDONLY);
+ archive->filter = filter_accept_all;
+ archive->buffer = path;
+ archive->action_data = data_extract_all_prefix;
+ archive->flags |= ARCHIVE_CREATE_LEADING_DIRS | ARCHIVE_PRESERVE_DATE | ARCHIVE_EXTRACT_UNCONDITIONAL;
+ while( get_header_tar_gz(archive) == EXIT_SUCCESS );
+ close(archive->src_fd);
+ free(archive);
+ free(path);
+ free(name);
+
+ return 0;
+}
+
+int pkg_extract_data_files_to_dir(pkg_t *pkg, const char *dir)
+{
+ archive_handle_t *archive;
+ char *name;
+ char *path;
+
+ extract_ipkg_file_to_dir(pkg, global_conf->tmp_dir, "./" IPKG_DATA_ARCHIVE);
+ sprintf_alloc(&name, "%s/%s", global_conf->tmp_dir, IPKG_DATA_ARCHIVE);
+ sprintf_alloc(&path, "%s/", dir);
+ archive = init_handle();
+ archive->src_fd = bb_xopen(name, O_RDONLY);
+ archive->filter = filter_accept_all;
+ archive->buffer = path;
+ archive->action_data = data_extract_all_prefix;
+ archive->flags |= ARCHIVE_CREATE_LEADING_DIRS | ARCHIVE_PRESERVE_DATE | ARCHIVE_EXTRACT_UNCONDITIONAL;
+ while( get_header_tar_gz(archive) == EXIT_SUCCESS );
+ close(archive->src_fd);
+ free(archive);
+ free(path);
+ free(name);
+
+ return 0;
+}
+
+int pkg_extract_data_file_names_to_file(pkg_t *pkg, const char *file_name)
+{
+ int err=0;
+ char *line, *data_file;
+ FILE *file;
+ FILE *tmp;
+
+ file = fopen(file_name, "w");
+ if (file == NULL) {
+ fprintf(stderr, "%s: ERROR: Failed to open %s for writing.\n",
+ __FUNCTION__, file_name);
+ return EINVAL;
+ }
+
+ tmp = tmpfile();
+ if (pkg->installed_files) {
+ str_list_elt_t *elt;
+ for (elt = pkg->installed_files->head; elt; elt = elt->next) {
+ fprintf(file, "%s\n", elt->data);
+ }
+ } else {
+ err = pkg_extract_data_file_names_to_stream(pkg, tmp);
+ if (err) {
+ fclose(file);
+ fclose(tmp);
+ return err;
+ }
+
+ /* Fixup data file names by removing the initial '.' */
+ rewind(tmp);
+ while (1) {
+ line = file_read_line_alloc(tmp);
+ if (line == NULL) {
+ break;
+ }
+
+ data_file = line;
+ if (*data_file == '.') {
+ data_file++;
+ }
+
+ if (*data_file != '/') {
+ fputs("/", file);
+ }
+
+ /* I have no idea why, but this is what dpkg does */
+ if (strcmp(data_file, "/\n") == 0) {
+ fputs("/.\n", file);
+ } else {
+ fputs(data_file, file);
+ }
+ }
+ }
+ fclose(tmp);
+ fclose(file);
+
+ return err;
+}
+
+int pkg_extract_data_file_names_to_stream(pkg_t *pkg, FILE *file)
+{
+ archive_handle_t *archive;
+ char *name;
+
+ extract_ipkg_file_to_dir(pkg, global_conf->tmp_dir, "./" IPKG_DATA_ARCHIVE);
+ sprintf_alloc(&name, "%s/%s", global_conf->tmp_dir, IPKG_DATA_ARCHIVE);
+ archive = init_handle();
+ archive->src_fd = bb_xopen(name, O_RDONLY);
+ archive->filter = filter_accept_all;
+ archive->action_data = data_extract_file_name_to_buffer;
+ while( get_header_tar_gz(archive) == EXIT_SUCCESS );
+ close(archive->src_fd);
+ fputs(archive->buffer, file);
+ free(archive->buffer);
+ free(archive);
+ free(name);
+
+ return 0;
+}
diff -ruN busybox-1.00-orig/archival/libipkg/pkg_extract.h busybox-1.00+ipkg-0.99.154/archival/libipkg/pkg_extract.h
--- busybox-1.00-orig/archival/libipkg/pkg_extract.h 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/pkg_extract.h 2005-10-26 17:36:46.000000000 +0200
@@ -0,0 +1,32 @@
+/* pkg_extract.c - the itsy package management system
+
+ Carl D. Worth
+
+ Copyright (C) 2001 University of Southern California
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#ifndef PKG_EXTRACT_H
+#define PKG_EXTRACT_H
+
+#include "pkg.h"
+
+int pkg_extract_control_file_to_stream(pkg_t *pkg, FILE *stream);
+int pkg_extract_control_files_to_dir(pkg_t *pkg, const char *dir);
+int pkg_extract_control_files_to_dir_with_prefix(pkg_t *pkg,
+ const char *dir,
+ const char *prefix);
+int pkg_extract_data_files_to_dir(pkg_t *pkg, const char *dir);
+int pkg_extract_data_file_names_to_file(pkg_t *pkg, const char *file_name);
+int pkg_extract_data_file_names_to_stream(pkg_t *pkg, FILE *file);
+
+#endif
diff -ruN busybox-1.00-orig/archival/libipkg/pkg_hash.c busybox-1.00+ipkg-0.99.154/archival/libipkg/pkg_hash.c
--- busybox-1.00-orig/archival/libipkg/pkg_hash.c 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/pkg_hash.c 2005-10-26 17:45:58.000000000 +0200
@@ -0,0 +1,608 @@
+/* ipkg_hash.c - the itsy package management system
+
+ Steven M. Ayer
+
+ Copyright (C) 2002 Compaq Computer Corporation
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#include "ipkg.h"
+#include <errno.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "hash_table.h"
+#include "pkg.h"
+#include "ipkg_message.h"
+#include "pkg_vec.h"
+#include "pkg_hash.h"
+#include "pkg_parse.h"
+#include "ipkg_utils.h"
+
+static abstract_pkg_t * add_new_abstract_pkg_by_name(hash_table_t * hash, const char * pkg_name);
+
+/*
+ * this will talk to both feeds-lists files and installed status files
+ * example api:
+ *
+ * hash_table_t hash;
+ * pkg_hash_init(name, &hash, 1000);
+ * pkg_hash_add_from_file(<feed filename>);
+ *
+ * the query function is just there as a shell to prove to me that this
+ * sort of works, but isn't far from doing something useful
+ *
+ * -sma, 12/21/01
+ * modified: CDW 3 Jan. 2002
+ */
+
+
+
+int pkg_hash_init(const char *name, hash_table_t *hash, int len)
+{
+ return hash_table_init(name, hash, len);
+}
+
+void pkg_hash_deinit(hash_table_t *hash)
+{
+ hash_table_deinit(hash);
+}
+
+
+/* Find the default arch for a given package status file if none is given. */
+static char *pkg_get_default_arch(ipkg_conf_t *conf)
+{
+ nv_pair_list_elt_t *l;
+ char *def_arch = HOST_CPU_STR; /* Default arch */
+ int def_prio = 0; /* Other archs override this */
+
+ l = conf->arch_list.head;
+
+ while (l) {
+ nv_pair_t *nv = l->data;
+ int priority = strtol(nv->value, NULL, 0);
+
+ /* Check if this arch has higher priority, and is valid */
+ if ((priority > def_prio) &&
+ (strcmp(nv->name, "all")) && (strcmp(nv->name, "noarch"))) {
+ /* Our new default */
+ def_prio = priority;
+ def_arch = nv->name;
+ }
+ l = l->next;
+ }
+
+ return strdup(def_arch);
+}
+
+int pkg_hash_add_from_file(ipkg_conf_t *conf, const char *file_name,
+ pkg_src_t *src, pkg_dest_t *dest, int is_status_file)
+{
+ hash_table_t *hash = &conf->pkg_hash;
+ char **raw;
+ char **raw_start;
+ pkg_t *pkg;
+
+ raw = raw_start = read_raw_pkgs_from_file(file_name);
+ if (!raw)
+ return -ENOMEM;
+
+ while(*raw){ /* don't worry, we'll increment raw in the parsing function */
+ pkg = pkg_new();
+ if (!pkg)
+ return -ENOMEM;
+
+ if (pkg_parse_raw(pkg, &raw, src, dest) == 0) {
+ if (!pkg->architecture) {
+ char *version_str = pkg_version_str_alloc(pkg);
+ pkg->architecture = pkg_get_default_arch(conf);
+ ipkg_message(conf, IPKG_ERROR, "Package %s version %s has no architecture specified, defaulting to %s.\n",
+ pkg->name, version_str, pkg->architecture);
+ free(version_str);
+ }
+ hash_insert_pkg(hash, pkg, is_status_file,conf);
+ } else {
+ free(pkg);
+ }
+ }
+
+ /* XXX: CLEANUP: I'd like a cleaner interface for cleaning up
+ memory after read_raw_pkgs_from_file */
+ raw = raw_start;
+ while (*raw) {
+ free(*raw++);
+ }
+ free(raw_start);
+ return 0;
+}
+
+abstract_pkg_t * abstract_pkg_fetch_by_name(hash_table_t * hash, const char * pkg_name)
+{
+ return (abstract_pkg_t *)hash_table_get(hash, pkg_name);
+}
+
+abstract_pkg_vec_t *pkg_hash_fetch_all_installation_candidates(hash_table_t *hash, const char *name)
+{
+ abstract_pkg_t *apkg = abstract_pkg_fetch_by_name(hash, name);
+ if (apkg)
+ return NULL;
+ return apkg->provided_by;
+}
+
+
+pkg_t *pkg_hash_fetch_best_installation_candidate(ipkg_conf_t *conf, abstract_pkg_t *apkg,
+ int (*constraint_fcn)(pkg_t *pkg, void *cdata), void *cdata, int quiet)
+{
+ int i;
+ int nprovides = 0;
+ int nmatching = 0;
+ pkg_vec_t *matching_pkgs = pkg_vec_alloc();
+ abstract_pkg_vec_t *matching_apkgs = abstract_pkg_vec_alloc();
+ abstract_pkg_vec_t *provided_apkg_vec;
+ abstract_pkg_t **provided_apkgs;
+ abstract_pkg_vec_t *providers = abstract_pkg_vec_alloc();
+ pkg_t *latest_installed_parent = NULL;
+ pkg_t *latest_matching = NULL;
+ pkg_t *held_pkg = NULL;
+ pkg_t *good_pkg_by_name = NULL;
+
+ if (matching_apkgs == NULL || providers == NULL ||
+ apkg == NULL || apkg->provided_by == NULL || (apkg->provided_by->len == 0))
+ return NULL;
+
+ ipkg_message(conf, IPKG_DEBUG, "best installation candidate for %s\n", apkg->name);
+
+ provided_apkg_vec = apkg->provided_by;
+ nprovides = provided_apkg_vec->len;
+ provided_apkgs = provided_apkg_vec->pkgs;
+ if (nprovides > 1)
+ ipkg_message(conf, IPKG_DEBUG, " apkg=%s nprovides=%d\n", apkg->name, nprovides);
+
+ /* accumulate all the providers */
+ for (i = 0; i < nprovides; i++) {
+ abstract_pkg_t *provider_apkg = provided_apkgs[i];
+ ipkg_message(conf, IPKG_DEBUG, " adding %s to providers\n", provider_apkg->name);
+ abstract_pkg_vec_insert(providers, provider_apkg);
+ }
+ nprovides = providers->len;
+
+ for (i = 0; i < nprovides; i++) {
+ abstract_pkg_t *provider_apkg = abstract_pkg_vec_get(providers, i);
+ abstract_pkg_t *replacement_apkg = NULL;
+ pkg_vec_t *vec;
+
+ if (provider_apkg->replaced_by && provider_apkg->replaced_by->len) {
+ replacement_apkg = provider_apkg->replaced_by->pkgs[0];
+ if (provider_apkg->replaced_by->len > 1) {
+ ipkg_message(conf, IPKG_NOTICE, "Multiple replacers for %s, using first one (%s)\n",
+ provider_apkg->name, replacement_apkg->name);
+ }
+ }
+
+ if (replacement_apkg)
+ ipkg_message(conf, IPKG_DEBUG, " replacement_apkg=%s for provider_apkg=%s\n",
+ replacement_apkg->name, provider_apkg->name);
+
+ if (replacement_apkg && (replacement_apkg != provider_apkg)) {
+ if (abstract_pkg_vec_contains(providers, replacement_apkg))
+ continue;
+ else
+ provider_apkg = replacement_apkg;
+ }
+
+ if (!(vec = provider_apkg->pkgs)) {
+ ipkg_message(conf, IPKG_DEBUG, " no pkgs for provider_apkg %s\n", provider_apkg->name);
+ continue;
+ }
+
+
+ /* now check for supported architecture */
+ {
+ int max_count = 0;
+ int i;
+
+ /* count packages matching max arch priority and keep track of last one */
+ for (i = 0; i < vec->len; i++) {
+ pkg_t *maybe = vec->pkgs[i];
+ ipkg_message(conf, IPKG_DEBUG, " %s arch=%s arch_priority=%d \n",
+ maybe->name, maybe->architecture, maybe->arch_priority);
+ if (maybe->arch_priority > 0) {
+ max_count++;
+ abstract_pkg_vec_insert(matching_apkgs, maybe->parent);
+ pkg_vec_insert(matching_pkgs, maybe);
+ }
+ }
+ }
+ }
+
+ if (matching_pkgs->len > 1)
+ pkg_vec_sort(matching_pkgs, pkg_name_version_and_architecture_compare);
+ if (matching_apkgs->len > 1)
+ abstract_pkg_vec_sort(matching_pkgs, abstract_pkg_name_compare);
+
+/* Here it is usefull, if ( matching_apkgs->len > 1 ), to test if one of this matching packages has the same name of the
+ needed package. In this case, I would return it for install, otherwise I will continue with the procedure */
+
+ for (i = 0; i < matching_pkgs->len; i++) {
+ pkg_t *matching = matching_pkgs->pkgs[i];
+ if (constraint_fcn(matching, cdata)) { /* We found it */
+ ipkg_message(conf, IPKG_DEBUG, " Found a valid candidate for the install: %s \n", matching->name) ;
+ good_pkg_by_name = matching;
+ }
+ }
+
+
+ for (i = 0; i < matching_pkgs->len; i++) {
+ pkg_t *matching = matching_pkgs->pkgs[i];
+ latest_matching = matching;
+ if (matching->parent->state_status == SS_INSTALLED || matching->parent->state_status == SS_UNPACKED)
+ latest_installed_parent = matching;
+ if (matching->state_flag & (SF_HOLD|SF_PREFER)) {
+ if (held_pkg)
+ ipkg_message(conf, IPKG_ERROR, "Multiple packages (%s and %s) providing same name marked HOLD or PREFER. Using latest.\n",
+ held_pkg->name, matching->name);
+ held_pkg = matching;
+ }
+ }
+
+ if (!good_pkg_by_name && !held_pkg && !latest_installed_parent && matching_apkgs->len > 1 && !quiet) {
+ ipkg_message(conf, IPKG_ERROR, "Package=%s, %d matching providers\n",
+ apkg->name, matching_apkgs->len);
+ for (i = 0; i < matching_apkgs->len; i++) {
+ abstract_pkg_t *matching = matching_apkgs->pkgs[i];
+ ipkg_message(conf, IPKG_ERROR, " %s\n", matching->name);
+ }
+ ipkg_message(conf, IPKG_ERROR, "Please select one with ipkg install or ipkg flag prefer\n");
+ }
+
+ if (matching_apkgs->len > 1 && conf->verbosity > 1) {
+ ipkg_message(conf, IPKG_NOTICE, "%s: for apkg=%s, %d matching pkgs\n",
+ __FUNCTION__, apkg->name, matching_pkgs->len);
+ for (i = 0; i < matching_pkgs->len; i++) {
+ pkg_t *matching = matching_pkgs->pkgs[i];
+ ipkg_message(conf, IPKG_INFO, " %s %s %s\n",
+ matching->name, matching->version, matching->architecture);
+ }
+ }
+
+ nmatching = matching_apkgs->len;
+
+ pkg_vec_free(matching_pkgs);
+ abstract_pkg_vec_free(matching_apkgs);
+ abstract_pkg_vec_free(providers);
+
+ if (good_pkg_by_name) { /* We found a good candidate, we will install it */
+ return good_pkg_by_name;
+ }
+ if (held_pkg) {
+ ipkg_message(conf, IPKG_INFO, " using held package %s\n", held_pkg->name);
+ return held_pkg;
+ }
+ if (latest_installed_parent) {
+ ipkg_message(conf, IPKG_INFO, " using latest version of installed package %s\n", latest_installed_parent->name);
+ return latest_installed_parent;
+ }
+ if (nmatching > 1) {
+ ipkg_message(conf, IPKG_INFO, " no matching pkg out of matching_apkgs=%d\n", nmatching);
+ return NULL;
+ }
+ if (latest_matching) {
+ ipkg_message(conf, IPKG_INFO, " using latest matching %s %s %s\n",
+ latest_matching->name, latest_matching->version, latest_matching->architecture);
+ return latest_matching;
+ }
+ return NULL;
+}
+
+static int pkg_name_constraint_fcn(pkg_t *pkg, void *cdata)
+{
+ const char *name = (const char *)cdata;
+ if (strcmp(pkg->name, name) == 0)
+ return 1;
+ else
+ return 0; /* Pigi */
+}
+
+pkg_t *pkg_hash_fetch_best_installation_candidate_by_name(ipkg_conf_t *conf, const char *name)
+{
+ hash_table_t *hash = &conf->pkg_hash;
+ abstract_pkg_t *apkg = NULL;
+
+ if (!(apkg = abstract_pkg_fetch_by_name(hash, name)))
+ return NULL;
+
+ return pkg_hash_fetch_best_installation_candidate(conf, apkg, pkg_name_constraint_fcn, apkg->name, 0);
+}
+
+
+pkg_t * pkg_hash_fetch_by_name_version(hash_table_t *hash,
+ const char *pkg_name,
+ const char * version)
+{
+ pkg_vec_t * vec;
+ register int i;
+ char *version_str = NULL;
+
+ if(!(vec = pkg_vec_fetch_by_name(hash, pkg_name)))
+ return NULL;
+
+ for(i = 0; i < vec->len; i++) {
+ version_str = pkg_version_str_alloc(vec->pkgs[i]);
+ if(!strcmp(version_str, version)) {
+ free(version_str);
+ break;
+ }
+ free(version_str);
+ }
+
+ if(i == vec->len)
+ return NULL;
+
+ return vec->pkgs[i];
+}
+
+pkg_t *pkg_hash_fetch_installed_by_name_dest(hash_table_t *hash,
+ const char *pkg_name,
+ pkg_dest_t *dest)
+{
+ pkg_vec_t * vec;
+ register int i;
+
+ if(!(vec = pkg_vec_fetch_by_name(hash, pkg_name))) {
+ return NULL;
+ }
+
+ for(i = 0; i < vec->len; i++)
+ if((vec->pkgs[i]->state_status == SS_INSTALLED || vec->pkgs[i]->state_status == SS_UNPACKED) && vec->pkgs[i]->dest == dest) {
+ return vec->pkgs[i];
+ }
+ return NULL;
+}
+
+pkg_t *pkg_hash_fetch_installed_by_name(hash_table_t *hash,
+ const char *pkg_name)
+{
+ pkg_vec_t * vec;
+ register int i;
+
+ if(!(vec = pkg_vec_fetch_by_name(hash, pkg_name))){
+ return NULL;
+ }
+
+ for(i = 0; i < vec->len; i++)
+ if (vec->pkgs[i]->state_status == SS_INSTALLED || vec->pkgs[i]->state_status == SS_UNPACKED){
+ return vec->pkgs[i];
+ }
+
+ return NULL;
+}
+
+pkg_vec_t *pkg_vec_fetch_by_name(hash_table_t *hash, const char *pkg_name)
+{
+ abstract_pkg_t * ab_pkg;
+
+ if(!(ab_pkg = abstract_pkg_fetch_by_name(hash, pkg_name))){
+ return NULL;
+ }
+
+ if (ab_pkg->pkgs) {
+ return ab_pkg->pkgs;
+ } else if (ab_pkg->provided_by) {
+ abstract_pkg_t *abpkg = abstract_pkg_vec_get(ab_pkg->provided_by, 0);
+ if (abpkg != NULL){
+ return abpkg->pkgs;
+ } else {
+ return ab_pkg->pkgs;
+ }
+ } else {
+ return NULL;
+ }
+}
+
+static int pkg_compare_names(const void *p1, const void *p2)
+{
+ const pkg_t *pkg1 = *(const pkg_t **)p1;
+ const pkg_t *pkg2 = *(const pkg_t **)p2;
+ if (pkg1->name == NULL)
+ return 1;
+ if (pkg2->name == NULL)
+ return -1;
+ return(strcmp(pkg1->name, pkg2->name));
+}
+
+
+static void pkg_hash_fetch_available_helper(const char *pkg_name, void *entry, void *data)
+{
+ int j;
+ abstract_pkg_t *ab_pkg = (abstract_pkg_t *)entry;
+ pkg_vec_t *all = (pkg_vec_t *)data;
+ pkg_vec_t *pkg_vec = ab_pkg->pkgs;
+ if (pkg_vec) {
+ for (j = 0; j < pkg_vec->len; j++) {
+ pkg_t *pkg = pkg_vec->pkgs[j];
+ pkg_vec_insert(all, pkg);
+ }
+ }
+}
+
+void pkg_hash_fetch_available(hash_table_t *hash, pkg_vec_t *all)
+{
+ hash_table_foreach(hash, pkg_hash_fetch_available_helper, all);
+ qsort(all->pkgs, all->len, sizeof(pkg_t *), pkg_compare_names);
+}
+
+static void pkg_hash_fetch_all_installed_helper(const char *pkg_name, void *entry, void *data)
+{
+ abstract_pkg_t *ab_pkg = (abstract_pkg_t *)entry;
+ pkg_vec_t *all = (pkg_vec_t *)data;
+ pkg_vec_t *pkg_vec = ab_pkg->pkgs;
+ int j;
+ if (pkg_vec) {
+ for (j = 0; j < pkg_vec->len; j++) {
+ pkg_t *pkg = pkg_vec->pkgs[j];
+ if (pkg->state_status == SS_INSTALLED || pkg->state_status == SS_UNPACKED) {
+ pkg_vec_insert(all, pkg);
+ }
+ }
+ }
+}
+void pkg_hash_fetch_all_installed(hash_table_t *hash, pkg_vec_t *all)
+{
+ hash_table_foreach(hash, pkg_hash_fetch_all_installed_helper, all);
+ qsort(all->pkgs, all->len, sizeof(void*), pkg_compare_names);
+}
+
+static void pkg_hash_dump_helper(const char *pkg_name, void *entry, void *data)
+{
+ int i;
+ pkg_t *pkg;
+ abstract_pkg_t *ab_pkg = (abstract_pkg_t *)entry;
+ ipkg_conf_t *conf = (ipkg_conf_t *)data;
+ abstract_pkg_t ** dependents = ab_pkg->depended_upon_by;
+ fprintf(stdout, "%s\n", ab_pkg->name);
+ i = 0;
+ if (dependents != NULL)
+ while (dependents [i] != NULL)
+ printf ("\tdepended upon by - %s\n", dependents [i ++]->name);
+ dependents = ab_pkg->provided_by->pkgs;
+ i = 0;
+ if (dependents != NULL)
+ while (dependents [i] != NULL && i < ab_pkg->provided_by->len)
+ printf ("\tprovided by - %s\n", dependents [i ++]->name);
+ pkg = pkg_hash_fetch_best_installation_candidate_by_name (conf, ab_pkg->name);
+ if (pkg) {
+ i = 0;
+ while (i < pkg->depends_count)
+ printf ("\tdepends on - %s\n", pkg->depends_str [i ++]);
+ }
+}
+void pkg_hash_dump(hash_table_t *hash, void *data)
+{
+
+ printf ("\n\n+=+%s+=+\n\n", __FUNCTION__);
+ hash_table_foreach(hash, pkg_hash_dump_helper, data);
+ printf ("\n+=+%s+=+\n\n", __FUNCTION__);
+}
+
+abstract_pkg_t * ensure_abstract_pkg_by_name(hash_table_t * hash, const char * pkg_name)
+{
+ abstract_pkg_t * ab_pkg;
+
+ if(!(ab_pkg = abstract_pkg_fetch_by_name(hash, pkg_name)))
+ ab_pkg = add_new_abstract_pkg_by_name(hash, pkg_name);
+
+ return ab_pkg;
+}
+
+pkg_t *hash_insert_pkg(hash_table_t *hash, pkg_t *pkg, int set_status,ipkg_conf_t *conf)
+{
+ abstract_pkg_t * ab_pkg;
+ int arch_priority;
+
+ if(!pkg)
+ return pkg;
+
+ arch_priority = pkg->arch_priority;
+
+ if (buildDepends(hash, pkg)<0){
+ fprintf(stderr, "%s : This should never happen. Report this Bug in bugzilla please \n ",__FUNCTION__);
+ return NULL;
+ }
+ ab_pkg = ensure_abstract_pkg_by_name(hash, pkg->name);
+
+ if (set_status) {
+ if (pkg->state_status == SS_INSTALLED) {
+ ab_pkg->state_status = SS_INSTALLED;
+ } else if (pkg->state_status == SS_UNPACKED) {
+ ab_pkg->state_status = SS_UNPACKED;
+ }
+ }
+
+ if(!ab_pkg->pkgs)
+ ab_pkg->pkgs = pkg_vec_alloc();
+
+ /* pkg_vec_insert_merge might munge package, but it returns an unmunged pkg */
+ pkg = pkg_vec_insert_merge(ab_pkg->pkgs, pkg, set_status,conf );
+ pkg->parent = ab_pkg;
+
+ if (buildProvides(hash, ab_pkg, pkg)<0){
+ fprintf(stderr, "%s : This should never happen. Report this Bug in bugzilla please \n ",__FUNCTION__);
+ return NULL;
+ }
+ /* need to build the conflicts graph before replaces for correct calculation of replaced_by relation */
+ if (buildConflicts(hash, ab_pkg, pkg)<0){
+ fprintf(stderr, "%s : This should never happen. Report this Bug in bugzilla please \n ",__FUNCTION__);
+ return NULL;
+ }
+ if (buildReplaces(hash, ab_pkg, pkg)<0) {
+ fprintf(stderr, "%s : This should never happen. Report this Bug in bugzilla please \n ",__FUNCTION__);
+ return NULL;
+ }
+
+ buildDependedUponBy(pkg, ab_pkg);
+ return pkg;
+}
+
+/*
+ * this will assume that we've already determined that
+ * the abstract pkg doesn't exist, 'cause we should know these things...
+ */
+static abstract_pkg_t * add_new_abstract_pkg_by_name(hash_table_t * hash, const char * pkg_name)
+{
+ abstract_pkg_t * ab_pkg;
+
+ ab_pkg = abstract_pkg_new();
+ if (ab_pkg == NULL) { return NULL; }
+
+ ab_pkg->name = strdup(pkg_name);
+ hash_table_insert(hash, pkg_name, ab_pkg);
+
+ return ab_pkg;
+}
+
+
+pkg_t *file_hash_get_file_owner(ipkg_conf_t *conf, const char *file_name)
+{
+ hash_table_t *file_hash = &conf->file_hash;
+
+ return hash_table_get(file_hash, file_name);
+}
+
+int file_hash_set_file_owner(ipkg_conf_t *conf, const char *file_name, pkg_t *owning_pkg)
+{
+ hash_table_t *file_hash = &conf->file_hash;
+ pkg_t *old_owning_pkg = hash_table_get(file_hash, file_name);
+ int file_name_len = strlen(file_name);
+
+ if (file_name[file_name_len -1] == '/')
+ return 0;
+
+ if (conf->offline_root) {
+ int len = strlen(conf->offline_root);
+ if (strncmp(file_name, conf->offline_root, len) == 0) {
+ file_name += len;
+ }
+ }
+
+ // ipkg_message(conf, IPKG_DEBUG2, "owning_pkg=%s filename=%s\n", owning_pkg->name, file_name);
+ hash_table_insert(file_hash, file_name, owning_pkg);
+ if (old_owning_pkg) {
+ str_list_remove_elt(old_owning_pkg->installed_files, file_name);
+ /* mark this package to have its filelist written */
+ old_owning_pkg->state_flag |= SF_FILELIST_CHANGED;
+ owning_pkg->state_flag |= SF_FILELIST_CHANGED;
+ }
+ return 0;
+}
+
+
diff -ruN busybox-1.00-orig/archival/libipkg/pkg_hash.h busybox-1.00+ipkg-0.99.154/archival/libipkg/pkg_hash.h
--- busybox-1.00-orig/archival/libipkg/pkg_hash.h 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/pkg_hash.h 2005-10-26 17:36:46.000000000 +0200
@@ -0,0 +1,61 @@
+/* pkg_hash.h - the itsy package management system
+
+ Steven M. Ayer
+
+ Copyright (C) 2002 Compaq Computer Corporation
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#ifndef PKG_HASH_H
+#define PKG_HASH_H
+
+#include "pkg.h"
+#include "pkg_vec.h"
+#include "hash_table.h"
+
+
+int pkg_hash_init(const char *name, hash_table_t *hash, int len);
+void pkg_hash_deinit(hash_table_t *hash);
+void pkg_hash_map(hash_table_t *hash, void (*f)(void *data, void *entry), void *data);
+
+void pkg_hash_dump(hash_table_t *hash, void *data);
+void pkg_hash_fetch_available(hash_table_t *hash, pkg_vec_t *available);
+
+int pkg_hash_add_from_file(ipkg_conf_t *conf, const char *file_name,
+ pkg_src_t *src, pkg_dest_t *dest, int is_status_file);
+pkg_t *hash_insert_pkg(hash_table_t *hash, pkg_t *pkg, int set_status,ipkg_conf_t *conf);
+
+abstract_pkg_t * ensure_abstract_pkg_by_name(hash_table_t * hash, const char * pkg_name);
+abstract_pkg_t * abstract_pkg_fetch_by_name(hash_table_t * hash, const char * pkg_name);
+pkg_vec_t *pkg_hash_fetch_by_name(hash_table_t *hash, const char *pkg_name);
+void pkg_hash_fetch_all_installed(hash_table_t *hash, pkg_vec_t *installed);
+pkg_t * pkg_hash_fetch_by_name_version(hash_table_t *hash,
+ const char *pkg_name,
+ const char * version);
+abstract_pkg_vec_t *pkg_hash_fetch_all_installation_candidates(hash_table_t *hash, const char *name);
+pkg_t *pkg_hash_fetch_best_installation_candidate(ipkg_conf_t *conf, abstract_pkg_t *apkg,
+ int (*constraint_fcn)(pkg_t *pkg, void *data), void *cdata, int quiet);
+pkg_t *pkg_hash_fetch_best_installation_candidate_by_name(ipkg_conf_t *conf, const char *name);
+pkg_t *pkg_hash_fetch_installed_by_name(hash_table_t *hash,
+ const char *pkg_name);
+pkg_t *pkg_hash_fetch_installed_by_name_dest(hash_table_t *hash,
+ const char *pkg_name,
+ pkg_dest_t *dest);
+
+pkg_t *file_hash_get_file_owner(ipkg_conf_t *conf, const char *file_name);
+int file_hash_set_file_owner(ipkg_conf_t *conf, const char *file_name, pkg_t *pkg);
+
+/* XXX: shouldn't this go in pkg_vec.[ch]? */
+pkg_vec_t *pkg_vec_fetch_by_name(hash_table_t *hash, const char *pkg_name);
+
+#endif
+
diff -ruN busybox-1.00-orig/archival/libipkg/pkg_parse.c busybox-1.00+ipkg-0.99.154/archival/libipkg/pkg_parse.c
--- busybox-1.00-orig/archival/libipkg/pkg_parse.c 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/pkg_parse.c 2005-10-26 17:36:46.000000000 +0200
@@ -0,0 +1,366 @@
+/* pkg_parse.c - the itsy package management system
+
+ Steven M. Ayer
+
+ Copyright (C) 2002 Compaq Computer Corporation
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#include "ipkg.h"
+#include <errno.h>
+#include <ctype.h>
+
+#include "pkg.h"
+#include "ipkg_utils.h"
+#include "pkg_parse.h"
+
+int isGenericFieldType(char * type, char * line)
+{
+ if(!strncmp(line, type, strlen(type)))
+ return 1;
+ return 0;
+}
+
+char * parseGenericFieldType(char * type, char * raw)
+{
+ char * field_value = raw + (strlen(type) + 1);
+ return trim_alloc(field_value);
+}
+
+void parseStatus(pkg_t *pkg, char * raw)
+{
+ char sw_str[64], sf_str[64], ss_str[64];
+
+ sscanf(raw, "Status: %s %s %s", sw_str, sf_str, ss_str);
+ pkg->state_want = pkg_state_want_from_str(sw_str);
+ pkg->state_flag = pkg_state_flag_from_str(sf_str);
+ pkg->state_status = pkg_state_status_from_str(ss_str);
+}
+
+char ** parseDependsString(char * raw, int * depends_count)
+{
+ char ** depends = NULL;
+ int line_count = 0;
+ char buff[2048], * dest;
+
+ while(raw && *raw && !isspace(*raw)) {
+ raw++;
+ }
+
+ if(line_is_blank(raw)){
+ *depends_count = line_count;
+ return NULL;
+ }
+ while(raw && *raw){
+ depends = (char **)realloc(depends, sizeof(char *) * (line_count + 1));
+
+ while(isspace(*raw)) raw++;
+
+ dest = buff;
+ while((*raw != ',') && *raw)
+ *dest++ = *raw++;
+
+ *dest = '\0';
+ depends[line_count] = trim_alloc(buff);
+ if(depends[line_count] ==NULL)
+ return NULL;
+ line_count++;
+ if(*raw == ',')
+ raw++;
+ }
+ *depends_count = line_count;
+ return depends;
+}
+
+void parseConffiles(pkg_t * pkg, char * raw)
+{
+ char file_name[1048], md5sum[1048]; /* please tell me there aren't any longer that 1k */
+
+ if(!strncmp(raw, "Conffiles:", 10))
+ raw += strlen("Conffiles:");
+
+ while(*raw && (sscanf(raw, "%s%s", file_name, md5sum) == 2)){
+ conffile_list_append(&pkg->conffiles, file_name, md5sum);
+ /* fprintf(stderr, "%s %s ", file_name, md5sum);*/
+ while (*raw && isspace(*raw)) {
+ raw++;
+ }
+ raw += strlen(file_name);
+ while (*raw && isspace(*raw)) {
+ raw++;
+ }
+ raw += strlen(md5sum);
+ }
+}
+
+int parseVersion(pkg_t *pkg, char *raw)
+{
+ char *colon, *eepochcolon;
+#ifdef USE_DEBVERSION
+ char *hyphen;
+#endif
+ unsigned long epoch;
+
+ if (!*raw) {
+ fprintf(stderr, "%s: ERROR: version string is empty", __FUNCTION__);
+ return EINVAL;
+ }
+
+ if (strncmp(raw, "Version:", 8) == 0) {
+ raw += 8;
+ }
+ while (*raw && isspace(*raw)) {
+ raw++;
+ }
+
+ colon= strchr(raw,':');
+ if (colon) {
+ epoch= strtoul(raw,&eepochcolon,10);
+ if (colon != eepochcolon) {
+ fprintf(stderr, "%s: ERROR: epoch in version is not number", __FUNCTION__);
+ return EINVAL;
+ }
+ if (!*++colon) {
+ fprintf(stderr, "%s: ERROR: nothing after colon in version number", __FUNCTION__);
+ return EINVAL;
+ }
+ raw= colon;
+ pkg->epoch= epoch;
+ } else {
+ pkg->epoch= 0;
+ }
+
+ pkg->revision = "";
+ pkg->familiar_revision = "";
+
+ pkg->version= malloc(strlen(raw)+1);
+ if ( pkg->version == NULL ) {
+ fprintf(stderr, "%s: out of memory \n", __FUNCTION__);
+ return ENOMEM;
+ }
+ strcpy(pkg->version, raw);
+
+#ifdef USE_DEBVERSION
+ hyphen= strrchr(pkg->version,'-');
+
+ if (hyphen) {
+ *hyphen++= 0;
+ if (strncmp("fam", hyphen, 3) == 0) {
+ pkg->familiar_revision=hyphen+3;
+ hyphen= strrchr(pkg->version,'-');
+ if (hyphen) {
+ *hyphen++= 0;
+ pkg->revision = hyphen;
+ }
+ } else {
+ pkg->revision = hyphen;
+ }
+ }
+#endif
+
+/*
+ fprintf(stderr,"Parsed version: %lu, %s, %s, %s\n",
+ pkg->epoch,
+ pkg->version,
+ pkg->revision,
+ pkg->familiar_revision);
+*/
+
+ return 0;
+}
+
+
+/* This code is needed to insert in first position the keyword for the aligning bug */
+
+int alterProvidesLine(char *raw, char *temp)
+{
+
+
+ if (!*raw) {
+ fprintf(stderr, "%s: ERROR: Provides string is empty", __FUNCTION__);
+ return -EINVAL;
+ }
+
+ if ( temp == NULL ) {
+ fprintf(stderr, "%s: out of memory \n", __FUNCTION__);
+ return -ENOMEM;
+ }
+
+ if (strncmp(raw, "Provides:", 9) == 0) {
+ raw += 9;
+ }
+ while (*raw && isspace(*raw)) {
+ raw++;
+ }
+
+ snprintf ( temp, 35, "Provides: ipkg_internal_use_only, "); /* First part of the line */
+ while (*raw) {
+ strncat( temp, raw++, 1);
+ }
+ return 0;
+
+}
+
+/* Some random thoughts from Carl:
+
+ This function could be considerably simplified if we just kept
+ an array of all the generic string-valued field names, and looped
+ through those looking for a match. Also, these fields could perhaps
+ be stored in the package as an array as well, (or, probably better,
+ as an nv_pair_list_t).
+
+ Fields which require special parsing or storage, (such as Depends:
+ and Status:) could be handled as they are now.
+*/
+/* XXX: FEATURE: The Suggests: field needs to be changed from a string
+ to a dependency list. And, since we already have
+ Depends/Pre-Depends and need to add Conflicts, Recommends, and
+ Enhances, perhaps we could generalize all of these and save some
+ code duplication.
+*/
+int pkg_parse_raw(pkg_t *pkg, char ***raw, pkg_src_t *src, pkg_dest_t *dest)
+{
+ int reading_conffiles, reading_description;
+ int pkg_false_provides=1;
+ char ** lines;
+ char * provide=NULL;
+
+ pkg->src = src;
+ pkg->dest = dest;
+
+ reading_conffiles = reading_description = 0;
+
+ for (lines = *raw; *lines; lines++) {
+ /* fprintf(stderr, "PARSING %s\n", *lines);*/
+ if(isGenericFieldType("Package:", *lines))
+ pkg->name = parseGenericFieldType("Package", *lines);
+ else if(isGenericFieldType("Architecture:", *lines))
+ pkg->architecture = parseGenericFieldType("Architecture", *lines);
+ else if(isGenericFieldType("Filename:", *lines))
+ pkg->filename = parseGenericFieldType("Filename", *lines);
+ else if(isGenericFieldType("Section:", *lines))
+ pkg->section = parseGenericFieldType("Section", *lines);
+ else if(isGenericFieldType("MD5sum:", *lines))
+ pkg->md5sum = parseGenericFieldType("MD5sum", *lines);
+ /* The old ipkg wrote out status files with the wrong case for MD5sum,
+ let's parse it either way */
+ else if(isGenericFieldType("MD5Sum:", *lines))
+ pkg->md5sum = parseGenericFieldType("MD5Sum", *lines);
+ else if(isGenericFieldType("Size:", *lines))
+ pkg->size = parseGenericFieldType("Size", *lines);
+ else if(isGenericFieldType("Source:", *lines))
+ pkg->source = parseGenericFieldType("Source", *lines);
+ else if(isGenericFieldType("Installed-Size:", *lines))
+ pkg->installed_size = parseGenericFieldType("Installed-Size", *lines);
+ else if(isGenericFieldType("Installed-Time:", *lines)) {
+ char *time_str = parseGenericFieldType("Installed-Time", *lines);
+ pkg->installed_time = strtoul(time_str, NULL, 0);
+ } else if(isGenericFieldType("Priority:", *lines))
+ pkg->priority = parseGenericFieldType("Priority", *lines);
+ else if(isGenericFieldType("Essential:", *lines)) {
+ char *essential_value;
+ essential_value = parseGenericFieldType("Essential", *lines);
+ if (strcmp(essential_value, "yes") == 0) {
+ pkg->essential = 1;
+ }
+ free(essential_value);
+ }
+ else if(isGenericFieldType("Status", *lines))
+ parseStatus(pkg, *lines);
+ else if(isGenericFieldType("Version", *lines))
+ parseVersion(pkg, *lines);
+ else if(isGenericFieldType("Maintainer", *lines))
+ pkg->maintainer = parseGenericFieldType("Maintainer", *lines);
+ else if(isGenericFieldType("Conffiles", *lines)){
+ parseConffiles(pkg, *lines);
+ reading_conffiles = 1;
+ }
+ else if(isGenericFieldType("Description", *lines)) {
+ pkg->description = parseGenericFieldType("Description", *lines);
+ reading_conffiles = 0;
+ reading_description = 1;
+ }
+
+ else if(isGenericFieldType("Provides", *lines)){
+/* Here we add the internal_use to align the off by one problem between provides_str and provides */
+ provide = (char * ) malloc(strlen(*lines)+ 35 ); /* Preparing the space for the new ipkg_internal_use_only */
+ if ( alterProvidesLine(*lines,provide) ){
+ return EINVAL;
+ }
+ pkg->provides_str = parseDependsString( provide, &pkg->provides_count);
+/* Let's try to hack a bit here.
+ The idea is that if a package has no Provides, we would add one generic, to permit the check of dependencies
+ in alot of other places. We will remove it before writing down the status database */
+ pkg_false_provides=0;
+ free(provide);
+ }
+
+ else if(isGenericFieldType("Depends", *lines))
+ pkg->depends_str = parseDependsString(*lines, &pkg->depends_count);
+ else if(isGenericFieldType("Pre-Depends", *lines))
+ pkg->pre_depends_str = parseDependsString(*lines, &pkg->pre_depends_count);
+ else if(isGenericFieldType("Recommends", *lines))
+ pkg->recommends_str = parseDependsString(*lines, &pkg->recommends_count);
+ else if(isGenericFieldType("Suggests", *lines))
+ pkg->suggests_str = parseDependsString(*lines, &pkg->suggests_count);
+ /* Abhaya: support for conflicts */
+ else if(isGenericFieldType("Conflicts", *lines))
+ pkg->conflicts_str = parseDependsString(*lines, &pkg->conflicts_count);
+ else if(isGenericFieldType("Replaces", *lines))
+ pkg->replaces_str = parseDependsString(*lines, &pkg->replaces_count);
+ else if(line_is_blank(*lines)) {
+ lines++;
+ break;
+ }
+ else if(**lines == ' '){
+ if(reading_description) {
+ /* we already know it's not blank, so the rest of description */
+ pkg->description = realloc(pkg->description,
+ strlen(pkg->description)
+ + 1 + strlen(*lines) + 1);
+ strcat(pkg->description, "\n");
+ strcat(pkg->description, (*lines));
+ }
+ else if(reading_conffiles)
+ parseConffiles(pkg, *lines);
+ }
+ }
+ *raw = lines;
+/* If the ipk has not a Provides line, we insert our false line */
+ if ( pkg_false_provides==1)
+ pkg->provides_str = parseDependsString ((char *)"Provides: ipkg_internal_use_only ", &pkg->provides_count);
+
+ if (pkg->name) {
+ return 0;
+ } else {
+ return EINVAL;
+ }
+}
+
+int pkg_valorize_other_field(pkg_t *pkg, char ***raw)
+{
+ char ** lines;
+
+ for (lines = *raw; *lines; lines++) {
+ if(isGenericFieldType("Essential:", *lines)) {
+ char *essential_value;
+ essential_value = parseGenericFieldType("Essential", *lines);
+ if (strcmp(essential_value, "yes") == 0) {
+ pkg->essential = 1;
+ }
+ free(essential_value);
+ }
+ }
+ *raw = lines;
+
+ return 0;
+}
diff -ruN busybox-1.00-orig/archival/libipkg/pkg_parse.h busybox-1.00+ipkg-0.99.154/archival/libipkg/pkg_parse.h
--- busybox-1.00-orig/archival/libipkg/pkg_parse.h 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/pkg_parse.h 2005-10-26 17:36:46.000000000 +0200
@@ -0,0 +1,31 @@
+/* pkg_parse.h - the itsy package management system
+
+ Steven M. Ayer
+
+ Copyright (C) 2002 Compaq Computer Corporation
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#ifndef PKG_PARSE_H
+#define PKG_PARSE_H
+
+int isGenericFieldType(char * type, char * line);
+char * parseGenericFieldType(char * type, char * raw);
+void parseStatus(pkg_t *pkg, char * raw);
+int parseVersion(pkg_t *pkg, char *raw);
+char ** parseDependsString(char * raw, int * depends_count);
+int parseVersion(pkg_t *pkg, char *raw);
+void parseConffiles(pkg_t * pkg, char * raw);
+int pkg_parse_raw(pkg_t *pkg, char ***raw, pkg_src_t *src, pkg_dest_t *dest);
+int pkg_valorize_other_field(pkg_t *pkg, char ***raw);
+
+#endif
diff -ruN busybox-1.00-orig/archival/libipkg/pkg_src.c busybox-1.00+ipkg-0.99.154/archival/libipkg/pkg_src.c
--- busybox-1.00-orig/archival/libipkg/pkg_src.c 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/pkg_src.c 2005-10-26 17:36:46.000000000 +0200
@@ -0,0 +1,43 @@
+/* pkg_src.c - the itsy package management system
+
+ Carl D. Worth
+
+ Copyright (C) 2001 University of Southern California
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#include "ipkg.h"
+
+#include "pkg_src.h"
+#include "str_util.h"
+
+int pkg_src_init(pkg_src_t *src, const char *name, const char *base_url, const char *extra_data, int gzip)
+{
+ src->gzip = gzip;
+ src->name = str_dup_safe (name);
+ src->value = str_dup_safe (base_url);
+ if (extra_data)
+ src->extra_data = str_dup_safe (extra_data);
+ else
+ src->extra_data = NULL;
+ return 0;
+}
+
+void pkg_src_deinit(pkg_src_t *src)
+{
+ free (src->name);
+ free (src->value);
+ if (src->extra_data)
+ free (src->extra_data);
+}
+
+
diff -ruN busybox-1.00-orig/archival/libipkg/pkg_src.h busybox-1.00+ipkg-0.99.154/archival/libipkg/pkg_src.h
--- busybox-1.00-orig/archival/libipkg/pkg_src.h 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/pkg_src.h 2005-10-26 17:36:46.000000000 +0200
@@ -0,0 +1,34 @@
+/* pkg_src.h - the itsy package management system
+
+ Carl D. Worth
+
+ Copyright (C) 2001 University of Southern California
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#ifndef PKG_SRC_H
+#define PKG_SRC_H
+
+#include "nv_pair.h"
+
+typedef struct
+{
+ char *name;
+ char *value;
+ char *extra_data;
+ int gzip;
+} pkg_src_t;
+
+int pkg_src_init(pkg_src_t *src, const char *name, const char *base_url, const char *extra_data, int gzip);
+void pkg_src_deinit(pkg_src_t *src);
+
+#endif
diff -ruN busybox-1.00-orig/archival/libipkg/pkg_src_list.c busybox-1.00+ipkg-0.99.154/archival/libipkg/pkg_src_list.c
--- busybox-1.00-orig/archival/libipkg/pkg_src_list.c 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/pkg_src_list.c 2005-10-26 17:36:46.000000000 +0200
@@ -0,0 +1,75 @@
+/* pkg_src_list.c - the itsy package management system
+
+ Carl D. Worth
+
+ Copyright (C) 2001 University of Southern California
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#include "ipkg.h"
+
+#include "pkg_src_list.h"
+#include "void_list.h"
+
+int pkg_src_list_init(pkg_src_list_t *list)
+{
+ return void_list_init((void_list_t *) list);
+}
+
+void pkg_src_list_deinit(pkg_src_list_t *list)
+{
+ pkg_src_list_elt_t *iter;
+ pkg_src_t *pkg_src;
+
+ for (iter = list->head; iter; iter = iter->next) {
+ pkg_src = iter->data;
+ pkg_src_deinit(pkg_src);
+
+ /* malloced in pkg_src_list_append */
+ free(pkg_src);
+ iter->data = NULL;
+ }
+ void_list_deinit((void_list_t *) list);
+}
+
+pkg_src_t *pkg_src_list_append(pkg_src_list_t *list,
+ const char *name, const char *base_url, const char *extra_data,
+ int gzip)
+{
+ int err;
+
+ /* freed in pkg_src_list_deinit */
+ pkg_src_t *pkg_src = malloc(sizeof(pkg_src_t));
+
+ if (pkg_src == NULL) {
+ fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
+ return NULL;
+ }
+ pkg_src_init(pkg_src, name, base_url, extra_data, gzip);
+
+ err = void_list_append((void_list_t *) list, pkg_src);
+ if (err) {
+ return NULL;
+ }
+
+ return pkg_src;
+}
+
+int pkg_src_list_push(pkg_src_list_t *list, pkg_src_t *data)
+{
+ return void_list_push((void_list_t *) list, data);
+}
+
+pkg_src_list_elt_t *pkg_src_list_pop(pkg_src_list_t *list)
+{
+ return (pkg_src_list_elt_t *) void_list_pop((void_list_t *) list);
+}
diff -ruN busybox-1.00-orig/archival/libipkg/pkg_src_list.h busybox-1.00+ipkg-0.99.154/archival/libipkg/pkg_src_list.h
--- busybox-1.00-orig/archival/libipkg/pkg_src_list.h 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/pkg_src_list.h 2005-10-26 17:36:46.000000000 +0200
@@ -0,0 +1,57 @@
+/* pkg_src_list.h - the itsy package management system
+
+ Carl D. Worth
+
+ Copyright (C) 2001 University of Southern California
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#ifndef PKG_SRC_LIST_H
+#define PKG_SRC_LIST_H
+
+#include "pkg_src.h"
+
+typedef struct pkg_src_list_elt pkg_src_list_elt_t;
+struct pkg_src_list_elt
+{
+ pkg_src_list_elt_t *next;
+ pkg_src_t *data;
+};
+
+typedef struct pkg_src_list pkg_src_list_t;
+struct pkg_src_list
+{
+ pkg_src_list_elt_t pre_head;
+ pkg_src_list_elt_t *head;
+ pkg_src_list_elt_t *tail;
+};
+
+static inline int pkg_src_list_empty(pkg_src_list_t *list)
+{
+ if (list->head == NULL)
+ return 1;
+ else
+ return 0;
+}
+
+int pkg_src_list_elt_init(pkg_src_list_elt_t *elt, nv_pair_t *data);
+void pkg_src_list_elt_deinit(pkg_src_list_elt_t *elt);
+
+int pkg_src_list_init(pkg_src_list_t *list);
+void pkg_src_list_deinit(pkg_src_list_t *list);
+
+pkg_src_t *pkg_src_list_append(pkg_src_list_t *list, const char *name, const char *root_dir, const char *extra_data, int gzip);
+int pkg_src_list_push(pkg_src_list_t *list, pkg_src_t *data);
+pkg_src_list_elt_t *pkg_src_list_pop(pkg_src_list_t *list);
+
+#endif
+
diff -ruN busybox-1.00-orig/archival/libipkg/pkg_vec.c busybox-1.00+ipkg-0.99.154/archival/libipkg/pkg_vec.c
--- busybox-1.00-orig/archival/libipkg/pkg_vec.c 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/pkg_vec.c 2005-10-26 17:36:46.000000000 +0200
@@ -0,0 +1,226 @@
+/* pkg_vec.c - the itsy package management system
+
+ Steven M. Ayer
+
+ Copyright (C) 2002 Compaq Computer Corporation
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#include <stdlib.h>
+#include <fnmatch.h>
+#include "xregex.h"
+#include "ipkg.h"
+#include "pkg.h"
+
+pkg_vec_t * pkg_vec_alloc(void)
+{
+ pkg_vec_t * vec = (pkg_vec_t *)malloc(sizeof(pkg_vec_t));
+ if (!vec) {
+ fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
+ return NULL;
+ }
+ vec->pkgs = NULL;
+ vec->len = 0;
+
+ return vec;
+}
+
+void pkg_vec_free(pkg_vec_t *vec)
+{
+ free(vec->pkgs);
+ free(vec);
+}
+
+/*
+ * assumption: all names in a vector are identical
+ * assumption: all version strings are trimmed,
+ * so identical versions have identical version strings,
+ * implying identical packages; let's marry these
+ */
+pkg_t *pkg_vec_insert_merge(pkg_vec_t *vec, pkg_t *pkg, int set_status,ipkg_conf_t *conf)
+{
+ int i;
+ int found = 0;
+
+ /* look for a duplicate pkg by name, version, and architecture */
+ for (i = 0; i < vec->len; i++)
+ if ((strcmp(pkg->name, vec->pkgs[i]->name) == 0)
+ && (pkg_compare_versions(pkg, vec->pkgs[i]) == 0)
+ && (strcmp(pkg->architecture, vec->pkgs[i]->architecture) == 0)) {
+ found = 1;
+ ipkg_message(conf, IPKG_DEBUG2, "Function: %s. Found duplicate for pkg=%s version=%s arch=%s\n",
+ __FUNCTION__, pkg->name, pkg->version, pkg->architecture);
+ break;
+ }
+
+ /* we didn't find one, add it */
+ if (!found){
+ ipkg_message(conf, IPKG_DEBUG2, "Function: %s. Adding new pkg=%s version=%s arch=%s\n",
+ __FUNCTION__, pkg->name, pkg->version, pkg->architecture);
+
+ vec->pkgs = (pkg_t **)realloc(vec->pkgs, (vec->len + 1) * sizeof(pkg_t *));
+ vec->pkgs[vec->len] = pkg;
+ vec->len++;
+ return pkg;
+ }
+ /* update the one that we have */
+ else {
+ ipkg_message(conf, IPKG_DEBUG2, "Function: %s. calling pkg_merge for pkg=%s version=%s arch=%s",
+ __FUNCTION__, pkg->name, pkg->version, pkg->architecture);
+ if (set_status) {
+ /* this is from the status file, so need to merge with existing database */
+ ipkg_message(conf, IPKG_DEBUG2, " with set_status\n");
+ pkg_merge(vec->pkgs[i], pkg, set_status);
+ /* XXX: CLEANUP: It's not so polite to free something here
+ that was passed in from above. */
+ pkg_deinit(pkg);
+ free(pkg);
+ } else {
+ ipkg_message(conf, IPKG_DEBUG2, " WITHOUT set_status\n");
+ /* just overwrite the old one */
+ pkg_deinit(vec->pkgs[i]);
+ free(vec->pkgs[i]);
+ vec->pkgs[i] = pkg;
+ }
+ return vec->pkgs[i];
+ }
+}
+
+void pkg_vec_insert(pkg_vec_t *vec, const pkg_t *pkg)
+{
+ int i;
+ int found = 0;
+
+ /* look for a duplicate pkg by name, version, and architecture */
+ for (i = 0; i < vec->len; i++)
+ if ((strcmp(pkg->name, vec->pkgs[i]->name) == 0)
+ && (pkg_compare_versions(pkg, vec->pkgs[i]) == 0)
+ && (strcmp(pkg->architecture, vec->pkgs[i]->name) == 0)) {
+ found = 1;
+ break;
+ }
+
+ /* we didn't find one, add it */
+ if(!found){
+ vec->pkgs = (pkg_t **)realloc(vec->pkgs, (vec->len + 1) * sizeof(pkg_t *));
+ *(const pkg_t **)&vec->pkgs[vec->len] = pkg;
+ vec->len++;
+ }
+}
+
+int pkg_vec_contains(pkg_vec_t *vec, pkg_t *apkg)
+{
+ int i;
+ for (i = 0; i < vec->len; i++)
+ if (vec->pkgs[i] == apkg)
+ return 1;
+ return 0;
+}
+
+typedef int (*compare_fcn_t)(const void *, const void *);
+void pkg_vec_sort(pkg_vec_t *vec, int (*compar)(pkg_t *, pkg_t *))
+{
+ qsort(vec->pkgs, vec->len, sizeof(pkg_t *), (compare_fcn_t)compar);
+}
+
+int pkg_vec_clear_marks(pkg_vec_t *vec)
+{
+ int npkgs = vec->len;
+ int i;
+ for (i = 0; i < npkgs; i++) {
+ pkg_t *pkg = vec->pkgs[i];
+ pkg->state_flag &= ~SF_MARKED;
+ }
+ return 0;
+}
+
+int pkg_vec_mark_if_matches(pkg_vec_t *vec, const char *pattern)
+{
+ int matching_count = 0;
+ pkg_t **pkgs = vec->pkgs;
+ int npkgs = vec->len;
+ int i;
+ for (i = 0; i < npkgs; i++) {
+ pkg_t *pkg = pkgs[i];
+ if (fnmatch(pattern, pkg->name, 0)==0) {
+ pkg->state_flag |= SF_MARKED;
+ matching_count++;
+ }
+ }
+ return matching_count;
+}
+
+
+abstract_pkg_vec_t * abstract_pkg_vec_alloc(void)
+{
+ abstract_pkg_vec_t * vec ;
+ vec = (abstract_pkg_vec_t *)malloc(sizeof(abstract_pkg_vec_t));
+ if (!vec) {
+ fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
+ return NULL;
+ }
+ vec->pkgs = NULL;
+ vec->len = 0;
+
+ return vec;
+}
+
+void abstract_pkg_vec_free(abstract_pkg_vec_t *vec)
+{
+ free(vec->pkgs);
+ free(vec);
+}
+
+/*
+ * assumption: all names in a vector are unique
+ */
+void abstract_pkg_vec_insert(abstract_pkg_vec_t *vec, abstract_pkg_t *pkg)
+{
+ int i;
+
+ /* look for a duplicate pkg by name */
+ for(i = 0; i < vec->len; i++)
+ if (strcmp(pkg->name, vec->pkgs[i]->name) == 0)
+ break;
+
+ /* we didn't find one, add it */
+ if(i == vec->len){
+ vec->pkgs =
+ (abstract_pkg_t **)
+ realloc(vec->pkgs, (vec->len + 1) * sizeof(abstract_pkg_t *));
+ vec->pkgs[vec->len] = pkg;
+ vec->len++;
+ }
+}
+
+abstract_pkg_t * abstract_pkg_vec_get(abstract_pkg_vec_t *vec, int i)
+{
+ if (vec->len > i)
+ return vec->pkgs[i];
+ else
+ return NULL;
+}
+
+int abstract_pkg_vec_contains(abstract_pkg_vec_t *vec, abstract_pkg_t *apkg)
+{
+ int i;
+ for (i = 0; i < vec->len; i++)
+ if (vec->pkgs[i] == apkg)
+ return 1;
+ return 0;
+}
+
+void abstract_pkg_vec_sort(pkg_vec_t *vec, int (*compar)(abstract_pkg_t *, abstract_pkg_t *))
+{
+ qsort(vec->pkgs, vec->len, sizeof(pkg_t *), (compare_fcn_t)compar);
+}
+
diff -ruN busybox-1.00-orig/archival/libipkg/pkg_vec.h busybox-1.00+ipkg-0.99.154/archival/libipkg/pkg_vec.h
--- busybox-1.00-orig/archival/libipkg/pkg_vec.h 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/pkg_vec.h 2005-10-26 17:36:46.000000000 +0200
@@ -0,0 +1,62 @@
+/* pkg_vec.h - the itsy package management system
+
+ Steven M. Ayer
+
+ Copyright (C) 2002 Compaq Computer Corporation
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#ifndef PKG_VEC_H
+#define PKG_VEC_H
+
+typedef struct pkg pkg_t;
+typedef struct abstract_pkg abstract_pkg_t;
+
+struct pkg_vec
+{
+ pkg_t **pkgs;
+ int len;
+};
+typedef struct pkg_vec pkg_vec_t;
+
+struct abstract_pkg_vec
+{
+ abstract_pkg_t **pkgs;
+ int len;
+};
+typedef struct abstract_pkg_vec abstract_pkg_vec_t;
+
+
+pkg_vec_t * pkg_vec_alloc(void);
+void pkg_vec_free(pkg_vec_t *vec);
+void marry_two_packages(pkg_t * newpkg, pkg_t * oldpkg);
+
+void pkg_vec_add(pkg_vec_t *vec, pkg_t *pkg);
+/* pkg_vec_insert_merge: might munge pkg.
+* returns the pkg that is in the pkg graph */
+pkg_t *pkg_vec_insert_merge(pkg_vec_t *vec, pkg_t *pkg, int set_status, ipkg_conf_t *conf);
+/* this one never munges pkg */
+void pkg_vec_insert(pkg_vec_t *vec, const pkg_t *pkg);
+int pkg_vec_contains(pkg_vec_t *vec, pkg_t *apkg);
+void pkg_vec_sort(pkg_vec_t *vec, int (*compar)(pkg_t *, pkg_t *));
+
+int pkg_vec_clear_marks(pkg_vec_t *vec);
+int pkg_vec_mark_if_matches(pkg_vec_t *vec, const char *pattern);
+
+abstract_pkg_vec_t * abstract_pkg_vec_alloc(void);
+void abstract_pkg_vec_free(abstract_pkg_vec_t *vec);
+void abstract_pkg_vec_insert(abstract_pkg_vec_t *vec, abstract_pkg_t *pkg);
+abstract_pkg_t * abstract_pkg_vec_get(abstract_pkg_vec_t *vec, int i);
+int abstract_pkg_vec_contains(abstract_pkg_vec_t *vec, abstract_pkg_t *apkg);
+void abstract_pkg_vec_sort(pkg_vec_t *vec, int (*compar)(abstract_pkg_t *, abstract_pkg_t *));
+#endif
+
diff -ruN busybox-1.00-orig/archival/libipkg/sprintf_alloc.h busybox-1.00+ipkg-0.99.154/archival/libipkg/sprintf_alloc.h
--- busybox-1.00-orig/archival/libipkg/sprintf_alloc.h 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/sprintf_alloc.h 2005-10-26 17:36:46.000000000 +0200
@@ -0,0 +1,25 @@
+/* sprintf_alloca.c -- like sprintf with memory allocation
+
+ Carl D. Worth
+
+ Copyright (C) 2001 University of Southern California
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+*/
+
+#ifndef SPRINTF_ALLOC_H
+#define SPRINTF_ALLOC_H
+
+#include "libbb.h"
+
+#define sprintf_alloc bb_xasprintf
+
+#endif
diff -ruN busybox-1.00-orig/archival/libipkg/str_list.c busybox-1.00+ipkg-0.99.154/archival/libipkg/str_list.c
--- busybox-1.00-orig/archival/libipkg/str_list.c 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/str_list.c 2005-10-26 17:36:46.000000000 +0200
@@ -0,0 +1,76 @@
+/* str_list.c - the itsy package management system
+
+ Carl D. Worth
+
+ Copyright (C) 2001 University of Southern California
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#include "ipkg.h"
+
+#include "str_list.h"
+
+int str_list_elt_init(str_list_elt_t *elt, char *data)
+{
+ return void_list_elt_init((void_list_elt_t *) elt, data);
+}
+
+void str_list_elt_deinit(str_list_elt_t *elt)
+{
+ void_list_elt_deinit((void_list_elt_t *) elt);
+}
+
+str_list_t *str_list_alloc()
+{
+ str_list_t *list = (str_list_t *)malloc(sizeof(str_list_t));
+ if (list)
+ str_list_init(list);
+ return list;
+}
+
+int str_list_init(str_list_t *list)
+{
+ return void_list_init((void_list_t *) list);
+}
+
+void str_list_deinit(str_list_t *list)
+{
+ void_list_deinit((void_list_t *) list);
+}
+
+int str_list_append(str_list_t *list, char *data)
+{
+ return void_list_append((void_list_t *) list, data);
+}
+
+int str_list_push(str_list_t *list, char *data)
+{
+ return void_list_push((void_list_t *) list, data);
+}
+
+str_list_elt_t *str_list_pop(str_list_t *list)
+{
+ return (str_list_elt_t *) void_list_pop((void_list_t *) list);
+}
+
+str_list_elt_t *str_list_remove(str_list_t *list, str_list_elt_t **iter)
+{
+ return (str_list_elt_t *) void_list_remove((void_list_t *) list,
+ (void_list_elt_t **) iter);
+}
+
+char *str_list_remove_elt(str_list_t *list, const char *target_str)
+{
+ return (char *)void_list_remove_elt((void_list_t *) list,
+ (void *)target_str,
+ (void_list_cmp_t)strcmp);
+}
diff -ruN busybox-1.00-orig/archival/libipkg/str_list.h busybox-1.00+ipkg-0.99.154/archival/libipkg/str_list.h
--- busybox-1.00-orig/archival/libipkg/str_list.h 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/str_list.h 2005-10-26 17:36:46.000000000 +0200
@@ -0,0 +1,51 @@
+/* str_list.h - the itsy package management system
+
+ Carl D. Worth
+
+ Copyright (C) 2001 University of Southern California
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#ifndef STR_LIST_H
+#define STR_LIST_H
+
+#include "void_list.h"
+
+typedef struct str_list_elt str_list_elt_t;
+struct str_list_elt
+{
+ str_list_elt_t *next;
+ char *data;
+};
+
+typedef struct xstr_list str_list_t;
+struct xstr_list
+{
+ str_list_elt_t pre_head;
+ str_list_elt_t *head;
+ str_list_elt_t *tail;
+};
+
+int str_list_elt_init(str_list_elt_t *elt, char *data);
+void str_list_elt_deinit(str_list_elt_t *elt);
+
+str_list_t *str_list_alloc(void);
+int str_list_init(str_list_t *list);
+void str_list_deinit(str_list_t *list);
+
+int str_list_append(str_list_t *list, char *data);
+int str_list_push(str_list_t *list, char *data);
+str_list_elt_t *str_list_pop(str_list_t *list);
+str_list_elt_t *str_list_remove(str_list_t *list, str_list_elt_t **iter);
+char *str_list_remove_elt(str_list_t *list, const char *target_str);
+
+#endif
diff -ruN busybox-1.00-orig/archival/libipkg/str_util.c busybox-1.00+ipkg-0.99.154/archival/libipkg/str_util.c
--- busybox-1.00-orig/archival/libipkg/str_util.c 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/str_util.c 2005-10-26 17:36:46.000000000 +0200
@@ -0,0 +1,73 @@
+/* str_utils.c - the itsy package management system
+
+ Carl D. Worth
+
+ Copyright (C) 2001 University of Southern California
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#include "ipkg.h"
+
+int str_starts_with(const char *str, const char *prefix)
+{
+ return (strncmp(str, prefix, strlen(prefix)) == 0);
+}
+
+int str_ends_with(const char *str, const char *suffix)
+{
+ int suffix_len;
+ int str_len;
+
+ str_len = strlen(str);
+ suffix_len = strlen(suffix);
+
+ if (str_len < suffix_len) {
+ return 0;
+ }
+
+ return (strcmp(str + str_len - suffix_len, suffix) == 0);
+}
+
+int str_chomp(char *str)
+{
+ if (str[strlen(str) - 1] == '\n') {
+ str[strlen(str) - 1] = '\0';
+ return 1;
+ }
+ return 0;
+}
+
+int str_tolower(char *str)
+{
+ while (*str) {
+ *str = tolower(*str);
+ str++;
+ }
+
+ return 0;
+}
+
+int str_toupper(char *str)
+{
+ while (*str) {
+ *str = toupper(*str);
+ str++;
+ }
+
+ return 0;
+}
+
+char *str_dup_safe(const char *str)
+{
+ return str ? strdup(str) : NULL;
+}
+
diff -ruN busybox-1.00-orig/archival/libipkg/str_util.h busybox-1.00+ipkg-0.99.154/archival/libipkg/str_util.h
--- busybox-1.00-orig/archival/libipkg/str_util.h 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/str_util.h 2005-10-26 17:36:46.000000000 +0200
@@ -0,0 +1,28 @@
+/* str_utils.h - the itsy package management system
+
+ Carl D. Worth
+
+ Copyright (C) 2001 University of Southern California
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#ifndef STR_UTILS_H
+#define STR_UTILS_H
+
+int str_starts_with(const char *str, const char *prefix);
+int str_ends_with(const char *str, const char *suffix);
+int str_chomp(char *str);
+int str_tolower(char *str);
+int str_toupper(char *str);
+char *str_dup_safe(const char *str);
+
+#endif
diff -ruN busybox-1.00-orig/archival/libipkg/user.c busybox-1.00+ipkg-0.99.154/archival/libipkg/user.c
--- busybox-1.00-orig/archival/libipkg/user.c 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/user.c 2005-10-26 17:36:46.000000000 +0200
@@ -0,0 +1,58 @@
+/* user.c - the itsy package management system
+
+ Jamey Hicks
+
+ Copyright (C) 2002 Hewlett Packard Company
+ Copyright (C) 2001 University of Southern California
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#include <stdio.h>
+#include <stdarg.h>
+#include "file_util.h"
+#include "str_util.h"
+#ifdef IPKG_LIB
+#include "libipkg.h"
+#endif
+
+
+#ifdef IPKG_LIB
+static char *question = NULL;
+static int question_len = 255;
+#endif
+char *get_user_response(const char *format, ...)
+{
+ int len = question_len;
+ va_list ap;
+ char *response;
+ va_start(ap, format);
+
+#ifndef IPKG_LIB
+ vprintf(format, ap);
+ do {
+ response = file_read_line_alloc(stdin);
+ } while (response == NULL);
+#else
+ do {
+ if (question == NULL || len > question_len) {
+ question = realloc(question, len + 1);
+ question_len = len;
+ }
+ len = vsnprintf(question,question_len,format,ap);
+ } while (len > question_len);
+ response = strdup(ipkg_cb_response(question));
+#endif
+ str_chomp(response);
+ str_tolower(response);
+
+ return response;
+}
diff -ruN busybox-1.00-orig/archival/libipkg/user.h busybox-1.00+ipkg-0.99.154/archival/libipkg/user.h
--- busybox-1.00-orig/archival/libipkg/user.h 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/user.h 2005-10-26 17:36:46.000000000 +0200
@@ -0,0 +1,23 @@
+/* user.c - the itsy package management system
+
+ Jamey Hicks
+
+ Copyright (C) 2002 Hewlett Packard Company
+ Copyright (C) 2001 University of Southern California
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#include <stdio.h>
+#include <stdarg.h>
+
+char *get_user_response(const char *format, ...);
+
diff -ruN busybox-1.00-orig/archival/libipkg/void_list.c busybox-1.00+ipkg-0.99.154/archival/libipkg/void_list.c
--- busybox-1.00-orig/archival/libipkg/void_list.c 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/void_list.c 2005-10-26 17:36:46.000000000 +0200
@@ -0,0 +1,194 @@
+/* void_list.c - the itsy package management system
+
+ Carl D. Worth
+
+ Copyright (C) 2001 University of Southern California
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#include "ipkg.h"
+#include <errno.h>
+
+#include "void_list.h"
+
+int void_list_elt_init(void_list_elt_t *elt, void *data)
+{
+ elt->next = NULL;
+ elt->data = data;
+
+ return 0;
+}
+
+void void_list_elt_deinit(void_list_elt_t *elt)
+{
+ void_list_elt_init(elt, NULL);
+}
+
+int void_list_init(void_list_t *list)
+{
+ void_list_elt_init(&list->pre_head, NULL);
+ list->head = NULL;
+ list->pre_head.next = list->head;
+ list->tail = NULL;
+
+ return 0;
+}
+
+void void_list_deinit(void_list_t *list)
+{
+ void_list_elt_t *elt;
+
+ while (list->head) {
+ elt = void_list_pop(list);
+ void_list_elt_deinit(elt);
+ /* malloced in void_list_append */
+ free(elt);
+ }
+}
+
+int void_list_append(void_list_t *list, void *data)
+{
+ void_list_elt_t *elt;
+
+ /* freed in void_list_deinit */
+ elt = malloc(sizeof(void_list_elt_t));
+ if (elt == NULL) {
+ fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
+ return ENOMEM;
+ }
+
+ void_list_elt_init(elt, data);
+
+ if (list->tail) {
+ list->tail->next = elt;
+ list->tail = elt;
+ } else {
+ list->head = elt;
+ list->pre_head.next = list->head;
+ list->tail = elt;
+ }
+
+ return 0;
+}
+
+int void_list_push(void_list_t *list, void *data)
+{
+ void_list_elt_t *elt;
+
+ elt = malloc(sizeof(void_list_elt_t));
+ if (elt == NULL) {
+ fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
+ return ENOMEM;
+ }
+
+ void_list_elt_init(elt, data);
+
+ elt->next = list->head;
+ list->head->next = elt;
+ if (list->tail == NULL) {
+ list->tail = list->head;
+ }
+
+ return 0;
+}
+
+void_list_elt_t *void_list_pop(void_list_t *list)
+{
+ void_list_elt_t *elt;
+
+ elt = list->head;
+
+ if (list->head) {
+ list->head = list->head->next;
+ list->pre_head.next = list->head;
+ if (list->head == NULL) {
+ list->tail = NULL;
+ }
+ }
+
+ return elt;
+}
+
+void *void_list_remove(void_list_t *list, void_list_elt_t **iter)
+{
+ void_list_elt_t *prior;
+ void_list_elt_t *old_elt;
+ void *old_data;
+
+ old_elt = *iter;
+ old_data = old_elt->data;
+
+ if (old_elt == list->head) {
+ prior = &list->pre_head;
+ void_list_pop(list);
+ } else {
+ for (prior = list->head; prior; prior = prior->next) {
+ if (prior->next == old_elt) {
+ break;
+ }
+ }
+ if (prior == NULL || prior->next != old_elt) {
+ fprintf(stderr, "%s: ERROR: element not found in list\n", __FUNCTION__);
+ return NULL;
+ }
+ prior->next = old_elt->next;
+
+ if (old_elt == list->tail) {
+ list->tail = prior;
+ }
+ }
+
+ void_list_elt_deinit(old_elt);
+ *iter = prior;
+
+ return old_data;
+}
+
+/* remove element containing elt data, using cmp(elt->data, target_data) == 0. */
+void *void_list_remove_elt(void_list_t *list, const void *target_data, void_list_cmp_t cmp)
+{
+ void_list_elt_t *prior;
+ void_list_elt_t *old_elt = NULL;
+ void *old_data = NULL;
+
+ /* first element */
+ if (list->head && list->head->data && (cmp(list->head->data, target_data) == 0)) {
+ old_elt = list->head;
+ old_data = list->head->data;
+ void_list_pop(list);
+ } else {
+ int found = 0;
+ for (prior = list->head; prior && prior->next; prior = prior->next) {
+ if (prior->next->data && (cmp(prior->next->data, target_data) == 0)) {
+ old_elt = prior->next;
+ old_data = old_elt->data;
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ return NULL;
+ }
+ prior->next = old_elt->next;
+
+ if (old_elt == list->tail) {
+ list->tail = prior;
+ }
+ }
+ if (old_elt)
+ void_list_elt_deinit(old_elt);
+
+ if (old_data)
+ return old_data;
+ else
+ return NULL;
+}
diff -ruN busybox-1.00-orig/archival/libipkg/void_list.h busybox-1.00+ipkg-0.99.154/archival/libipkg/void_list.h
--- busybox-1.00-orig/archival/libipkg/void_list.h 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/void_list.h 2005-10-26 17:36:46.000000000 +0200
@@ -0,0 +1,59 @@
+/* void_list.h - the itsy package management system
+
+ Carl D. Worth
+
+ Copyright (C) 2001 University of Southern California
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#ifndef VOID_LIST_H
+#define VOID_LIST_H
+
+typedef struct void_list_elt void_list_elt_t;
+struct void_list_elt
+{
+ void_list_elt_t *next;
+ void *data;
+};
+
+typedef struct void_list void_list_t;
+struct void_list
+{
+ void_list_elt_t pre_head;
+ void_list_elt_t *head;
+ void_list_elt_t *tail;
+};
+
+static inline int void_list_empty(void_list_t *list)
+{
+ if (list->head == NULL)
+ return 1;
+ else
+ return 0;
+}
+
+int void_list_elt_init(void_list_elt_t *elt, void *data);
+void void_list_elt_deinit(void_list_elt_t *elt);
+
+int void_list_init(void_list_t *list);
+void void_list_deinit(void_list_t *list);
+
+int void_list_append(void_list_t *list, void *data);
+int void_list_push(void_list_t *list, void *data);
+void_list_elt_t *void_list_pop(void_list_t *list);
+
+void *void_list_remove(void_list_t *list, void_list_elt_t **iter);
+/* remove element containing elt data, using cmp(elt->data, target_data) == 0. */
+typedef int (*void_list_cmp_t)(const void *, const void *);
+void *void_list_remove_elt(void_list_t *list, const void *target_data, void_list_cmp_t cmp);
+
+#endif
diff -ruN busybox-1.00-orig/archival/libipkg/xregex.h busybox-1.00+ipkg-0.99.154/archival/libipkg/xregex.h
--- busybox-1.00-orig/archival/libipkg/xregex.h 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/xregex.h 2005-10-26 17:36:46.000000000 +0200
@@ -0,0 +1,29 @@
+/* xregex.h - regex functions with error messages
+
+ Carl D. Worth
+
+ Copyright (C) 2001 University of Southern California
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+*/
+
+#ifndef XREGEX_H
+#define XREGEX_H
+
+#include "libbb.h"
+
+static inline void xregfree(regex_t *preg)
+{
+ regfree(preg);
+}
+
+
+#endif
diff -ruN busybox-1.00-orig/archival/libipkg/xsystem.c busybox-1.00+ipkg-0.99.154/archival/libipkg/xsystem.c
--- busybox-1.00-orig/archival/libipkg/xsystem.c 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/xsystem.c 2005-10-26 17:36:46.000000000 +0200
@@ -0,0 +1,64 @@
+/* xsystem.c - system(3) with error messages
+
+ Carl D. Worth
+
+ Copyright (C) 2001 University of Southern California
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#include "ipkg.h"
+#include <sys/wait.h>
+
+#include "xsystem.h"
+
+/* XXX: FEATURE: I shouldn't actually use system(3) at all. I don't
+ really need the /bin/sh invocation which takes resources and
+ introduces security problems. I should switch all of this to a sort
+ of execl() or execv() interface/implementation.
+*/
+
+/* Like system(3), but with error messages printed if the fork fails
+ or if the child process dies due to an uncaught signal. Also, the
+ return value is a bit simpler:
+
+ -1 if there was any problem
+ Otherwise, the 8-bit return value of the program ala WEXITSTATUS
+ as defined in <sys/wait.h>.
+*/
+int xsystem(const char *cmd)
+{
+ int err;
+
+ err = system(cmd);
+
+ if (err == -1) {
+ fprintf(stderr, "%s: ERROR: fork failed before execution: `%s'\n",
+ __FUNCTION__, cmd);
+ return -1;
+ }
+
+ if (WIFSIGNALED(err)) {
+ fprintf(stderr, "%s: ERROR: Child process died due to signal %d: `%s'\n",
+ __FUNCTION__, WTERMSIG(err), cmd);
+ return -1;
+ }
+
+ if (WIFEXITED(err)) {
+ /* Normal child exit */
+ return WEXITSTATUS(err);
+ }
+
+ fprintf(stderr, "%s: ERROR: Received unintelligible return value from system: %d",
+ __FUNCTION__, err);
+ return -1;
+}
+
diff -ruN busybox-1.00-orig/archival/libipkg/xsystem.h busybox-1.00+ipkg-0.99.154/archival/libipkg/xsystem.h
--- busybox-1.00-orig/archival/libipkg/xsystem.h 1970-01-01 01:00:00.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/archival/libipkg/xsystem.h 2005-10-26 17:36:46.000000000 +0200
@@ -0,0 +1,34 @@
+/* xsystem.h - system(3) with error messages
+
+ Carl D. Worth
+
+ Copyright (C) 2001 University of Southern California
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+*/
+
+#ifndef XSYSTEM_H
+#define XSYSTEM_H
+
+#include <stdlib.h>
+
+/* Like system(3), but with error messages printed if the fork fails
+ or if the child process dies due to an uncaught signal. Also, the
+ return value is a bit simpler:
+
+ -1 if there was any problem
+ Otherwise, the 8-bit return value of the program ala WEXITSTATUS
+ as defined in <sys/wait.h>.
+*/
+int xsystem(const char *cmd);
+
+#endif
+
diff -ruN busybox-1.00-orig/archival/libunarchive/data_extract_all.c busybox-1.00+ipkg-0.99.154/archival/libunarchive/data_extract_all.c
--- busybox-1.00-orig/archival/libunarchive/data_extract_all.c 2004-10-13 08:25:51.000000000 +0200
+++ busybox-1.00+ipkg-0.99.154/archival/libunarchive/data_extract_all.c 2005-10-26 17:36:46.000000000 +0200
@@ -122,3 +122,17 @@
utime(file_header->name, &t);
}
}
+
+extern void data_extract_all_prefix(archive_handle_t *archive_handle)
+{
+ char *name_ptr = archive_handle->file_header->name;
+
+ name_ptr += strspn(name_ptr, "./");
+ if (name_ptr[0] != '\0') {
+ archive_handle->file_header->name = xmalloc(strlen(archive_handle->buffer) + 1 + strlen(name_ptr) + 1);
+ strcpy(archive_handle->file_header->name, archive_handle->buffer);
+ strcat(archive_handle->file_header->name, name_ptr);
+ data_extract_all(archive_handle);
+ }
+}
+
diff -ruN busybox-1.00-orig/include/applets.h busybox-1.00+ipkg-0.99.154/include/applets.h
--- busybox-1.00-orig/include/applets.h 2004-08-27 01:01:34.000000000 +0200
+++ busybox-1.00+ipkg-0.99.154/include/applets.h 2005-10-26 17:36:46.000000000 +0200
@@ -298,6 +298,9 @@
#ifdef CONFIG_IPCALC
APPLET(ipcalc, ipcalc_main, _BB_DIR_BIN, _BB_SUID_NEVER)
#endif
+#ifdef CONFIG_IPKG
+ APPLET(ipkg, ipkg_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER)
+#endif
#ifdef CONFIG_IPLINK
APPLET(iplink, iplink_main, _BB_DIR_BIN, _BB_SUID_NEVER)
#endif
diff -ruN busybox-1.00-orig/include/libbb.h busybox-1.00+ipkg-0.99.154/include/libbb.h
--- busybox-1.00-orig/include/libbb.h 2004-09-15 05:04:07.000000000 +0200
+++ busybox-1.00+ipkg-0.99.154/include/libbb.h 2005-10-26 17:36:46.000000000 +0200
@@ -484,4 +484,17 @@
#define HASH_MD5 2
extern int hash_fd(int fd, const size_t size, const uint8_t hash_algo, uint8_t *hashval);
+struct md5_ctx_t {
+ uint32_t A;
+ uint32_t B;
+ uint32_t C;
+ uint32_t D;
+ uint32_t total[2];
+ uint32_t buflen;
+ char buffer[128];
+};
+extern void md5_begin(struct md5_ctx_t *ctx);
+extern void md5_hash(const void *buffer, size_t length, void *md5_ctx);
+extern void *md5_end(void *resbuf, struct md5_ctx_t *ctx);
+
#endif /* __LIBCONFIG_H__ */
diff -ruN busybox-1.00-orig/include/unarchive.h busybox-1.00+ipkg-0.99.154/include/unarchive.h
--- busybox-1.00-orig/include/unarchive.h 2004-03-15 09:28:38.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/include/unarchive.h 2005-10-26 17:36:46.000000000 +0200
@@ -72,6 +72,7 @@
extern void data_skip(archive_handle_t *archive_handle);
extern void data_extract_all(archive_handle_t *archive_handle);
+extern void data_extract_all_prefix(archive_handle_t *archive_handle);
extern void data_extract_to_stdout(archive_handle_t *archive_handle);
extern void data_extract_to_buffer(archive_handle_t *archive_handle);
diff -ruN busybox-1.00-orig/include/usage.h busybox-1.00+ipkg-0.99.154/include/usage.h
--- busybox-1.00-orig/include/usage.h 2004-09-14 18:23:56.000000000 +0200
+++ busybox-1.00+ipkg-0.99.154/include/usage.h 2005-10-26 17:36:46.000000000 +0200
@@ -836,6 +836,82 @@
"$ ls -la /tmp/busybox*\n" \
"-rw-rw-r-- 1 andersen andersen 554058 Apr 14 17:49 /tmp/busybox.tar.gz\n"
+#define ipkg_trivial_usage \
+ "[options...] sub-command [arguments...]"
+#define ipkg_full_usage \
+ "ipkg is an utility to install, remove and manage .ipk packages.\n" \
+ "\n" \
+ "Sub-commands:\n" \
+ "\nPackage Manipulation:\n" \
+ "\tupdate Update list of available packages\n" \
+ "\tupgrade Upgrade all installed packages to latest version\n" \
+ "\tinstall <pkg> Download and install <pkg> (and dependencies)\n" \
+ "\tinstall <file.ipk> Install package <file.ipk>\n" \
+ "\tconfigure [<pkg>] Configure unpacked packages\n" \
+ "\tremove <pkg|regexp> Remove package <pkg|packages following regexp>\n" \
+ "\tflag <flag> <pkg> ... Flag package(s) <pkg>\n" \
+ "\t <flag>=hold|noprune|user|ok|installed|unpacked (one per invocation) \n" \
+ "\n" \
+ "Informational Commands:\n" \
+ "\tlist List available packages and descriptions\n" \
+ "\tlist_installed List all and only the installed packages and description \n" \
+ "\tfiles <pkg> List all files belonging to <pkg>\n" \
+ "\tsearch <file|regexp> Search for a package providing <file>\n" \
+ "\tinfo [pkg|regexp [<field>]] Display all/some info fields for <pkg> or all\n" \
+ "\tstatus [pkg|regexp [<field>]] Display all/some status fields for <pkg> or all\n" \
+ "\tdownload <pkg> Download <pkg> to current directory.\n" \
+ "\tcompare_versions <v1> <op> <v2>\n" \
+ "\t compare versions using <= < > >= = << >>\n" \
+ "\tprint_architecture prints the architecture.\n" \
+ "\tprint_installation_architecture\n" \
+ "\twhatdepends [-A] [pkgname|pat]+\n" \
+ "\twhatdependsrec [-A] [pkgname|pat]+\n" \
+ "\twhatprovides [-A] [pkgname|pat]+\n" \
+ "\twhatconflicts [-A] [pkgname|pat]+\n" \
+ "\twhatreplaces [-A] [pkgname|pat]+\n" \
+ "\t prints the installation architecture.\n" \
+ "\n" \
+ "\nOptions:\n" \
+ "\t-A Query all packages with whatdepends, whatprovides, whatreplaces, whatconflicts\n" \
+ "\t-V <level> Set verbosity level to <level>. If no value is\n" \
+ "\t--verbosity <level> provided increase verbosity by one. Verbosity levels:\n" \
+ "\t 0 errors only\n" \
+ "\t 1 normal messages (default)\n" \
+ "\t 2 informative messages\n" \
+ "\t 3 debug output\n" \
+ "\t-f <conf_file> Use <conf_file> as the ipkg configuration file\n" \
+ "\t-conf <conf_file> Default configuration file location\n" \
+ " is /etc/ipkg.conf\n" \
+ "\t-d <dest_name> Use <dest_name> as the the root directory for\n" \
+ "\t-dest <dest_name> package installation, removal, upgrading.\n" \
+ " <dest_name> should be a defined dest name from\n" \
+ " the configuration file, (but can also be a\n" \
+ " directory name in a pinch).\n" \
+ "\t-o <offline_root> Use <offline_root> as the root directory for\n" \
+ "\t-offline <offline_root> offline installation of packages.\n" \
+ "\t-verbose_wget more wget messages\n" \
+ "\n" \
+ "Force Options (use when ipkg is too smart for its own good):\n" \
+ "\t-force-depends Make dependency checks warnings instead of errors\n" \
+ "\t Install/remove package in spite of failed dependences\n" \
+ "\t-force-defaults Use default options for questions asked by ipkg.\n" \
+ " (no prompts). Note that this will not prevent\n" \
+ " package installation scripts from prompting.\n" \
+ "\t-force-reinstall Allow ipkg to reinstall a package.\n" \
+ "\t-force-overwrite Allow ipkg to overwrite files from another package during an install.\n" \
+ "\t-force-downgrade Allow ipkg to downgrade packages.\n" \
+ "\t-force_space Install even if there does not seem to be enough space.\n" \
+ "\t-noaction No action -- test only\n" \
+ "\t-nodeps Do not follow dependences\n" \
+ "\t-force-removal-of-dependent-packages\n" \
+ "\t-recursive Allow ipkg to remove package and all that depend on it.\n" \
+ "\t-test No action -- test only\n" \
+ "\t-t Specify tmp-dir.\n" \
+ "\t--tmp-dir Specify tmp-dir.\n" \
+ "\n" \
+ "\tregexp could be something like 'pkgname*' '*file*' or similar\n" \
+ "\teg: ipkg info 'libstd*' or ipkg search '*libop*' or ipkg remove 'libncur*'\n"
+
#define halt_trivial_usage \
"[-d<delay>]"
#define halt_full_usage \
diff -ruN busybox-1.00-orig/libbb/hash_fd.c busybox-1.00+ipkg-0.99.154/libbb/hash_fd.c
--- busybox-1.00-orig/libbb/hash_fd.c 2004-03-15 09:28:42.000000000 +0100
+++ busybox-1.00+ipkg-0.99.154/libbb/hash_fd.c 2005-10-26 17:36:46.000000000 +0200
@@ -288,21 +288,10 @@
static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ };
# endif /* MD5SUM_SIZE_VS_SPEED == 0 */
-/* Structure to save state of computation between the single steps. */
-struct md5_ctx_t {
- uint32_t A;
- uint32_t B;
- uint32_t C;
- uint32_t D;
- uint32_t total[2];
- uint32_t buflen;
- char buffer[128];
-};
-
/* Initialize structure containing state of computation.
* (RFC 1321, 3.3: Step 3)
*/
-static void md5_begin(struct md5_ctx_t *ctx)
+extern void md5_begin(struct md5_ctx_t *ctx)
{
ctx->A = 0x67452301;
ctx->B = 0xefcdab89;
@@ -706,7 +695,7 @@
}
}
-static void md5_hash(const void *buffer, size_t length, void *md5_ctx)
+extern void md5_hash(const void *buffer, size_t length, void *md5_ctx)
{
if (length % 64 == 0) {
md5_hash_block(buffer, length, md5_ctx);
@@ -723,7 +712,7 @@
* IMPORTANT: On some systems it is required that RESBUF is correctly
* aligned for a 32 bits value.
*/
-static void *md5_end(void *resbuf, struct md5_ctx_t *ctx)
+extern void *md5_end(void *resbuf, struct md5_ctx_t *ctx)
{
/* Take yet unprocessed bytes into account. */
uint32_t bytes = ctx->buflen;