diff --git a/src/Makefile b/src/Makefile index e0e97f1..9f3249d 100644 --- a/src/Makefile +++ b/src/Makefile @@ -7,7 +7,7 @@ endif progs-y += apk apk-objs := state.o database.o package.o archive.o \ version.o io.o url.o gunzip.o blob.o hash.o apk.o \ - add.o del.o update.o info.o search.o upgrade.o \ + add.o del.o fix.o update.o info.o search.o upgrade.o \ cache.o ver.o index.o fetch.o audit.o verify.o CFLAGS += -D_ATFILE_SOURCE CFLAGS_apk.o := -DAPK_VERSION=\"$(FULL_VERSION)\" diff --git a/src/apk_database.h b/src/apk_database.h index 094725d..1ded91e 100644 --- a/src/apk_database.h +++ b/src/apk_database.h @@ -63,6 +63,7 @@ struct apk_db_dir_instance { }; #define APK_NAME_TOPLEVEL 0x0001 +#define APK_NAME_REINSTALL 0x0002 struct apk_name { apk_hash_node hash_node; diff --git a/src/database.c b/src/database.c index 9a09ecd..804e6c4 100644 --- a/src/database.c +++ b/src/database.c @@ -1425,6 +1425,7 @@ static int apk_db_install_archive_entry(void *_ctx, return -1; } + opkg = NULL; file = apk_db_file_query(db, bdir, bfile); if (file != NULL) { opkg = file->diri->pkg; @@ -1442,8 +1443,10 @@ static int apk_db_install_archive_entry(void *_ctx, } } - /* Create the file entry without adding it to hash */ - file = apk_db_file_new(diri, bfile, &ctx->file_diri_node); + if (opkg != pkg) { + /* Create the file entry without adding it to hash */ + file = apk_db_file_new(diri, bfile, &ctx->file_diri_node); + } if (apk_verbosity >= 3) apk_message("%s", ae->name); @@ -1555,7 +1558,7 @@ static void apk_db_migrate_files(struct apk_database *db, struct apk_file_info fi; struct hlist_node *dc, *dn, *fc, *fn; unsigned long hash; - char name[1024], tmpname[1024]; + char name[PATH_MAX], tmpname[PATH_MAX]; int cstype, r; hlist_for_each_entry_safe(diri, dc, dn, &pkg->owned_dirs, pkg_dirs_list) { @@ -1610,22 +1613,25 @@ static void apk_db_migrate_files(struct apk_database *db, } /* Claim ownership of the file in db */ - if (ofile != NULL) { - hlist_del(&ofile->diri_files_list, - &ofile->diri->owned_files); - apk_hash_delete_hashed(&db->installed.files, - APK_BLOB_BUF(&key), hash); - } else - db->installed.stats.files++; + if (ofile != file) { + if (ofile != NULL) { + hlist_del(&ofile->diri_files_list, + &ofile->diri->owned_files); + apk_hash_delete_hashed(&db->installed.files, + APK_BLOB_BUF(&key), hash); + } else + db->installed.stats.files++; - apk_hash_insert_hashed(&db->installed.files, file, hash); + apk_hash_insert_hashed(&db->installed.files, file, hash); + } } } } static int apk_db_unpack_pkg(struct apk_database *db, struct apk_package *newpkg, - int upgrade, apk_progress_cb cb, void *cb_ctx) + int upgrade, int reinstall, + apk_progress_cb cb, void *cb_ctx) { struct install_ctx ctx; struct apk_bstream *bs = NULL; @@ -1706,7 +1712,8 @@ static int apk_db_unpack_pkg(struct apk_database *db, return 0; err: - apk_db_purge_pkg(db, newpkg, ".apk-new"); + if (!reinstall) + apk_db_purge_pkg(db, newpkg, ".apk-new"); return r; } @@ -1733,14 +1740,14 @@ int apk_db_install_pkg(struct apk_database *db, /* Install the new stuff */ if (newpkg->installed_size != 0) { - r = apk_db_unpack_pkg(db, newpkg, (oldpkg != NULL), cb, cb_ctx); + r = apk_db_unpack_pkg(db, newpkg, (oldpkg != NULL), + (oldpkg == newpkg), cb, cb_ctx); if (r != 0) return r; } apk_pkg_set_state(db, newpkg, APK_PKG_INSTALLED); - - if (oldpkg != NULL) + if (oldpkg != NULL && oldpkg != newpkg) apk_db_purge_pkg(db, oldpkg, NULL); r = apk_pkg_run_script(newpkg, db->root_fd, diff --git a/src/fix.c b/src/fix.c new file mode 100644 index 0000000..3086428 --- /dev/null +++ b/src/fix.c @@ -0,0 +1,113 @@ +/* fix.c - Alpine Package Keeper (APK) + * + * Copyright (C) 2005-2008 Natanael Copa + * Copyright (C) 2008 Timo Teräs + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. See http://www.gnu.org/ for details. + */ + +#include +#include +#include "apk_applet.h" +#include "apk_database.h" +#include "apk_state.h" + +struct fix_ctx { + unsigned int reinstall : 1; +}; + +static int fix_parse(void *pctx, int optch, int optindex, const char *optarg) +{ + struct fix_ctx *ctx = (struct fix_ctx *) pctx; + switch (optch) { + case 'u': + apk_flags |= APK_UPGRADE; + break; + case 'r': + ctx->reinstall = 1; + break; + default: + return -1; + } + return 0; +} + +static int fix_main(void *pctx, int argc, char **argv) +{ + struct fix_ctx *ctx = (struct fix_ctx *) pctx; + struct apk_database db; + struct apk_state *state = NULL; + struct apk_name *name; + int r, i, j; + + r = apk_db_open(&db, apk_root, APK_OPENF_WRITE); + if (r != 0) + return r; + + state = apk_state_new(&db); + if (state == NULL) + goto err; + + for (i = 0; i < argc; i++) { + name = apk_db_get_name(&db, APK_BLOB_STR(argv[i])); + if (name == NULL) + goto err; + + for (j = 0; j < name->pkgs->num; j++) { + if (apk_pkg_get_state(name->pkgs->item[j]) == APK_PKG_INSTALLED) + break; + } + if (j >= name->pkgs->num) { + apk_error("Package '%s' is not installed", name->name); + goto err; + } + + if (ctx->reinstall) + name->flags |= APK_NAME_REINSTALL; + } + + for (i = 0; i < argc; i++) { + struct apk_dependency dep; + + r = apk_dep_from_blob(&dep, &db, APK_BLOB_STR(argv[i])); + if (r != 0) + goto err; + + r = apk_state_lock_dependency(state, &dep); + if (r != 0) { + if (!(apk_flags & APK_FORCE)) + goto err; + } + } + r = apk_state_commit(state, &db); +err: + if (r != 0 && i < argc) + apk_error("Error while processing '%s'", argv[i]); + if (state != NULL) + apk_state_unref(state); + apk_db_close(&db); + return r; +} + +static struct apk_option fix_options[] = { + { 'u', "upgrade", "Upgrade package if possible" }, + { 'r', "reinstall", "Reinstall the package" }, +}; + +static struct apk_applet apk_fix = { + .name = "fix", + .help = "Repair package or upgrade it without modifying main " + "dependencies.", + .arguments = "PACKAGE...", + .context_size = sizeof(struct fix_ctx), + .num_options = ARRAY_SIZE(fix_options), + .options = fix_options, + .parse = fix_parse, + .main = fix_main, +}; + +APK_DEFINE_APPLET(apk_fix); + diff --git a/src/state.c b/src/state.c index 28a411f..c723460 100644 --- a/src/state.c +++ b/src/state.c @@ -319,7 +319,9 @@ int apk_state_lock_dependency(struct apk_state *state, if (apk_flags & APK_UPGRADE) { use = latest; } else { - if (installed != NULL) + if (installed != NULL && + (installed->repos != 0 || + !(name->flags & APK_NAME_REINSTALL))) use = installed; else use = latest; @@ -500,7 +502,7 @@ int apk_state_lock_name(struct apk_state *state, } /* If the chosen package is installed, all is done here */ - if (oldpkg == newpkg) + if (oldpkg == newpkg && !(newpkg->name->flags & APK_NAME_REINSTALL)) return 0; /* Track change */