X-Git-Url: https://git.librecmc.org/?p=oweals%2Fopkg-lede.git;a=blobdiff_plain;f=libopkg%2Fopkg_install.c;h=6003f4f34081feb62127dbfb067becff27ccde44;hp=e28f6b49be240850b9d36c5356d19280dba6d960;hb=76bcf4ec07e560ce724744bbbc71781dee35307b;hpb=a6d79aecf9bb27c27e3f9fbef544e190592f24b7 diff --git a/libopkg/opkg_install.c b/libopkg/opkg_install.c index e28f6b4..6003f4f 100644 --- a/libopkg/opkg_install.c +++ b/libopkg/opkg_install.c @@ -21,9 +21,6 @@ #include #include #include -#ifndef __USE_GNU -typedef void (*sighandler_t)(int); -#endif #include "pkg.h" #include "pkg_hash.h" @@ -46,269 +43,8 @@ typedef void (*sighandler_t)(int); #include "user.h" #include "libbb/libbb.h" -static int verify_pkg_installable(opkg_conf_t *conf, pkg_t *pkg); -static int unpack_pkg_control_files(opkg_conf_t *conf, pkg_t *pkg); - -static int prerm_upgrade_old_pkg(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg); -static int prerm_upgrade_old_pkg_unwind(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg); -static int prerm_deconfigure_conflictors(opkg_conf_t *conf, pkg_t *pkg, pkg_vec_t *conflictors); -static int prerm_deconfigure_conflictors_unwind(opkg_conf_t *conf, pkg_t *pkg, pkg_vec_t *conflictors); -static int preinst_configure(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg); -static int preinst_configure_unwind(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg); -static int check_data_file_clashes(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg); -static int check_data_file_clashes_change(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg); -static int check_data_file_clashes_unwind(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg); -static int backup_modified_conffiles(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg); -static int backup_modified_conffiles_unwind(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg); -static int postrm_upgrade_old_pkg(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg); -static int postrm_upgrade_old_pkg_unwind(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg); - -static int remove_obsolesced_files(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg); -static int install_maintainer_scripts(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg); -static int remove_disappeared(opkg_conf_t *conf, pkg_t *pkg); -static int install_data_files(opkg_conf_t *conf, pkg_t *pkg); -static int resolve_conffiles(opkg_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(opkg_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 opkg_install_from_file(opkg_conf_t *conf, const char *filename) -{ - int err, cmp; - pkg_t *pkg, *old; - char *old_version, *new_version; - - pkg = pkg_new(); - - err = pkg_init_from_file(pkg, filename); - if (err) { - return err; - } - - if (!pkg->architecture) { - opkg_message(conf, OPKG_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); - - 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 opkg 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) { - opkg_message(conf, OPKG_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); - } - } - - opkg_message(conf, OPKG_DEBUG2,"Function: %s calling opkg_install_pkg \n",__FUNCTION__); - return opkg_install_pkg(conf, pkg,0); -} - -opkg_error_t opkg_install_by_name(opkg_conf_t *conf, const char *pkg_name) -{ - int cmp, err = 0; - pkg_t *old, *new; - char *old_version, *new_version; - - opkg_message(conf, OPKG_DEBUG2, " Getting old from pkg_hash_fetch \n" ); - old = pkg_hash_fetch_installed_by_name(&conf->pkg_hash, pkg_name); - if ( old ) - opkg_message(conf, OPKG_DEBUG2, " Old versions from pkg_hash_fetch %s \n", old->version ); - - opkg_message(conf, OPKG_DEBUG2, " Getting new from pkg_hash_fetch \n" ); - new = pkg_hash_fetch_best_installation_candidate_by_name(conf, pkg_name, &err); - if ( new ) - opkg_message(conf, OPKG_DEBUG2, " New versions from pkg_hash_fetch %s \n", new->version ); - -/* Pigi Basically here is broken the version stuff. - What's happening is that nothing provide the version to differents - functions, so the returned struct is always the latest. - That's why the install by name don't work. -*/ - opkg_message(conf, OPKG_DEBUG2, " Versions from pkg_hash_fetch in %s ", __FUNCTION__ ); - - if ( old ) - opkg_message(conf, OPKG_DEBUG2, " old %s ", old->version ); - if ( new ) - opkg_message(conf, OPKG_DEBUG2, " new %s ", new->version ); - opkg_message(conf, OPKG_DEBUG2, " \n"); - - if (new == NULL) { - if (err) - return err; - else - return OPKG_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 */ - opkg_message(conf, OPKG_DEBUG, " Forcing downgrade \n"); - cmp = -1 ; /* then we force opkg 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 */ - } - opkg_message(conf, OPKG_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) { - opkg_message(conf, OPKG_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) { - opkg_message(conf, OPKG_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 */ - free(old_version); - free(new_version); - } - } - - /* XXX: CLEANUP: The error code of opkg_install_by_name is really - supposed to be an opkg_error_t, but opkg_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 libopkg. */ - - opkg_message(conf, OPKG_DEBUG2,"Function: %s calling opkg_install_pkg \n",__FUNCTION__); - return opkg_install_pkg(conf, new,0); -} - -opkg_error_t opkg_install_multi_by_name(opkg_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; - opkg_error_t err; - abstract_pkg_t *ppkg ; - - if (providers == NULL) - return OPKG_PKG_HAS_NO_CANDIDATE; - - for (i = 0; i < providers->len; i++) { - ppkg = abstract_pkg_vec_get(providers, i); - opkg_message(conf, OPKG_DEBUG2,"Function: %s calling opkg_install_by_name %d \n",__FUNCTION__, i); - err = opkg_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(opkg_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) { - opkg_message(conf, OPKG_ERROR, - "%s: Cannot satisfy the following dependencies for %s:\n\t", - conf->force_depends ? "Warning" : "ERROR", pkg->name); - while (*unresolved) { - opkg_message(conf, OPKG_ERROR, " %s", *unresolved); - unresolved++; - } - opkg_message(conf, OPKG_ERROR, "\n"); - if (! conf->force_depends) { - opkg_message(conf, OPKG_INFO, - "This could mean that your package list is out of date or that the packages\n" - "mentioned above do not yet exist (try 'opkg update'). To proceed in spite\n" - "of this problem try again with the '-force-depends' option.\n"); - pkg_vec_free(depends); - return OPKG_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 satisfy_dependencies_for(opkg_conf_t *conf, pkg_t *pkg) +static int +satisfy_dependencies_for(opkg_conf_t *conf, pkg_t *pkg) { int i, err; pkg_vec_t *depends = pkg_vec_alloc(); @@ -377,25 +113,8 @@ int satisfy_dependencies_for(opkg_conf_t *conf, pkg_t *pkg) return 0; } - -/* check all packages have their dependences satisfied, e.g., in case an upgraded package split */ -int opkg_satisfy_all_dependences(opkg_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(opkg_conf_t *conf, pkg_t *pkg) +static int +check_conflicts_for(opkg_conf_t *conf, pkg_t *pkg) { int i; pkg_vec_t *conflicts = NULL; @@ -425,7 +144,8 @@ static int check_conflicts_for(opkg_conf_t *conf, pkg_t *pkg) return 0; } -static int update_file_ownership(opkg_conf_t *conf, pkg_t *new_pkg, pkg_t *old_pkg) +static int +update_file_ownership(opkg_conf_t *conf, pkg_t *new_pkg, pkg_t *old_pkg) { str_list_t *new_list = pkg_get_installed_files(conf, new_pkg); str_list_elt_t *iter, *niter; @@ -458,7 +178,8 @@ static int update_file_ownership(opkg_conf_t *conf, pkg_t *new_pkg, pkg_t *old_p return 0; } -static int verify_pkg_installable(opkg_conf_t *conf, pkg_t *pkg) +static int +verify_pkg_installable(opkg_conf_t *conf, pkg_t *pkg) { /* XXX: FEATURE: Anything else needed here? Maybe a check on free space? */ @@ -491,7 +212,8 @@ static int verify_pkg_installable(opkg_conf_t *conf, pkg_t *pkg) return 0; } -static int unpack_pkg_control_files(opkg_conf_t *conf, pkg_t *pkg) +static int +unpack_pkg_control_files(opkg_conf_t *conf, pkg_t *pkg) { int err; char *conffiles_file_name; @@ -586,7 +308,16 @@ pkg_remove_orphan_dependent(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg) struct compound_depend *cd0, *cd1; abstract_pkg_t **dependents; - for (i=0; idepends_count; i++) { + int count0 = old_pkg->pre_depends_count + + old_pkg->depends_count + + old_pkg->recommends_count + + old_pkg->suggests_count; + int count1 = pkg->pre_depends_count + + pkg->depends_count + + pkg->recommends_count + + pkg->suggests_count; + + for (i=0; idepends[i]; if (cd0->type != DEPEND) continue; @@ -594,7 +325,7 @@ pkg_remove_orphan_dependent(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg) found = 0; - for (k=0; kdepends_count; k++) { + for (k=0; kdepends[i]; if (cd1->type != DEPEND) continue; @@ -653,7 +384,8 @@ pkg_remove_orphan_dependent(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg) } /* returns number of installed replacees */ -int pkg_get_installed_replacees(opkg_conf_t *conf, pkg_t *pkg, pkg_vec_t *installed_replacees) +static int +pkg_get_installed_replacees(opkg_conf_t *conf, pkg_t *pkg, pkg_vec_t *installed_replacees) { abstract_pkg_t **replaces = pkg->replaces; int replaces_count = pkg->replaces_count; @@ -675,7 +407,8 @@ int pkg_get_installed_replacees(opkg_conf_t *conf, pkg_t *pkg, pkg_vec_t *instal return installed_replacees->len; } -int pkg_remove_installed_replacees(opkg_conf_t *conf, pkg_vec_t *replacees) +static int +pkg_remove_installed_replacees(opkg_conf_t *conf, pkg_vec_t *replacees) { int i; int replaces_count = replacees->len; @@ -691,7 +424,8 @@ int pkg_remove_installed_replacees(opkg_conf_t *conf, pkg_vec_t *replacees) } /* to unwind the removal: make sure they are installed */ -int pkg_remove_installed_replacees_unwind(opkg_conf_t *conf, pkg_vec_t *replacees) +static int +pkg_remove_installed_replacees_unwind(opkg_conf_t *conf, pkg_vec_t *replacees) { int i, err; int replaces_count = replacees->len; @@ -708,7 +442,8 @@ int pkg_remove_installed_replacees_unwind(opkg_conf_t *conf, pkg_vec_t *replacee } /* compares versions of pkg and old_pkg, returns 0 if OK to proceed with installation of pkg, 1 otherwise */ -static int opkg_install_check_downgrade(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg, int message) +static int +opkg_install_check_downgrade(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg, int message) { if (old_pkg) { char message_out[15]; @@ -770,426 +505,195 @@ static int opkg_install_check_downgrade(opkg_conf_t *conf, pkg_t *pkg, pkg_t *ol } } -/** - * @brief Really install a pkg_t - */ -int opkg_install_pkg(opkg_conf_t *conf, pkg_t *pkg, int from_upgrade) + +static int +prerm_upgrade_old_pkg(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg) { - int err = 0; - int message = 0; - pkg_t *old_pkg = NULL; - pkg_vec_t *replacees; - abstract_pkg_t *ab_pkg = NULL; - int old_state_flag; - char* file_md5; -#ifdef HAVE_SHA256 - char* file_sha256; -#endif + /* 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; +} - if ( from_upgrade ) - message = 1; /* Coming from an upgrade, and should change the output message */ +static int +prerm_upgrade_old_pkg_unwind(opkg_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; +} - if (!pkg) { - opkg_message(conf, OPKG_ERROR, - "INTERNAL ERROR: null pkg passed to opkg_install_pkg\n"); - return OPKG_INSTALL_ERR_INTERNAL; - } +static int +prerm_deconfigure_conflictors(opkg_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 - opkg_message(conf, OPKG_DEBUG2, "Function: %s calling pkg_arch_supported %s \n", __FUNCTION__, __FUNCTION__); + 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; +} - if (!pkg_arch_supported(conf, pkg)) { - opkg_message(conf, OPKG_ERROR, "INTERNAL ERROR: architecture %s for pkg %s is unsupported.\n", - pkg->architecture, pkg->name); - return OPKG_INSTALL_ERR_INTERNAL; - } - if (pkg->state_status == SS_INSTALLED && conf->force_reinstall == 0 && conf->nodeps == 0) { - err = satisfy_dependencies_for(conf, pkg); - if (err) { return OPKG_INSTALL_ERR_DEPENDENCIES; } +static int +prerm_deconfigure_conflictors_unwind(opkg_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; +} - opkg_message(conf, OPKG_NOTICE, - "Package %s is already installed in %s.\n", - pkg->name, pkg->dest->name); - return 0; - } +static int +preinst_configure(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg) +{ + int err; + char *preinst_args; - if (pkg->dest == NULL) { - pkg->dest = conf->default_dest; + 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 = xstrdup("install"); } - old_pkg = pkg_hash_fetch_installed_by_name(&conf->pkg_hash, pkg->name); - - err = opkg_install_check_downgrade(conf, pkg, old_pkg, message); - if (err) { return OPKG_INSTALL_ERR_NO_DOWNGRADE; } - - pkg->state_want = SW_INSTALL; - if (old_pkg){ - old_pkg->state_want = SW_DEINSTALL; /* needed for check_data_file_clashes of dependences */ + err = pkg_run_script(conf, pkg, "preinst", preinst_args); + if (err) { + opkg_message(conf, OPKG_ERROR, + "Aborting installation of %s\n", pkg->name); + return 1; } + free(preinst_args); - /* Abhaya: conflicts check */ - err = check_conflicts_for(conf, pkg); - if (err) { return OPKG_INSTALL_ERR_CONFLICTS; } - - /* 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 OPKG_INSTALL_ERR_NO_SPACE; } + return 0; +} - if (pkg->local_filename == NULL) { - err = opkg_download_pkg(conf, pkg, conf->tmp_dir); - if (err) { - opkg_message(conf, OPKG_ERROR, - "Failed to download %s. Perhaps you need to run 'opkg update'?\n", - pkg->name); - return OPKG_INSTALL_ERR_DOWNLOAD; - } - } +static int +preinst_configure_unwind(opkg_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; +} - /* check that the repository is valid */ - #if defined(HAVE_GPGME) || defined(HAVE_OPENSSL) - char *list_file_name, *sig_file_name, *lists_dir; +static char * +backup_filename_alloc(const char *file_name) +{ + char *backup; - /* check to ensure the package has come from a repository */ - if (conf->check_signature && pkg->src) - { - sprintf_alloc (&lists_dir, "%s", - (conf->restrict_to_default_dest) - ? conf->default_dest->lists_dir - : conf->lists_dir); - sprintf_alloc (&list_file_name, "%s/%s", lists_dir, pkg->src->name); - sprintf_alloc (&sig_file_name, "%s/%s.sig", lists_dir, pkg->src->name); + sprintf_alloc(&backup, "%s%s", file_name, OPKG_BACKUP_SUFFIX); - if (file_exists (sig_file_name)) - { - if (opkg_verify_file (conf, list_file_name, sig_file_name)){ - opkg_message(conf, OPKG_ERROR, "Failed to verify the signature of: %s\n", - list_file_name); - return OPKG_INSTALL_ERR_SIGNATURE; - } - }else{ - opkg_message(conf, OPKG_ERROR, "Signature file is missing. " - "Perhaps you need to run 'opkg update'?\n"); - return OPKG_INSTALL_ERR_SIGNATURE; - } + return backup; +} - free (lists_dir); - free (list_file_name); - free (sig_file_name); - } - #endif - /* Check for md5 values */ - if (pkg->md5sum) - { - file_md5 = file_md5sum_alloc(pkg->local_filename); - if (file_md5 && strcmp(file_md5, pkg->md5sum)) - { - opkg_message(conf, OPKG_ERROR, - "Package %s md5sum mismatch. Either the opkg or the package index are corrupt. Try 'opkg update'.\n", - pkg->name); - free(file_md5); - return OPKG_INSTALL_ERR_MD5; - } - if (file_md5) - free(file_md5); +static int +backup_make_backup(opkg_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) { + opkg_message(conf, OPKG_ERROR, + "%s: Failed to copy %s to %s\n", + __FUNCTION__, file_name, backup); } -#ifdef HAVE_SHA256 - /* Check for sha256 value */ - if(pkg->sha256sum) - { - file_sha256 = file_sha256sum_alloc(pkg->local_filename); - if (file_sha256 && strcmp(file_sha256, pkg->sha256sum)) - { - opkg_message(conf, OPKG_ERROR, - "Package %s sha256sum mismatch. Either the opkg or the package index are corrupt. Try 'opkg update'.\n", - pkg->name); - free(file_sha256); - return OPKG_INSTALL_ERR_SHA256; - } - if (file_sha256) - free(file_sha256); - } -#endif + free(backup); - if (pkg->tmp_unpack_dir == NULL) { - unpack_pkg_control_files(conf, pkg); - } + return err; +} - /* We should update the filelist here, so that upgrades of packages that split will not fail. -Jamey 27-MAR-03 */ -/* Pigi: check if it will pass from here when replacing. It seems to fail */ -/* That's rather strange that files don't change owner. Investigate !!!!!!*/ - err = update_file_ownership(conf, pkg, old_pkg); - if (err) { return OPKG_ERR_UNKNOWN; } +static int +backup_exists_for(const char *file_name) +{ + int ret; + char *backup; - if (conf->nodeps == 0) { - err = satisfy_dependencies_for(conf, pkg); - if (err) { return OPKG_INSTALL_ERR_DEPENDENCIES; } - if (pkg->state_status == SS_UNPACKED) - /* Circular dependency has installed it for us. */ - return 0; - } + backup = backup_filename_alloc(file_name); - replacees = pkg_vec_alloc(); - pkg_get_installed_replacees(conf, pkg, replacees); + ret = file_exists(backup); - /* this next section we do with SIGINT blocked to prevent inconsistency between opkg database and filesystem */ - { - sigset_t newset, oldset; + free(backup); - sigemptyset(&newset); - sigaddset(&newset, SIGINT); - sigprocmask(SIG_BLOCK, &newset, &oldset); + return ret; +} - opkg_state_changed++; - pkg->state_flag |= SF_FILELIST_CHANGED; +static int +backup_remove(const char *file_name) +{ + char *backup; - if (old_pkg) - pkg_remove_orphan_dependent(conf, pkg, old_pkg); + backup = backup_filename_alloc(file_name); + unlink(backup); + free(backup); - /* 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; + return 0; +} - err = prerm_upgrade_old_pkg(conf, pkg, old_pkg); - if (err) goto UNWIND_PRERM_UPGRADE_OLD_PKG; +static int +backup_modified_conffiles(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg) +{ + int err; + conffile_list_elt_t *iter; + conffile_t *cf; - err = prerm_deconfigure_conflictors(conf, pkg, replacees); - if (err) goto UNWIND_PRERM_DECONFIGURE_CONFLICTORS; + if (conf->noaction) return 0; - err = preinst_configure(conf, pkg, old_pkg); - if (err) goto UNWIND_PREINST_CONFIGURE; + /* Backup all modified conffiles */ + if (old_pkg) { + for (iter = nv_pair_list_first(&old_pkg->conffiles); iter; iter = nv_pair_list_next(&old_pkg->conffiles, iter)) { + char *cf_name; + + cf = iter->data; + cf_name = root_filename_alloc(conf, cf->name); - 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) { - opkg_message(conf, OPKG_INFO, - " not removing obsolesced files because package marked noprune\n"); - } else { - opkg_message(conf, OPKG_INFO, - " removing obsolesced files\n"); - remove_obsolesced_files(conf, pkg, old_pkg); - } - /* removing files from old package, to avoid ghost files */ - remove_data_files_and_list(conf, old_pkg); -/* Pigi : It should be better to remove also maintainer and postrem scripts here, just in case*/ - remove_maintainer_scripts_except_postrm(conf, old_pkg); - remove_postrm(conf, old_pkg); -/* Pigi */ - - } - - - opkg_message(conf, OPKG_INFO, - " installing maintainer scripts\n"); - install_maintainer_scripts(conf, pkg, old_pkg); - - /* the following just returns 0 */ - remove_disappeared(conf, pkg); - - opkg_message(conf, OPKG_INFO, - " installing data files\n"); - install_data_files(conf, pkg); - -/* read comments from function for detail but I will execute this here as all other tests are ok.*/ - err = check_data_file_clashes_change(conf, pkg, old_pkg); - - opkg_message(conf, OPKG_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; - opkg_message(conf, OPKG_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); - - ab_pkg = pkg->parent; - if (ab_pkg) - ab_pkg->state_status = pkg->state_status; - - opkg_message(conf, OPKG_INFO, "Done.\n"); - - sigprocmask(SIG_UNBLOCK, &newset, &oldset); - pkg_vec_free (replacees); - 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); - - opkg_message(conf, OPKG_INFO, - "Failed.\n"); - - sigprocmask(SIG_UNBLOCK, &newset, &oldset); - - pkg_vec_free (replacees); - return OPKG_ERR_UNKNOWN; - } -} - -static int prerm_upgrade_old_pkg(opkg_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(opkg_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(opkg_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(opkg_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(opkg_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 = xstrdup("install"); - } - - err = pkg_run_script(conf, pkg, "preinst", preinst_args); - if (err) { - opkg_message(conf, OPKG_ERROR, - "Aborting installation of %s\n", pkg->name); - return 1; - } - - free(preinst_args); - - return 0; -} - -static int preinst_configure_unwind(opkg_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(opkg_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 = nv_pair_list_first(&old_pkg->conffiles); iter; iter = nv_pair_list_next(&old_pkg->conffiles, iter)) { - 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); - } - } + /* 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 = nv_pair_list_first(&pkg->conffiles); iter; iter = nv_pair_list_next(&pkg->conffiles, iter)) { @@ -1213,7 +717,8 @@ static int backup_modified_conffiles(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_p return 0; } -static int backup_modified_conffiles_unwind(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg) +static int +backup_modified_conffiles_unwind(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg) { conffile_list_elt_t *iter; @@ -1231,7 +736,8 @@ static int backup_modified_conffiles_unwind(opkg_conf_t *conf, pkg_t *pkg, pkg_t } -static int check_data_file_clashes(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg) +static int +check_data_file_clashes(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg) { /* DPKG_INCOMPATIBILITY: opkg takes a slightly different approach than dpkg at this @@ -1325,7 +831,8 @@ static int check_data_file_clashes(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg return clashes; } -static int check_data_file_clashes_change(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg) +static int +check_data_file_clashes_change(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg) { /* Basically that's the worst hack I could do to be able to change ownership of file list, but, being that we have no way to unwind the mods, due to structure @@ -1386,13 +893,15 @@ static int check_data_file_clashes_change(opkg_conf_t *conf, pkg_t *pkg, pkg_t * return clashes; } -static int check_data_file_clashes_unwind(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg) +static int +check_data_file_clashes_unwind(opkg_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(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg) +static int +postrm_upgrade_old_pkg(opkg_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 @@ -1404,7 +913,8 @@ static int postrm_upgrade_old_pkg(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg) return 0; } -static int postrm_upgrade_old_pkg_unwind(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg) +static int +postrm_upgrade_old_pkg_unwind(opkg_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? @@ -1413,7 +923,8 @@ static int postrm_upgrade_old_pkg_unwind(opkg_conf_t *conf, pkg_t *pkg, pkg_t *o return 0; } -static int remove_obsolesced_files(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg) +static int +remove_obsolesced_files(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg) { int err; str_list_t *old_files; @@ -1472,7 +983,8 @@ static int remove_obsolesced_files(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg return 0; } -static int install_maintainer_scripts(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg) +static int +install_maintainer_scripts(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_pkg) { int ret; char *prefix; @@ -1485,7 +997,8 @@ static int install_maintainer_scripts(opkg_conf_t *conf, pkg_t *pkg, pkg_t *old_ return ret; } -static int remove_disappeared(opkg_conf_t *conf, pkg_t *pkg) +static int +remove_disappeared(opkg_conf_t *conf, pkg_t *pkg) { /* DPKG_INCOMPATIBILITY: This is a fairly sophisticated dpkg operation. Shall we @@ -1505,7 +1018,8 @@ static int remove_disappeared(opkg_conf_t *conf, pkg_t *pkg) return 0; } -static int install_data_files(opkg_conf_t *conf, pkg_t *pkg) +static int +install_data_files(opkg_conf_t *conf, pkg_t *pkg) { int err; @@ -1521,185 +1035,516 @@ static int install_data_files(opkg_conf_t *conf, pkg_t *pkg) 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) ; - - opkg_message(conf, OPKG_DEBUG, " Calling pkg_write_filelist from %s\n", __FUNCTION__); - err = pkg_write_filelist(conf, pkg); - 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) ; + + opkg_message(conf, OPKG_DEBUG, " Calling pkg_write_filelist from %s\n", __FUNCTION__); + err = pkg_write_filelist(conf, pkg); + if (err) + return err; + + /* XXX: FEATURE: opkg 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 opkg to install + a clashing package with a user force. */ + + 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 (response == NULL) + return 1; + + if (strcmp(response, "y") == 0 + || strcmp(response, "i") == 0 + || strcmp(response, "yes") == 0) { + free(response); + return 0; + } + + if (strcmp(response, "d") == 0) { + const char *argv[] = {"diff", "-u", backup, file_name, NULL}; + xsystem(argv); + printf(" [Press ENTER to continue]\n"); + response = file_read_line_alloc(stdin); + free(response); + continue; + } + + free(response); + return 1; + } +} + +static int +resolve_conffiles(opkg_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 = nv_pair_list_first(&pkg->conffiles); iter; iter = nv_pair_list_next(&pkg->conffiles, iter)) { + char *root_filename; + cf = (conffile_t *)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 (md5sum && cf->value && strcmp(cf->value,md5sum) != 0 ) { + if (conf->force_maintainer) { + opkg_message(conf, OPKG_NOTICE, "Conffile %s using maintainer's setting.\n", cf_backup); + } else if (conf->force_defaults + || user_prefers_old_conffile(root_filename, cf_backup) ) { + rename(cf_backup, root_filename); + } + } + unlink(cf_backup); + if (md5sum) + free(md5sum); + } + + free(cf_backup); + free(root_filename); + } + + return 0; +} + + +opkg_error_t +opkg_install_by_name(opkg_conf_t *conf, const char *pkg_name) +{ + int cmp, err = 0; + pkg_t *old, *new; + char *old_version, *new_version; + + opkg_message(conf, OPKG_DEBUG2, " Getting old from pkg_hash_fetch \n" ); + old = pkg_hash_fetch_installed_by_name(&conf->pkg_hash, pkg_name); + if ( old ) + opkg_message(conf, OPKG_DEBUG2, " Old versions from pkg_hash_fetch %s \n", old->version ); + + opkg_message(conf, OPKG_DEBUG2, " Getting new from pkg_hash_fetch \n" ); + new = pkg_hash_fetch_best_installation_candidate_by_name(conf, pkg_name, &err); + if ( new ) + opkg_message(conf, OPKG_DEBUG2, " New versions from pkg_hash_fetch %s \n", new->version ); + +/* Pigi Basically here is broken the version stuff. + What's happening is that nothing provide the version to differents + functions, so the returned struct is always the latest. + That's why the install by name don't work. +*/ + opkg_message(conf, OPKG_DEBUG2, " Versions from pkg_hash_fetch in %s ", __FUNCTION__ ); + + if ( old ) + opkg_message(conf, OPKG_DEBUG2, " old %s ", old->version ); + if ( new ) + opkg_message(conf, OPKG_DEBUG2, " new %s ", new->version ); + opkg_message(conf, OPKG_DEBUG2, " \n"); + + if (new == NULL) { + if (err) + return err; + else + return OPKG_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 */ + opkg_message(conf, OPKG_DEBUG, " Forcing downgrade \n"); + cmp = -1 ; /* then we force opkg 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 */ + } + opkg_message(conf, OPKG_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) { + opkg_message(conf, OPKG_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) { + opkg_message(conf, OPKG_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 */ + } + free(old_version); + free(new_version); + } + + /* XXX: CLEANUP: The error code of opkg_install_by_name is really + supposed to be an opkg_error_t, but opkg_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 libopkg. */ + + opkg_message(conf, OPKG_DEBUG2,"Function: %s calling opkg_install_pkg \n",__FUNCTION__); + return opkg_install_pkg(conf, new,0); +} + +/** + * @brief Really install a pkg_t + */ +int +opkg_install_pkg(opkg_conf_t *conf, pkg_t *pkg, int from_upgrade) +{ + int err = 0; + int message = 0; + pkg_t *old_pkg = NULL; + pkg_vec_t *replacees; + abstract_pkg_t *ab_pkg = NULL; + int old_state_flag; + char* file_md5; +#ifdef HAVE_SHA256 + char* file_sha256; +#endif + + if ( from_upgrade ) + message = 1; /* Coming from an upgrade, and should change the output message */ + + if (!pkg) { + opkg_message(conf, OPKG_ERROR, + "INTERNAL ERROR: null pkg passed to opkg_install_pkg\n"); + return OPKG_INSTALL_ERR_INTERNAL; + } + + opkg_message(conf, OPKG_DEBUG2, "Function: %s calling pkg_arch_supported %s \n", __FUNCTION__, __FUNCTION__); + + if (!pkg_arch_supported(conf, pkg)) { + opkg_message(conf, OPKG_ERROR, "INTERNAL ERROR: architecture %s for pkg %s is unsupported.\n", + pkg->architecture, pkg->name); + return OPKG_INSTALL_ERR_INTERNAL; + } + if (pkg->state_status == SS_INSTALLED && conf->force_reinstall == 0 && conf->nodeps == 0) { + err = satisfy_dependencies_for(conf, pkg); + if (err) { return OPKG_INSTALL_ERR_DEPENDENCIES; } + + opkg_message(conf, OPKG_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 = opkg_install_check_downgrade(conf, pkg, old_pkg, message); + if (err) { return OPKG_INSTALL_ERR_NO_DOWNGRADE; } + + 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 OPKG_INSTALL_ERR_CONFLICTS; } + + /* 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 OPKG_INSTALL_ERR_NO_SPACE; } + + if (pkg->local_filename == NULL) { + err = opkg_download_pkg(conf, pkg, conf->tmp_dir); + if (err) { + opkg_message(conf, OPKG_ERROR, + "Failed to download %s. Perhaps you need to run 'opkg update'?\n", + pkg->name); + return OPKG_INSTALL_ERR_DOWNLOAD; + } + } + + /* check that the repository is valid */ + #if defined(HAVE_GPGME) || defined(HAVE_OPENSSL) + char *list_file_name, *sig_file_name, *lists_dir; + + /* check to ensure the package has come from a repository */ + if (conf->check_signature && pkg->src) + { + sprintf_alloc (&lists_dir, "%s", + (conf->restrict_to_default_dest) + ? conf->default_dest->lists_dir + : conf->lists_dir); + sprintf_alloc (&list_file_name, "%s/%s", lists_dir, pkg->src->name); + sprintf_alloc (&sig_file_name, "%s/%s.sig", lists_dir, pkg->src->name); + + if (file_exists (sig_file_name)) + { + if (opkg_verify_file (conf, list_file_name, sig_file_name)){ + opkg_message(conf, OPKG_ERROR, "Failed to verify the signature of: %s\n", + list_file_name); + return OPKG_INSTALL_ERR_SIGNATURE; + } + }else{ + opkg_message(conf, OPKG_ERROR, "Signature file is missing. " + "Perhaps you need to run 'opkg update'?\n"); + return OPKG_INSTALL_ERR_SIGNATURE; + } + + free (lists_dir); + free (list_file_name); + free (sig_file_name); + } + #endif + + /* Check for md5 values */ + if (pkg->md5sum) + { + file_md5 = file_md5sum_alloc(pkg->local_filename); + if (file_md5 && strcmp(file_md5, pkg->md5sum)) + { + opkg_message(conf, OPKG_ERROR, + "Package %s md5sum mismatch. Either the opkg or the package index are corrupt. Try 'opkg update'.\n", + pkg->name); + free(file_md5); + return OPKG_INSTALL_ERR_MD5; + } + if (file_md5) + free(file_md5); + } + +#ifdef HAVE_SHA256 + /* Check for sha256 value */ + if(pkg->sha256sum) + { + file_sha256 = file_sha256sum_alloc(pkg->local_filename); + if (file_sha256 && strcmp(file_sha256, pkg->sha256sum)) + { + opkg_message(conf, OPKG_ERROR, + "Package %s sha256sum mismatch. Either the opkg or the package index are corrupt. Try 'opkg update'.\n", + pkg->name); + free(file_sha256); + return OPKG_INSTALL_ERR_SHA256; + } + if (file_sha256) + free(file_sha256); + } +#endif + + if (pkg->tmp_unpack_dir == NULL) { + unpack_pkg_control_files(conf, pkg); + } - /* XXX: FEATURE: opkg 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 opkg to install - a clashing package with a user force. */ + /* We should update the filelist here, so that upgrades of packages that split will not fail. -Jamey 27-MAR-03 */ +/* Pigi: check if it will pass from here when replacing. It seems to fail */ +/* That's rather strange that files don't change owner. Investigate !!!!!!*/ + err = update_file_ownership(conf, pkg, old_pkg); + if (err) { return OPKG_ERR_UNKNOWN; } - return 0; -} + if (conf->nodeps == 0) { + err = satisfy_dependencies_for(conf, pkg); + if (err) { return OPKG_INSTALL_ERR_DEPENDENCIES; } + if (pkg->state_status == SS_UNPACKED) + /* Circular dependency has installed it for us. */ + return 0; + } -static int resolve_conffiles(opkg_conf_t *conf, pkg_t *pkg) -{ - conffile_list_elt_t *iter; - conffile_t *cf; - char *cf_backup; - char *md5sum; + replacees = pkg_vec_alloc(); + pkg_get_installed_replacees(conf, pkg, replacees); - if (conf->noaction) return 0; + /* this next section we do with SIGINT blocked to prevent inconsistency between opkg database and filesystem */ + { + sigset_t newset, oldset; - for (iter = nv_pair_list_first(&pkg->conffiles); iter; iter = nv_pair_list_next(&pkg->conffiles, iter)) { - char *root_filename; - cf = (conffile_t *)iter->data; - root_filename = root_filename_alloc(conf, cf->name); + sigemptyset(&newset); + sigaddset(&newset, SIGINT); + sigprocmask(SIG_BLOCK, &newset, &oldset); - /* Might need to initialize the md5sum for each conffile */ - if (cf->value == NULL) { - cf->value = file_md5sum_alloc(root_filename); - } + opkg_state_changed++; + pkg->state_flag |= SF_FILELIST_CHANGED; - if (!file_exists(root_filename)) { - free(root_filename); - continue; - } + if (old_pkg) + pkg_remove_orphan_dependent(conf, pkg, old_pkg); - cf_backup = backup_filename_alloc(root_filename); + /* 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; - if (file_exists(cf_backup)) { - /* Let's compute md5 to test if files are changed */ - md5sum = file_md5sum_alloc(cf_backup); - if (md5sum && cf->value && strcmp(cf->value,md5sum) != 0 ) { - if (conf->force_maintainer) { - opkg_message(conf, OPKG_NOTICE, "Conffile %s using maintainer's setting.\n", cf_backup); - } else if (conf->force_defaults - || user_prefers_old_conffile(root_filename, cf_backup) ) { - rename(cf_backup, root_filename); - } - } - unlink(cf_backup); - if (md5sum) - free(md5sum); - } + err = prerm_deconfigure_conflictors(conf, pkg, replacees); + if (err) goto UNWIND_PRERM_DECONFIGURE_CONFLICTORS; - free(cf_backup); - free(root_filename); - } + err = preinst_configure(conf, pkg, old_pkg); + if (err) goto UNWIND_PREINST_CONFIGURE; - return 0; -} + err = backup_modified_conffiles(conf, pkg, old_pkg); + if (err) goto UNWIND_BACKUP_MODIFIED_CONFFILES; -static int user_prefers_old_conffile(const char *file_name, const char *backup) -{ - char *response; - const char *short_file_name; + err = check_data_file_clashes(conf, pkg, old_pkg); + if (err) goto UNWIND_CHECK_DATA_FILE_CLASHES; - short_file_name = strrchr(file_name, '/'); - if (short_file_name) { - short_file_name++; - } else { - short_file_name = file_name; - } + err = postrm_upgrade_old_pkg(conf, pkg, old_pkg); + if (err) goto UNWIND_POSTRM_UPGRADE_OLD_PKG; - 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 (conf->noaction) return 0; - if (response == NULL) - return 1; + /* point of no return: no unwinding after this */ + if (old_pkg && !conf->force_reinstall) { + old_pkg->state_want = SW_DEINSTALL; - if (strcmp(response, "y") == 0 - || strcmp(response, "i") == 0 - || strcmp(response, "yes") == 0) { - free(response); - return 0; - } + if (old_pkg->state_flag & SF_NOPRUNE) { + opkg_message(conf, OPKG_INFO, + " not removing obsolesced files because package marked noprune\n"); + } else { + opkg_message(conf, OPKG_INFO, + " removing obsolesced files\n"); + remove_obsolesced_files(conf, pkg, old_pkg); + } - if (strcmp(response, "d") == 0) { - const char *argv[] = {"diff", "-u", backup, file_name, NULL}; - xsystem(argv); - printf(" [Press ENTER to continue]\n"); - response = file_read_line_alloc(stdin); - free(response); - continue; + /* removing files from old package, to avoid ghost files */ + remove_data_files_and_list(conf, old_pkg); + remove_maintainer_scripts(conf, old_pkg); } - free(response); - return 1; - } -} -static char *backup_filename_alloc(const char *file_name) -{ - char *backup; + opkg_message(conf, OPKG_INFO, + " installing maintainer scripts\n"); + install_maintainer_scripts(conf, pkg, old_pkg); - sprintf_alloc(&backup, "%s%s", file_name, OPKG_BACKUP_SUFFIX); + /* the following just returns 0 */ + remove_disappeared(conf, pkg); - return backup; -} + opkg_message(conf, OPKG_INFO, + " installing data files\n"); + install_data_files(conf, pkg); -int backup_make_backup(opkg_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) { - opkg_message(conf, OPKG_ERROR, - "%s: Failed to copy %s to %s\n", - __FUNCTION__, file_name, backup); - } +/* read comments from function for detail but I will execute this here as all other tests are ok.*/ + err = check_data_file_clashes_change(conf, pkg, old_pkg); - free(backup); + opkg_message(conf, OPKG_INFO, + " resolving conf files\n"); + resolve_conffiles(conf, pkg); - return err; -} + pkg->state_status = SS_UNPACKED; + old_state_flag = pkg->state_flag; + pkg->state_flag &= ~SF_PREFER; + opkg_message(conf, OPKG_DEBUG, " pkg=%s old_state_flag=%x state_flag=%x\n", pkg->name, old_state_flag, pkg->state_flag); -static int backup_exists_for(const char *file_name) -{ - int ret; - char *backup; + if (old_pkg && !conf->force_reinstall) { + old_pkg->state_status = SS_NOT_INSTALLED; + } - backup = backup_filename_alloc(file_name); + time(&pkg->installed_time); - ret = file_exists(backup); + ab_pkg = pkg->parent; + if (ab_pkg) + ab_pkg->state_status = pkg->state_status; - free(backup); + opkg_message(conf, OPKG_INFO, "Done.\n"); - return ret; -} + sigprocmask(SIG_UNBLOCK, &newset, &oldset); + pkg_vec_free (replacees); + return 0; + -static int backup_remove(const char *file_name) -{ - char *backup; + 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); - backup = backup_filename_alloc(file_name); - unlink(backup); - free(backup); + opkg_message(conf, OPKG_INFO, + "Failed.\n"); - return 0; -} + sigprocmask(SIG_UNBLOCK, &newset, &oldset); + pkg_vec_free (replacees); + return OPKG_ERR_UNKNOWN; + } +}