diff -Nur busybox-1.26.0.orig/archival/ipkg.c busybox-1.26.0/archival/ipkg.c --- busybox-1.26.0.orig/archival/ipkg.c 1970-01-01 01:00:00.000000000 +0100 +++ busybox-1.26.0/archival/ipkg.c 2016-12-22 17:08:30.972837164 +0100 @@ -0,0 +1,39 @@ +/* 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 + +*/ + +//config:config IPKG +//config: bool "ipkg" +//config: default n +//config: help +//config: ipkg is a tool to install, build, remove and manage +//config: packages. +//config: + +//applet:IF_IPKG(APPLET(ipkg, BB_DIR_USR_BIN, BB_SUID_DROP)) +//kbuild:lib-$(CONFIG_IPKG) += ipkg.o + +#include "libbb.h" +#include "libipkg/libipkg.h" + +int ipkg_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int ipkg_main(int argc, char **argv) +{ + return ipkg_op(argc, argv); +} diff -Nur busybox-1.26.0.orig/archival/libarchive/Kbuild.src busybox-1.26.0/archival/libarchive/Kbuild.src --- busybox-1.26.0.orig/archival/libarchive/Kbuild.src 2016-12-12 08:46:14.000000000 +0100 +++ busybox-1.26.0/archival/libarchive/Kbuild.src 2016-12-22 17:08:30.972837164 +0100 @@ -25,6 +25,8 @@ \ data_align.o \ find_list_entry.o \ + get_header_tar.o \ + get_header_tar_gz.o \ init_handle.o DPKG_FILES:= \ @@ -32,8 +34,6 @@ filter_accept_list_reassign.o \ unsafe_prefix.o \ get_header_ar.o \ - get_header_tar.o \ - get_header_tar_gz.o \ get_header_tar_bz2.o \ get_header_tar_lzma.o \ get_header_tar_xz.o \ diff -Nur busybox-1.26.0.orig/archival/libipkg/args.c busybox-1.26.0/archival/libipkg/args.c --- busybox-1.26.0.orig/archival/libipkg/args.c 1970-01-01 01:00:00.000000000 +0100 +++ busybox-1.26.0/archival/libipkg/args.c 2016-12-22 17:08:30.972837164 +0100 @@ -0,0 +1,242 @@ +/* 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) +{ + const 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; + args->noreadfeedsfile = 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(const 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 -Nur busybox-1.26.0.orig/archival/libipkg/args.h busybox-1.26.0/archival/libipkg/args.h --- busybox-1.26.0.orig/archival/libipkg/args.h 1970-01-01 01:00:00.000000000 +0100 +++ busybox-1.26.0/archival/libipkg/args.h 2016-12-22 17:08:30.976839427 +0100 @@ -0,0 +1,72 @@ +/* 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; + int noreadfeedsfile; + 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(const char *complaint); + +#endif diff -Nur busybox-1.26.0.orig/archival/libipkg/conffile.c busybox-1.26.0/archival/libipkg/conffile.c --- busybox-1.26.0.orig/archival/libipkg/conffile.c 1970-01-01 01:00:00.000000000 +0100 +++ busybox-1.26.0/archival/libipkg/conffile.c 2016-12-22 17:08:30.976839427 +0100 @@ -0,0 +1,65 @@ +/* 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 "libbb.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 uint8_t *md5sum) +{ + return nv_pair_init(conffile, file_name, (char *)md5sum); +} + +void conffile_deinit(conffile_t *conffile) +{ + nv_pair_deinit(conffile); +} + +int conffile_has_been_modified(ipkg_conf_t *conf, conffile_t *conffile) +{ + uint8_t *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((char *)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 -Nur busybox-1.26.0.orig/archival/libipkg/conffile.h busybox-1.26.0/archival/libipkg/conffile.h --- busybox-1.26.0.orig/archival/libipkg/conffile.h 1970-01-01 01:00:00.000000000 +0100 +++ busybox-1.26.0/archival/libipkg/conffile.h 2016-12-22 17:08:30.976839427 +0100 @@ -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 uint8_t *md5sum); +void conffile_deinit(conffile_t *conffile); +int conffile_has_been_modified(struct ipkg_conf *conf, conffile_t *conffile); + +#endif + diff -Nur busybox-1.26.0.orig/archival/libipkg/conffile_list.c busybox-1.26.0/archival/libipkg/conffile_list.c --- busybox-1.26.0.orig/archival/libipkg/conffile_list.c 1970-01-01 01:00:00.000000000 +0100 +++ busybox-1.26.0/archival/libipkg/conffile_list.c 2016-12-22 17:08:30.984843942 +0100 @@ -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 -Nur busybox-1.26.0.orig/archival/libipkg/conffile_list.h busybox-1.26.0/archival/libipkg/conffile_list.h --- busybox-1.26.0.orig/archival/libipkg/conffile_list.h 1970-01-01 01:00:00.000000000 +0100 +++ busybox-1.26.0/archival/libipkg/conffile_list.h 2016-12-22 17:08:30.984843942 +0100 @@ -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 -Nur busybox-1.26.0.orig/archival/libipkg/file_util.c busybox-1.26.0/archival/libipkg/file_util.c --- busybox-1.26.0.orig/archival/libipkg/file_util.c 1970-01-01 01:00:00.000000000 +0100 +++ busybox-1.26.0/archival/libipkg/file_util.c 2016-12-22 17:08:30.984843942 +0100 @@ -0,0 +1,186 @@ +/* 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 "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(char *path, long mode) +{ + return bb_make_directory(path, mode, FILEUTILS_RECUR); +} + +static unsigned char *hash_bin_to_hex(unsigned char *hash_value, + unsigned hash_length) +{ + /* xzalloc zero-terminates */ + char *hex_value = xzalloc((hash_length * 2) + 1); + bin2hex(hex_value, (char*)hash_value, hash_length); + return (unsigned char *)hex_value; +} + +static uint8_t *hash_file(const char *filename, hash_algo_t hash_algo) +{ + int src_fd, hash_len, count; + union _ctx_ { + sha1_ctx_t sha1; + md5_ctx_t md5; + } context; + uint8_t *hash_value = NULL; + RESERVE_CONFIG_UBUFFER(in_buf, 4096); + void FAST_FUNC (*update)(void*, const void*, size_t); + void FAST_FUNC (*final)(void*, void*); + + src_fd = open_or_warn_stdin(filename); + if (src_fd < 0) { + return NULL; + } + + /* figure specific hash algorithims */ + if (ENABLE_MD5SUM && hash_algo == HASH_MD5) { + md5_begin(&context.md5); + update = (void*)md5_hash; + final = (void*)md5_end; + hash_len = 16; + } else { + bb_error_msg_and_die("algorithm not supported"); + } + + while ((count = safe_read(src_fd, in_buf, 4096)) > 0) { + update(&context, in_buf, count); + } + + if (count == 0) { + final(&context, in_buf); + hash_value = hash_bin_to_hex(in_buf, hash_len); + } + + RELEASE_CONFIG_BUFFER(in_buf); + + if (src_fd != STDIN_FILENO) { + close(src_fd); + } + + return hash_value; +} + +uint8_t *file_md5sum_alloc(const char *file_name) +{ + return hash_file(file_name, HASH_MD5); +} + diff -Nur busybox-1.26.0.orig/archival/libipkg/file_util.h busybox-1.26.0/archival/libipkg/file_util.h --- busybox-1.26.0.orig/archival/libipkg/file_util.h 1970-01-01 01:00:00.000000000 +0100 +++ busybox-1.26.0/archival/libipkg/file_util.h 2016-12-22 17:08:30.984843942 +0100 @@ -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(char *path, long mode); +uint8_t *file_md5sum_alloc(const char *file_name); + +#endif diff -Nur busybox-1.26.0.orig/archival/libipkg/hash_table.c busybox-1.26.0/archival/libipkg/hash_table.c --- busybox-1.26.0.orig/archival/libipkg/hash_table.c 1970-01-01 01:00:00.000000000 +0100 +++ busybox-1.26.0/archival/libipkg/hash_table.c 2016-12-22 17:08:30.984843942 +0100 @@ -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 -Nur busybox-1.26.0.orig/archival/libipkg/hash_table.h busybox-1.26.0/archival/libipkg/hash_table.h --- busybox-1.26.0.orig/archival/libipkg/hash_table.h 1970-01-01 01:00:00.000000000 +0100 +++ busybox-1.26.0/archival/libipkg/hash_table.h 2016-12-22 17:08:30.984843942 +0100 @@ -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 -Nur busybox-1.26.0.orig/archival/libipkg/ipkg_cmd.c busybox-1.26.0/archival/libipkg/ipkg_cmd.c --- busybox-1.26.0.orig/archival/libipkg/ipkg_cmd.c 1970-01-01 01:00:00.000000000 +0100 +++ busybox-1.26.0/archival/libipkg/ipkg_cmd.c 2016-12-22 17:08:30.992848456 +0100 @@ -0,0 +1,1367 @@ +/* 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 <dirent.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 "bb_archive.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" + +#include "libipkg.h" +static void *p_userdata = NULL; + +static int ipkg_update_cmd(ipkg_conf_t *conf); +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); +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); +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; +} + +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; +} + +static int ipkg_update_cmd(ipkg_conf_t *conf) +{ + int err; + int failures; + char *lists_dir; + pkg_src_list_elt_t *iter; + pkg_src_t *src; + + + sprintf_alloc(&lists_dir, "%s", conf->restrict_to_default_dest ? conf->default_dest->lists_dir : conf->lists_dir); + + if (! file_is_dir(lists_dir)) { + if (file_exists(lists_dir)) { + 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) { + transformer_state_t xstate; + init_transformer_state(&xstate); + inflate_unzip (&xstate); + } 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; + + ipkg_message(conf, IPKG_DEBUG2, "Debug mfs: %s \n",filename ); + + err = ipkg_prepare_url_for_install(conf, filename, &argv[i]); + if (err) + return err; + } + return 0; +} + +struct ipkg_intercept +{ + char *oldpath; + char *statedir; +}; + +typedef struct ipkg_intercept *ipkg_intercept_t; +ipkg_intercept_t ipkg_prep_intercepts(void); + +ipkg_intercept_t ipkg_prep_intercepts(void) +{ + ipkg_intercept_t ctx; + char *newpath; + int gen; + + ctx = malloc (sizeof (*ctx)); + ctx->oldpath = strdup (getenv ("PATH")); + + sprintf_alloc (&newpath, "%s/ipkg/intercept:%s", IPKGLIBDIR, ctx->oldpath); + setenv ("PATH", newpath, 1); + free (newpath); + + gen = 0; + retry: + sprintf_alloc (&ctx->statedir, "/tmp/ipkg-intercept-%d-%d", getpid (), gen); + if (mkdir (ctx->statedir, 0770) < 0) { + if (errno == EEXIST) { + free (ctx->statedir); + gen++; + goto retry; + } + perror (ctx->statedir); + return NULL; + } + setenv ("IPKG_INTERCEPT_DIR", ctx->statedir, 1); + return ctx; +} + +int ipkg_finalize_intercepts(ipkg_intercept_t ctx); + +int ipkg_finalize_intercepts(ipkg_intercept_t ctx) +{ + char *cmd; + DIR *dir; + int err = 0; + + setenv ("PATH", ctx->oldpath, 1); + free (ctx->oldpath); + + dir = opendir (ctx->statedir); + if (dir) { + struct dirent *de; + while (de = readdir (dir), de != NULL) { + char *path; + + if (de->d_name[0] == '.') + continue; + + sprintf_alloc (&path, "%s/%s", ctx->statedir, de->d_name); + if (access (path, X_OK) == 0) { + if (system (path)) { + err = errno; + perror (de->d_name); + } + } + free (path); + } + } else + perror (ctx->statedir); + + sprintf_alloc (&cmd, "rm -rf %s", ctx->statedir); + system (cmd); + free (cmd); + + free (ctx->statedir); + free (ctx); + + return err; +} + +int ipkg_configure_packages(ipkg_conf_t *conf, char *pkg_name) +{ + pkg_vec_t *all; + int i; + pkg_t *pkg; + ipkg_intercept_t ic; + int r, err = 0; + + ipkg_message(conf, IPKG_INFO, + "Configuring unpacked packages\n"); + fflush( stdout ); + + all = pkg_vec_alloc(); + pkg_hash_fetch_available(&conf->pkg_hash, all); + + ic = ipkg_prep_intercepts(); + + 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 ); + r = ipkg_configure(conf, pkg); + if (r == 0) { + pkg->state_status = SS_INSTALLED; + pkg->parent->state_status = SS_INSTALLED; + pkg->state_flag &= ~SF_PREFER; + } else { + if (!err) + err = r; + } + } + } + + r = ipkg_finalize_intercepts (ic); + if (r && !err) + err = r; + + pkg_vec_free(all); + return err; +} + +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]; + + ipkg_message(conf, IPKG_DEBUG2, "Debug install_cmd: %s \n",arg ); + 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'; + } + 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); + } + } + 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'; + } + 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); + } + } + + 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; + } + buff = pkg_formatted_info(pkg); + if ( buff ) { + if (ipkg_cb_status) ipkg_cb_status(pkg->name, + pkg->state_status, + buff, + p_userdata); + free(buff); + } + 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); + } + } + } + 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 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,0); + done = 1; + } + free (pkg_name); + } + pkg_vec_free(available); + } else { + pkg_vec_t *installed_pkgs = pkg_vec_alloc(); + 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 = installed_pkgs->pkgs[i]; + if (pkg->state_flag & SF_USER) { + flagged_pkg_count++; + } else { + if (!pkg_has_installed_dependents(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 = installed_pkgs->pkgs[i]; + if (!(pkg->state_flag & SF_USER) + && !pkg_has_installed_dependents(pkg, NULL)) { + removed++; + ipkg_message(conf, IPKG_NOTICE, "Removing non-user leaf package %s\n"); + ipkg_remove_pkg(conf, pkg,0); + 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; + 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); + + 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); + } + + 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) { + const 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++) { + pk