From 60b87557e57ca4e23126bf8c25b1cb978e380dfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Fri, 14 Feb 2020 13:49:41 +0200 Subject: rename all applets sources to app_*.c --- src/Makefile | 10 +- src/add.c | 207 ----------------------- src/app_add.c | 207 +++++++++++++++++++++++ src/app_audit.c | 357 +++++++++++++++++++++++++++++++++++++++ src/app_cache.c | 193 +++++++++++++++++++++ src/app_del.c | 178 +++++++++++++++++++ src/app_dot.c | 179 ++++++++++++++++++++ src/app_fetch.c | 355 ++++++++++++++++++++++++++++++++++++++ src/app_fix.c | 127 ++++++++++++++ src/app_index.c | 265 +++++++++++++++++++++++++++++ src/app_info.c | 488 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/app_list.c | 272 +++++++++++++++++++++++++++++ src/app_manifest.c | 133 +++++++++++++++ src/app_policy.c | 80 +++++++++ src/app_search.c | 217 ++++++++++++++++++++++++ src/app_stats.c | 64 +++++++ src/app_update.c | 57 +++++++ src/app_upgrade.c | 198 ++++++++++++++++++++++ src/app_verify.c | 59 +++++++ src/app_version.c | 207 +++++++++++++++++++++++ src/audit.c | 357 --------------------------------------- src/cache.c | 193 --------------------- src/del.c | 178 ------------------- src/dot.c | 179 -------------------- src/fetch.c | 355 -------------------------------------- src/fix.c | 127 -------------- src/index.c | 265 ----------------------------- src/info.c | 488 ----------------------------------------------------- src/list.c | 272 ----------------------------- src/manifest.c | 133 --------------- src/policy.c | 80 --------- src/search.c | 217 ------------------------ src/stats.c | 64 ------- src/update.c | 57 ------- src/upgrade.c | 198 ---------------------- src/ver.c | 207 ----------------------- src/verify.c | 59 ------- 37 files changed, 3643 insertions(+), 3639 deletions(-) delete mode 100644 src/add.c create mode 100644 src/app_add.c create mode 100644 src/app_audit.c create mode 100644 src/app_cache.c create mode 100644 src/app_del.c create mode 100644 src/app_dot.c create mode 100644 src/app_fetch.c create mode 100644 src/app_fix.c create mode 100644 src/app_index.c create mode 100644 src/app_info.c create mode 100644 src/app_list.c create mode 100644 src/app_manifest.c create mode 100644 src/app_policy.c create mode 100644 src/app_search.c create mode 100644 src/app_stats.c create mode 100644 src/app_update.c create mode 100644 src/app_upgrade.c create mode 100644 src/app_verify.c create mode 100644 src/app_version.c delete mode 100644 src/audit.c delete mode 100644 src/cache.c delete mode 100644 src/del.c delete mode 100644 src/dot.c delete mode 100644 src/fetch.c delete mode 100644 src/fix.c delete mode 100644 src/index.c delete mode 100644 src/info.c delete mode 100644 src/list.c delete mode 100644 src/manifest.c delete mode 100644 src/policy.c delete mode 100644 src/search.c delete mode 100644 src/stats.c delete mode 100644 src/update.c delete mode 100644 src/upgrade.c delete mode 100644 src/ver.c delete mode 100644 src/verify.c diff --git a/src/Makefile b/src/Makefile index 52ea1b2..36242d7 100644 --- a/src/Makefile +++ b/src/Makefile @@ -23,9 +23,13 @@ install-LUA_LIB-y := $(INSTALLDIR) $(DESTDIR)$(LUA_LIBDIR) && \ endif progs-y += apk -apk-objs := apk.o add.o del.o fix.o update.o info.o list.o \ - search.o upgrade.o cache.o ver.o index.o fetch.o \ - audit.o verify.o dot.o policy.o stats.o manifest.o +apk-objs := apk.o \ + app_add.o app_del.o app_fix.o app_update.o app_upgrade.o \ + app_info.o app_list.o app_search.o app_manifest.o \ + app_policy.o app_stats.o \ + app_cache.o app_version.o \ + app_index.o app_fetch.o app_verify.o app_dot.o \ + app_audit.o libapk.so-objs := common.o database.o package.o archive.o \ version.o io.o url.o gunzip.o blob.o hash.o print.o \ diff --git a/src/add.c b/src/add.c deleted file mode 100644 index 4ca1dc5..0000000 --- a/src/add.c +++ /dev/null @@ -1,207 +0,0 @@ -/* add.c - Alpine Package Keeper (APK) - * - * Copyright (C) 2005-2008 Natanael Copa - * Copyright (C) 2008-2011 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 -#include "apk_applet.h" -#include "apk_database.h" -#include "apk_print.h" -#include "apk_solver.h" - -struct add_ctx { - const char *virtpkg; - unsigned short solver_flags; -}; - -static int option_parse_applet(void *ctx, struct apk_db_options *dbopts, int optch, const char *optarg) -{ - struct add_ctx *actx = (struct add_ctx *) ctx; - - switch (optch) { - case 0x10000: - dbopts->open_flags |= APK_OPENF_CREATE; - break; - case 'u': - actx->solver_flags |= APK_SOLVERF_UPGRADE; - break; - case 'l': - actx->solver_flags |= APK_SOLVERF_LATEST; - break; - case 't': - actx->virtpkg = optarg; - break; - default: - return -ENOTSUP; - } - return 0; -} - -static const struct apk_option options_applet[] = { - { 0x10000, "initdb" }, - { 'u', "upgrade" }, - { 'l', "latest" }, - { 't', "virtual", required_argument, "NAME" }, -}; - -static const struct apk_option_group optgroup_applet = { - .name = "Add", - .options = options_applet, - .num_options = ARRAY_SIZE(options_applet), - .parse = option_parse_applet, -}; - -static int non_repository_check(struct apk_database *db) -{ - if (apk_force & APK_FORCE_NON_REPOSITORY) - return 0; - if (apk_db_cache_active(db)) - return 0; - if (apk_db_permanent(db)) - return 0; - - apk_error("You tried to add a non-repository package to system, " - "but it would be lost on next reboot. Enable package caching " - "(apk cache --help) or use --force-non-repository " - "if you know what you are doing."); - return 1; -} - -static struct apk_package *create_virtual_package(struct apk_database *db, struct apk_name *name) -{ - char ver[32]; - struct apk_package *virtpkg; - struct tm tm; - EVP_MD_CTX *mdctx; - time_t now = time(NULL); - pid_t pid = getpid(); - - gmtime_r(&now, &tm); - strftime(ver, sizeof ver, "%Y%m%d.%H%M%S", &tm); - - virtpkg = apk_pkg_new(); - if (virtpkg == NULL) return 0; - - virtpkg->name = name; - virtpkg->version = apk_blob_atomize_dup(APK_BLOB_STR(ver)); - virtpkg->description = strdup("virtual meta package"); - virtpkg->arch = apk_blob_atomize(APK_BLOB_STR("noarch")); - - mdctx = EVP_MD_CTX_new(); - EVP_DigestInit_ex(mdctx, apk_checksum_default(), NULL); - EVP_DigestUpdate(mdctx, &tm, sizeof tm); - EVP_DigestUpdate(mdctx, &pid, sizeof pid); - EVP_DigestUpdate(mdctx, virtpkg->name->name, strlen(virtpkg->name->name) + 1); - virtpkg->csum.type = EVP_MD_CTX_size(mdctx); - EVP_DigestFinal_ex(mdctx, virtpkg->csum.data, NULL); - EVP_MD_CTX_free(mdctx); - - return virtpkg; -} - -static int add_main(void *ctx, struct apk_database *db, struct apk_string_array *args) -{ - struct add_ctx *actx = (struct add_ctx *) ctx; - struct apk_package *virtpkg = NULL; - struct apk_dependency virtdep; - struct apk_dependency_array *world = NULL; - char **parg; - int r = 0; - - apk_dependency_array_copy(&world, db->world); - - if (actx->virtpkg) { - apk_blob_t b = APK_BLOB_STR(actx->virtpkg); - apk_blob_pull_dep(&b, db, &virtdep); - if (APK_BLOB_IS_NULL(b) || virtdep.conflict || - virtdep.result_mask != APK_DEPMASK_ANY || - virtdep.version != &apk_null_blob) { - apk_error("%s: bad package specifier"); - return -1; - } - if (virtdep.name->name[0] != '.' && non_repository_check(db)) - return -1; - - virtpkg = create_virtual_package(db, virtdep.name); - if (!virtpkg) { - apk_error("Failed to allocate virtual meta package"); - return -1; - } - - virtdep.result_mask = APK_VERSION_EQUAL; - virtdep.version = virtpkg->version; - } - - foreach_array_item(parg, args) { - struct apk_dependency dep; - - if (strstr(*parg, ".apk") != NULL) { - struct apk_package *pkg = NULL; - struct apk_sign_ctx sctx; - - if (non_repository_check(db)) - return -1; - - apk_sign_ctx_init(&sctx, APK_SIGN_VERIFY_AND_GENERATE, - NULL, db->keys_fd); - r = apk_pkg_read(db, *parg, &sctx, &pkg); - apk_sign_ctx_free(&sctx); - if (r != 0) { - apk_error("%s: %s", *parg, apk_error_str(r)); - return -1; - } - apk_dep_from_pkg(&dep, db, pkg); - } else { - apk_blob_t b = APK_BLOB_STR(*parg); - - apk_blob_pull_dep(&b, db, &dep); - if (APK_BLOB_IS_NULL(b) || b.len > 0 || (virtpkg != NULL && dep.repository_tag)) { - apk_error("'%s' is not a valid %s dependency, format is %s", - *parg, virtpkg == NULL ? "world" : "child", - virtpkg == NULL ? "name(@tag)([<>~=]version)" : "name([<>~=]version)"); - return -1; - } - } - - if (virtpkg == NULL) { - apk_deps_add(&world, &dep); - apk_solver_set_name_flags(dep.name, - actx->solver_flags, - actx->solver_flags); - } else { - apk_deps_add(&virtpkg->depends, &dep); - } - } - if (virtpkg) { - virtpkg = apk_db_pkg_add(db, virtpkg); - apk_deps_add(&world, &virtdep); - apk_solver_set_name_flags(virtdep.name, - actx->solver_flags, - actx->solver_flags); - } - - r = apk_solver_commit(db, 0, world); - apk_dependency_array_free(&world); - - return r; -} - -static struct apk_applet apk_add = { - .name = "add", - .arguments = "PACKAGE...", - .open_flags = APK_OPENF_WRITE, - .command_groups = APK_COMMAND_GROUP_INSTALL, - .context_size = sizeof(struct add_ctx), - .optgroups = { &optgroup_global, &optgroup_commit, &optgroup_applet }, - .main = add_main, -}; - -APK_DEFINE_APPLET(apk_add); diff --git a/src/app_add.c b/src/app_add.c new file mode 100644 index 0000000..8b0ed1a --- /dev/null +++ b/src/app_add.c @@ -0,0 +1,207 @@ +/* app_add.c - Alpine Package Keeper (APK) + * + * Copyright (C) 2005-2008 Natanael Copa + * Copyright (C) 2008-2011 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 +#include "apk_applet.h" +#include "apk_database.h" +#include "apk_print.h" +#include "apk_solver.h" + +struct add_ctx { + const char *virtpkg; + unsigned short solver_flags; +}; + +static int option_parse_applet(void *ctx, struct apk_db_options *dbopts, int optch, const char *optarg) +{ + struct add_ctx *actx = (struct add_ctx *) ctx; + + switch (optch) { + case 0x10000: + dbopts->open_flags |= APK_OPENF_CREATE; + break; + case 'u': + actx->solver_flags |= APK_SOLVERF_UPGRADE; + break; + case 'l': + actx->solver_flags |= APK_SOLVERF_LATEST; + break; + case 't': + actx->virtpkg = optarg; + break; + default: + return -ENOTSUP; + } + return 0; +} + +static const struct apk_option options_applet[] = { + { 0x10000, "initdb" }, + { 'u', "upgrade" }, + { 'l', "latest" }, + { 't', "virtual", required_argument, "NAME" }, +}; + +static const struct apk_option_group optgroup_applet = { + .name = "Add", + .options = options_applet, + .num_options = ARRAY_SIZE(options_applet), + .parse = option_parse_applet, +}; + +static int non_repository_check(struct apk_database *db) +{ + if (apk_force & APK_FORCE_NON_REPOSITORY) + return 0; + if (apk_db_cache_active(db)) + return 0; + if (apk_db_permanent(db)) + return 0; + + apk_error("You tried to add a non-repository package to system, " + "but it would be lost on next reboot. Enable package caching " + "(apk cache --help) or use --force-non-repository " + "if you know what you are doing."); + return 1; +} + +static struct apk_package *create_virtual_package(struct apk_database *db, struct apk_name *name) +{ + char ver[32]; + struct apk_package *virtpkg; + struct tm tm; + EVP_MD_CTX *mdctx; + time_t now = time(NULL); + pid_t pid = getpid(); + + gmtime_r(&now, &tm); + strftime(ver, sizeof ver, "%Y%m%d.%H%M%S", &tm); + + virtpkg = apk_pkg_new(); + if (virtpkg == NULL) return 0; + + virtpkg->name = name; + virtpkg->version = apk_blob_atomize_dup(APK_BLOB_STR(ver)); + virtpkg->description = strdup("virtual meta package"); + virtpkg->arch = apk_blob_atomize(APK_BLOB_STR("noarch")); + + mdctx = EVP_MD_CTX_new(); + EVP_DigestInit_ex(mdctx, apk_checksum_default(), NULL); + EVP_DigestUpdate(mdctx, &tm, sizeof tm); + EVP_DigestUpdate(mdctx, &pid, sizeof pid); + EVP_DigestUpdate(mdctx, virtpkg->name->name, strlen(virtpkg->name->name) + 1); + virtpkg->csum.type = EVP_MD_CTX_size(mdctx); + EVP_DigestFinal_ex(mdctx, virtpkg->csum.data, NULL); + EVP_MD_CTX_free(mdctx); + + return virtpkg; +} + +static int add_main(void *ctx, struct apk_database *db, struct apk_string_array *args) +{ + struct add_ctx *actx = (struct add_ctx *) ctx; + struct apk_package *virtpkg = NULL; + struct apk_dependency virtdep; + struct apk_dependency_array *world = NULL; + char **parg; + int r = 0; + + apk_dependency_array_copy(&world, db->world); + + if (actx->virtpkg) { + apk_blob_t b = APK_BLOB_STR(actx->virtpkg); + apk_blob_pull_dep(&b, db, &virtdep); + if (APK_BLOB_IS_NULL(b) || virtdep.conflict || + virtdep.result_mask != APK_DEPMASK_ANY || + virtdep.version != &apk_null_blob) { + apk_error("%s: bad package specifier"); + return -1; + } + if (virtdep.name->name[0] != '.' && non_repository_check(db)) + return -1; + + virtpkg = create_virtual_package(db, virtdep.name); + if (!virtpkg) { + apk_error("Failed to allocate virtual meta package"); + return -1; + } + + virtdep.result_mask = APK_VERSION_EQUAL; + virtdep.version = virtpkg->version; + } + + foreach_array_item(parg, args) { + struct apk_dependency dep; + + if (strstr(*parg, ".apk") != NULL) { + struct apk_package *pkg = NULL; + struct apk_sign_ctx sctx; + + if (non_repository_check(db)) + return -1; + + apk_sign_ctx_init(&sctx, APK_SIGN_VERIFY_AND_GENERATE, + NULL, db->keys_fd); + r = apk_pkg_read(db, *parg, &sctx, &pkg); + apk_sign_ctx_free(&sctx); + if (r != 0) { + apk_error("%s: %s", *parg, apk_error_str(r)); + return -1; + } + apk_dep_from_pkg(&dep, db, pkg); + } else { + apk_blob_t b = APK_BLOB_STR(*parg); + + apk_blob_pull_dep(&b, db, &dep); + if (APK_BLOB_IS_NULL(b) || b.len > 0 || (virtpkg != NULL && dep.repository_tag)) { + apk_error("'%s' is not a valid %s dependency, format is %s", + *parg, virtpkg == NULL ? "world" : "child", + virtpkg == NULL ? "name(@tag)([<>~=]version)" : "name([<>~=]version)"); + return -1; + } + } + + if (virtpkg == NULL) { + apk_deps_add(&world, &dep); + apk_solver_set_name_flags(dep.name, + actx->solver_flags, + actx->solver_flags); + } else { + apk_deps_add(&virtpkg->depends, &dep); + } + } + if (virtpkg) { + virtpkg = apk_db_pkg_add(db, virtpkg); + apk_deps_add(&world, &virtdep); + apk_solver_set_name_flags(virtdep.name, + actx->solver_flags, + actx->solver_flags); + } + + r = apk_solver_commit(db, 0, world); + apk_dependency_array_free(&world); + + return r; +} + +static struct apk_applet apk_add = { + .name = "add", + .arguments = "PACKAGE...", + .open_flags = APK_OPENF_WRITE, + .command_groups = APK_COMMAND_GROUP_INSTALL, + .context_size = sizeof(struct add_ctx), + .optgroups = { &optgroup_global, &optgroup_commit, &optgroup_applet }, + .main = add_main, +}; + +APK_DEFINE_APPLET(apk_add); diff --git a/src/app_audit.c b/src/app_audit.c new file mode 100644 index 0000000..696599b --- /dev/null +++ b/src/app_audit.c @@ -0,0 +1,357 @@ +/* app_audit.c - Alpine Package Keeper (APK) + * + * Copyright (C) 2005-2008 Natanael Copa + * Copyright (C) 2008-2011 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 +#include +#include +#include +#include +#include +#include "apk_applet.h" +#include "apk_database.h" +#include "apk_print.h" + +/* Use (unused) highest bit of mode_t as seen flag of our internal + * database file entries */ +#define S_SEENFLAG 0x80000000 + +enum { + MODE_BACKUP = 0, + MODE_SYSTEM +}; + +struct audit_ctx { + unsigned mode : 1; + unsigned recursive : 1; + unsigned check_permissions : 1; + unsigned packages_only : 1; +}; + +static int option_parse_applet(void *ctx, struct apk_db_options *dbopts, int optch, const char *optarg) +{ + struct audit_ctx *actx = (struct audit_ctx *) ctx; + + switch (optch) { + case 0x10000: + actx->mode = MODE_BACKUP; + break; + case 0x10001: + actx->mode = MODE_SYSTEM; + break; + case 0x10002: + actx->check_permissions = 1; + break; + case 0x10003: + actx->packages_only = 1; + break; + case 'r': + actx->recursive = 1; + break; + default: + return -ENOTSUP; + } + return 0; +} + +static const struct apk_option options_applet[] = { + { 0x10000, "backup" }, + { 0x10001, "system" }, + { 0x10002, "check-permissions" }, + { 'r', "recursive" }, + { 0x10003, "packages" }, +}; + +static const struct apk_option_group optgroup_applet = { + .name = "Audit", + .options = options_applet, + .num_options = ARRAY_SIZE(options_applet), + .parse = option_parse_applet, +}; + +struct audit_tree_ctx { + struct audit_ctx *actx; + struct apk_database *db; + struct apk_db_dir *dir; + size_t pathlen; + char path[PATH_MAX]; +}; + +static int audit_file(struct audit_ctx *actx, + struct apk_database *db, + struct apk_db_file *dbf, + int dirfd, const char *name) +{ + struct apk_file_info fi; + int rv = 0; + + if (dbf == NULL) + return 'A'; + + dbf->audited = 1; + + if (apk_fileinfo_get(dirfd, name, + APK_FI_NOFOLLOW | + APK_FI_XATTR_CSUM(dbf->acl->xattr_csum.type ?: APK_CHECKSUM_DEFAULT) | + APK_FI_CSUM(dbf->csum.type), + &fi) != 0) + return -EPERM; + + if (dbf->csum.type != APK_CHECKSUM_NONE && + apk_checksum_compare(&fi.csum, &dbf->csum) != 0) + rv = 'U'; + else if (!S_ISLNK(fi.mode) && !dbf->diri->pkg->ipkg->broken_xattr && + apk_checksum_compare(&fi.xattr_csum, &dbf->acl->xattr_csum) != 0) + rv = 'x'; + else if (S_ISLNK(fi.mode) && dbf->csum.type == APK_CHECKSUM_NONE) + rv = 'U'; + else if (actx->check_permissions) { + if ((fi.mode & 07777) != (dbf->acl->mode & 07777)) + rv = 'M'; + else if (fi.uid != dbf->acl->uid || fi.gid != dbf->acl->gid) + rv = 'M'; + } + apk_fileinfo_free(&fi); + + return rv; +} + +static int audit_directory(struct audit_ctx *actx, + struct apk_database *db, + struct apk_db_dir *dbd, + struct apk_file_info *fi) +{ + if (dbd != NULL) dbd->mode |= S_SEENFLAG; + + if (dbd == NULL || dbd->refs == 1) + return actx->recursive ? 'd' : 'D'; + + if (actx->check_permissions && + ((dbd->mode & ~S_SEENFLAG) || dbd->uid || dbd->gid)) { + if ((fi->mode & 07777) != (dbd->mode & 07777)) + return 'm'; + if (fi->uid != dbd->uid || fi->gid != dbd->gid) + return 'm'; + } + + return 0; +} + +static void report_audit(struct audit_ctx *actx, + char reason, apk_blob_t bfull, struct apk_package *pkg) +{ + if (!reason) + return; + + if (actx->packages_only) { + if (pkg == NULL || pkg->state_int != 0) + return; + pkg->state_int = 1; + if (apk_verbosity < 1) + printf("%s\n", pkg->name->name); + else + printf(PKG_VER_FMT "\n", PKG_VER_PRINTF(pkg)); + } else if (apk_verbosity < 1) { + printf(BLOB_FMT "\n", BLOB_PRINTF(bfull)); + } else + printf("%c " BLOB_FMT "\n", reason, BLOB_PRINTF(bfull)); +} + +static int audit_directory_tree_item(void *ctx, int dirfd, const char *name) +{ + struct audit_tree_ctx *atctx = (struct audit_tree_ctx *) ctx; + apk_blob_t bdir = APK_BLOB_PTR_LEN(atctx->path, atctx->pathlen); + apk_blob_t bent = APK_BLOB_STR(name); + apk_blob_t bfull; + struct audit_ctx *actx = atctx->actx; + struct apk_database *db = atctx->db; + struct apk_db_dir *dir = atctx->dir, *child = NULL; + struct apk_file_info fi; + int reason = 0; + + if (bdir.len + bent.len + 1 >= sizeof(atctx->path)) return 0; + if (apk_fileinfo_get(dirfd, name, APK_FI_NOFOLLOW, &fi) < 0) return 0; + + memcpy(&atctx->path[atctx->pathlen], bent.ptr, bent.len); + atctx->pathlen += bent.len; + bfull = APK_BLOB_PTR_LEN(atctx->path, atctx->pathlen); + + if (S_ISDIR(fi.mode)) { + int recurse = TRUE; + + if (actx->mode == MODE_BACKUP) { + child = apk_db_dir_get(db, bfull); + if (!child->has_protected_children) + recurse = FALSE; + if (child->protect_mode == APK_PROTECT_NONE) + goto recurse_check; + } else { + child = apk_db_dir_query(db, bfull); + if (child == NULL) + goto done; + child = apk_db_dir_ref(child); + } + + reason = audit_directory(actx, db, child, &fi); + if (reason < 0) + goto done; + +recurse_check: + atctx->path[atctx->pathlen++] = '/'; + bfull.len++; + report_audit(actx, reason, bfull, NULL); + if (reason != 'D' && recurse) { + atctx->dir = child; + reason = apk_dir_foreach_file( + openat(dirfd, name, O_RDONLY|O_CLOEXEC), + audit_directory_tree_item, atctx); + atctx->dir = dir; + } + bfull.len--; + atctx->pathlen--; + } else { + struct apk_db_file *dbf; + struct apk_protected_path *ppath; + int protect_mode = dir->protect_mode; + + /* inherit file's protection mask */ + foreach_array_item(ppath, dir->protected_paths) { + char *slash = strchr(ppath->relative_pattern, '/'); + if (slash == NULL) { + if (fnmatch(ppath->relative_pattern, name, FNM_PATHNAME) != 0) + continue; + protect_mode = ppath->protect_mode; + } + } + + if (actx->mode == MODE_BACKUP) { + switch (protect_mode) { + case APK_PROTECT_NONE: + goto done; + case APK_PROTECT_CHANGED: + break; + case APK_PROTECT_SYMLINKS_ONLY: + if (!S_ISLNK(fi.mode)) + goto done; + break; + case APK_PROTECT_ALL: + reason = 'A'; + break; + } + } + + dbf = apk_db_file_query(db, bdir, bent); + if (reason == 0) + reason = audit_file(actx, db, dbf, dirfd, name); + if (reason < 0) + goto done; + if (actx->mode == MODE_SYSTEM && + (reason == 'A' || protect_mode != APK_PROTECT_NONE)) + goto done; + if (actx->mode == MODE_BACKUP && + reason == 'A' && + apk_blob_ends_with(bent, APK_BLOB_STR(".apk-new"))) + goto done; + report_audit(actx, reason, bfull, dbf ? dbf->diri->pkg : NULL); + } + +done: + if (child) + apk_db_dir_unref(db, child, FALSE); + + atctx->pathlen -= bent.len; + return 0; +} + +static int audit_directory_tree(struct audit_tree_ctx *atctx, int dirfd) +{ + apk_blob_t path; + int r; + + path = APK_BLOB_PTR_LEN(atctx->path, atctx->pathlen); + if (path.len && path.ptr[path.len-1] == '/') + path.len--; + + atctx->dir = apk_db_dir_get(atctx->db, path); + atctx->dir->mode |= S_SEENFLAG; + r = apk_dir_foreach_file(dirfd, audit_directory_tree_item, atctx); + apk_db_dir_unref(atctx->db, atctx->dir, FALSE); + + return r; +} + +static int audit_missing_files(apk_hash_item item, void *pctx) +{ + struct audit_ctx *actx = pctx; + struct apk_db_file *file = item; + struct apk_db_dir *dir; + char path[PATH_MAX]; + int len; + + if (file->audited) return 0; + + dir = file->diri->dir; + if (dir->mode & S_SEENFLAG) { + len = snprintf(path, sizeof(path), DIR_FILE_FMT, DIR_FILE_PRINTF(dir, file)); + report_audit(actx, 'X', APK_BLOB_PTR_LEN(path, len), file->diri->pkg); + } + + return 0; +} + +static int audit_main(void *ctx, struct apk_database *db, struct apk_string_array *args) +{ + struct audit_tree_ctx atctx; + struct audit_ctx *actx = (struct audit_ctx *) ctx; + char **parg, *arg; + int r = 0; + + atctx.db = db; + atctx.actx = actx; + atctx.pathlen = 0; + atctx.path[0] = 0; + + if (args->num == 0) { + r |= audit_directory_tree(&atctx, dup(db->root_fd)); + } else { + foreach_array_item(parg, args) { + arg = *parg; + if (arg[0] != '/') { + apk_warning("%s: relative path skipped.\n", arg); + continue; + } + arg++; + atctx.pathlen = strlen(arg); + memcpy(atctx.path, arg, atctx.pathlen); + if (atctx.path[atctx.pathlen-1] != '/') + atctx.path[atctx.pathlen++] = '/'; + + r |= audit_directory_tree(&atctx, openat(db->root_fd, arg, O_RDONLY|O_CLOEXEC)); + } + } + if (actx->mode == MODE_SYSTEM) + apk_hash_foreach(&db->installed.files, audit_missing_files, ctx); + + return r; +} + +static struct apk_applet apk_audit = { + .name = "audit", + .arguments = "[directory to audit]...", + .open_flags = APK_OPENF_READ|APK_OPENF_NO_SCRIPTS|APK_OPENF_NO_REPOS, + .context_size = sizeof(struct audit_ctx), + .optgroups = { &optgroup_global, &optgroup_applet }, + .main = audit_main, +}; + +APK_DEFINE_APPLET(apk_audit); + diff --git a/src/app_cache.c b/src/app_cache.c new file mode 100644 index 0000000..7ea5356 --- /dev/null +++ b/src/app_cache.c @@ -0,0 +1,193 @@ +/* app_cache.c - Alpine Package Keeper (APK) + * + * Copyright (C) 2005-2008 Natanael Copa + * Copyright (C) 2008-2011 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 +#include +#include +#include + +#include "apk_defines.h" +#include "apk_applet.h" +#include "apk_database.h" +#include "apk_package.h" +#include "apk_print.h" +#include "apk_solver.h" + +#define CACHE_CLEAN BIT(0) +#define CACHE_DOWNLOAD BIT(1) + +struct cache_ctx { + unsigned short solver_flags; +}; + +static int option_parse_applet(void *ctx, struct apk_db_options *dbopts, int optch, const char *optarg) +{ + struct cache_ctx *cctx = (struct cache_ctx *) ctx; + + switch (optch) { + case 'u': + cctx->solver_flags |= APK_SOLVERF_UPGRADE; + break; + case 'l': + cctx->solver_flags |= APK_SOLVERF_LATEST; + break; + default: + return -ENOTSUP; + } + return 0; +} + +static const struct apk_option options_applet[] = { + { 'u', "upgrade" }, + { 'l', "latest" }, +}; + +static const struct apk_option_group optgroup_applet = { + .name = "Cache", + .options = options_applet, + .num_options = ARRAY_SIZE(options_applet), + .parse = option_parse_applet, +}; + +struct progress { + size_t done, total; +}; + +static void progress_cb(void *ctx, size_t bytes_done) +{ + struct progress *prog = (struct progress *) ctx; + apk_print_progress(prog->done + bytes_done, prog->total); +} + +static int cache_download(struct cache_ctx *cctx, struct apk_database *db) +{ + struct apk_changeset changeset = {}; + struct apk_change *change; + struct apk_package *pkg; + struct apk_repository *repo; + struct progress prog = { 0, 0 }; + int r, ret = 0; + + r = apk_solver_solve(db, cctx->solver_flags, db->world, &changeset); + if (r < 0) { + apk_error("Unable to select packages. Run apk fix."); + return r; + } + + foreach_array_item(change, changeset.changes) { + pkg = change->new_pkg; + if ((pkg != NULL) && !(pkg->repos & db->local_repos)) + prog.total += pkg->size; + } + + foreach_array_item(change, changeset.changes) { + pkg = change->new_pkg; + if ((pkg == NULL) || (pkg->repos & db->local_repos)) + continue; + + repo = apk_db_select_repo(db, pkg); + if (repo == NULL) + continue; + + r = apk_cache_download(db, repo, pkg, APK_SIGN_VERIFY_IDENTITY, 0, + progress_cb, &prog); + if (r && r != -EALREADY) { + apk_error(PKG_VER_FMT ": %s", PKG_VER_PRINTF(pkg), apk_error_str(r)); + ret++; + } + prog.done += pkg->size; + } + + return ret; +} + +static void cache_clean_item(struct apk_database *db, int dirfd, const char *name, struct apk_package *pkg) +{ + char tmp[PATH_MAX]; + apk_blob_t b; + int i; + + if (strcmp(name, "installed") == 0) return; + + if (pkg) { + if ((apk_flags & APK_PURGE) && pkg->ipkg == NULL) goto delete; + if (pkg->repos & db->local_repos & ~BIT(APK_REPOSITORY_CACHED)) goto delete; + if (pkg->ipkg == NULL && !(pkg->repos & ~BIT(APK_REPOSITORY_CACHED))) goto delete; + return; + } + + b = APK_BLOB_STR(name); + for (i = 0; i < db->num_repos; i++) { + /* Check if this is a valid index */ + apk_repo_format_cache_index(APK_BLOB_BUF(tmp), &db->repos[i]); + if (apk_blob_compare(b, APK_BLOB_STR(tmp)) == 0) return; + } + +delete: + if (apk_verbosity >= 2) + apk_message("deleting %s", name); + if (!(apk_flags & APK_SIMULATE)) { + if (unlinkat(dirfd, name, 0) < 0 && errno == EISDIR) + unlinkat(dirfd, name, AT_REMOVEDIR); + } +} + +static int cache_clean(struct apk_database *db) +{ + return apk_db_cache_foreach_item(db, cache_clean_item); +} + +static int cache_main(void *ctx, struct apk_database *db, struct apk_string_array *args) +{ + struct cache_ctx *cctx = (struct cache_ctx *) ctx; + char *arg; + int r = 0, actions = 0; + + if (args->num != 1) + return -EINVAL; + + arg = args->item[0]; + if (strcmp(arg, "sync") == 0) + actions = CACHE_CLEAN | CACHE_DOWNLOAD; + else if (strcmp(arg, "clean") == 0) + actions = CACHE_CLEAN; + else if (strcmp(arg, "download") == 0) + actions = CACHE_DOWNLOAD; + else + return -EINVAL; + + if (!apk_db_cache_active(db)) { + apk_error("Package cache is not enabled.\n"); + r = 2; + goto err; + } + + if (r == 0 && (actions & CACHE_CLEAN)) + r = cache_clean(db); + if (r == 0 && (actions & CACHE_DOWNLOAD)) + r = cache_download(cctx, db); +err: + return r; +} + +static struct apk_applet apk_cache = { + .name = "cache", + .arguments = "sync | clean | download", + .open_flags = APK_OPENF_READ|APK_OPENF_NO_SCRIPTS|APK_OPENF_CACHE_WRITE, + .command_groups = APK_COMMAND_GROUP_SYSTEM, + .context_size = sizeof(struct cache_ctx), + .optgroups = { &optgroup_global, &optgroup_applet }, + .main = cache_main, +}; + +APK_DEFINE_APPLET(apk_cache); diff --git a/src/app_del.c b/src/app_del.c new file mode 100644 index 0000000..a5e8ddd --- /dev/null +++ b/src/app_del.c @@ -0,0 +1,178 @@ +/* app_del.c - Alpine Package Keeper (APK) + * + * Copyright (C) 2005-2008 Natanael Copa + * Copyright (C) 2008-2011 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 "apk_applet.h" +#include "apk_database.h" +#include "apk_print.h" +#include "apk_solver.h" + +struct del_ctx { + int recursive_delete : 1; + struct apk_dependency_array *world; + int errors; +}; + +static int option_parse_applet(void *pctx, struct apk_db_options *dbopts, int optch, const char *optarg) +{ + struct del_ctx *ctx = (struct del_ctx *) pctx; + + switch (optch) { + case 'r': + ctx->recursive_delete = 1; + break; + default: + return -ENOTSUP; + } + return 0; +} + +static const struct apk_option options_applet[] = { + { 'r', "rdepends" }, +}; + +static const struct apk_option_group optgroup_applet = { + .name = "Delete", + .options = options_applet, + .num_options = ARRAY_SIZE(options_applet), + .parse = option_parse_applet, +}; + +struct not_deleted_ctx { + struct apk_indent indent; + struct apk_name *name; + unsigned int matches; + int header; +}; + +static void print_not_deleted_pkg(struct apk_package *pkg0, struct apk_dependency *dep0, + struct apk_package *pkg, void *pctx) +{ + struct not_deleted_ctx *ctx = (struct not_deleted_ctx *) pctx; + struct apk_dependency *d; + struct apk_provider *p; + + if (pkg0->name != ctx->name) { + if (!ctx->header) { + apk_message("World updated, but the following packages are not removed due to:"); + ctx->header = 1; + } + if (!ctx->indent.indent) { + ctx->indent.x = printf(" %s:", ctx->name->name); + ctx->indent.indent = ctx->indent.x + 1; + } + + apk_print_indented(&ctx->indent, APK_BLOB_STR(pkg0->name->name)); + } + + apk_pkg_foreach_reverse_dependency(pkg0, ctx->matches, print_not_deleted_pkg, pctx); + foreach_array_item(d, pkg0->install_if) { + foreach_array_item(p, d->name->providers) { + if (!p->pkg->marked) continue; + if (apk_pkg_match_genid(p->pkg, ctx->matches)) continue; + print_not_deleted_pkg(p->pkg, NULL, NULL, pctx); + } + } +} + +static void print_not_deleted_name(struct apk_database *db, const char *match, + struct apk_name *name, void *pctx) +{ + struct not_deleted_ctx *ctx = (struct not_deleted_ctx *) pctx; + struct apk_provider *p; + + ctx->indent.indent = 0; + ctx->name = name; + ctx->matches = apk_foreach_genid() | APK_FOREACH_MARKED | APK_DEP_SATISFIES; + foreach_array_item(p, name->providers) + if (p->pkg->marked) + print_not_deleted_pkg(p->pkg, NULL, NULL, ctx); + if (ctx->indent.indent) + printf("\n"); +} + +static void delete_pkg(struct apk_package *pkg0, struct apk_dependency *dep0, + struct apk_package *pkg, void *pctx) +{ + struct del_ctx *ctx = (struct del_ctx *) pctx; + + apk_deps_del(&ctx->world, pkg0->name); + if (ctx->recursive_delete) + apk_pkg_foreach_reverse_dependency( + pkg0, APK_FOREACH_INSTALLED | APK_DEP_SATISFIES, + delete_pkg, pctx); +} + +static void delete_name(struct apk_database *db, const char *match, + struct apk_name *name, void *pctx) +{ + struct del_ctx *ctx = (struct del_ctx *) pctx; + struct apk_package *pkg; + + if (!name) { + apk_error("No such package: %s", match); + ctx->errors++; + return; + } + + pkg = apk_pkg_get_installed(name); + if (pkg != NULL) + delete_pkg(pkg, NULL, NULL, pctx); + else + apk_deps_del(&ctx->world, name); +} + +static int del_main(void *pctx, struct apk_database *db, struct apk_string_array *args) +{ + struct del_ctx *ctx = (struct del_ctx *) pctx; + struct not_deleted_ctx ndctx = {}; + struct apk_changeset changeset = {}; + struct apk_change *change; + int r = 0; + + apk_dependency_array_copy(&ctx->world, db->world); + apk_name_foreach_matching(db, args, apk_foreach_genid(), delete_name, ctx); + if (ctx->errors) return ctx->errors; + + r = apk_solver_solve(db, 0, ctx->world, &changeset); + if (r == 0) { + /* check for non-deleted package names */ + foreach_array_item(change, changeset.changes) + if (change->new_pkg != NULL) + change->new_pkg->marked = 1; + apk_name_foreach_matching( + db, args, + apk_foreach_genid() | APK_FOREACH_MARKED | APK_DEP_SATISFIES, + print_not_deleted_name, &ndctx); + if (ndctx.header) + printf("\n"); + + r = apk_solver_commit_changeset(db, &changeset, ctx->world); + } else { + apk_solver_print_errors(db, &changeset, ctx->world); + } + apk_change_array_free(&changeset.changes); + apk_dependency_array_free(&ctx->world); + + return r; +} + +static struct apk_applet apk_del = { + .name = "del", + .arguments = "PACKAGE...", + .open_flags = APK_OPENF_WRITE | APK_OPENF_NO_AUTOUPDATE, + .command_groups = APK_COMMAND_GROUP_INSTALL, + .context_size = sizeof(struct del_ctx), + .optgroups = { &optgroup_global, &optgroup_commit, &optgroup_applet }, + .main = del_main, +}; + +APK_DEFINE_APPLET(apk_del); diff --git a/src/app_dot.c b/src/app_dot.c new file mode 100644 index 0000000..b85d69b --- /dev/null +++ b/src/app_dot.c @@ -0,0 +1,179 @@ +/* app_dot.c - Alpine Package Keeper (APK) + * + * Copyright (C) 2008-2011 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_print.h" + +#define S_EVALUATED -1 +#define S_EVALUATING -2 + +struct dot_ctx { + int not_empty : 1; + int errors_only : 1; + int installed_only : 1; +}; + +static int option_parse_applet(void *pctx, struct apk_db_options *dbopts, int optch, const char *optarg) +{ + struct dot_ctx *ctx = (struct dot_ctx *) pctx; + + switch (optch) { + case 0x10000: + ctx->errors_only = 1; + break; + case 0x10001: + ctx->installed_only = 1; + dbopts->open_flags &= ~APK_OPENF_NO_INSTALLED; + break; + default: + return -ENOTSUP; + } + return 0; +} + +static const struct apk_option options_applet[] = { + { 0x10000, "errors" }, + { 0x10001, "installed" }, +}; + +static const struct apk_option_group optgroup_applet = { + .name = "Dot", + .options = options_applet, + .num_options = ARRAY_SIZE(options_applet), + .parse = option_parse_applet, +}; + +static void start_graph(struct dot_ctx *ctx) +{ + if (ctx->not_empty) + return; + ctx->not_empty = 1; + + printf( "digraph \"apkindex\" {\n" + " rankdir=LR;\n" + " node [shape=box];\n"); +} + +static void dump_name(struct dot_ctx *ctx, struct apk_name *name) +{ + if (name->state_int) + return; + name->state_int = 1; + + if (name->providers->num == 0) { + start_graph(ctx); + printf(" \"%s\" [style=dashed, color=red, fontcolor=red, shape=octagon];\n", + name->name); + } +} + +static int dump_pkg(struct dot_ctx *ctx, struct apk_package *pkg) +{ + struct apk_dependency *dep; + struct apk_provider *p0; + int r, ret = 0; + + if (ctx->installed_only && pkg->ipkg == NULL) + return 0; + + if (pkg->state_int == S_EVALUATED) + return 0; + + if (pkg->state_int <= S_EVALUATING) { + pkg->state_int--; + return 1; + } + + pkg->state_int = S_EVALUATING; + foreach_array_item(dep, pkg->depends) { + struct apk_name *name = dep->name; + + dump_name(ctx, name); + + if (name->providers->num == 0) { + printf(" \"" PKG_VER_FMT "\" -> \"%s\" [color=red];\n", + PKG_VER_PRINTF(pkg), name->name); + continue; + } + + foreach_array_item(p0, name->providers) { + if (ctx->installed_only && p0->pkg->ipkg == NULL) + continue; + if (!apk_dep_is_provided(dep, p0)) + continue; + + r = dump_pkg(ctx, p0->pkg); + ret += r; + if (r || (!ctx->errors_only)) { + start_graph(ctx); + + printf(" \"" PKG_VER_FMT "\" -> \"" PKG_VER_FMT "\"[", + PKG_VER_PRINTF(pkg), + PKG_VER_PRINTF(p0->pkg)); + if (r) + printf("color=red,"); + if (p0->pkg->name != dep->name) + printf("arrowhead=inv,label=\"%s\",", dep->name->name); + printf("];\n"); + } + } + } + ret -= S_EVALUATING - pkg->state_int; + pkg->state_int = S_EVALUATED; + + return ret; +} + +static int foreach_pkg(apk_hash_item item, void *ctx) +{ + dump_pkg((struct dot_ctx *) ctx, (struct apk_package *) item); + return 0; +} + +static int dot_main(void *pctx, struct apk_database *db, struct apk_string_array *args) +{ + struct dot_ctx *ctx = (struct dot_ctx *) pctx; + struct apk_provider *p; + char **parg; + + if (args->num) { + foreach_array_item(parg, args) { + struct apk_name *name = apk_db_get_name(db, APK_BLOB_STR(*parg)); + if (!name) + continue; + foreach_array_item(p, name->providers) + dump_pkg(ctx, p->pkg); + } + } else { + apk_hash_foreach(&db->available.packages, foreach_pkg, pctx); + } + + if (!ctx->not_empty) + return 1; + + printf("}\n"); + return 0; +} + +static struct apk_applet apk_dot = { + .name = "dot", + .arguments = "PKGMASK...", + .open_flags = APK_OPENF_READ | APK_OPENF_NO_STATE, + .command_groups = APK_COMMAND_GROUP_QUERY, + .context_size = sizeof(struct dot_ctx), + .optgroups = { &optgroup_global, &optgroup_applet }, + .main = dot_main, +}; + +APK_DEFINE_APPLET(apk_dot); diff --git a/src/app_fetch.c b/src/app_fetch.c new file mode 100644 index 0000000..677fabf --- /dev/null +++ b/src/app_fetch.c @@ -0,0 +1,355 @@ +/* app_fetch.c - Alpine Package Keeper (APK) + * + * Copyright (C) 2005-2008 Natanael Copa + * Copyright (C) 2008-2011 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 +#include +#include +#include + +#include "apk_applet.h" +#include "apk_database.h" +#include "apk_io.h" +#include "apk_print.h" +#include "apk_solver.h" + +#define FETCH_RECURSIVE 1 +#define FETCH_STDOUT 2 +#define FETCH_LINK 4 + +struct fetch_ctx { + unsigned int flags; + int outdir_fd, errors; + struct apk_database *db; + size_t done, total; + struct apk_dependency_array *world; +}; + +static int cup(void) +{ + /* compressed/uncompressed size is 259/1213 */ + static unsigned char z[] = { + 0x78,0x9c,0x9d,0x94,0x3d,0x8e,0xc4,0x20,0x0c,0x85,0xfb,0x9c, + 0xc2,0x72,0x43,0x46,0x8a,0x4d,0x3f,0x67,0x89,0x64,0x77,0x2b, + 0x6d,0xbb,0x6d,0x0e,0x3f,0xc6,0x84,0x4d,0x08,0x84,0x55,0xd6, + 0xa2,0xe0,0xef,0x7b,0x36,0xe1,0x11,0x80,0x6e,0xcc,0x53,0x7f, + 0x3e,0xc5,0xeb,0xcf,0x1d,0x20,0x22,0xcc,0x3c,0x53,0x8e,0x17, + 0xd9,0x80,0x6d,0xee,0x0e,0x61,0x42,0x3c,0x8b,0xcf,0xc7,0x12, + 0x22,0x71,0x8b,0x31,0x05,0xd5,0xb0,0x11,0x4b,0xa7,0x32,0x2f, + 0x80,0x69,0x6b,0xb0,0x98,0x40,0xe2,0xcd,0xba,0x6a,0xba,0xe4, + 0x65,0xed,0x61,0x23,0x44,0xb5,0x95,0x06,0x8b,0xde,0x6c,0x61, + 0x70,0xde,0x0e,0xb6,0xed,0xc4,0x43,0x0c,0x56,0x6f,0x8f,0x31, + 0xd0,0x35,0xb5,0xc7,0x58,0x06,0xff,0x81,0x49,0x84,0xb8,0x0e, + 0xb1,0xd8,0xc1,0x66,0x31,0x0e,0x46,0x5c,0x43,0xc9,0xef,0xe5, + 0xdc,0x63,0xb1,0xdc,0x67,0x6d,0x31,0xb3,0xc9,0x69,0x74,0x87, + 0xc7,0xa3,0x1b,0x6a,0xb3,0xbd,0x2f,0x3b,0xd5,0x0c,0x57,0x3b, + 0xce,0x7c,0x5e,0xe5,0x48,0xd0,0x48,0x01,0x92,0x49,0x8b,0xf7, + 0xfc,0x58,0x67,0xb3,0xf7,0x14,0x20,0x5c,0x4c,0x9e,0xcc,0xeb, + 0x78,0x7e,0x64,0xa6,0xa1,0xf5,0xb2,0x70,0x38,0x09,0x7c,0x7f, + 0xfd,0xc0,0x8a,0x4e,0xc8,0x55,0xe8,0x12,0xe2,0x9f,0x1a,0xb1, + 0xb9,0x82,0x52,0x02,0x7a,0xe5,0xf9,0xd9,0x88,0x47,0x79,0x3b, + 0x46,0x61,0x27,0xf9,0x51,0xb1,0x17,0xb0,0x2c,0x0e,0xd5,0x39, + 0x2d,0x96,0x25,0x27,0xd6,0xd1,0x3f,0xa5,0x08,0xe1,0x9e,0x4e, + 0xa7,0xe9,0x03,0xb1,0x0a,0xb6,0x75 + }; + unsigned char buf[1213]; + unsigned long len = sizeof(buf); + + uncompress(buf, &len, z, sizeof(z)); + return write(STDOUT_FILENO, buf, len) != len; +} + +static int option_parse_applet(void *ctx, struct apk_db_options *dbopts, int optch, const char *optarg) +{ + struct fetch_ctx *fctx = (struct fetch_ctx *) ctx; + + switch (optch) { + case 'R': + fctx->flags |= FETCH_RECURSIVE; + break; + case 's': + fctx->flags |= FETCH_STDOUT; + break; + case 'L': + fctx->flags |= FETCH_LINK; + break; + case 'o': + fctx->outdir_fd = openat(AT_FDCWD, optarg, O_RDONLY | O_CLOEXEC); + break; + default: + return -ENOTSUP; + } + return 0; +} + +static const struct apk_option options_applet[] = { + { 'L', "link" }, + { 'R', "recursive" }, + { 0x104, "simulate" }, + { 's', "stdout" }, + { 'o', "output", required_argument, "DIR" }, +}; + +static const struct apk_option_group optgroup_applet = { + .name = "Fetch", + .options = options_applet, + .num_options = ARRAY_SIZE(options_applet), + .parse = option_parse_applet, +}; + +static void progress_cb(void *pctx, size_t bytes_done) +{ + struct fetch_ctx *ctx = (struct fetch_ctx *) pctx; + apk_print_progress(ctx->done + bytes_done, ctx->total); +} + +static int fetch_package(apk_hash_item item, void *pctx) +{ + struct fetch_ctx *ctx = (struct fetch_ctx *) pctx; + struct apk_database *db = ctx->db; + struct apk_package *pkg = (struct apk_package *) item; + struct apk_istream *is; + struct apk_repository *repo; + struct apk_file_info fi; + char url[PATH_MAX], filename[256]; + int r, fd, urlfd; + + if (!pkg->marked) + return 0; + + repo = apk_db_select_repo(db, pkg); + if (repo == NULL) { + r = -ENOPKG; + goto err; + } + + if (snprintf(filename, sizeof(filename), PKG_FILE_FMT, PKG_FILE_PRINTF(pkg)) >= sizeof(filename)) { + r = -ENOBUFS; + goto err; + } + + if (!(ctx->flags & FETCH_STDOUT)) { + if (apk_fileinfo_get(ctx->outdir_fd, filename, APK_CHECKSUM_NONE, &fi) == 0 && + fi.size == pkg->size) + return 0; + } + + apk_message("Downloading " PKG_VER_FMT, PKG_VER_PRINTF(pkg)); + if (apk_flags & APK_SIMULATE) + return 0; + + r = apk_repo_format_item(db, repo, pkg, &urlfd, url, sizeof(url)); + if (r < 0) + goto err; + + if (ctx->flags & FETCH_STDOUT) { + fd = STDOUT_FILENO; + } else { + if ((ctx->flags & FETCH_LINK) && urlfd >= 0) { + if (linkat(urlfd, url, + ctx->outdir_fd, filename, + AT_SYMLINK_FOLLOW) == 0) + return 0; + } + fd = openat(ctx->outdir_fd, filename, + O_CREAT|O_RDWR|O_TRUNC|O_CLOEXEC, 0644); + if (fd < 0) { + r = -errno; + goto err; + } + } + + is = apk_istream_from_fd_url(urlfd, url); + if (IS_ERR_OR_NULL(is)) { + r = PTR_ERR(is) ?: -EIO; + goto err; + } + + r = apk_istream_splice(is, fd, pkg->size, progress_cb, ctx); + if (fd != STDOUT_FILENO) { + struct apk_file_meta meta; + apk_istream_get_meta(is, &meta); + apk_file_meta_to_fd(fd, &meta); + close(fd); + } + apk_istream_close(is); + + if (r != pkg->size) { + unlinkat(ctx->outdir_fd, filename, 0); + if (r >= 0) r = -EIO; + goto err; + } + + ctx->done += pkg->size; + return 0; + +err: + apk_error(PKG_VER_FMT ": %s", PKG_VER_PRINTF(pkg), apk_error_str(r)); + ctx->errors++; + return 0; +} + +static void mark_package(struct fetch_ctx *ctx, struct apk_package *pkg) +{ + if (pkg == NULL || pkg->marked) + return; + ctx->total += pkg->size; + pkg->marked = 1; +} + +static void mark_error(struct fetch_ctx *ctx, const char *match, struct apk_name *name) +{ + if (strchr(match, '*') != NULL) + return; + + apk_message("%s: unable to select package (or its dependencies)", name ? name->name : match); + ctx->errors++; +} + +static void mark_name_flags(struct apk_database *db, const char *match, struct apk_name *name, void *pctx) +{ + struct fetch_ctx *ctx = (struct fetch_ctx *) pctx; + struct apk_dependency dep = (struct apk_dependency) { + .name = name, + .version = &apk_null_blob, + .result_mask = APK_DEPMASK_ANY, + }; + + if (!IS_ERR_OR_NULL(name)) { + name->auto_select_virtual = 1; + apk_deps_add(&ctx->world, &dep); + } else { + ctx->errors++; + mark_error(ctx, match, name); + } +} + +static void mark_names_recursive(struct apk_database *db, struct apk_string_array *args, void *pctx) +{ + struct fetch_ctx *ctx = (struct fetch_ctx *) pctx; + struct apk_changeset changeset = {}; + struct apk_change *change; + int r; + + r = apk_solver_solve(db, APK_SOLVERF_IGNORE_CONFLICT, ctx->world, &changeset); + if (r == 0) { + foreach_array_item(change, changeset.changes) + mark_package(ctx, change->new_pkg); + } else { + apk_solver_print_errors(db, &changeset, ctx->world); + ctx->errors++; + } + apk_change_array_free(&changeset.changes); +} + +static void mark_name(struct apk_database *db, const char *match, struct apk_name *name, void *ctx) +{ + struct apk_package *pkg = NULL; + struct apk_provider *p; + + if (!name) goto err; + + foreach_array_item(p, name->providers) + if (pkg == NULL || apk_pkg_version_compare(p->pkg, pkg) == APK_VERSION_GREATER) + pkg = p->pkg; + + if (!pkg) goto err; + mark_package(ctx, pkg); + return; + +err: + mark_error(ctx, match, name); +} + +static int purge_package(void *pctx, int dirfd, const char *filename) +{ + char tmp[PATH_MAX]; + struct fetch_ctx *ctx = (struct fetch_ctx *) pctx; + struct apk_database *db = ctx->db; + struct apk_provider *p0; + struct apk_name *name; + apk_blob_t b = APK_BLOB_STR(filename), bname, bver; + size_t l; + + if (apk_pkg_parse_name(b, &bname, &bver)) return 0; + name = apk_db_get_name(db, bname); + if (!name) return 0; + + foreach_array_item(p0, name->providers) { + if (p0->pkg->name != name) continue; + l = snprintf(tmp, sizeof tmp, PKG_FILE_FMT, PKG_FILE_PRINTF(p0->pkg)); + if (l > sizeof tmp) continue; + if (apk_blob_compare(b, APK_BLOB_PTR_LEN(tmp, l)) != 0) continue; + if (p0->pkg->marked) return 0; + break; + } + + apk_message("Purging %s", filename); + if (apk_flags & APK_SIMULATE) + return 0; + + unlinkat(dirfd, filename, 0); + return 0; +} + +static int fetch_main(void *pctx, struct apk_database *db, struct apk_string_array *args) +{ + struct fetch_ctx *ctx = (struct fetch_ctx *) pctx; + + if (ctx->flags & FETCH_STDOUT) { + apk_flags &= ~APK_PROGRESS; + apk_verbosity = 0; + } + + if (ctx->outdir_fd == 0) + ctx->outdir_fd = AT_FDCWD; + + if ((args->num == 1) && (strcmp(args->item[0], "coffee") == 0)) { + if (apk_force) return cup(); + apk_message("Go and fetch your own coffee."); + return 0; + } + + ctx->db = db; + + if (ctx->flags & FETCH_RECURSIVE) { + apk_dependency_array_init(&ctx->world); + apk_name_foreach_matching(db, args, apk_foreach_genid(), mark_name_flags, ctx); + if (ctx->errors == 0) + mark_names_recursive(db, args, ctx); + apk_dependency_array_free(&ctx->world); + } else { + apk_name_foreach_matching(db, args, apk_foreach_genid(), mark_name, ctx); + } + if (!ctx->errors) + apk_hash_foreach(&db->available.packages, fetch_package, ctx); + + /* Remove packages not matching download spec from the output directory */ + if (!ctx->errors && (apk_flags & APK_PURGE) && + !(ctx->flags & FETCH_STDOUT) && ctx->outdir_fd > 0) + apk_dir_foreach_file(ctx->outdir_fd, purge_package, ctx); + + return ctx->errors; +} + +static struct apk_applet apk_fetch = { + .name = "fetch", + .arguments = "PACKAGE...", + .open_flags = APK_OPENF_READ | APK_OPENF_NO_STATE, + .command_groups = APK_COMMAND_GROUP_REPO, + .context_size = sizeof(struct fetch_ctx), + .optgroups = { &optgroup_global, &optgroup_applet }, + .main = fetch_main, +}; + +APK_DEFINE_APPLET(apk_fetch); + diff --git a/src/app_fix.c b/src/app_fix.c new file mode 100644 index 0000000..ed1ff76 --- /dev/null +++ b/src/app_fix.c @@ -0,0 +1,127 @@ +/* app_fix.c - Alpine Package Keeper (APK) + * + * Copyright (C) 2005-2008 Natanael Copa + * Copyright (C) 2008-2011 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_print.h" +#include "apk_solver.h" + +struct fix_ctx { + unsigned short solver_flags; + int fix_depends : 1; + int fix_xattrs : 1; + int fix_directory_permissions : 1; + int errors; +}; + +static int option_parse_applet(void *pctx, struct apk_db_options *dbopts, int optch, const char *optarg) +{ + struct fix_ctx *ctx = (struct fix_ctx *) pctx; + switch (optch) { + case 'd': + ctx->fix_depends = 1; + break; + case 'x': + ctx->fix_xattrs = 1; + break; + case 'u': + ctx->solver_flags |= APK_SOLVERF_UPGRADE; + break; + case 'r': + ctx->solver_flags |= APK_SOLVERF_REINSTALL; + break; + case 0x10000: + ctx->fix_directory_permissions = 1; + break; + default: + return -ENOTSUP; + } + return 0; +} + +static const struct apk_option options_applet[] = { + { 'd', "depends" }, + { 'r', "reinstall" }, + { 'u', "upgrade" }, + { 'x', "xattr" }, + { 0x10000, "directory-permissions" }, +}; + +static const struct apk_option_group optgroup_applet = { + .name = "Fix", + .options = options_applet, + .num_options = ARRAY_SIZE(options_applet), + .parse = option_parse_applet, +}; + +static int mark_recalculate(apk_hash_item item, void *ctx) +{ + struct apk_db_dir *dir = (struct apk_db_dir *) item; + if (dir->refs == 0) return 0; + dir->update_permissions = 1; + return 0; +} + +static void mark_fix(struct fix_ctx *ctx, struct apk_name *name) +{ + apk_solver_set_name_flags(name, ctx->solver_flags, ctx->fix_depends ? ctx->solver_flags : 0); +} + +static void set_solver_flags(struct apk_database *db, const char *match, struct apk_name *name, void *pctx) +{ + struct fix_ctx *ctx = pctx; + + if (!name) { + apk_error("Package '%s' not found", match); + ctx->errors++; + } else + mark_fix(ctx, name); +} + +static int fix_main(void *pctx, struct apk_database *db, struct apk_string_array *args) +{ + struct fix_ctx *ctx = (struct fix_ctx *) pctx; + struct apk_installed_package *ipkg; + + if (!ctx->solver_flags) + ctx->solver_flags = APK_SOLVERF_REINSTALL; + + if (ctx->fix_directory_permissions) + apk_hash_foreach(&db->installed.dirs, mark_recalculate, db); + + if (args->num == 0) { + list_for_each_entry(ipkg, &db->installed.packages, installed_pkgs_list) { + if (ipkg->broken_files || ipkg->broken_script || + (ipkg->broken_xattr && ctx->fix_xattrs)) + mark_fix(ctx, ipkg->pkg->name); + } + } else + apk_name_foreach_matching(db, args, apk_foreach_genid(), set_solver_flags, ctx); + + if (ctx->errors) return ctx->errors; + + return apk_solver_commit(db, 0, db->world); +} + +static struct apk_applet apk_fix = { + .name = "fix", + .arguments = "PACKAGE...", + .open_flags = APK_OPENF_WRITE, + .command_groups = APK_COMMAND_GROUP_SYSTEM, + .context_size = sizeof(struct fix_ctx), + .optgroups = { &optgroup_global, &optgroup_commit, &optgroup_applet }, + .main = fix_main, +}; + +APK_DEFINE_APPLET(apk_fix); + diff --git a/src/app_index.c b/src/app_index.c new file mode 100644 index 0000000..3e3e437 --- /dev/null +++ b/src/app_index.c @@ -0,0 +1,265 @@ +/* app_index.c - Alpine Package Keeper (APK) + * + * Copyright (C) 2005-2008 Natanael Copa + * Copyright (C) 2008-2011 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 +#include +#include + +#include "apk_applet.h" +#include "apk_database.h" +#include "apk_print.h" + +struct counts { + int unsatisfied; +}; + +struct index_ctx { + const char *index; + const char *output; + const char *description; + apk_blob_t *rewrite_arch; + time_t index_mtime; + int method; +}; + +static int option_parse_applet(void *ctx, struct apk_db_options *dbopts, int optch, const char *optarg) +{ + struct index_ctx *ictx = (struct index_ctx *) ctx; + + switch (optch) { + case 'x': + ictx->index = optarg; + break; + case 'o': + ictx->output = optarg; + break; + case 'd': + ictx->description = optarg; + break; + case 0x10000: + ictx->rewrite_arch = apk_blob_atomize(APK_BLOB_STR(optarg)); + break; + default: + return -ENOTSUP; + } + return 0; +} + +static const struct apk_option options_applet[] = { + { 'o', "output", required_argument, "FILE" }, + { 'x', "index", required_argument, "INDEX" }, + { 'd', "description", required_argument, "TEXT" }, + { 0x10000, "rewrite-arch", required_argument, "ARCH" }, +}; + +static const struct apk_option_group optgroup_applet = { + .name = "Index", + .options = options_applet, + .num_options = ARRAY_SIZE(options_applet), + .parse = option_parse_applet, +}; + +static int index_read_file(struct apk_database *db, struct index_ctx *ictx) +{ + struct apk_file_info fi; + + if (ictx->index == NULL) + return 0; + if (apk_fileinfo_get(AT_FDCWD, ictx->index, APK_CHECKSUM_NONE, &fi) < 0) + return 0; + + ictx->index_mtime = fi.mtime; + return apk_db_index_read_file(db, ictx->index, 0); +} + +static int warn_if_no_providers(apk_hash_item item, void *ctx) +{ + struct counts *counts = (struct counts *) ctx; + struct apk_name *name = (struct apk_name *) item; + + if (!name->is_dependency) return 0; + if (name->providers->num) return 0; + + if (++counts->unsatisfied < 10) { + apk_warning("No provider for dependency '%s'", + name->name); + } else if (counts->unsatisfied == 10) { + apk_warning("Too many unsatisfiable dependencies, " + "not reporting the rest."); + } + + return 0; +} + +static int index_main(void *ctx, struct apk_database *db, struct apk_string_array *args) +{ + struct counts counts = {0}; + struct apk_ostream *os; + struct apk_file_info fi; + int total, r, found, newpkgs = 0, errors = 0; + struct index_ctx *ictx = (struct index_ctx *) ctx; + struct apk_package *pkg; + char **parg; + + if (isatty(STDOUT_FILENO) && ictx->output == NULL && + !(apk_force & APK_FORCE_BINARY_STDOUT)) { + apk_error("Will not write binary index to console. " + "Use --force-binary-stdout to override."); + return -1; + } + + if (ictx->method == 0) + ictx->method = APK_SIGN_GENERATE; + + if ((r = index_read_file(db, ictx)) < 0) { + apk_error("%s: %s", ictx->index, apk_error_str(r)); + return r; + } + + foreach_array_item(parg, args) { + if (apk_fileinfo_get(AT_FDCWD, *parg, APK_CHECKSUM_NONE, &fi) < 0) { + apk_warning("File '%s' is unaccessible", *parg); + continue; + } + + found = FALSE; + do { + struct apk_provider *p; + struct apk_name *name; + char *fname, *fend; + apk_blob_t bname, bver; + + /* Check if index is newer than package */ + if (ictx->index == NULL || ictx->index_mtime < fi.mtime) + break; + + /* Check that it looks like a package name */ + fname = strrchr(*parg, '/'); + if (fname == NULL) + fname = *parg; + else + fname++; + fend = strstr(fname, ".apk"); + if (fend == NULL) + break; + if (apk_pkg_parse_name(APK_BLOB_PTR_PTR(fname, fend-1), + &bname, &bver) < 0) + break; + + /* If we have it in the old index already? */ + name = apk_db_query_name(db, bname); + if (name == NULL) + break; + + foreach_array_item(p, name->providers) { + pkg = p->pkg; + if (pkg->name != name) + continue; + if (apk_blob_compare(bver, *pkg->version) != 0) + continue; + if (pkg->size != fi.size) + continue; + pkg->filename = strdup(*parg); + if (ictx->rewrite_arch != NULL) + pkg->arch = ictx->rewrite_arch; + found = TRUE; + break; + } + } while (0); + + if (!found) { + struct apk_sign_ctx sctx; + apk_sign_ctx_init(&sctx, ictx->method, NULL, db->keys_fd); + r = apk_pkg_read(db, *parg, &sctx, &pkg); + if (r < 0) { + apk_error("%s: %s", *parg, apk_error_str(r)); + errors++; + } else { + newpkgs++; + if (ictx->rewrite_arch != NULL) + pkg->arch = ictx->rewrite_arch; + } + apk_sign_ctx_free(&sctx); + } + } + if (errors) + return -1; + + if (ictx->output != NULL) + os = apk_ostream_to_file(AT_FDCWD, ictx->output, NULL, 0644); + else + os = apk_ostream_to_fd(STDOUT_FILENO); + if (IS_ERR_OR_NULL(os)) return -1; + + if (ictx->method == APK_SIGN_GENERATE) { + struct apk_ostream *counter; + + memset(&fi, 0, sizeof(fi)); + fi.mode = 0644 | S_IFREG; + fi.name = "APKINDEX"; + counter = apk_ostream_counter(&fi.size); + r = apk_db_index_write(db, counter); + apk_ostream_close(counter); + + if (r >= 0) { + os = apk_ostream_gzip(os); + if (ictx->description != NULL) { + struct apk_file_info fi_desc; + memset(&fi_desc, 0, sizeof(fi)); + fi_desc.mode = 0644 | S_IFREG; + fi_desc.name = "DESCRIPTION"; + fi_desc.size = strlen(ictx->description); + apk_tar_write_entry(os, &fi_desc, ictx->description); + } + + apk_tar_write_entry(os, &fi, NULL); + r = apk_db_index_write(db, os); + apk_tar_write_padding(os, &fi); + + apk_tar_write_entry(os, NULL, NULL); + } + } else { + r = apk_db_index_write(db, os); + } + apk_ostream_close(os); + + if (r < 0) { + apk_error("Index generation failed: %s", apk_error_str(r)); + return r; + } + + total = r; + apk_hash_foreach(&db->available.names, warn_if_no_providers, &counts); + + if (counts.unsatisfied != 0) + apk_warning("Total of %d unsatisfiable package " + "names. Your repository may be broken.", + counts.unsatisfied); + apk_message("Index has %d packages (of which %d are new)", + total, newpkgs); + + return 0; +} + +static struct apk_applet apk_index = { + .name = "index", + .arguments = "FILE...", + .open_flags = APK_OPENF_READ | APK_OPENF_NO_STATE | APK_OPENF_NO_REPOS, + .command_groups = APK_COMMAND_GROUP_REPO, + .context_size = sizeof(struct index_ctx), + .optgroups = { &optgroup_global, &optgroup_applet }, + .main = index_main, +}; + +APK_DEFINE_APPLET(apk_index); + diff --git a/src/app_info.c b/src/app_info.c new file mode 100644 index 0000000..ee9a0aa --- /dev/null +++ b/src/app_info.c @@ -0,0 +1,488 @@ +/* app_info.c - Alpine Package Keeper (APK) + * + * Copyright (C) 2005-2009 Natanael Copa + * Copyright (C) 2008-2011 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 +#include "apk_defines.h" +#include "apk_applet.h" +#include "apk_package.h" +#include "apk_database.h" +#include "apk_print.h" + +struct info_ctx { + struct apk_database *db; + void (*action)(struct info_ctx *ctx, struct apk_database *db, struct apk_string_array *args); + int subaction_mask; + int errors; +}; + +/* These need to stay in sync with the function pointer array in + * info_subaction() */ +#define APK_INFO_DESC 0x01 +#define APK_INFO_URL 0x02 +#define APK_INFO_SIZE 0x04 +#define APK_INFO_DEPENDS 0x08 +#define APK_INFO_PROVIDES 0x10 +#define APK_INFO_RDEPENDS 0x20 +#define APK_INFO_CONTENTS 0x40 +#define APK_INFO_TRIGGERS 0x80 +#define APK_INFO_INSTALL_IF 0x100 +#define APK_INFO_RINSTALL_IF 0x200 +#define APK_INFO_REPLACES 0x400 +#define APK_INFO_LICENSE 0x800 + +static void verbose_print_pkg(struct apk_package *pkg, int minimal_verbosity) +{ + int verbosity = apk_verbosity; + if (verbosity < minimal_verbosity) + verbosity = minimal_verbosity; + + if (pkg == NULL || verbosity < 1) + return; + + printf("%s", pkg->name->name); + if (apk_verbosity > 1) + printf("-" BLOB_FMT, BLOB_PRINTF(*pkg->version)); + if (apk_verbosity > 2) + printf(" - %s", pkg->description); + printf("\n"); +} + +static void info_exists(struct info_ctx *ctx, struct apk_database *db, + struct apk_string_array *args) +{ + struct apk_name *name; + struct apk_dependency dep; + struct apk_provider *p; + char **parg; + int ok; + + foreach_array_item(parg, args) { + apk_blob_t b = APK_BLOB_STR(*parg); + + apk_blob_pull_dep(&b, db, &dep); + if (APK_BLOB_IS_NULL(b) || b.len > 0) + continue; + + name = dep.name; + if (name == NULL) + continue; + + ok = apk_dep_is_provided(&dep, NULL); + foreach_array_item(p, name->providers) { + if (!p->pkg->ipkg) continue; + ok = apk_dep_is_provided(&dep, p); + if (ok) verbose_print_pkg(p->pkg, 0); + break; + } + if (!ok) ctx->errors++; + } +} + +static void info_who_owns(struct info_ctx *ctx, struct apk_database *db, + struct apk_string_array *args) +{ + struct apk_package *pkg; + struct apk_dependency_array *deps; + struct apk_dependency dep; + struct apk_ostream *os; + const char *via; + char **parg, fnbuf[PATH_MAX], buf[PATH_MAX]; + apk_blob_t fn; + ssize_t r; + + apk_dependency_array_init(&deps); + foreach_array_item(parg, args) { + if (*parg[0] != '/' && realpath(*parg, fnbuf)) + fn = APK_BLOB_STR(fnbuf); + else + fn = APK_BLOB_STR(*parg); + + via = ""; + pkg = apk_db_get_file_owner(db, fn); + if (pkg == NULL) { + r = readlinkat(db->root_fd, *parg, buf, sizeof(buf)); + if (r > 0 && r < PATH_MAX && buf[0] == '/') { + pkg = apk_db_get_file_owner(db, APK_BLOB_STR(buf)); + via = "symlink target "; + } + } + + if (pkg == NULL) { + apk_error(BLOB_FMT ": Could not find owner package", + BLOB_PRINTF(fn)); + ctx->errors++; + continue; + } + + if (apk_verbosity < 1) { + dep = (struct apk_dependency) { + .name = pkg->name, + .version = apk_blob_atomize(APK_BLOB_NULL), + .result_mask = APK_DEPMASK_ANY, + }; + apk_deps_add(&deps, &dep); + } else { + printf(BLOB_FMT " %sis owned by " PKG_VER_FMT "\n", + BLOB_PRINTF(fn), via, PKG_VER_PRINTF(pkg)); + } + } + if (apk_verbosity < 1 && deps->num != 0) { + os = apk_ostream_to_fd(STDOUT_FILENO); + if (!IS_ERR_OR_NULL(os)) { + apk_deps_write(db, deps, os, APK_BLOB_PTR_LEN(" ", 1)); + apk_ostream_write(os, "\n", 1); + apk_ostream_close(os); + } + } + apk_dependency_array_free(&deps); +} + +static void info_print_description(struct apk_database *db, struct apk_package *pkg) +{ + if (apk_verbosity > 1) + printf("%s: %s", pkg->name->name, pkg->description); + else + printf(PKG_VER_FMT " description:\n%s\n", + PKG_VER_PRINTF(pkg), + pkg->description); +} + +static void info_print_url(struct apk_database *db, struct apk_package *pkg) +{ + if (apk_verbosity > 1) + printf("%s: %s", pkg->name->name, pkg->url); + else + printf(PKG_VER_FMT " webpage:\n%s\n", + PKG_VER_PRINTF(pkg), + pkg->url); +} + +static void info_print_license(struct apk_database *db, struct apk_package *pkg) +{ + if (apk_verbosity > 1) + printf("%s: " BLOB_FMT , pkg->name->name, BLOB_PRINTF(*pkg->license)); + else + printf(PKG_VER_FMT " license:\n" BLOB_FMT "\n", + PKG_VER_PRINTF(pkg), + BLOB_PRINTF(*pkg->license)); +} + +static void info_print_size(struct apk_database *db, struct apk_package *pkg) +{ + off_t size; + const char *size_unit; + + size_unit = apk_get_human_size(pkg->installed_size, &size); + if (apk_verbosity > 1) + printf("%s: %lld %s", pkg->name->name, + (long long)size, size_unit); + else + printf(PKG_VER_FMT " installed size:\n%lld %s\n", + PKG_VER_PRINTF(pkg), (long long)size, size_unit); +} + +static void info_print_dep_array(struct apk_database *db, struct apk_package *pkg, + struct apk_dependency_array *deps, const char *dep_text) +{ + struct apk_dependency *d; + apk_blob_t separator = APK_BLOB_STR(apk_verbosity > 1 ? " " : "\n"); + char buf[256]; + + if (apk_verbosity == 1) + printf(PKG_VER_FMT " %s:\n", PKG_VER_PRINTF(pkg), dep_text); + if (apk_verbosity > 1) + printf("%s: ", pkg->name->name); + foreach_array_item(d, deps) { + apk_blob_t b = APK_BLOB_BUF(buf); + apk_blob_push_dep(&b, db, d); + apk_blob_push_blob(&b, separator); + b = apk_blob_pushed(APK_BLOB_BUF(buf), b); + fwrite(b.ptr, b.len, 1, stdout); + } +} + +static void info_print_depends(struct apk_database *db, struct apk_package *pkg) +{ + info_print_dep_array(db, pkg, pkg->depends, "depends on"); +} + +static void info_print_provides(struct apk_database *db, struct apk_package *pkg) +{ + info_print_dep_array(db, pkg, pkg->provides, "provides"); +} + +static void print_rdep_pkg(struct apk_package *pkg0, struct apk_dependency *dep0, struct apk_package *pkg, void *pctx) +{ + printf(PKG_VER_FMT "%s", PKG_VER_PRINTF(pkg0), apk_verbosity > 1 ? " " : "\n"); +} + +static void info_print_required_by(struct apk_database *db, struct apk_package *pkg) +{ + if (apk_verbosity == 1) + printf(PKG_VER_FMT " is required by:\n", PKG_VER_PRINTF(pkg)); + if (apk_verbosity > 1) + printf("%s: ", pkg->name->name); + apk_pkg_foreach_reverse_dependency( + pkg, + APK_FOREACH_INSTALLED | APK_DEP_SATISFIES | apk_foreach_genid(), + print_rdep_pkg, NULL); +} + +static void info_print_install_if(struct apk_database *db, struct apk_package *pkg) +{ + info_print_dep_array(db, pkg, pkg->install_if, "has auto-install rule"); +} + +static void info_print_rinstall_if(struct apk_database *db, struct apk_package *pkg) +{ + int i, j; + char *separator = apk_verbosity > 1 ? " " : "\n"; + + if (apk_verbosity == 1) + printf(PKG_VER_FMT " affects auto-installation of:\n", + PKG_VER_PRINTF(pkg)); + if (apk_verbosity > 1) + printf("%s: ", pkg->name->name); + for (i = 0; i < pkg->name->rinstall_if->num; i++) { + struct apk_name *name0; + struct apk_package *pkg0; + + /* Check only the package that is installed, and that + * it actually has this package in install_if. */ + name0 = pkg->name->rinstall_if->item[i]; + pkg0 = apk_pkg_get_installed(name0); + if (pkg0 == NULL) + continue; + + for (j = 0; j < pkg0->install_if->num; j++) { + if (pkg0->install_if->item[j].name != pkg->name) + continue; + printf(PKG_VER_FMT "%s", + PKG_VER_PRINTF(pkg0), + separator); + break; + } + } +} + +static void info_print_contents(struct apk_database *db, struct apk_package *pkg) +{ + struct apk_installed_package *ipkg = pkg->ipkg; + struct apk_db_dir_instance *diri; + struct apk_db_file *file; + struct hlist_node *dc, *dn, *fc, *fn; + + if (apk_verbosity == 1) + printf(PKG_VER_FMT " contains:\n", + PKG_VER_PRINTF(pkg)); + + hlist_for_each_entry_safe(diri, dc, dn, &ipkg->owned_dirs, + pkg_dirs_list) { + hlist_for_each_entry_safe(file, fc, fn, &diri->owned_files, + diri_files_list) { + if (apk_verbosity > 1) + printf("%s: ", pkg->name->name); + printf(DIR_FILE_FMT "\n", DIR_FILE_PRINTF(diri->dir, file)); + } + } +} + +static void info_print_triggers(struct apk_database *db, struct apk_package *pkg) +{ + struct apk_installed_package *ipkg = pkg->ipkg; + char **trigger; + + if (apk_verbosity == 1) + printf(PKG_VER_FMT " triggers:\n", + PKG_VER_PRINTF(pkg)); + + foreach_array_item(trigger, ipkg->triggers) { + if (apk_verbosity > 1) + printf("%s: trigger ", pkg->name->name); + printf("%s\n", *trigger); + } +} + +static void info_print_replaces(struct apk_database *db, struct apk_package *pkg) +{ + info_print_dep_array(db, pkg, pkg->ipkg->replaces, "replaces"); +} + +static void info_subaction(struct info_ctx *ctx, struct apk_package *pkg) +{ + typedef void (*subaction_t)(struct apk_database *, struct apk_package *); + static subaction_t subactions[] = { + info_print_description, + info_print_url, + info_print_size, + info_print_depends, + info_print_provides, + info_print_required_by, + info_print_contents, + info_print_triggers, + info_print_install_if, + info_print_rinstall_if, + info_print_replaces, + info_print_license, + }; + const int requireipkg = + APK_INFO_CONTENTS | APK_INFO_TRIGGERS | APK_INFO_RDEPENDS | + APK_INFO_RINSTALL_IF | APK_INFO_REPLACES; + int i; + + for (i = 0; i < ARRAY_SIZE(subactions); i++) { + if (!(BIT(i) & ctx->subaction_mask)) + continue; + + if (pkg->ipkg == NULL && (BIT(i) & requireipkg)) + continue; + + subactions[i](ctx->db, pkg); + puts(""); + } +} + +static void print_name_info(struct apk_database *db, const char *match, struct apk_name *name, void *pctx) +{ + struct info_ctx *ctx = (struct info_ctx *) pctx; + struct apk_provider *p; + + if (name == NULL) { + ctx->errors++; + return; + } + + foreach_array_item(p, name->providers) + info_subaction(ctx, p->pkg); +} + +static int option_parse_applet(void *pctx, struct apk_db_options *dbopts, int optch, const char *optarg) +{ + struct info_ctx *ctx = (struct info_ctx *) pctx; + + ctx->action = NULL; + switch (optch) { + case 'e': + ctx->action = info_exists; + dbopts->open_flags |= APK_OPENF_NO_REPOS; + break; + case 'W': + ctx->action = info_who_owns; + dbopts->open_flags |= APK_OPENF_NO_REPOS; + break; + case 'w': + ctx->subaction_mask |= APK_INFO_URL; + break; + case 'R': + ctx->subaction_mask |= APK_INFO_DEPENDS; + break; + case 'P': + ctx->subaction_mask |= APK_INFO_PROVIDES; + break; + case 'r': + ctx->subaction_mask |= APK_INFO_RDEPENDS; + break; + case 0x10002: + ctx->subaction_mask |= APK_INFO_INSTALL_IF; + break; + case 0x10003: + ctx->subaction_mask |= APK_INFO_RINSTALL_IF; + break; + case 's': + ctx->subaction_mask |= APK_INFO_SIZE; + break; + case 'd': + ctx->subaction_mask |= APK_INFO_DESC; + break; + case 'L': + ctx->subaction_mask |= APK_INFO_CONTENTS; + break; + case 't': + ctx->subaction_mask |= APK_INFO_TRIGGERS; + break; + case 0x10000: + ctx->subaction_mask |= APK_INFO_REPLACES; + break; + case 0x10001: + ctx->subaction_mask |= APK_INFO_LICENSE; + break; + case 'a': + ctx->subaction_mask = 0xffffffff; + break; + default: + return -ENOTSUP; + } + return 0; +} + +static int info_main(void *ctx, struct apk_database *db, struct apk_string_array *args) +{ + struct info_ctx *ictx = (struct info_ctx *) ctx; + struct apk_installed_package *ipkg; + + ictx->db = db; + if (ictx->subaction_mask == 0) + ictx->subaction_mask = APK_INFO_DESC | APK_INFO_URL | APK_INFO_SIZE; + if (ictx->action != NULL) { + ictx->action(ictx, db, args); + } else if (args->num > 0) { + /* Print info on given names */ + apk_name_foreach_matching( + db, args, APK_FOREACH_NULL_MATCHES_ALL | apk_foreach_genid(), + print_name_info, ctx); + } else { + /* Print all installed packages */ + list_for_each_entry(ipkg, &db->installed.packages, installed_pkgs_list) + verbose_print_pkg(ipkg->pkg, 1); + } + + return ictx->errors; +} + +static const struct apk_option options_applet[] = { + { 'L', "contents" }, + { 'e', "installed" }, + { 'W', "who-owns" }, + { 'R', "depends" }, + { 'P', "provides" }, + { 'r', "rdepends" }, + { 0x10000, "replaces" }, + { 0x10002, "install-if" }, + { 0x10003, "rinstall-if" }, + { 'w', "webpage" }, + { 's', "size" }, + { 'd', "description" }, + { 0x10001, "license" }, + { 't', "triggers" }, + { 'a', "all" }, +}; + +static const struct apk_option_group optgroup_applet = { + .name = "Info", + .options = options_applet, + .num_options = ARRAY_SIZE(options_applet), + .parse = option_parse_applet, +}; + +static struct apk_applet apk_info = { + .name = "info", + .arguments = "PACKAGE...", + .open_flags = APK_OPENF_READ, + .command_groups = APK_COMMAND_GROUP_QUERY, + .context_size = sizeof(struct info_ctx), + .optgroups = { &optgroup_global, &optgroup_applet }, + .main = info_main, +}; + +APK_DEFINE_APPLET(apk_info); + diff --git a/src/app_list.c b/src/app_list.c new file mode 100644 index 0000000..3315ea3 --- /dev/null +++ b/src/app_list.c @@ -0,0 +1,272 @@ +/* app_list.c - Alpine Package Keeper (APK) + * + * Copyright (C) 2005-2009 Natanael Copa + * Copyright (C) 2008-2011 Timo Teräs + * Copyright (C) 2018 William Pitcock + * 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 +#include "apk_defines.h" +#include "apk_applet.h" +#include "apk_package.h" +#include "apk_database.h" +#include "apk_print.h" + +struct list_ctx { + unsigned int installed : 1; + unsigned int orphaned : 1; + unsigned int available : 1; + unsigned int upgradable : 1; + unsigned int match_origin : 1; + unsigned int match_depends : 1; + unsigned int match_providers : 1; + + struct apk_string_array *filters; +}; + +static int origin_matches(const struct list_ctx *ctx, const struct apk_package *pkg) +{ + char **pmatch; + + if (pkg->origin == NULL) + return 0; + + foreach_array_item(pmatch, ctx->filters) + { + if (apk_blob_compare(APK_BLOB_STR(*pmatch), *pkg->origin) == 0) + return 1; + } + + return 0; +} + +static int is_orphaned(const struct apk_name *name) +{ + struct apk_provider *p; + unsigned int repos = 0; + + if (name == NULL) + return 0; + + foreach_array_item(p, name->providers) + repos |= p->pkg->repos; + + /* repo 1 is always installed-db, so if other bits are set it means the package is available somewhere + * (either cache or in a proper repo) + */ + return (repos & ~BIT(APK_REPOSITORY_CACHED)) == 0; +} + +/* returns the currently installed package if there is a newer package that satisfies `name` */ +static const struct apk_package *is_upgradable(struct apk_name *name, const struct apk_package *pkg0) +{ + struct apk_provider *p; + struct apk_package *ipkg; + apk_blob_t *latest = apk_blob_atomize(APK_BLOB_STR("")); + + if (name == NULL) + return NULL; + + ipkg = apk_pkg_get_installed(name); + if (ipkg == NULL) + return NULL; + + if (pkg0 == NULL) + { + foreach_array_item(p, name->providers) + { + pkg0 = p->pkg; + int r; + + if (pkg0 == ipkg) + continue; + + r = apk_version_compare_blob(*pkg0->version, *latest); + if (r == APK_VERSION_GREATER) + latest = pkg0->version; + } + } + else + latest = pkg0->version; + + return apk_version_compare_blob(*ipkg->version, *latest) == APK_VERSION_LESS ? ipkg : NULL; +} + +static void print_package(const struct apk_package *pkg, const struct list_ctx *ctx) +{ + printf(PKG_VER_FMT " " BLOB_FMT " ", + PKG_VER_PRINTF(pkg), BLOB_PRINTF(*pkg->arch)); + + if (pkg->origin != NULL) + printf("{" BLOB_FMT "}", BLOB_PRINTF(*pkg->origin)); + else + printf("{%s}", pkg->name->name); + + printf(" (" BLOB_FMT ")", BLOB_PRINTF(*pkg->license)); + + if (pkg->ipkg) + printf(" [installed]"); + else + { + const struct apk_package *u; + + u = is_upgradable(pkg->name, pkg); + if (u != NULL) + printf(" [upgradable from: " PKG_VER_FMT "]", PKG_VER_PRINTF(u)); + } + + + if (apk_verbosity > 1) + { + printf("\n %s\n", pkg->description); + if (apk_verbosity > 2) + printf(" <%s>\n", pkg->url); + } + + printf("\n"); +} + +static void filter_package(const struct apk_package *pkg, const struct list_ctx *ctx) +{ + if (ctx->match_origin && !origin_matches(ctx, pkg)) + return; + + if (ctx->installed && pkg->ipkg == NULL) + return; + + if (ctx->orphaned && !is_orphaned(pkg->name)) + return; + + if (ctx->available && pkg->repos == BIT(APK_REPOSITORY_CACHED)) + return; + + if (ctx->upgradable && !is_upgradable(pkg->name, pkg)) + return; + + print_package(pkg, ctx); +} + +static void iterate_providers(const struct apk_name *name, const struct list_ctx *ctx) +{ + struct apk_provider *p; + + foreach_array_item(p, name->providers) + { + if (!ctx->match_providers && p->pkg->name != name) + continue; + + if (ctx->match_providers) + printf("<%s> ", name->name); + + filter_package(p->pkg, ctx); + } +} + +static void print_result(struct apk_database *db, const char *match, struct apk_name *name, void *pctx) +{ + struct list_ctx *ctx = pctx; + + if (name == NULL) + return; + + if (ctx->match_depends) + { + struct apk_name **pname; + + foreach_array_item(pname, name->rdepends) + iterate_providers(*pname, ctx); + } + else + iterate_providers(name, ctx); +} + +static int option_parse_applet(void *pctx, struct apk_db_options *dbopts, int optch, const char *optarg) +{ + struct list_ctx *ctx = pctx; + + switch (optch) + { + case 'I': + ctx->installed = 1; + break; + case 'O': + ctx->installed = 1; + ctx->orphaned = 1; + break; + case 'u': + ctx->available = 1; + ctx->orphaned = 0; + ctx->installed = 0; + ctx->upgradable = 1; + break; + case 'a': + ctx->available = 1; + ctx->orphaned = 0; + break; + case 'o': + ctx->match_origin = 1; + break; + case 'd': + ctx->match_depends = 1; + break; + case 'P': + ctx->match_providers = 1; + break; + default: + return -ENOTSUP; + } + + return 0; +} + +static const struct apk_option options_applet[] = { + { 'I', "installed" }, + { 'O', "orphaned" }, + { 'a', "available" }, + { 'u', "upgradable" }, + { 'o', "origin" }, + { 'd', "depends" }, + { 'P', "providers" }, +}; + +static const struct apk_option_group optgroup_applet = { + .name = "List", + .options = options_applet, + .num_options = ARRAY_SIZE(options_applet), + .parse = option_parse_applet, +}; + +static int list_main(void *pctx, struct apk_database *db, struct apk_string_array *args) +{ + struct list_ctx *ctx = pctx; + + ctx->filters = args; + + if (ctx->match_origin) + args = NULL; + + apk_name_foreach_matching( + db, args, APK_FOREACH_NULL_MATCHES_ALL | apk_foreach_genid(), + print_result, ctx); + + return 0; +} + +static struct apk_applet apk_list = { + .name = "list", + .arguments = "PATTERN", + .open_flags = APK_OPENF_READ, + .command_groups = APK_COMMAND_GROUP_QUERY, + .context_size = sizeof(struct list_ctx), + .optgroups = { &optgroup_global, &optgroup_applet }, + .main = list_main, +}; + +APK_DEFINE_APPLET(apk_list); diff --git a/src/app_manifest.c b/src/app_manifest.c new file mode 100644 index 0000000..fe64bea --- /dev/null +++ b/src/app_manifest.c @@ -0,0 +1,133 @@ +/* app_manifest.c - Alpine Package Keeper (APK) + * + * Copyright (C) 2005-2017 Natanael Copa + * Copyright (C) 2008-2017 Timo Teräs + * Copyright (C) 2017 William Pitcock + * 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_defines.h" +#include "apk_applet.h" +#include "apk_database.h" +#include "apk_version.h" +#include "apk_print.h" + +/* TODO: support package files as well as generating manifest from the installed DB. */ +static char *csum_types[APK_CHECKSUM_SHA1 + 1] = { + /* Note: if adding new algorithms, update apk-manifest(8) */ + [APK_CHECKSUM_MD5] = "md5", + [APK_CHECKSUM_SHA1] = "sha1", +}; + +struct manifest_file_ctx { + const char *file; + struct apk_sign_ctx *sctx; +}; + +static void process_package(struct apk_database *db, struct apk_package *pkg) +{ + struct apk_installed_package *ipkg = pkg->ipkg; + struct apk_db_dir_instance *diri; + struct apk_db_file *file; + struct hlist_node *dc, *dn, *fc, *fn; + char csum_buf[APK_BLOB_CHECKSUM_BUF]; + + if (ipkg == NULL) + return; + + hlist_for_each_entry_safe(diri, dc, dn, &ipkg->owned_dirs, + pkg_dirs_list) { + hlist_for_each_entry_safe(file, fc, fn, &diri->owned_files, + diri_files_list) { + apk_blob_t csum_blob = APK_BLOB_BUF(csum_buf); + + memset(csum_buf, '\0', sizeof(csum_buf)); + apk_blob_push_hexdump(&csum_blob, APK_BLOB_CSUM(file->csum)); + + if (apk_verbosity > 1) + printf("%s: ", pkg->name->name); + + printf("%s:%s " DIR_FILE_FMT "\n", csum_types[file->csum.type], csum_buf, DIR_FILE_PRINTF(diri->dir, file)); + } + } +} + +static int read_file_entry(void *ctx, const struct apk_file_info *ae, + struct apk_istream *is) +{ + struct manifest_file_ctx *mctx = ctx; + char csum_buf[APK_BLOB_CHECKSUM_BUF]; + apk_blob_t csum_blob = APK_BLOB_BUF(csum_buf); + int r; + + r = apk_sign_ctx_verify_tar(mctx->sctx, ae, is); + if (r != 0) + return r; + + if (!mctx->sctx->data_started) + return 0; + + if ((ae->mode & S_IFMT) != S_IFREG) + return 0; + + memset(csum_buf, '\0', sizeof(csum_buf)); + apk_blob_push_hexdump(&csum_blob, APK_BLOB_CSUM(ae->csum)); + + if (apk_verbosity > 1) + printf("%s: ", mctx->file); + + printf("%s:%s %s\n", csum_types[ae->csum.type], csum_buf, ae->name); + + return 0; +} + +static void process_file(struct apk_database *db, const char *match) +{ + struct apk_sign_ctx sctx; + struct manifest_file_ctx ctx = {match, &sctx}; + int r; + + apk_sign_ctx_init(&sctx, APK_SIGN_VERIFY, NULL, db->keys_fd); + r = apk_tar_parse( + apk_istream_gunzip_mpart(apk_istream_from_file(AT_FDCWD, match), apk_sign_ctx_mpart_cb, &sctx), + read_file_entry, &ctx, &db->id_cache); + apk_sign_ctx_free(&sctx); + if (r < 0) apk_error("%s: %s", match, apk_error_str(r)); +} + +static void process_match(struct apk_database *db, const char *match, struct apk_name *name, void *ctx) +{ + struct apk_provider *p; + + if (name == NULL) + { + process_file(db, match); + return; + } + + foreach_array_item(p, name->providers) + process_package(db, p->pkg); +} + +static int manifest_main(void *ctx, struct apk_database *db, struct apk_string_array *args) +{ + apk_name_foreach_matching(db, args, apk_foreach_genid(), process_match, NULL); + return 0; +} + +static struct apk_applet apk_manifest = { + .name = "manifest", + .arguments = "PACKAGE...", + .open_flags = APK_OPENF_READ, + .command_groups = APK_COMMAND_GROUP_REPO, + .main = manifest_main, +}; + +APK_DEFINE_APPLET(apk_manifest); diff --git a/src/app_policy.c b/src/app_policy.c new file mode 100644 index 0000000..2d6ae4f --- /dev/null +++ b/src/app_policy.c @@ -0,0 +1,80 @@ +/* app_policy.c - Alpine Package Keeper (APK) + * + * Copyright (C) 2013 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 "apk_defines.h" +#include "apk_applet.h" +#include "apk_database.h" +#include "apk_version.h" +#include "apk_print.h" + +extern const char * const apk_installed_file; + +static void print_policy(struct apk_database *db, const char *match, struct apk_name *name, void *ctx) +{ + struct apk_provider *p; + struct apk_repository *repo; + int i, j, num = 0; + + if (!name) return; + +/* +zlib1g policy: + 2.0: + @testing http://nl.alpinelinux.org/alpine/edge/testing + 1.7: + @edge http://nl.alpinelinux.org/alpine/edge/main + 1.2.3.5 (upgradeable): + http://nl.alpinelinux.org/alpine/v2.6/main + 1.2.3.4 (installed): + /media/cdrom/... + http://nl.alpinelinux.org/alpine/v2.5/main + 1.1: + http://nl.alpinelinux.org/alpine/v2.4/main +*/ + foreach_array_item(p, name->providers) { + if (p->pkg->name != name) + continue; + if (num++ == 0) + printf("%s policy:\n", name->name); + printf(" " BLOB_FMT ":\n", BLOB_PRINTF(*p->version)); + if (p->pkg->ipkg != NULL) + printf(" %s\n", apk_installed_file); + for (i = 0; i < db->num_repos; i++) { + repo = &db->repos[i]; + if (!(BIT(i) & p->pkg->repos)) + continue; + for (j = 0; j < db->num_repo_tags; j++) { + if (db->repo_tags[j].allowed_repos & p->pkg->repos) + printf(" "BLOB_FMT"%s%s\n", + BLOB_PRINTF(db->repo_tags[j].tag), + j == 0 ? "" : " ", + repo->url); + } + } + } +} + +static int policy_main(void *ctx, struct apk_database *db, struct apk_string_array *args) +{ + apk_name_foreach_matching(db, args, apk_foreach_genid(), print_policy, NULL); + return 0; +} + +static struct apk_applet apk_policy = { + .name = "policy", + .open_flags = APK_OPENF_READ, + .command_groups = APK_COMMAND_GROUP_QUERY, + .main = policy_main, +}; + +APK_DEFINE_APPLET(apk_policy); + + diff --git a/src/app_search.c b/src/app_search.c new file mode 100644 index 0000000..9bf64b2 --- /dev/null +++ b/src/app_search.c @@ -0,0 +1,217 @@ +/* app_search.c - Alpine Package Keeper (APK) + * + * Copyright (C) 2005-2009 Natanael Copa + * Copyright (C) 2008-2011 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_defines.h" +#include "apk_applet.h" +#include "apk_package.h" +#include "apk_database.h" + +struct search_ctx { + void (*print_result)(struct search_ctx *ctx, struct apk_package *pkg); + void (*print_package)(struct search_ctx *ctx, struct apk_package *pkg); + + int show_all : 1; + int search_exact : 1; + int search_description : 1; + int search_origin : 1; + + unsigned int matches; + struct apk_string_array *filter; +}; + +static int unique_match(struct apk_package *pkg) +{ + if (pkg->state_int) return 0; + pkg->state_int = 1; + return 1; +} + +static void print_package_name(struct search_ctx *ctx, struct apk_package *pkg) +{ + if (!unique_match(pkg)) return; + printf("%s", pkg->name->name); + if (apk_verbosity > 0) + printf("-" BLOB_FMT, BLOB_PRINTF(*pkg->version)); + if (apk_verbosity > 1) + printf(" - %s", pkg->description); + printf("\n"); +} + +static void print_origin_name(struct search_ctx *ctx, struct apk_package *pkg) +{ + if (!unique_match(pkg)) return; + if (pkg->origin != NULL) + printf(BLOB_FMT, BLOB_PRINTF(*pkg->origin)); + else + printf("%s", pkg->name->name); + if (apk_verbosity > 0) + printf("-" BLOB_FMT, BLOB_PRINTF(*pkg->version)); + printf("\n"); +} + +static void print_rdep_pkg(struct apk_package *pkg0, struct apk_dependency *dep0, struct apk_package *pkg, void *pctx) +{ + struct search_ctx *ctx = (struct search_ctx *) pctx; + ctx->print_package(ctx, pkg0); +} + +static void print_rdepends(struct search_ctx *ctx, struct apk_package *pkg) +{ + if (apk_verbosity > 0) { + ctx->matches = apk_foreach_genid() | APK_DEP_SATISFIES; + printf(PKG_VER_FMT " is required by:\n", PKG_VER_PRINTF(pkg)); + } + apk_pkg_foreach_reverse_dependency(pkg, ctx->matches, print_rdep_pkg, ctx); +} + +static int option_parse_applet(void *ctx, struct apk_db_options *dbopts, int optch, const char *optarg) +{ + struct search_ctx *ictx = (struct search_ctx *) ctx; + + switch (optch) { + case 'a': + ictx->show_all = 1; + break; + case 'd': + ictx->search_description = 1; + ictx->search_exact = 1; + ictx->show_all = 1; + break; + case 'e': + case 'x': + ictx->search_exact = 1; + break; + case 'o': + ictx->print_package = print_origin_name; + break; + case 'r': + ictx->print_result = print_rdepends; + break; + case 0x10000: + ictx->search_origin = 1; + ictx->search_exact = 1; + ictx->show_all = 1; + break; + default: + return -ENOTSUP; + } + return 0; +} + +static const struct apk_option options_applet[] = { + { 'a', "all" }, + { 'd', "description" }, + { 'x', "exact" }, + { 'e', NULL }, + { 'o', "origin" }, + { 'r', "rdepends" }, + { 0x10000, "has-origin" }, +}; + +static const struct apk_option_group optgroup_applet = { + .name = "Search", + .options = options_applet, + .num_options = ARRAY_SIZE(options_applet), + .parse = option_parse_applet, +}; + +static void print_result_pkg(struct search_ctx *ctx, struct apk_package *pkg) +{ + char **pmatch; + + if (ctx->search_description) { + foreach_array_item(pmatch, ctx->filter) { + if (strstr(pkg->description, *pmatch) != NULL || + strstr(pkg->name->name, *pmatch) != NULL) + goto match; + } + return; + } + if (ctx->search_origin) { + foreach_array_item(pmatch, ctx->filter) { + if (pkg->origin && apk_blob_compare(APK_BLOB_STR(*pmatch), *pkg->origin) == 0) + goto match; + } + return; + } +match: + ctx->print_result(ctx, pkg); +} + +static void print_result(struct apk_database *db, const char *match, struct apk_name *name, void *pctx) +{ + struct search_ctx *ctx = pctx; + struct apk_provider *p; + struct apk_package *pkg = NULL; + + if (!name) return; + + if (ctx->show_all) { + foreach_array_item(p, name->providers) + print_result_pkg(ctx, p->pkg); + } else { + foreach_array_item(p, name->providers) { + if (pkg == NULL || + apk_version_compare_blob(*p->version, *pkg->version) == APK_VERSION_GREATER) + pkg = p->pkg; + } + if (pkg) + print_result_pkg(ctx, pkg); + } +} + +static int print_pkg(apk_hash_item item, void *pctx) +{ + print_result_pkg((struct search_ctx *) pctx, (struct apk_package *) item); + return 0; +} + +static int search_main(void *pctx, struct apk_database *db, struct apk_string_array *args) +{ + struct search_ctx *ctx = (struct search_ctx *) pctx; + char *tmp, **pmatch; + + ctx->filter = args; + ctx->matches = apk_foreach_genid() | APK_DEP_SATISFIES; + if (ctx->print_package == NULL) + ctx->print_package = print_package_name; + if (ctx->print_result == NULL) + ctx->print_result = ctx->print_package; + + if (ctx->search_description || ctx->search_origin) + return apk_hash_foreach(&db->available.packages, print_pkg, ctx); + + if (!ctx->search_exact) { + foreach_array_item(pmatch, ctx->filter) { + tmp = alloca(strlen(*pmatch) + 3); + sprintf(tmp, "*%s*", *pmatch); + *pmatch = tmp; + } + } + apk_name_foreach_matching( + db, args, APK_FOREACH_NULL_MATCHES_ALL | apk_foreach_genid(), + print_result, ctx); + return 0; +} + +static struct apk_applet apk_search = { + .name = "search", + .arguments = "PATTERN", + .open_flags = APK_OPENF_READ | APK_OPENF_NO_STATE, + .command_groups = APK_COMMAND_GROUP_QUERY, + .context_size = sizeof(struct search_ctx), + .optgroups = { &optgroup_global, &optgroup_applet }, + .main = search_main, +}; + +APK_DEFINE_APPLET(apk_search); diff --git a/src/app_stats.c b/src/app_stats.c new file mode 100644 index 0000000..f800777 --- /dev/null +++ b/src/app_stats.c @@ -0,0 +1,64 @@ +/* app_stats.c - Alpine Package Keeper (APK) + * + * Copyright (C) 2013 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 "apk_defines.h" +#include "apk_applet.h" +#include "apk_database.h" + +static int list_count(struct list_head *h) +{ + struct list_head *n; + int c = 0; + + list_for_each(n, h) + c++; + + return c; +} + +static int stats_main(void *ctx, struct apk_database *db, struct apk_string_array *args) +{ + extern struct apk_hash atom_hash; + + printf( + "installed:\n" + " packages: %d\n" + " dirs: %d\n" + " files: %d\n" + " bytes: %zu\n" + " triggers: %d\n" + "available:\n" + " names: %d\n" + " packages: %d\n" + "atoms:\n" + " num: %d\n" + , + db->installed.stats.packages, + db->installed.stats.dirs, + db->installed.stats.files, + db->installed.stats.bytes, + list_count(&db->installed.triggers), + db->available.names.num_items, + db->available.packages.num_items, + atom_hash.num_items + ); + return 0; +} + +static struct apk_applet stats_applet = { + .name = "stats", + .open_flags = APK_OPENF_READ, + .main = stats_main, +}; + +APK_DEFINE_APPLET(stats_applet); + + diff --git a/src/app_update.c b/src/app_update.c new file mode 100644 index 0000000..bbb2b09 --- /dev/null +++ b/src/app_update.c @@ -0,0 +1,57 @@ +/* app_update.c - Alpine Package Keeper (APK) + * + * Copyright (C) 2005-2008 Natanael Copa + * Copyright (C) 2008-2011 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 "apk_defines.h" +#include "apk_applet.h" +#include "apk_database.h" +#include "apk_version.h" +#include "apk_print.h" + +static int update_main(void *ctx, struct apk_database *db, struct apk_string_array *args) +{ + struct apk_repository *repo; + int i; + char buf[32] = "OK:"; + + if (apk_verbosity < 1) + return db->repo_update_errors; + + for (i = 0; i < db->num_repos; i++) { + repo = &db->repos[i]; + + if (APK_BLOB_IS_NULL(repo->description)) + continue; + + apk_message(BLOB_FMT " [%s]", + BLOB_PRINTF(repo->description), + db->repos[i].url); + } + + if (db->repo_update_errors != 0) + snprintf(buf, sizeof(buf), "%d errors;", + db->repo_update_errors); + apk_message("%s %d distinct packages available", buf, + db->available.packages.num_items); + + return db->repo_update_errors; +} + +static struct apk_applet apk_update = { + .name = "update", + .open_flags = APK_OPENF_WRITE, + .forced_force = APK_FORCE_REFRESH, + .command_groups = APK_COMMAND_GROUP_SYSTEM, + .main = update_main, +}; + +APK_DEFINE_APPLET(apk_update); + diff --git a/src/app_upgrade.c b/src/app_upgrade.c new file mode 100644 index 0000000..02b1ae7 --- /dev/null +++ b/src/app_upgrade.c @@ -0,0 +1,198 @@ +/* app_upgrade.c - Alpine Package Keeper (APK) + * + * Copyright (C) 2005-2008 Natanael Copa + * Copyright (C) 2008-2011 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 +#include +#include "apk_applet.h" +#include "apk_database.h" +#include "apk_print.h" +#include "apk_solver.h" + +struct upgrade_ctx { + unsigned short solver_flags; + int no_self_upgrade : 1; + int self_upgrade_only : 1; + int ignore : 1; +}; + +static int option_parse_applet(void *ctx, struct apk_db_options *dbopts, int optch, const char *optarg) +{ + struct upgrade_ctx *uctx = (struct upgrade_ctx *) ctx; + + switch (optch) { + case 0x10000: + uctx->no_self_upgrade = 1; + break; + case 0x10001: + uctx->self_upgrade_only = 1; + break; + case 0x10002: + uctx->ignore = 1; + break; + case 'a': + uctx->solver_flags |= APK_SOLVERF_AVAILABLE; + break; + case 'l': + uctx->solver_flags |= APK_SOLVERF_LATEST; + break; + default: + return -ENOTSUP; + } + return 0; +} + +static const struct apk_option options_applet[] = { + { 'a', "available" }, + { 'l', "latest" }, + { 0x10000, "no-self-upgrade" }, + { 0x10001, "self-upgrade-only" }, + { 0x10002, "ignore" }, +}; + +static const struct apk_option_group optgroup_applet = { + .name = "Upgrade", + .options = options_applet, + .num_options = ARRAY_SIZE(options_applet), + .parse = option_parse_applet, +}; + +int apk_do_self_upgrade(struct apk_database *db, unsigned short solver_flags, unsigned int self_upgrade_only) +{ + struct apk_name *name; + struct apk_package *pkg; + struct apk_provider *p0; + struct apk_changeset changeset = {}; + int r; + + name = apk_db_get_name(db, APK_BLOB_STR("apk-tools")); + + /* First check if new version is even available */ + r = 0; + pkg = apk_pkg_get_installed(name); + if (!pkg) goto ret; + + foreach_array_item(p0, name->providers) { + struct apk_package *pkg0 = p0->pkg; + if (pkg0->name != name || pkg0->repos == 0) + continue; + if (apk_version_compare_blob(*pkg0->version, *pkg->version) == APK_VERSION_GREATER) { + r = 1; + break; + } + } + + if (r == 0) goto ret; + + /* Create new commit upgrading apk-tools only with minimal other changes */ + db->performing_self_upgrade = 1; + apk_solver_set_name_flags(name, solver_flags, 0); + + r = apk_solver_solve(db, 0, db->world, &changeset); + if (r != 0) { + apk_warning("Failed to perform initial self-upgrade, continuing with full upgrade."); + r = 0; + goto ret; + } + + if (changeset.num_total_changes == 0) + goto ret; + + if (!self_upgrade_only && apk_flags & APK_SIMULATE) { + apk_warning("This simulation is not reliable as apk-tools upgrade is available."); + goto ret; + } + + apk_message("Upgrading critical system libraries and apk-tools:"); + apk_solver_commit_changeset(db, &changeset, db->world); + if (self_upgrade_only) goto ret; + + apk_db_close(db); + + apk_message("Continuing the upgrade transaction with new apk-tools:"); + for (r = 0; apk_argv[r] != NULL; r++) + ; + apk_argv[r] = "--no-self-upgrade"; + execvp(apk_argv[0], apk_argv); + + apk_error("PANIC! Failed to re-execute new apk-tools!"); + exit(1); + +ret: + apk_change_array_free(&changeset.changes); + db->performing_self_upgrade = 0; + return r; +} + +static int upgrade_main(void *ctx, struct apk_database *db, struct apk_string_array *args) +{ + struct upgrade_ctx *uctx = (struct upgrade_ctx *) ctx; + unsigned short solver_flags; + struct apk_dependency *dep; + struct apk_dependency_array *world = NULL; + int r = 0; + + if (apk_db_check_world(db, db->world) != 0) { + apk_error("Not continuing with upgrade due to missing repository tags. " + "Use --force-broken-world to override."); + return -1; + } + + solver_flags = APK_SOLVERF_UPGRADE | uctx->solver_flags; + if (!uctx->no_self_upgrade) { + r = apk_do_self_upgrade(db, solver_flags, uctx->self_upgrade_only); + if (r != 0) + return r; + } + if (uctx->self_upgrade_only) + return 0; + + if (uctx->ignore) { + char **pkg_name; + struct apk_name *name; + foreach_array_item(pkg_name, args) { + name = apk_db_get_name(db, APK_BLOB_STR(*pkg_name)); + apk_solver_set_name_flags(name, solver_flags | APK_SOLVERF_IGNORE_UPGRADE, 0); + } + } + + if (solver_flags & APK_SOLVERF_AVAILABLE) { + apk_dependency_array_copy(&world, db->world); + foreach_array_item(dep, world) { + if (dep->result_mask == APK_DEPMASK_CHECKSUM) { + dep->result_mask = APK_DEPMASK_ANY; + dep->version = apk_blob_atomize(APK_BLOB_NULL); + } + } + } else { + world = db->world; + } + + r = apk_solver_commit(db, solver_flags, world); + + if (solver_flags & APK_SOLVERF_AVAILABLE) + apk_dependency_array_free(&world); + + return r; +} + +static struct apk_applet apk_upgrade = { + .name = "upgrade", + .open_flags = APK_OPENF_WRITE, + .command_groups = APK_COMMAND_GROUP_SYSTEM, + .context_size = sizeof(struct upgrade_ctx), + .optgroups = { &optgroup_global, &optgroup_commit, &optgroup_applet }, + .main = upgrade_main, +}; + +APK_DEFINE_APPLET(apk_upgrade); + diff --git a/src/app_verify.c b/src/app_verify.c new file mode 100644 index 0000000..296253c --- /dev/null +++ b/src/app_verify.c @@ -0,0 +1,59 @@ +/* app_verify.c - Alpine Package Keeper (APK) + * + * Copyright (C) 2008-2011 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 +#include + +#include "apk_applet.h" +#include "apk_database.h" +#include "apk_print.h" + +static int verify_main(void *ctx, struct apk_database *db, struct apk_string_array *args) +{ + struct apk_sign_ctx sctx; + char **parg; + int r, ok, rc = 0; + + foreach_array_item(parg, args) { + apk_sign_ctx_init(&sctx, APK_SIGN_VERIFY, NULL, db->keys_fd); + r = apk_tar_parse( + apk_istream_gunzip_mpart(apk_istream_from_file(AT_FDCWD, *parg), + apk_sign_ctx_mpart_cb, &sctx), + apk_sign_ctx_verify_tar, &sctx, &db->id_cache); + ok = sctx.control_verified && sctx.data_verified; + if (apk_verbosity >= 1) + apk_message("%s: %d - %s", *parg, r, + r < 0 ? apk_error_str(r) : + ok ? "OK" : + !sctx.control_verified ? "UNTRUSTED" : "FAILED"); + else if (!ok) + printf("%s\n", *parg); + if (!ok) + rc++; + + apk_sign_ctx_free(&sctx); + } + + return rc; +} + +static struct apk_applet apk_verify = { + .name = "verify", + .arguments = "FILE...", + .open_flags = APK_OPENF_READ | APK_OPENF_NO_STATE, + .command_groups = APK_COMMAND_GROUP_REPO, + .forced_flags = APK_ALLOW_UNTRUSTED, + .main = verify_main, +}; + +APK_DEFINE_APPLET(apk_verify); + diff --git a/src/app_version.c b/src/app_version.c new file mode 100644 index 0000000..a29d899 --- /dev/null +++ b/src/app_version.c @@ -0,0 +1,207 @@ +/* app_version.c - Alpine Package Keeper (APK) + * + * Copyright (C) 2005-2008 Natanael Copa + * Copyright (C) 2008-2011 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 "apk_defines.h" +#include "apk_applet.h" +#include "apk_database.h" +#include "apk_version.h" +#include "apk_print.h" + +struct ver_ctx { + int (*action)(struct apk_database *db, struct apk_string_array *args); + const char *limchars; + int all_tags : 1; +}; + +static int ver_indexes(struct apk_database *db, struct apk_string_array *args) +{ + struct apk_repository *repo; + int i; + + for (i = 0; i < db->num_repos; i++) { + repo = &db->repos[i]; + + if (APK_BLOB_IS_NULL(repo->description)) + continue; + + printf(BLOB_FMT " [%s]\n", + BLOB_PRINTF(repo->description), + db->repos[i].url); + } + + return 0; +} + +static int ver_test(struct apk_database *db, struct apk_string_array *args) +{ + int r; + + if (args->num != 2) + return 1; + + r = apk_version_compare(args->item[0], args->item[1]); + printf("%s\n", apk_version_op_string(r)); + return 0; +} + +static int ver_validate(struct apk_database *db, struct apk_string_array *args) +{ + char **parg; + int errors = 0; + + foreach_array_item(parg, args) { + if (!apk_version_validate(APK_BLOB_STR(*parg))) { + if (apk_verbosity > 0) + printf("%s\n", *parg); + errors++; + } + } + return errors; +} + +static int option_parse_applet(void *ctx, struct apk_db_options *dbopts, int optch, const char *optarg) +{ + struct ver_ctx *ictx = (struct ver_ctx *) ctx; + switch (optch) { + case 'I': + ictx->action = ver_indexes; + break; + case 't': + ictx->action = ver_test; + dbopts->open_flags |= APK_OPENF_NO_STATE | APK_OPENF_NO_REPOS; + break; + case 'c': + ictx->action = ver_validate; + dbopts->open_flags |= APK_OPENF_NO_STATE | APK_OPENF_NO_REPOS; + break; + case 'l': + ictx->limchars = optarg; + break; + case 'a': + ictx->all_tags = 1; + break; + default: + return -ENOTSUP; + } + return 0; +} + +static const struct apk_option options_applet[] = { + { 'I', "indexes" }, + { 't', "test" }, + { 'c', "check" }, + { 'a', "all" }, + { 'l', "limit", required_argument, "LIMCHARs" }, +}; + +static const struct apk_option_group optgroup_applet = { + .name = "Version", + .options = options_applet, + .num_options = ARRAY_SIZE(options_applet), + .parse = option_parse_applet, +}; + +static void ver_print_package_status(struct apk_database *db, const char *match, struct apk_name *name, void *pctx) +{ + struct ver_ctx *ctx = (struct ver_ctx *) pctx; + struct apk_package *pkg; + struct apk_provider *p0; + char pkgname[41]; + const char *opstr; + apk_blob_t *latest = apk_blob_atomize(APK_BLOB_STR("")); + unsigned int latest_repos = 0; + int i, r = -1; + unsigned short tag, allowed_repos; + + if (!name) return; + + pkg = apk_pkg_get_installed(name); + if (!pkg) return; + + tag = pkg->ipkg->repository_tag; + allowed_repos = db->repo_tags[tag].allowed_repos; + + foreach_array_item(p0, name->providers) { + struct apk_package *pkg0 = p0->pkg; + if (pkg0->name != name || pkg0->repos == 0) + continue; + if (!(ctx->all_tags || (pkg0->repos & allowed_repos))) + continue; + r = apk_version_compare_blob(*pkg0->version, *latest); + switch (r) { + case APK_VERSION_GREATER: + latest = pkg0->version; + latest_repos = pkg0->repos; + break; + case APK_VERSION_EQUAL: + latest_repos |= pkg0->repos; + break; + } + } + r = latest->len ? apk_version_compare_blob(*pkg->version, *latest) + : APK_VERSION_UNKNOWN; + opstr = apk_version_op_string(r); + if ((ctx->limchars != NULL) && (strchr(ctx->limchars, *opstr) == NULL)) + return; + if (apk_verbosity <= 0) { + printf("%s\n", pkg->name->name); + return; + } + + tag = APK_DEFAULT_REPOSITORY_TAG; + for (i = 1; i < db->num_repo_tags; i++) { + if (latest_repos & db->repo_tags[i].allowed_repos) { + tag = i; + break; + } + } + + snprintf(pkgname, sizeof(pkgname), PKG_VER_FMT, PKG_VER_PRINTF(pkg)); + printf("%-40s%s " BLOB_FMT " " BLOB_FMT "\n", + pkgname, opstr, + BLOB_PRINTF(*latest), + BLOB_PRINTF(db->repo_tags[tag].tag)); +} + +static int ver_main(void *pctx, struct apk_database *db, struct apk_string_array *args) +{ + struct ver_ctx *ctx = (struct ver_ctx *) pctx; + + if (ctx->limchars) { + if (strlen(ctx->limchars) == 0) + ctx->limchars = NULL; + } else if (args->num == 0 && apk_verbosity == 1) { + ctx->limchars = "<"; + } + + if (ctx->action != NULL) + return ctx->action(db, args); + + if (apk_verbosity > 0) + printf("%-42sAvailable:\n", "Installed:"); + + apk_name_foreach_matching( + db, args, APK_FOREACH_NULL_MATCHES_ALL | apk_foreach_genid(), + ver_print_package_status, ctx); + + return 0; +} + +static struct apk_applet apk_ver = { + .name = "version", + .open_flags = APK_OPENF_READ, + .context_size = sizeof(struct ver_ctx), + .optgroups = { &optgroup_global, &optgroup_applet }, + .main = ver_main, +}; + +APK_DEFINE_APPLET(apk_ver); diff --git a/src/audit.c b/src/audit.c deleted file mode 100644 index 4f86b40..0000000 --- a/src/audit.c +++ /dev/null @@ -1,357 +0,0 @@ -/* audit.c - Alpine Package Keeper (APK) - * - * Copyright (C) 2005-2008 Natanael Copa - * Copyright (C) 2008-2011 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 -#include -#include -#include -#include -#include -#include "apk_applet.h" -#include "apk_database.h" -#include "apk_print.h" - -/* Use (unused) highest bit of mode_t as seen flag of our internal - * database file entries */ -#define S_SEENFLAG 0x80000000 - -enum { - MODE_BACKUP = 0, - MODE_SYSTEM -}; - -struct audit_ctx { - unsigned mode : 1; - unsigned recursive : 1; - unsigned check_permissions : 1; - unsigned packages_only : 1; -}; - -static int option_parse_applet(void *ctx, struct apk_db_options *dbopts, int optch, const char *optarg) -{ - struct audit_ctx *actx = (struct audit_ctx *) ctx; - - switch (optch) { - case 0x10000: - actx->mode = MODE_BACKUP; - break; - case 0x10001: - actx->mode = MODE_SYSTEM; - break; - case 0x10002: - actx->check_permissions = 1; - break; - case 0x10003: - actx->packages_only = 1; - break; - case 'r': - actx->recursive = 1; - break; - default: - return -ENOTSUP; - } - return 0; -} - -static const struct apk_option options_applet[] = { - { 0x10000, "backup" }, - { 0x10001, "system" }, - { 0x10002, "check-permissions" }, - { 'r', "recursive" }, - { 0x10003, "packages" }, -}; - -static const struct apk_option_group optgroup_applet = { - .name = "Audit", - .options = options_applet, - .num_options = ARRAY_SIZE(options_applet), - .parse = option_parse_applet, -}; - -struct audit_tree_ctx { - struct audit_ctx *actx; - struct apk_database *db; - struct apk_db_dir *dir; - size_t pathlen; - char path[PATH_MAX]; -}; - -static int audit_file(struct audit_ctx *actx, - struct apk_database *db, - struct apk_db_file *dbf, - int dirfd, const char *name) -{ - struct apk_file_info fi; - int rv = 0; - - if (dbf == NULL) - return 'A'; - - dbf->audited = 1; - - if (apk_fileinfo_get(dirfd, name, - APK_FI_NOFOLLOW | - APK_FI_XATTR_CSUM(dbf->acl->xattr_csum.type ?: APK_CHECKSUM_DEFAULT) | - APK_FI_CSUM(dbf->csum.type), - &fi) != 0) - return -EPERM; - - if (dbf->csum.type != APK_CHECKSUM_NONE && - apk_checksum_compare(&fi.csum, &dbf->csum) != 0) - rv = 'U'; - else if (!S_ISLNK(fi.mode) && !dbf->diri->pkg->ipkg->broken_xattr && - apk_checksum_compare(&fi.xattr_csum, &dbf->acl->xattr_csum) != 0) - rv = 'x'; - else if (S_ISLNK(fi.mode) && dbf->csum.type == APK_CHECKSUM_NONE) - rv = 'U'; - else if (actx->check_permissions) { - if ((fi.mode & 07777) != (dbf->acl->mode & 07777)) - rv = 'M'; - else if (fi.uid != dbf->acl->uid || fi.gid != dbf->acl->gid) - rv = 'M'; - } - apk_fileinfo_free(&fi); - - return rv; -} - -static int audit_directory(struct audit_ctx *actx, - struct apk_database *db, - struct apk_db_dir *dbd, - struct apk_file_info *fi) -{ - if (dbd != NULL) dbd->mode |= S_SEENFLAG; - - if (dbd == NULL || dbd->refs == 1) - return actx->recursive ? 'd' : 'D'; - - if (actx->check_permissions && - ((dbd->mode & ~S_SEENFLAG) || dbd->uid || dbd->gid)) { - if ((fi->mode & 07777) != (dbd->mode & 07777)) - return 'm'; - if (fi->uid != dbd->uid || fi->gid != dbd->gid) - return 'm'; - } - - return 0; -} - -static void report_audit(struct audit_ctx *actx, - char reason, apk_blob_t bfull, struct apk_package *pkg) -{ - if (!reason) - return; - - if (actx->packages_only) { - if (pkg == NULL || pkg->state_int != 0) - return; - pkg->state_int = 1; - if (apk_verbosity < 1) - printf("%s\n", pkg->name->name); - else - printf(PKG_VER_FMT "\n", PKG_VER_PRINTF(pkg)); - } else if (apk_verbosity < 1) { - printf(BLOB_FMT "\n", BLOB_PRINTF(bfull)); - } else - printf("%c " BLOB_FMT "\n", reason, BLOB_PRINTF(bfull)); -} - -static int audit_directory_tree_item(void *ctx, int dirfd, const char *name) -{ - struct audit_tree_ctx *atctx = (struct audit_tree_ctx *) ctx; - apk_blob_t bdir = APK_BLOB_PTR_LEN(atctx->path, atctx->pathlen); - apk_blob_t bent = APK_BLOB_STR(name); - apk_blob_t bfull; - struct audit_ctx *actx = atctx->actx; - struct apk_database *db = atctx->db; - struct apk_db_dir *dir = atctx->dir, *child = NULL; - struct apk_file_info fi; - int reason = 0; - - if (bdir.len + bent.len + 1 >= sizeof(atctx->path)) return 0; - if (apk_fileinfo_get(dirfd, name, APK_FI_NOFOLLOW, &fi) < 0) return 0; - - memcpy(&atctx->path[atctx->pathlen], bent.ptr, bent.len); - atctx->pathlen += bent.len; - bfull = APK_BLOB_PTR_LEN(atctx->path, atctx->pathlen); - - if (S_ISDIR(fi.mode)) { - int recurse = TRUE; - - if (actx->mode == MODE_BACKUP) { - child = apk_db_dir_get(db, bfull); - if (!child->has_protected_children) - recurse = FALSE; - if (child->protect_mode == APK_PROTECT_NONE) - goto recurse_check; - } else { - child = apk_db_dir_query(db, bfull); - if (child == NULL) - goto done; - child = apk_db_dir_ref(child); - } - - reason = audit_directory(actx, db, child, &fi); - if (reason < 0) - goto done; - -recurse_check: - atctx->path[atctx->pathlen++] = '/'; - bfull.len++; - report_audit(actx, reason, bfull, NULL); - if (reason != 'D' && recurse) { - atctx->dir = child; - reason = apk_dir_foreach_file( - openat(dirfd, name, O_RDONLY|O_CLOEXEC), - audit_directory_tree_item, atctx); - atctx->dir = dir; - } - bfull.len--; - atctx->pathlen--; - } else { - struct apk_db_file *dbf; - struct apk_protected_path *ppath; - int protect_mode = dir->protect_mode; - - /* inherit file's protection mask */ - foreach_array_item(ppath, dir->protected_paths) { - char *slash = strchr(ppath->relative_pattern, '/'); - if (slash == NULL) { - if (fnmatch(ppath->relative_pattern, name, FNM_PATHNAME) != 0) - continue; - protect_mode = ppath->protect_mode; - } - } - - if (actx->mode == MODE_BACKUP) { - switch (protect_mode) { - case APK_PROTECT_NONE: - goto done; - case APK_PROTECT_CHANGED: - break; - case APK_PROTECT_SYMLINKS_ONLY: - if (!S_ISLNK(fi.mode)) - goto done; - break; - case APK_PROTECT_ALL: - reason = 'A'; - break; - } - } - - dbf = apk_db_file_query(db, bdir, bent); - if (reason == 0) - reason = audit_file(actx, db, dbf, dirfd, name); - if (reason < 0) - goto done; - if (actx->mode == MODE_SYSTEM && - (reason == 'A' || protect_mode != APK_PROTECT_NONE)) - goto done; - if (actx->mode == MODE_BACKUP && - reason == 'A' && - apk_blob_ends_with(bent, APK_BLOB_STR(".apk-new"))) - goto done; - report_audit(actx, reason, bfull, dbf ? dbf->diri->pkg : NULL); - } - -done: - if (child) - apk_db_dir_unref(db, child, FALSE); - - atctx->pathlen -= bent.len; - return 0; -} - -static int audit_directory_tree(struct audit_tree_ctx *atctx, int dirfd) -{ - apk_blob_t path; - int r; - - path = APK_BLOB_PTR_LEN(atctx->path, atctx->pathlen); - if (path.len && path.ptr[path.len-1] == '/') - path.len--; - - atctx->dir = apk_db_dir_get(atctx->db, path); - atctx->dir->mode |= S_SEENFLAG; - r = apk_dir_foreach_file(dirfd, audit_directory_tree_item, atctx); - apk_db_dir_unref(atctx->db, atctx->dir, FALSE); - - return r; -} - -static int audit_missing_files(apk_hash_item item, void *pctx) -{ - struct audit_ctx *actx = pctx; - struct apk_db_file *file = item; - struct apk_db_dir *dir; - char path[PATH_MAX]; - int len; - - if (file->audited) return 0; - - dir = file->diri->dir; - if (dir->mode & S_SEENFLAG) { - len = snprintf(path, sizeof(path), DIR_FILE_FMT, DIR_FILE_PRINTF(dir, file)); - report_audit(actx, 'X', APK_BLOB_PTR_LEN(path, len), file->diri->pkg); - } - - return 0; -} - -static int audit_main(void *ctx, struct apk_database *db, struct apk_string_array *args) -{ - struct audit_tree_ctx atctx; - struct audit_ctx *actx = (struct audit_ctx *) ctx; - char **parg, *arg; - int r = 0; - - atctx.db = db; - atctx.actx = actx; - atctx.pathlen = 0; - atctx.path[0] = 0; - - if (args->num == 0) { - r |= audit_directory_tree(&atctx, dup(db->root_fd)); - } else { - foreach_array_item(parg, args) { - arg = *parg; - if (arg[0] != '/') { - apk_warning("%s: relative path skipped.\n", arg); - continue; - } - arg++; - atctx.pathlen = strlen(arg); - memcpy(atctx.path, arg, atctx.pathlen); - if (atctx.path[atctx.pathlen-1] != '/') - atctx.path[atctx.pathlen++] = '/'; - - r |= audit_directory_tree(&atctx, openat(db->root_fd, arg, O_RDONLY|O_CLOEXEC)); - } - } - if (actx->mode == MODE_SYSTEM) - apk_hash_foreach(&db->installed.files, audit_missing_files, ctx); - - return r; -} - -static struct apk_applet apk_audit = { - .name = "audit", - .arguments = "[directory to audit]...", - .open_flags = APK_OPENF_READ|APK_OPENF_NO_SCRIPTS|APK_OPENF_NO_REPOS, - .context_size = sizeof(struct audit_ctx), - .optgroups = { &optgroup_global, &optgroup_applet }, - .main = audit_main, -}; - -APK_DEFINE_APPLET(apk_audit); - diff --git a/src/cache.c b/src/cache.c deleted file mode 100644 index d663f56..0000000 --- a/src/cache.c +++ /dev/null @@ -1,193 +0,0 @@ -/* cache.c - Alpine Package Keeper (APK) - * - * Copyright (C) 2005-2008 Natanael Copa - * Copyright (C) 2008-2011 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 -#include -#include -#include - -#include "apk_defines.h" -#include "apk_applet.h" -#include "apk_database.h" -#include "apk_package.h" -#include "apk_print.h" -#include "apk_solver.h" - -#define CACHE_CLEAN BIT(0) -#define CACHE_DOWNLOAD BIT(1) - -struct cache_ctx { - unsigned short solver_flags; -}; - -static int option_parse_applet(void *ctx, struct apk_db_options *dbopts, int optch, const char *optarg) -{ - struct cache_ctx *cctx = (struct cache_ctx *) ctx; - - switch (optch) { - case 'u': - cctx->solver_flags |= APK_SOLVERF_UPGRADE; - break; - case 'l': - cctx->solver_flags |= APK_SOLVERF_LATEST; - break; - default: - return -ENOTSUP; - } - return 0; -} - -static const struct apk_option options_applet[] = { - { 'u', "upgrade" }, - { 'l', "latest" }, -}; - -static const struct apk_option_group optgroup_applet = { - .name = "Cache", - .options = options_applet, - .num_options = ARRAY_SIZE(options_applet), - .parse = option_parse_applet, -}; - -struct progress { - size_t done, total; -}; - -static void progress_cb(void *ctx, size_t bytes_done) -{ - struct progress *prog = (struct progress *) ctx; - apk_print_progress(prog->done + bytes_done, prog->total); -} - -static int cache_download(struct cache_ctx *cctx, struct apk_database *db) -{ - struct apk_changeset changeset = {}; - struct apk_change *change; - struct apk_package *pkg; - struct apk_repository *repo; - struct progress prog = { 0, 0 }; - int r, ret = 0; - - r = apk_solver_solve(db, cctx->solver_flags, db->world, &changeset); - if (r < 0) { - apk_error("Unable to select packages. Run apk fix."); - return r; - } - - foreach_array_item(change, changeset.changes) { - pkg = change->new_pkg; - if ((pkg != NULL) && !(pkg->repos & db->local_repos)) - prog.total += pkg->size; - } - - foreach_array_item(change, changeset.changes) { - pkg = change->new_pkg; - if ((pkg == NULL) || (pkg->repos & db->local_repos)) - continue; - - repo = apk_db_select_repo(db, pkg); - if (repo == NULL) - continue; - - r = apk_cache_download(db, repo, pkg, APK_SIGN_VERIFY_IDENTITY, 0, - progress_cb, &prog); - if (r && r != -EALREADY) { - apk_error(PKG_VER_FMT ": %s", PKG_VER_PRINTF(pkg), apk_error_str(r)); - ret++; - } - prog.done += pkg->size; - } - - return ret; -} - -static void cache_clean_item(struct apk_database *db, int dirfd, const char *name, struct apk_package *pkg) -{ - char tmp[PATH_MAX]; - apk_blob_t b; - int i; - - if (strcmp(name, "installed") == 0) return; - - if (pkg) { - if ((apk_flags & APK_PURGE) && pkg->ipkg == NULL) goto delete; - if (pkg->repos & db->local_repos & ~BIT(APK_REPOSITORY_CACHED)) goto delete; - if (pkg->ipkg == NULL && !(pkg->repos & ~BIT(APK_REPOSITORY_CACHED))) goto delete; - return; - } - - b = APK_BLOB_STR(name); - for (i = 0; i < db->num_repos; i++) { - /* Check if this is a valid index */ - apk_repo_format_cache_index(APK_BLOB_BUF(tmp), &db->repos[i]); - if (apk_blob_compare(b, APK_BLOB_STR(tmp)) == 0) return; - } - -delete: - if (apk_verbosity >= 2) - apk_message("deleting %s", name); - if (!(apk_flags & APK_SIMULATE)) { - if (unlinkat(dirfd, name, 0) < 0 && errno == EISDIR) - unlinkat(dirfd, name, AT_REMOVEDIR); - } -} - -static int cache_clean(struct apk_database *db) -{ - return apk_db_cache_foreach_item(db, cache_clean_item); -} - -static int cache_main(void *ctx, struct apk_database *db, struct apk_string_array *args) -{ - struct cache_ctx *cctx = (struct cache_ctx *) ctx; - char *arg; - int r = 0, actions = 0; - - if (args->num != 1) - return -EINVAL; - - arg = args->item[0]; - if (strcmp(arg, "sync") == 0) - actions = CACHE_CLEAN | CACHE_DOWNLOAD; - else if (strcmp(arg, "clean") == 0) - actions = CACHE_CLEAN; - else if (strcmp(arg, "download") == 0) - actions = CACHE_DOWNLOAD; - else - return -EINVAL; - - if (!apk_db_cache_active(db)) { - apk_error("Package cache is not enabled.\n"); - r = 2; - goto err; - } - - if (r == 0 && (actions & CACHE_CLEAN)) - r = cache_clean(db); - if (r == 0 && (actions & CACHE_DOWNLOAD)) - r = cache_download(cctx, db); -err: - return r; -} - -static struct apk_applet apk_cache = { - .name = "cache", - .arguments = "sync | clean | download", - .open_flags = APK_OPENF_READ|APK_OPENF_NO_SCRIPTS|APK_OPENF_CACHE_WRITE, - .command_groups = APK_COMMAND_GROUP_SYSTEM, - .context_size = sizeof(struct cache_ctx), - .optgroups = { &optgroup_global, &optgroup_applet }, - .main = cache_main, -}; - -APK_DEFINE_APPLET(apk_cache); diff --git a/src/del.c b/src/del.c deleted file mode 100644 index c48cd21..0000000 --- a/src/del.c +++ /dev/null @@ -1,178 +0,0 @@ -/* del.c - Alpine Package Keeper (APK) - * - * Copyright (C) 2005-2008 Natanael Copa - * Copyright (C) 2008-2011 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 "apk_applet.h" -#include "apk_database.h" -#include "apk_print.h" -#include "apk_solver.h" - -struct del_ctx { - int recursive_delete : 1; - struct apk_dependency_array *world; - int errors; -}; - -static int option_parse_applet(void *pctx, struct apk_db_options *dbopts, int optch, const char *optarg) -{ - struct del_ctx *ctx = (struct del_ctx *) pctx; - - switch (optch) { - case 'r': - ctx->recursive_delete = 1; - break; - default: - return -ENOTSUP; - } - return 0; -} - -static const struct apk_option options_applet[] = { - { 'r', "rdepends" }, -}; - -static const struct apk_option_group optgroup_applet = { - .name = "Delete", - .options = options_applet, - .num_options = ARRAY_SIZE(options_applet), - .parse = option_parse_applet, -}; - -struct not_deleted_ctx { - struct apk_indent indent; - struct apk_name *name; - unsigned int matches; - int header; -}; - -static void print_not_deleted_pkg(struct apk_package *pkg0, struct apk_dependency *dep0, - struct apk_package *pkg, void *pctx) -{ - struct not_deleted_ctx *ctx = (struct not_deleted_ctx *) pctx; - struct apk_dependency *d; - struct apk_provider *p; - - if (pkg0->name != ctx->name) { - if (!ctx->header) { - apk_message("World updated, but the following packages are not removed due to:"); - ctx->header = 1; - } - if (!ctx->indent.indent) { - ctx->indent.x = printf(" %s:", ctx->name->name); - ctx->indent.indent = ctx->indent.x + 1; - } - - apk_print_indented(&ctx->indent, APK_BLOB_STR(pkg0->name->name)); - } - - apk_pkg_foreach_reverse_dependency(pkg0, ctx->matches, print_not_deleted_pkg, pctx); - foreach_array_item(d, pkg0->install_if) { - foreach_array_item(p, d->name->providers) { - if (!p->pkg->marked) continue; - if (apk_pkg_match_genid(p->pkg, ctx->matches)) continue; - print_not_deleted_pkg(p->pkg, NULL, NULL, pctx); - } - } -} - -static void print_not_deleted_name(struct apk_database *db, const char *match, - struct apk_name *name, void *pctx) -{ - struct not_deleted_ctx *ctx = (struct not_deleted_ctx *) pctx; - struct apk_provider *p; - - ctx->indent.indent = 0; - ctx->name = name; - ctx->matches = apk_foreach_genid() | APK_FOREACH_MARKED | APK_DEP_SATISFIES; - foreach_array_item(p, name->providers) - if (p->pkg->marked) - print_not_deleted_pkg(p->pkg, NULL, NULL, ctx); - if (ctx->indent.indent) - printf("\n"); -} - -static void delete_pkg(struct apk_package *pkg0, struct apk_dependency *dep0, - struct apk_package *pkg, void *pctx) -{ - struct del_ctx *ctx = (struct del_ctx *) pctx; - - apk_deps_del(&ctx->world, pkg0->name); - if (ctx->recursive_delete) - apk_pkg_foreach_reverse_dependency( - pkg0, APK_FOREACH_INSTALLED | APK_DEP_SATISFIES, - delete_pkg, pctx); -} - -static void delete_name(struct apk_database *db, const char *match, - struct apk_name *name, void *pctx) -{ - struct del_ctx *ctx = (struct del_ctx *) pctx; - struct apk_package *pkg; - - if (!name) { - apk_error("No such package: %s", match); - ctx->errors++; - return; - } - - pkg = apk_pkg_get_installed(name); - if (pkg != NULL) - delete_pkg(pkg, NULL, NULL, pctx); - else - apk_deps_del(&ctx->world, name); -} - -static int del_main(void *pctx, struct apk_database *db, struct apk_string_array *args) -{ - struct del_ctx *ctx = (struct del_ctx *) pctx; - struct not_deleted_ctx ndctx = {}; - struct apk_changeset changeset = {}; - struct apk_change *change; - int r = 0; - - apk_dependency_array_copy(&ctx->world, db->world); - apk_name_foreach_matching(db, args, apk_foreach_genid(), delete_name, ctx); - if (ctx->errors) return ctx->errors; - - r = apk_solver_solve(db, 0, ctx->world, &changeset); - if (r == 0) { - /* check for non-deleted package names */ - foreach_array_item(change, changeset.changes) - if (change->new_pkg != NULL) - change->new_pkg->marked = 1; - apk_name_foreach_matching( - db, args, - apk_foreach_genid() | APK_FOREACH_MARKED | APK_DEP_SATISFIES, - print_not_deleted_name, &ndctx); - if (ndctx.header) - printf("\n"); - - r = apk_solver_commit_changeset(db, &changeset, ctx->world); - } else { - apk_solver_print_errors(db, &changeset, ctx->world); - } - apk_change_array_free(&changeset.changes); - apk_dependency_array_free(&ctx->world); - - return r; -} - -static struct apk_applet apk_del = { - .name = "del", - .arguments = "PACKAGE...", - .open_flags = APK_OPENF_WRITE | APK_OPENF_NO_AUTOUPDATE, - .command_groups = APK_COMMAND_GROUP_INSTALL, - .context_size = sizeof(struct del_ctx), - .optgroups = { &optgroup_global, &optgroup_commit, &optgroup_applet }, - .main = del_main, -}; - -APK_DEFINE_APPLET(apk_del); diff --git a/src/dot.c b/src/dot.c deleted file mode 100644 index 7b48486..0000000 --- a/src/dot.c +++ /dev/null @@ -1,179 +0,0 @@ -/* dot.c - Alpine Package Keeper (APK) - * - * Copyright (C) 2008-2011 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_print.h" - -#define S_EVALUATED -1 -#define S_EVALUATING -2 - -struct dot_ctx { - int not_empty : 1; - int errors_only : 1; - int installed_only : 1; -}; - -static int option_parse_applet(void *pctx, struct apk_db_options *dbopts, int optch, const char *optarg) -{ - struct dot_ctx *ctx = (struct dot_ctx *) pctx; - - switch (optch) { - case 0x10000: - ctx->errors_only = 1; - break; - case 0x10001: - ctx->installed_only = 1; - dbopts->open_flags &= ~APK_OPENF_NO_INSTALLED; - break; - default: - return -ENOTSUP; - } - return 0; -} - -static const struct apk_option options_applet[] = { - { 0x10000, "errors" }, - { 0x10001, "installed" }, -}; - -static const struct apk_option_group optgroup_applet = { - .name = "Dot", - .options = options_applet, - .num_options = ARRAY_SIZE(options_applet), - .parse = option_parse_applet, -}; - -static void start_graph(struct dot_ctx *ctx) -{ - if (ctx->not_empty) - return; - ctx->not_empty = 1; - - printf( "digraph \"apkindex\" {\n" - " rankdir=LR;\n" - " node [shape=box];\n"); -} - -static void dump_name(struct dot_ctx *ctx, struct apk_name *name) -{ - if (name->state_int) - return; - name->state_int = 1; - - if (name->providers->num == 0) { - start_graph(ctx); - printf(" \"%s\" [style=dashed, color=red, fontcolor=red, shape=octagon];\n", - name->name); - } -} - -static int dump_pkg(struct dot_ctx *ctx, struct apk_package *pkg) -{ - struct apk_dependency *dep; - struct apk_provider *p0; - int r, ret = 0; - - if (ctx->installed_only && pkg->ipkg == NULL) - return 0; - - if (pkg->state_int == S_EVALUATED) - return 0; - - if (pkg->state_int <= S_EVALUATING) { - pkg->state_int--; - return 1; - } - - pkg->state_int = S_EVALUATING; - foreach_array_item(dep, pkg->depends) { - struct apk_name *name = dep->name; - - dump_name(ctx, name); - - if (name->providers->num == 0) { - printf(" \"" PKG_VER_FMT "\" -> \"%s\" [color=red];\n", - PKG_VER_PRINTF(pkg), name->name); - continue; - } - - foreach_array_item(p0, name->providers) { - if (ctx->installed_only && p0->pkg->ipkg == NULL) - continue; - if (!apk_dep_is_provided(dep, p0)) - continue; - - r = dump_pkg(ctx, p0->pkg); - ret += r; - if (r || (!ctx->errors_only)) { - start_graph(ctx); - - printf(" \"" PKG_VER_FMT "\" -> \"" PKG_VER_FMT "\"[", - PKG_VER_PRINTF(pkg), - PKG_VER_PRINTF(p0->pkg)); - if (r) - printf("color=red,"); - if (p0->pkg->name != dep->name) - printf("arrowhead=inv,label=\"%s\",", dep->name->name); - printf("];\n"); - } - } - } - ret -= S_EVALUATING - pkg->state_int; - pkg->state_int = S_EVALUATED; - - return ret; -} - -static int foreach_pkg(apk_hash_item item, void *ctx) -{ - dump_pkg((struct dot_ctx *) ctx, (struct apk_package *) item); - return 0; -} - -static int dot_main(void *pctx, struct apk_database *db, struct apk_string_array *args) -{ - struct dot_ctx *ctx = (struct dot_ctx *) pctx; - struct apk_provider *p; - char **parg; - - if (args->num) { - foreach_array_item(parg, args) { - struct apk_name *name = apk_db_get_name(db, APK_BLOB_STR(*parg)); - if (!name) - continue; - foreach_array_item(p, name->providers) - dump_pkg(ctx, p->pkg); - } - } else { - apk_hash_foreach(&db->available.packages, foreach_pkg, pctx); - } - - if (!ctx->not_empty) - return 1; - - printf("}\n"); - return 0; -} - -static struct apk_applet apk_dot = { - .name = "dot", - .arguments = "PKGMASK...", - .open_flags = APK_OPENF_READ | APK_OPENF_NO_STATE, - .command_groups = APK_COMMAND_GROUP_QUERY, - .context_size = sizeof(struct dot_ctx), - .optgroups = { &optgroup_global, &optgroup_applet }, - .main = dot_main, -}; - -APK_DEFINE_APPLET(apk_dot); diff --git a/src/fetch.c b/src/fetch.c deleted file mode 100644 index dacc7d1..0000000 --- a/src/fetch.c +++ /dev/null @@ -1,355 +0,0 @@ -/* fetch.c - Alpine Package Keeper (APK) - * - * Copyright (C) 2005-2008 Natanael Copa - * Copyright (C) 2008-2011 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 -#include -#include -#include - -#include "apk_applet.h" -#include "apk_database.h" -#include "apk_io.h" -#include "apk_print.h" -#include "apk_solver.h" - -#define FETCH_RECURSIVE 1 -#define FETCH_STDOUT 2 -#define FETCH_LINK 4 - -struct fetch_ctx { - unsigned int flags; - int outdir_fd, errors; - struct apk_database *db; - size_t done, total; - struct apk_dependency_array *world; -}; - -static int cup(void) -{ - /* compressed/uncompressed size is 259/1213 */ - static unsigned char z[] = { - 0x78,0x9c,0x9d,0x94,0x3d,0x8e,0xc4,0x20,0x0c,0x85,0xfb,0x9c, - 0xc2,0x72,0x43,0x46,0x8a,0x4d,0x3f,0x67,0x89,0x64,0x77,0x2b, - 0x6d,0xbb,0x6d,0x0e,0x3f,0xc6,0x84,0x4d,0x08,0x84,0x55,0xd6, - 0xa2,0xe0,0xef,0x7b,0x36,0xe1,0x11,0x80,0x6e,0xcc,0x53,0x7f, - 0x3e,0xc5,0xeb,0xcf,0x1d,0x20,0x22,0xcc,0x3c,0x53,0x8e,0x17, - 0xd9,0x80,0x6d,0xee,0x0e,0x61,0x42,0x3c,0x8b,0xcf,0xc7,0x12, - 0x22,0x71,0x8b,0x31,0x05,0xd5,0xb0,0x11,0x4b,0xa7,0x32,0x2f, - 0x80,0x69,0x6b,0xb0,0x98,0x40,0xe2,0xcd,0xba,0x6a,0xba,0xe4, - 0x65,0xed,0x61,0x23,0x44,0xb5,0x95,0x06,0x8b,0xde,0x6c,0x61, - 0x70,0xde,0x0e,0xb6,0xed,0xc4,0x43,0x0c,0x56,0x6f,0x8f,0x31, - 0xd0,0x35,0xb5,0xc7,0x58,0x06,0xff,0x81,0x49,0x84,0xb8,0x0e, - 0xb1,0xd8,0xc1,0x66,0x31,0x0e,0x46,0x5c,0x43,0xc9,0xef,0xe5, - 0xdc,0x63,0xb1,0xdc,0x67,0x6d,0x31,0xb3,0xc9,0x69,0x74,0x87, - 0xc7,0xa3,0x1b,0x6a,0xb3,0xbd,0x2f,0x3b,0xd5,0x0c,0x57,0x3b, - 0xce,0x7c,0x5e,0xe5,0x48,0xd0,0x48,0x01,0x92,0x49,0x8b,0xf7, - 0xfc,0x58,0x67,0xb3,0xf7,0x14,0x20,0x5c,0x4c,0x9e,0xcc,0xeb, - 0x78,0x7e,0x64,0xa6,0xa1,0xf5,0xb2,0x70,0x38,0x09,0x7c,0x7f, - 0xfd,0xc0,0x8a,0x4e,0xc8,0x55,0xe8,0x12,0xe2,0x9f,0x1a,0xb1, - 0xb9,0x82,0x52,0x02,0x7a,0xe5,0xf9,0xd9,0x88,0x47,0x79,0x3b, - 0x46,0x61,0x27,0xf9,0x51,0xb1,0x17,0xb0,0x2c,0x0e,0xd5,0x39, - 0x2d,0x96,0x25,0x27,0xd6,0xd1,0x3f,0xa5,0x08,0xe1,0x9e,0x4e, - 0xa7,0xe9,0x03,0xb1,0x0a,0xb6,0x75 - }; - unsigned char buf[1213]; - unsigned long len = sizeof(buf); - - uncompress(buf, &len, z, sizeof(z)); - return write(STDOUT_FILENO, buf, len) != len; -} - -static int option_parse_applet(void *ctx, struct apk_db_options *dbopts, int optch, const char *optarg) -{ - struct fetch_ctx *fctx = (struct fetch_ctx *) ctx; - - switch (optch) { - case 'R': - fctx->flags |= FETCH_RECURSIVE; - break; - case 's': - fctx->flags |= FETCH_STDOUT; - break; - case 'L': - fctx->flags |= FETCH_LINK; - break; - case 'o': - fctx->outdir_fd = openat(AT_FDCWD, optarg, O_RDONLY | O_CLOEXEC); - break; - default: - return -ENOTSUP; - } - return 0; -} - -static const struct apk_option options_applet[] = { - { 'L', "link" }, - { 'R', "recursive" }, - { 0x104, "simulate" }, - { 's', "stdout" }, - { 'o', "output", required_argument, "DIR" }, -}; - -static const struct apk_option_group optgroup_applet = { - .name = "Fetch", - .options = options_applet, - .num_options = ARRAY_SIZE(options_applet), - .parse = option_parse_applet, -}; - -static void progress_cb(void *pctx, size_t bytes_done) -{ - struct fetch_ctx *ctx = (struct fetch_ctx *) pctx; - apk_print_progress(ctx->done + bytes_done, ctx->total); -} - -static int fetch_package(apk_hash_item item, void *pctx) -{ - struct fetch_ctx *ctx = (struct fetch_ctx *) pctx; - struct apk_database *db = ctx->db; - struct apk_package *pkg = (struct apk_package *) item; - struct apk_istream *is; - struct apk_repository *repo; - struct apk_file_info fi; - char url[PATH_MAX], filename[256]; - int r, fd, urlfd; - - if (!pkg->marked) - return 0; - - repo = apk_db_select_repo(db, pkg); - if (repo == NULL) { - r = -ENOPKG; - goto err; - } - - if (snprintf(filename, sizeof(filename), PKG_FILE_FMT, PKG_FILE_PRINTF(pkg)) >= sizeof(filename)) { - r = -ENOBUFS; - goto err; - } - - if (!(ctx->flags & FETCH_STDOUT)) { - if (apk_fileinfo_get(ctx->outdir_fd, filename, APK_CHECKSUM_NONE, &fi) == 0 && - fi.size == pkg->size) - return 0; - } - - apk_message("Downloading " PKG_VER_FMT, PKG_VER_PRINTF(pkg)); - if (apk_flags & APK_SIMULATE) - return 0; - - r = apk_repo_format_item(db, repo, pkg, &urlfd, url, sizeof(url)); - if (r < 0) - goto err; - - if (ctx->flags & FETCH_STDOUT) { - fd = STDOUT_FILENO; - } else { - if ((ctx->flags & FETCH_LINK) && urlfd >= 0) { - if (linkat(urlfd, url, - ctx->outdir_fd, filename, - AT_SYMLINK_FOLLOW) == 0) - return 0; - } - fd = openat(ctx->outdir_fd, filename, - O_CREAT|O_RDWR|O_TRUNC|O_CLOEXEC, 0644); - if (fd < 0) { - r = -errno; - goto err; - } - } - - is = apk_istream_from_fd_url(urlfd, url); - if (IS_ERR_OR_NULL(is)) { - r = PTR_ERR(is) ?: -EIO; - goto err; - } - - r = apk_istream_splice(is, fd, pkg->size, progress_cb, ctx); - if (fd != STDOUT_FILENO) { - struct apk_file_meta meta; - apk_istream_get_meta(is, &meta); - apk_file_meta_to_fd(fd, &meta); - close(fd); - } - apk_istream_close(is); - - if (r != pkg->size) { - unlinkat(ctx->outdir_fd, filename, 0); - if (r >= 0) r = -EIO; - goto err; - } - - ctx->done += pkg->size; - return 0; - -err: - apk_error(PKG_VER_FMT ": %s", PKG_VER_PRINTF(pkg), apk_error_str(r)); - ctx->errors++; - return 0; -} - -static void mark_package(struct fetch_ctx *ctx, struct apk_package *pkg) -{ - if (pkg == NULL || pkg->marked) - return; - ctx->total += pkg->size; - pkg->marked = 1; -} - -static void mark_error(struct fetch_ctx *ctx, const char *match, struct apk_name *name) -{ - if (strchr(match, '*') != NULL) - return; - - apk_message("%s: unable to select package (or its dependencies)", name ? name->name : match); - ctx->errors++; -} - -static void mark_name_flags(struct apk_database *db, const char *match, struct apk_name *name, void *pctx) -{ - struct fetch_ctx *ctx = (struct fetch_ctx *) pctx; - struct apk_dependency dep = (struct apk_dependency) { - .name = name, - .version = &apk_null_blob, - .result_mask = APK_DEPMASK_ANY, - }; - - if (!IS_ERR_OR_NULL(name)) { - name->auto_select_virtual = 1; - apk_deps_add(&ctx->world, &dep); - } else { - ctx->errors++; - mark_error(ctx, match, name); - } -} - -static void mark_names_recursive(struct apk_database *db, struct apk_string_array *args, void *pctx) -{ - struct fetch_ctx *ctx = (struct fetch_ctx *) pctx; - struct apk_changeset changeset = {}; - struct apk_change *change; - int r; - - r = apk_solver_solve(db, APK_SOLVERF_IGNORE_CONFLICT, ctx->world, &changeset); - if (r == 0) { - foreach_array_item(change, changeset.changes) - mark_package(ctx, change->new_pkg); - } else { - apk_solver_print_errors(db, &changeset, ctx->world); - ctx->errors++; - } - apk_change_array_free(&changeset.changes); -} - -static void mark_name(struct apk_database *db, const char *match, struct apk_name *name, void *ctx) -{ - struct apk_package *pkg = NULL; - struct apk_provider *p; - - if (!name) goto err; - - foreach_array_item(p, name->providers) - if (pkg == NULL || apk_pkg_version_compare(p->pkg, pkg) == APK_VERSION_GREATER) - pkg = p->pkg; - - if (!pkg) goto err; - mark_package(ctx, pkg); - return; - -err: - mark_error(ctx, match, name); -} - -static int purge_package(void *pctx, int dirfd, const char *filename) -{ - char tmp[PATH_MAX]; - struct fetch_ctx *ctx = (struct fetch_ctx *) pctx; - struct apk_database *db = ctx->db; - struct apk_provider *p0; - struct apk_name *name; - apk_blob_t b = APK_BLOB_STR(filename), bname, bver; - size_t l; - - if (apk_pkg_parse_name(b, &bname, &bver)) return 0; - name = apk_db_get_name(db, bname); - if (!name) return 0; - - foreach_array_item(p0, name->providers) { - if (p0->pkg->name != name) continue; - l = snprintf(tmp, sizeof tmp, PKG_FILE_FMT, PKG_FILE_PRINTF(p0->pkg)); - if (l > sizeof tmp) continue; - if (apk_blob_compare(b, APK_BLOB_PTR_LEN(tmp, l)) != 0) continue; - if (p0->pkg->marked) return 0; - break; - } - - apk_message("Purging %s", filename); - if (apk_flags & APK_SIMULATE) - return 0; - - unlinkat(dirfd, filename, 0); - return 0; -} - -static int fetch_main(void *pctx, struct apk_database *db, struct apk_string_array *args) -{ - struct fetch_ctx *ctx = (struct fetch_ctx *) pctx; - - if (ctx->flags & FETCH_STDOUT) { - apk_flags &= ~APK_PROGRESS; - apk_verbosity = 0; - } - - if (ctx->outdir_fd == 0) - ctx->outdir_fd = AT_FDCWD; - - if ((args->num == 1) && (strcmp(args->item[0], "coffee") == 0)) { - if (apk_force) return cup(); - apk_message("Go and fetch your own coffee."); - return 0; - } - - ctx->db = db; - - if (ctx->flags & FETCH_RECURSIVE) { - apk_dependency_array_init(&ctx->world); - apk_name_foreach_matching(db, args, apk_foreach_genid(), mark_name_flags, ctx); - if (ctx->errors == 0) - mark_names_recursive(db, args, ctx); - apk_dependency_array_free(&ctx->world); - } else { - apk_name_foreach_matching(db, args, apk_foreach_genid(), mark_name, ctx); - } - if (!ctx->errors) - apk_hash_foreach(&db->available.packages, fetch_package, ctx); - - /* Remove packages not matching download spec from the output directory */ - if (!ctx->errors && (apk_flags & APK_PURGE) && - !(ctx->flags & FETCH_STDOUT) && ctx->outdir_fd > 0) - apk_dir_foreach_file(ctx->outdir_fd, purge_package, ctx); - - return ctx->errors; -} - -static struct apk_applet apk_fetch = { - .name = "fetch", - .arguments = "PACKAGE...", - .open_flags = APK_OPENF_READ | APK_OPENF_NO_STATE, - .command_groups = APK_COMMAND_GROUP_REPO, - .context_size = sizeof(struct fetch_ctx), - .optgroups = { &optgroup_global, &optgroup_applet }, - .main = fetch_main, -}; - -APK_DEFINE_APPLET(apk_fetch); - diff --git a/src/fix.c b/src/fix.c deleted file mode 100644 index 8a7c6b2..0000000 --- a/src/fix.c +++ /dev/null @@ -1,127 +0,0 @@ -/* fix.c - Alpine Package Keeper (APK) - * - * Copyright (C) 2005-2008 Natanael Copa - * Copyright (C) 2008-2011 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_print.h" -#include "apk_solver.h" - -struct fix_ctx { - unsigned short solver_flags; - int fix_depends : 1; - int fix_xattrs : 1; - int fix_directory_permissions : 1; - int errors; -}; - -static int option_parse_applet(void *pctx, struct apk_db_options *dbopts, int optch, const char *optarg) -{ - struct fix_ctx *ctx = (struct fix_ctx *) pctx; - switch (optch) { - case 'd': - ctx->fix_depends = 1; - break; - case 'x': - ctx->fix_xattrs = 1; - break; - case 'u': - ctx->solver_flags |= APK_SOLVERF_UPGRADE; - break; - case 'r': - ctx->solver_flags |= APK_SOLVERF_REINSTALL; - break; - case 0x10000: - ctx->fix_directory_permissions = 1; - break; - default: - return -ENOTSUP; - } - return 0; -} - -static const struct apk_option options_applet[] = { - { 'd', "depends" }, - { 'r', "reinstall" }, - { 'u', "upgrade" }, - { 'x', "xattr" }, - { 0x10000, "directory-permissions" }, -}; - -static const struct apk_option_group optgroup_applet = { - .name = "Fix", - .options = options_applet, - .num_options = ARRAY_SIZE(options_applet), - .parse = option_parse_applet, -}; - -static int mark_recalculate(apk_hash_item item, void *ctx) -{ - struct apk_db_dir *dir = (struct apk_db_dir *) item; - if (dir->refs == 0) return 0; - dir->update_permissions = 1; - return 0; -} - -static void mark_fix(struct fix_ctx *ctx, struct apk_name *name) -{ - apk_solver_set_name_flags(name, ctx->solver_flags, ctx->fix_depends ? ctx->solver_flags : 0); -} - -static void set_solver_flags(struct apk_database *db, const char *match, struct apk_name *name, void *pctx) -{ - struct fix_ctx *ctx = pctx; - - if (!name) { - apk_error("Package '%s' not found", match); - ctx->errors++; - } else - mark_fix(ctx, name); -} - -static int fix_main(void *pctx, struct apk_database *db, struct apk_string_array *args) -{ - struct fix_ctx *ctx = (struct fix_ctx *) pctx; - struct apk_installed_package *ipkg; - - if (!ctx->solver_flags) - ctx->solver_flags = APK_SOLVERF_REINSTALL; - - if (ctx->fix_directory_permissions) - apk_hash_foreach(&db->installed.dirs, mark_recalculate, db); - - if (args->num == 0) { - list_for_each_entry(ipkg, &db->installed.packages, installed_pkgs_list) { - if (ipkg->broken_files || ipkg->broken_script || - (ipkg->broken_xattr && ctx->fix_xattrs)) - mark_fix(ctx, ipkg->pkg->name); - } - } else - apk_name_foreach_matching(db, args, apk_foreach_genid(), set_solver_flags, ctx); - - if (ctx->errors) return ctx->errors; - - return apk_solver_commit(db, 0, db->world); -} - -static struct apk_applet apk_fix = { - .name = "fix", - .arguments = "PACKAGE...", - .open_flags = APK_OPENF_WRITE, - .command_groups = APK_COMMAND_GROUP_SYSTEM, - .context_size = sizeof(struct fix_ctx), - .optgroups = { &optgroup_global, &optgroup_commit, &optgroup_applet }, - .main = fix_main, -}; - -APK_DEFINE_APPLET(apk_fix); - diff --git a/src/index.c b/src/index.c deleted file mode 100644 index 2508e9e..0000000 --- a/src/index.c +++ /dev/null @@ -1,265 +0,0 @@ -/* index.c - Alpine Package Keeper (APK) - * - * Copyright (C) 2005-2008 Natanael Copa - * Copyright (C) 2008-2011 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 -#include -#include - -#include "apk_applet.h" -#include "apk_database.h" -#include "apk_print.h" - -struct counts { - int unsatisfied; -}; - -struct index_ctx { - const char *index; - const char *output; - const char *description; - apk_blob_t *rewrite_arch; - time_t index_mtime; - int method; -}; - -static int option_parse_applet(void *ctx, struct apk_db_options *dbopts, int optch, const char *optarg) -{ - struct index_ctx *ictx = (struct index_ctx *) ctx; - - switch (optch) { - case 'x': - ictx->index = optarg; - break; - case 'o': - ictx->output = optarg; - break; - case 'd': - ictx->description = optarg; - break; - case 0x10000: - ictx->rewrite_arch = apk_blob_atomize(APK_BLOB_STR(optarg)); - break; - default: - return -ENOTSUP; - } - return 0; -} - -static const struct apk_option options_applet[] = { - { 'o', "output", required_argument, "FILE" }, - { 'x', "index", required_argument, "INDEX" }, - { 'd', "description", required_argument, "TEXT" }, - { 0x10000, "rewrite-arch", required_argument, "ARCH" }, -}; - -static const struct apk_option_group optgroup_applet = { - .name = "Index", - .options = options_applet, - .num_options = ARRAY_SIZE(options_applet), - .parse = option_parse_applet, -}; - -static int index_read_file(struct apk_database *db, struct index_ctx *ictx) -{ - struct apk_file_info fi; - - if (ictx->index == NULL) - return 0; - if (apk_fileinfo_get(AT_FDCWD, ictx->index, APK_CHECKSUM_NONE, &fi) < 0) - return 0; - - ictx->index_mtime = fi.mtime; - return apk_db_index_read_file(db, ictx->index, 0); -} - -static int warn_if_no_providers(apk_hash_item item, void *ctx) -{ - struct counts *counts = (struct counts *) ctx; - struct apk_name *name = (struct apk_name *) item; - - if (!name->is_dependency) return 0; - if (name->providers->num) return 0; - - if (++counts->unsatisfied < 10) { - apk_warning("No provider for dependency '%s'", - name->name); - } else if (counts->unsatisfied == 10) { - apk_warning("Too many unsatisfiable dependencies, " - "not reporting the rest."); - } - - return 0; -} - -static int index_main(void *ctx, struct apk_database *db, struct apk_string_array *args) -{ - struct counts counts = {0}; - struct apk_ostream *os; - struct apk_file_info fi; - int total, r, found, newpkgs = 0, errors = 0; - struct index_ctx *ictx = (struct index_ctx *) ctx; - struct apk_package *pkg; - char **parg; - - if (isatty(STDOUT_FILENO) && ictx->output == NULL && - !(apk_force & APK_FORCE_BINARY_STDOUT)) { - apk_error("Will not write binary index to console. " - "Use --force-binary-stdout to override."); - return -1; - } - - if (ictx->method == 0) - ictx->method = APK_SIGN_GENERATE; - - if ((r = index_read_file(db, ictx)) < 0) { - apk_error("%s: %s", ictx->index, apk_error_str(r)); - return r; - } - - foreach_array_item(parg, args) { - if (apk_fileinfo_get(AT_FDCWD, *parg, APK_CHECKSUM_NONE, &fi) < 0) { - apk_warning("File '%s' is unaccessible", *parg); - continue; - } - - found = FALSE; - do { - struct apk_provider *p; - struct apk_name *name; - char *fname, *fend; - apk_blob_t bname, bver; - - /* Check if index is newer than package */ - if (ictx->index == NULL || ictx->index_mtime < fi.mtime) - break; - - /* Check that it looks like a package name */ - fname = strrchr(*parg, '/'); - if (fname == NULL) - fname = *parg; - else - fname++; - fend = strstr(fname, ".apk"); - if (fend == NULL) - break; - if (apk_pkg_parse_name(APK_BLOB_PTR_PTR(fname, fend-1), - &bname, &bver) < 0) - break; - - /* If we have it in the old index already? */ - name = apk_db_query_name(db, bname); - if (name == NULL) - break; - - foreach_array_item(p, name->providers) { - pkg = p->pkg; - if (pkg->name != name) - continue; - if (apk_blob_compare(bver, *pkg->version) != 0) - continue; - if (pkg->size != fi.size) - continue; - pkg->filename = strdup(*parg); - if (ictx->rewrite_arch != NULL) - pkg->arch = ictx->rewrite_arch; - found = TRUE; - break; - } - } while (0); - - if (!found) { - struct apk_sign_ctx sctx; - apk_sign_ctx_init(&sctx, ictx->method, NULL, db->keys_fd); - r = apk_pkg_read(db, *parg, &sctx, &pkg); - if (r < 0) { - apk_error("%s: %s", *parg, apk_error_str(r)); - errors++; - } else { - newpkgs++; - if (ictx->rewrite_arch != NULL) - pkg->arch = ictx->rewrite_arch; - } - apk_sign_ctx_free(&sctx); - } - } - if (errors) - return -1; - - if (ictx->output != NULL) - os = apk_ostream_to_file(AT_FDCWD, ictx->output, NULL, 0644); - else - os = apk_ostream_to_fd(STDOUT_FILENO); - if (IS_ERR_OR_NULL(os)) return -1; - - if (ictx->method == APK_SIGN_GENERATE) { - struct apk_ostream *counter; - - memset(&fi, 0, sizeof(fi)); - fi.mode = 0644 | S_IFREG; - fi.name = "APKINDEX"; - counter = apk_ostream_counter(&fi.size); - r = apk_db_index_write(db, counter); - apk_ostream_close(counter); - - if (r >= 0) { - os = apk_ostream_gzip(os); - if (ictx->description != NULL) { - struct apk_file_info fi_desc; - memset(&fi_desc, 0, sizeof(fi)); - fi_desc.mode = 0644 | S_IFREG; - fi_desc.name = "DESCRIPTION"; - fi_desc.size = strlen(ictx->description); - apk_tar_write_entry(os, &fi_desc, ictx->description); - } - - apk_tar_write_entry(os, &fi, NULL); - r = apk_db_index_write(db, os); - apk_tar_write_padding(os, &fi); - - apk_tar_write_entry(os, NULL, NULL); - } - } else { - r = apk_db_index_write(db, os); - } - apk_ostream_close(os); - - if (r < 0) { - apk_error("Index generation failed: %s", apk_error_str(r)); - return r; - } - - total = r; - apk_hash_foreach(&db->available.names, warn_if_no_providers, &counts); - - if (counts.unsatisfied != 0) - apk_warning("Total of %d unsatisfiable package " - "names. Your repository may be broken.", - counts.unsatisfied); - apk_message("Index has %d packages (of which %d are new)", - total, newpkgs); - - return 0; -} - -static struct apk_applet apk_index = { - .name = "index", - .arguments = "FILE...", - .open_flags = APK_OPENF_READ | APK_OPENF_NO_STATE | APK_OPENF_NO_REPOS, - .command_groups = APK_COMMAND_GROUP_REPO, - .context_size = sizeof(struct index_ctx), - .optgroups = { &optgroup_global, &optgroup_applet }, - .main = index_main, -}; - -APK_DEFINE_APPLET(apk_index); - diff --git a/src/info.c b/src/info.c deleted file mode 100644 index 89e5521..0000000 --- a/src/info.c +++ /dev/null @@ -1,488 +0,0 @@ -/* info.c - Alpine Package Keeper (APK) - * - * Copyright (C) 2005-2009 Natanael Copa - * Copyright (C) 2008-2011 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 -#include "apk_defines.h" -#include "apk_applet.h" -#include "apk_package.h" -#include "apk_database.h" -#include "apk_print.h" - -struct info_ctx { - struct apk_database *db; - void (*action)(struct info_ctx *ctx, struct apk_database *db, struct apk_string_array *args); - int subaction_mask; - int errors; -}; - -/* These need to stay in sync with the function pointer array in - * info_subaction() */ -#define APK_INFO_DESC 0x01 -#define APK_INFO_URL 0x02 -#define APK_INFO_SIZE 0x04 -#define APK_INFO_DEPENDS 0x08 -#define APK_INFO_PROVIDES 0x10 -#define APK_INFO_RDEPENDS 0x20 -#define APK_INFO_CONTENTS 0x40 -#define APK_INFO_TRIGGERS 0x80 -#define APK_INFO_INSTALL_IF 0x100 -#define APK_INFO_RINSTALL_IF 0x200 -#define APK_INFO_REPLACES 0x400 -#define APK_INFO_LICENSE 0x800 - -static void verbose_print_pkg(struct apk_package *pkg, int minimal_verbosity) -{ - int verbosity = apk_verbosity; - if (verbosity < minimal_verbosity) - verbosity = minimal_verbosity; - - if (pkg == NULL || verbosity < 1) - return; - - printf("%s", pkg->name->name); - if (apk_verbosity > 1) - printf("-" BLOB_FMT, BLOB_PRINTF(*pkg->version)); - if (apk_verbosity > 2) - printf(" - %s", pkg->description); - printf("\n"); -} - -static void info_exists(struct info_ctx *ctx, struct apk_database *db, - struct apk_string_array *args) -{ - struct apk_name *name; - struct apk_dependency dep; - struct apk_provider *p; - char **parg; - int ok; - - foreach_array_item(parg, args) { - apk_blob_t b = APK_BLOB_STR(*parg); - - apk_blob_pull_dep(&b, db, &dep); - if (APK_BLOB_IS_NULL(b) || b.len > 0) - continue; - - name = dep.name; - if (name == NULL) - continue; - - ok = apk_dep_is_provided(&dep, NULL); - foreach_array_item(p, name->providers) { - if (!p->pkg->ipkg) continue; - ok = apk_dep_is_provided(&dep, p); - if (ok) verbose_print_pkg(p->pkg, 0); - break; - } - if (!ok) ctx->errors++; - } -} - -static void info_who_owns(struct info_ctx *ctx, struct apk_database *db, - struct apk_string_array *args) -{ - struct apk_package *pkg; - struct apk_dependency_array *deps; - struct apk_dependency dep; - struct apk_ostream *os; - const char *via; - char **parg, fnbuf[PATH_MAX], buf[PATH_MAX]; - apk_blob_t fn; - ssize_t r; - - apk_dependency_array_init(&deps); - foreach_array_item(parg, args) { - if (*parg[0] != '/' && realpath(*parg, fnbuf)) - fn = APK_BLOB_STR(fnbuf); - else - fn = APK_BLOB_STR(*parg); - - via = ""; - pkg = apk_db_get_file_owner(db, fn); - if (pkg == NULL) { - r = readlinkat(db->root_fd, *parg, buf, sizeof(buf)); - if (r > 0 && r < PATH_MAX && buf[0] == '/') { - pkg = apk_db_get_file_owner(db, APK_BLOB_STR(buf)); - via = "symlink target "; - } - } - - if (pkg == NULL) { - apk_error(BLOB_FMT ": Could not find owner package", - BLOB_PRINTF(fn)); - ctx->errors++; - continue; - } - - if (apk_verbosity < 1) { - dep = (struct apk_dependency) { - .name = pkg->name, - .version = apk_blob_atomize(APK_BLOB_NULL), - .result_mask = APK_DEPMASK_ANY, - }; - apk_deps_add(&deps, &dep); - } else { - printf(BLOB_FMT " %sis owned by " PKG_VER_FMT "\n", - BLOB_PRINTF(fn), via, PKG_VER_PRINTF(pkg)); - } - } - if (apk_verbosity < 1 && deps->num != 0) { - os = apk_ostream_to_fd(STDOUT_FILENO); - if (!IS_ERR_OR_NULL(os)) { - apk_deps_write(db, deps, os, APK_BLOB_PTR_LEN(" ", 1)); - apk_ostream_write(os, "\n", 1); - apk_ostream_close(os); - } - } - apk_dependency_array_free(&deps); -} - -static void info_print_description(struct apk_database *db, struct apk_package *pkg) -{ - if (apk_verbosity > 1) - printf("%s: %s", pkg->name->name, pkg->description); - else - printf(PKG_VER_FMT " description:\n%s\n", - PKG_VER_PRINTF(pkg), - pkg->description); -} - -static void info_print_url(struct apk_database *db, struct apk_package *pkg) -{ - if (apk_verbosity > 1) - printf("%s: %s", pkg->name->name, pkg->url); - else - printf(PKG_VER_FMT " webpage:\n%s\n", - PKG_VER_PRINTF(pkg), - pkg->url); -} - -static void info_print_license(struct apk_database *db, struct apk_package *pkg) -{ - if (apk_verbosity > 1) - printf("%s: " BLOB_FMT , pkg->name->name, BLOB_PRINTF(*pkg->license)); - else - printf(PKG_VER_FMT " license:\n" BLOB_FMT "\n", - PKG_VER_PRINTF(pkg), - BLOB_PRINTF(*pkg->license)); -} - -static void info_print_size(struct apk_database *db, struct apk_package *pkg) -{ - off_t size; - const char *size_unit; - - size_unit = apk_get_human_size(pkg->installed_size, &size); - if (apk_verbosity > 1) - printf("%s: %lld %s", pkg->name->name, - (long long)size, size_unit); - else - printf(PKG_VER_FMT " installed size:\n%lld %s\n", - PKG_VER_PRINTF(pkg), (long long)size, size_unit); -} - -static void info_print_dep_array(struct apk_database *db, struct apk_package *pkg, - struct apk_dependency_array *deps, const char *dep_text) -{ - struct apk_dependency *d; - apk_blob_t separator = APK_BLOB_STR(apk_verbosity > 1 ? " " : "\n"); - char buf[256]; - - if (apk_verbosity == 1) - printf(PKG_VER_FMT " %s:\n", PKG_VER_PRINTF(pkg), dep_text); - if (apk_verbosity > 1) - printf("%s: ", pkg->name->name); - foreach_array_item(d, deps) { - apk_blob_t b = APK_BLOB_BUF(buf); - apk_blob_push_dep(&b, db, d); - apk_blob_push_blob(&b, separator); - b = apk_blob_pushed(APK_BLOB_BUF(buf), b); - fwrite(b.ptr, b.len, 1, stdout); - } -} - -static void info_print_depends(struct apk_database *db, struct apk_package *pkg) -{ - info_print_dep_array(db, pkg, pkg->depends, "depends on"); -} - -static void info_print_provides(struct apk_database *db, struct apk_package *pkg) -{ - info_print_dep_array(db, pkg, pkg->provides, "provides"); -} - -static void print_rdep_pkg(struct apk_package *pkg0, struct apk_dependency *dep0, struct apk_package *pkg, void *pctx) -{ - printf(PKG_VER_FMT "%s", PKG_VER_PRINTF(pkg0), apk_verbosity > 1 ? " " : "\n"); -} - -static void info_print_required_by(struct apk_database *db, struct apk_package *pkg) -{ - if (apk_verbosity == 1) - printf(PKG_VER_FMT " is required by:\n", PKG_VER_PRINTF(pkg)); - if (apk_verbosity > 1) - printf("%s: ", pkg->name->name); - apk_pkg_foreach_reverse_dependency( - pkg, - APK_FOREACH_INSTALLED | APK_DEP_SATISFIES | apk_foreach_genid(), - print_rdep_pkg, NULL); -} - -static void info_print_install_if(struct apk_database *db, struct apk_package *pkg) -{ - info_print_dep_array(db, pkg, pkg->install_if, "has auto-install rule"); -} - -static void info_print_rinstall_if(struct apk_database *db, struct apk_package *pkg) -{ - int i, j; - char *separator = apk_verbosity > 1 ? " " : "\n"; - - if (apk_verbosity == 1) - printf(PKG_VER_FMT " affects auto-installation of:\n", - PKG_VER_PRINTF(pkg)); - if (apk_verbosity > 1) - printf("%s: ", pkg->name->name); - for (i = 0; i < pkg->name->rinstall_if->num; i++) { - struct apk_name *name0; - struct apk_package *pkg0; - - /* Check only the package that is installed, and that - * it actually has this package in install_if. */ - name0 = pkg->name->rinstall_if->item[i]; - pkg0 = apk_pkg_get_installed(name0); - if (pkg0 == NULL) - continue; - - for (j = 0; j < pkg0->install_if->num; j++) { - if (pkg0->install_if->item[j].name != pkg->name) - continue; - printf(PKG_VER_FMT "%s", - PKG_VER_PRINTF(pkg0), - separator); - break; - } - } -} - -static void info_print_contents(struct apk_database *db, struct apk_package *pkg) -{ - struct apk_installed_package *ipkg = pkg->ipkg; - struct apk_db_dir_instance *diri; - struct apk_db_file *file; - struct hlist_node *dc, *dn, *fc, *fn; - - if (apk_verbosity == 1) - printf(PKG_VER_FMT " contains:\n", - PKG_VER_PRINTF(pkg)); - - hlist_for_each_entry_safe(diri, dc, dn, &ipkg->owned_dirs, - pkg_dirs_list) { - hlist_for_each_entry_safe(file, fc, fn, &diri->owned_files, - diri_files_list) { - if (apk_verbosity > 1) - printf("%s: ", pkg->name->name); - printf(DIR_FILE_FMT "\n", DIR_FILE_PRINTF(diri->dir, file)); - } - } -} - -static void info_print_triggers(struct apk_database *db, struct apk_package *pkg) -{ - struct apk_installed_package *ipkg = pkg->ipkg; - char **trigger; - - if (apk_verbosity == 1) - printf(PKG_VER_FMT " triggers:\n", - PKG_VER_PRINTF(pkg)); - - foreach_array_item(trigger, ipkg->triggers) { - if (apk_verbosity > 1) - printf("%s: trigger ", pkg->name->name); - printf("%s\n", *trigger); - } -} - -static void info_print_replaces(struct apk_database *db, struct apk_package *pkg) -{ - info_print_dep_array(db, pkg, pkg->ipkg->replaces, "replaces"); -} - -static void info_subaction(struct info_ctx *ctx, struct apk_package *pkg) -{ - typedef void (*subaction_t)(struct apk_database *, struct apk_package *); - static subaction_t subactions[] = { - info_print_description, - info_print_url, - info_print_size, - info_print_depends, - info_print_provides, - info_print_required_by, - info_print_contents, - info_print_triggers, - info_print_install_if, - info_print_rinstall_if, - info_print_replaces, - info_print_license, - }; - const int requireipkg = - APK_INFO_CONTENTS | APK_INFO_TRIGGERS | APK_INFO_RDEPENDS | - APK_INFO_RINSTALL_IF | APK_INFO_REPLACES; - int i; - - for (i = 0; i < ARRAY_SIZE(subactions); i++) { - if (!(BIT(i) & ctx->subaction_mask)) - continue; - - if (pkg->ipkg == NULL && (BIT(i) & requireipkg)) - continue; - - subactions[i](ctx->db, pkg); - puts(""); - } -} - -static void print_name_info(struct apk_database *db, const char *match, struct apk_name *name, void *pctx) -{ - struct info_ctx *ctx = (struct info_ctx *) pctx; - struct apk_provider *p; - - if (name == NULL) { - ctx->errors++; - return; - } - - foreach_array_item(p, name->providers) - info_subaction(ctx, p->pkg); -} - -static int option_parse_applet(void *pctx, struct apk_db_options *dbopts, int optch, const char *optarg) -{ - struct info_ctx *ctx = (struct info_ctx *) pctx; - - ctx->action = NULL; - switch (optch) { - case 'e': - ctx->action = info_exists; - dbopts->open_flags |= APK_OPENF_NO_REPOS; - break; - case 'W': - ctx->action = info_who_owns; - dbopts->open_flags |= APK_OPENF_NO_REPOS; - break; - case 'w': - ctx->subaction_mask |= APK_INFO_URL; - break; - case 'R': - ctx->subaction_mask |= APK_INFO_DEPENDS; - break; - case 'P': - ctx->subaction_mask |= APK_INFO_PROVIDES; - break; - case 'r': - ctx->subaction_mask |= APK_INFO_RDEPENDS; - break; - case 0x10002: - ctx->subaction_mask |= APK_INFO_INSTALL_IF; - break; - case 0x10003: - ctx->subaction_mask |= APK_INFO_RINSTALL_IF; - break; - case 's': - ctx->subaction_mask |= APK_INFO_SIZE; - break; - case 'd': - ctx->subaction_mask |= APK_INFO_DESC; - break; - case 'L': - ctx->subaction_mask |= APK_INFO_CONTENTS; - break; - case 't': - ctx->subaction_mask |= APK_INFO_TRIGGERS; - break; - case 0x10000: - ctx->subaction_mask |= APK_INFO_REPLACES; - break; - case 0x10001: - ctx->subaction_mask |= APK_INFO_LICENSE; - break; - case 'a': - ctx->subaction_mask = 0xffffffff; - break; - default: - return -ENOTSUP; - } - return 0; -} - -static int info_main(void *ctx, struct apk_database *db, struct apk_string_array *args) -{ - struct info_ctx *ictx = (struct info_ctx *) ctx; - struct apk_installed_package *ipkg; - - ictx->db = db; - if (ictx->subaction_mask == 0) - ictx->subaction_mask = APK_INFO_DESC | APK_INFO_URL | APK_INFO_SIZE; - if (ictx->action != NULL) { - ictx->action(ictx, db, args); - } else if (args->num > 0) { - /* Print info on given names */ - apk_name_foreach_matching( - db, args, APK_FOREACH_NULL_MATCHES_ALL | apk_foreach_genid(), - print_name_info, ctx); - } else { - /* Print all installed packages */ - list_for_each_entry(ipkg, &db->installed.packages, installed_pkgs_list) - verbose_print_pkg(ipkg->pkg, 1); - } - - return ictx->errors; -} - -static const struct apk_option options_applet[] = { - { 'L', "contents" }, - { 'e', "installed" }, - { 'W', "who-owns" }, - { 'R', "depends" }, - { 'P', "provides" }, - { 'r', "rdepends" }, - { 0x10000, "replaces" }, - { 0x10002, "install-if" }, - { 0x10003, "rinstall-if" }, - { 'w', "webpage" }, - { 's', "size" }, - { 'd', "description" }, - { 0x10001, "license" }, - { 't', "triggers" }, - { 'a', "all" }, -}; - -static const struct apk_option_group optgroup_applet = { - .name = "Info", - .options = options_applet, - .num_options = ARRAY_SIZE(options_applet), - .parse = option_parse_applet, -}; - -static struct apk_applet apk_info = { - .name = "info", - .arguments = "PACKAGE...", - .open_flags = APK_OPENF_READ, - .command_groups = APK_COMMAND_GROUP_QUERY, - .context_size = sizeof(struct info_ctx), - .optgroups = { &optgroup_global, &optgroup_applet }, - .main = info_main, -}; - -APK_DEFINE_APPLET(apk_info); - diff --git a/src/list.c b/src/list.c deleted file mode 100644 index f121ae5..0000000 --- a/src/list.c +++ /dev/null @@ -1,272 +0,0 @@ -/* list.c - Alpine Package Keeper (APK) - * - * Copyright (C) 2005-2009 Natanael Copa - * Copyright (C) 2008-2011 Timo Teräs - * Copyright (C) 2018 William Pitcock - * 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 -#include "apk_defines.h" -#include "apk_applet.h" -#include "apk_package.h" -#include "apk_database.h" -#include "apk_print.h" - -struct list_ctx { - unsigned int installed : 1; - unsigned int orphaned : 1; - unsigned int available : 1; - unsigned int upgradable : 1; - unsigned int match_origin : 1; - unsigned int match_depends : 1; - unsigned int match_providers : 1; - - struct apk_string_array *filters; -}; - -static int origin_matches(const struct list_ctx *ctx, const struct apk_package *pkg) -{ - char **pmatch; - - if (pkg->origin == NULL) - return 0; - - foreach_array_item(pmatch, ctx->filters) - { - if (apk_blob_compare(APK_BLOB_STR(*pmatch), *pkg->origin) == 0) - return 1; - } - - return 0; -} - -static int is_orphaned(const struct apk_name *name) -{ - struct apk_provider *p; - unsigned int repos = 0; - - if (name == NULL) - return 0; - - foreach_array_item(p, name->providers) - repos |= p->pkg->repos; - - /* repo 1 is always installed-db, so if other bits are set it means the package is available somewhere - * (either cache or in a proper repo) - */ - return (repos & ~BIT(APK_REPOSITORY_CACHED)) == 0; -} - -/* returns the currently installed package if there is a newer package that satisfies `name` */ -static const struct apk_package *is_upgradable(struct apk_name *name, const struct apk_package *pkg0) -{ - struct apk_provider *p; - struct apk_package *ipkg; - apk_blob_t *latest = apk_blob_atomize(APK_BLOB_STR("")); - - if (name == NULL) - return NULL; - - ipkg = apk_pkg_get_installed(name); - if (ipkg == NULL) - return NULL; - - if (pkg0 == NULL) - { - foreach_array_item(p, name->providers) - { - pkg0 = p->pkg; - int r; - - if (pkg0 == ipkg) - continue; - - r = apk_version_compare_blob(*pkg0->version, *latest); - if (r == APK_VERSION_GREATER) - latest = pkg0->version; - } - } - else - latest = pkg0->version; - - return apk_version_compare_blob(*ipkg->version, *latest) == APK_VERSION_LESS ? ipkg : NULL; -} - -static void print_package(const struct apk_package *pkg, const struct list_ctx *ctx) -{ - printf(PKG_VER_FMT " " BLOB_FMT " ", - PKG_VER_PRINTF(pkg), BLOB_PRINTF(*pkg->arch)); - - if (pkg->origin != NULL) - printf("{" BLOB_FMT "}", BLOB_PRINTF(*pkg->origin)); - else - printf("{%s}", pkg->name->name); - - printf(" (" BLOB_FMT ")", BLOB_PRINTF(*pkg->license)); - - if (pkg->ipkg) - printf(" [installed]"); - else - { - const struct apk_package *u; - - u = is_upgradable(pkg->name, pkg); - if (u != NULL) - printf(" [upgradable from: " PKG_VER_FMT "]", PKG_VER_PRINTF(u)); - } - - - if (apk_verbosity > 1) - { - printf("\n %s\n", pkg->description); - if (apk_verbosity > 2) - printf(" <%s>\n", pkg->url); - } - - printf("\n"); -} - -static void filter_package(const struct apk_package *pkg, const struct list_ctx *ctx) -{ - if (ctx->match_origin && !origin_matches(ctx, pkg)) - return; - - if (ctx->installed && pkg->ipkg == NULL) - return; - - if (ctx->orphaned && !is_orphaned(pkg->name)) - return; - - if (ctx->available && pkg->repos == BIT(APK_REPOSITORY_CACHED)) - return; - - if (ctx->upgradable && !is_upgradable(pkg->name, pkg)) - return; - - print_package(pkg, ctx); -} - -static void iterate_providers(const struct apk_name *name, const struct list_ctx *ctx) -{ - struct apk_provider *p; - - foreach_array_item(p, name->providers) - { - if (!ctx->match_providers && p->pkg->name != name) - continue; - - if (ctx->match_providers) - printf("<%s> ", name->name); - - filter_package(p->pkg, ctx); - } -} - -static void print_result(struct apk_database *db, const char *match, struct apk_name *name, void *pctx) -{ - struct list_ctx *ctx = pctx; - - if (name == NULL) - return; - - if (ctx->match_depends) - { - struct apk_name **pname; - - foreach_array_item(pname, name->rdepends) - iterate_providers(*pname, ctx); - } - else - iterate_providers(name, ctx); -} - -static int option_parse_applet(void *pctx, struct apk_db_options *dbopts, int optch, const char *optarg) -{ - struct list_ctx *ctx = pctx; - - switch (optch) - { - case 'I': - ctx->installed = 1; - break; - case 'O': - ctx->installed = 1; - ctx->orphaned = 1; - break; - case 'u': - ctx->available = 1; - ctx->orphaned = 0; - ctx->installed = 0; - ctx->upgradable = 1; - break; - case 'a': - ctx->available = 1; - ctx->orphaned = 0; - break; - case 'o': - ctx->match_origin = 1; - break; - case 'd': - ctx->match_depends = 1; - break; - case 'P': - ctx->match_providers = 1; - break; - default: - return -ENOTSUP; - } - - return 0; -} - -static const struct apk_option options_applet[] = { - { 'I', "installed" }, - { 'O', "orphaned" }, - { 'a', "available" }, - { 'u', "upgradable" }, - { 'o', "origin" }, - { 'd', "depends" }, - { 'P', "providers" }, -}; - -static const struct apk_option_group optgroup_applet = { - .name = "List", - .options = options_applet, - .num_options = ARRAY_SIZE(options_applet), - .parse = option_parse_applet, -}; - -static int list_main(void *pctx, struct apk_database *db, struct apk_string_array *args) -{ - struct list_ctx *ctx = pctx; - - ctx->filters = args; - - if (ctx->match_origin) - args = NULL; - - apk_name_foreach_matching( - db, args, APK_FOREACH_NULL_MATCHES_ALL | apk_foreach_genid(), - print_result, ctx); - - return 0; -} - -static struct apk_applet apk_list = { - .name = "list", - .arguments = "PATTERN", - .open_flags = APK_OPENF_READ, - .command_groups = APK_COMMAND_GROUP_QUERY, - .context_size = sizeof(struct list_ctx), - .optgroups = { &optgroup_global, &optgroup_applet }, - .main = list_main, -}; - -APK_DEFINE_APPLET(apk_list); diff --git a/src/manifest.c b/src/manifest.c deleted file mode 100644 index 1106a74..0000000 --- a/src/manifest.c +++ /dev/null @@ -1,133 +0,0 @@ -/* manifest.c - Alpine Package Keeper (APK) - * - * Copyright (C) 2005-2017 Natanael Copa - * Copyright (C) 2008-2017 Timo Teräs - * Copyright (C) 2017 William Pitcock - * 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_defines.h" -#include "apk_applet.h" -#include "apk_database.h" -#include "apk_version.h" -#include "apk_print.h" - -/* TODO: support package files as well as generating manifest from the installed DB. */ -static char *csum_types[APK_CHECKSUM_SHA1 + 1] = { - /* Note: if adding new algorithms, update apk-manifest(8) */ - [APK_CHECKSUM_MD5] = "md5", - [APK_CHECKSUM_SHA1] = "sha1", -}; - -struct manifest_file_ctx { - const char *file; - struct apk_sign_ctx *sctx; -}; - -static void process_package(struct apk_database *db, struct apk_package *pkg) -{ - struct apk_installed_package *ipkg = pkg->ipkg; - struct apk_db_dir_instance *diri; - struct apk_db_file *file; - struct hlist_node *dc, *dn, *fc, *fn; - char csum_buf[APK_BLOB_CHECKSUM_BUF]; - - if (ipkg == NULL) - return; - - hlist_for_each_entry_safe(diri, dc, dn, &ipkg->owned_dirs, - pkg_dirs_list) { - hlist_for_each_entry_safe(file, fc, fn, &diri->owned_files, - diri_files_list) { - apk_blob_t csum_blob = APK_BLOB_BUF(csum_buf); - - memset(csum_buf, '\0', sizeof(csum_buf)); - apk_blob_push_hexdump(&csum_blob, APK_BLOB_CSUM(file->csum)); - - if (apk_verbosity > 1) - printf("%s: ", pkg->name->name); - - printf("%s:%s " DIR_FILE_FMT "\n", csum_types[file->csum.type], csum_buf, DIR_FILE_PRINTF(diri->dir, file)); - } - } -} - -static int read_file_entry(void *ctx, const struct apk_file_info *ae, - struct apk_istream *is) -{ - struct manifest_file_ctx *mctx = ctx; - char csum_buf[APK_BLOB_CHECKSUM_BUF]; - apk_blob_t csum_blob = APK_BLOB_BUF(csum_buf); - int r; - - r = apk_sign_ctx_verify_tar(mctx->sctx, ae, is); - if (r != 0) - return r; - - if (!mctx->sctx->data_started) - return 0; - - if ((ae->mode & S_IFMT) != S_IFREG) - return 0; - - memset(csum_buf, '\0', sizeof(csum_buf)); - apk_blob_push_hexdump(&csum_blob, APK_BLOB_CSUM(ae->csum)); - - if (apk_verbosity > 1) - printf("%s: ", mctx->file); - - printf("%s:%s %s\n", csum_types[ae->csum.type], csum_buf, ae->name); - - return 0; -} - -static void process_file(struct apk_database *db, const char *match) -{ - struct apk_sign_ctx sctx; - struct manifest_file_ctx ctx = {match, &sctx}; - int r; - - apk_sign_ctx_init(&sctx, APK_SIGN_VERIFY, NULL, db->keys_fd); - r = apk_tar_parse( - apk_istream_gunzip_mpart(apk_istream_from_file(AT_FDCWD, match), apk_sign_ctx_mpart_cb, &sctx), - read_file_entry, &ctx, &db->id_cache); - apk_sign_ctx_free(&sctx); - if (r < 0) apk_error("%s: %s", match, apk_error_str(r)); -} - -static void process_match(struct apk_database *db, const char *match, struct apk_name *name, void *ctx) -{ - struct apk_provider *p; - - if (name == NULL) - { - process_file(db, match); - return; - } - - foreach_array_item(p, name->providers) - process_package(db, p->pkg); -} - -static int manifest_main(void *ctx, struct apk_database *db, struct apk_string_array *args) -{ - apk_name_foreach_matching(db, args, apk_foreach_genid(), process_match, NULL); - return 0; -} - -static struct apk_applet apk_manifest = { - .name = "manifest", - .arguments = "PACKAGE...", - .open_flags = APK_OPENF_READ, - .command_groups = APK_COMMAND_GROUP_REPO, - .main = manifest_main, -}; - -APK_DEFINE_APPLET(apk_manifest); diff --git a/src/policy.c b/src/policy.c deleted file mode 100644 index dc33a0b..0000000 --- a/src/policy.c +++ /dev/null @@ -1,80 +0,0 @@ -/* policy.c - Alpine Package Keeper (APK) - * - * Copyright (C) 2013 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 "apk_defines.h" -#include "apk_applet.h" -#include "apk_database.h" -#include "apk_version.h" -#include "apk_print.h" - -extern const char * const apk_installed_file; - -static void print_policy(struct apk_database *db, const char *match, struct apk_name *name, void *ctx) -{ - struct apk_provider *p; - struct apk_repository *repo; - int i, j, num = 0; - - if (!name) return; - -/* -zlib1g policy: - 2.0: - @testing http://nl.alpinelinux.org/alpine/edge/testing - 1.7: - @edge http://nl.alpinelinux.org/alpine/edge/main - 1.2.3.5 (upgradeable): - http://nl.alpinelinux.org/alpine/v2.6/main - 1.2.3.4 (installed): - /media/cdrom/... - http://nl.alpinelinux.org/alpine/v2.5/main - 1.1: - http://nl.alpinelinux.org/alpine/v2.4/main -*/ - foreach_array_item(p, name->providers) { - if (p->pkg->name != name) - continue; - if (num++ == 0) - printf("%s policy:\n", name->name); - printf(" " BLOB_FMT ":\n", BLOB_PRINTF(*p->version)); - if (p->pkg->ipkg != NULL) - printf(" %s\n", apk_installed_file); - for (i = 0; i < db->num_repos; i++) { - repo = &db->repos[i]; - if (!(BIT(i) & p->pkg->repos)) - continue; - for (j = 0; j < db->num_repo_tags; j++) { - if (db->repo_tags[j].allowed_repos & p->pkg->repos) - printf(" "BLOB_FMT"%s%s\n", - BLOB_PRINTF(db->repo_tags[j].tag), - j == 0 ? "" : " ", - repo->url); - } - } - } -} - -static int policy_main(void *ctx, struct apk_database *db, struct apk_string_array *args) -{ - apk_name_foreach_matching(db, args, apk_foreach_genid(), print_policy, NULL); - return 0; -} - -static struct apk_applet apk_policy = { - .name = "policy", - .open_flags = APK_OPENF_READ, - .command_groups = APK_COMMAND_GROUP_QUERY, - .main = policy_main, -}; - -APK_DEFINE_APPLET(apk_policy); - - diff --git a/src/search.c b/src/search.c deleted file mode 100644 index fa5b267..0000000 --- a/src/search.c +++ /dev/null @@ -1,217 +0,0 @@ -/* search.c - Alpine Package Keeper (APK) - * - * Copyright (C) 2005-2009 Natanael Copa - * Copyright (C) 2008-2011 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_defines.h" -#include "apk_applet.h" -#include "apk_package.h" -#include "apk_database.h" - -struct search_ctx { - void (*print_result)(struct search_ctx *ctx, struct apk_package *pkg); - void (*print_package)(struct search_ctx *ctx, struct apk_package *pkg); - - int show_all : 1; - int search_exact : 1; - int search_description : 1; - int search_origin : 1; - - unsigned int matches; - struct apk_string_array *filter; -}; - -static int unique_match(struct apk_package *pkg) -{ - if (pkg->state_int) return 0; - pkg->state_int = 1; - return 1; -} - -static void print_package_name(struct search_ctx *ctx, struct apk_package *pkg) -{ - if (!unique_match(pkg)) return; - printf("%s", pkg->name->name); - if (apk_verbosity > 0) - printf("-" BLOB_FMT, BLOB_PRINTF(*pkg->version)); - if (apk_verbosity > 1) - printf(" - %s", pkg->description); - printf("\n"); -} - -static void print_origin_name(struct search_ctx *ctx, struct apk_package *pkg) -{ - if (!unique_match(pkg)) return; - if (pkg->origin != NULL) - printf(BLOB_FMT, BLOB_PRINTF(*pkg->origin)); - else - printf("%s", pkg->name->name); - if (apk_verbosity > 0) - printf("-" BLOB_FMT, BLOB_PRINTF(*pkg->version)); - printf("\n"); -} - -static void print_rdep_pkg(struct apk_package *pkg0, struct apk_dependency *dep0, struct apk_package *pkg, void *pctx) -{ - struct search_ctx *ctx = (struct search_ctx *) pctx; - ctx->print_package(ctx, pkg0); -} - -static void print_rdepends(struct search_ctx *ctx, struct apk_package *pkg) -{ - if (apk_verbosity > 0) { - ctx->matches = apk_foreach_genid() | APK_DEP_SATISFIES; - printf(PKG_VER_FMT " is required by:\n", PKG_VER_PRINTF(pkg)); - } - apk_pkg_foreach_reverse_dependency(pkg, ctx->matches, print_rdep_pkg, ctx); -} - -static int option_parse_applet(void *ctx, struct apk_db_options *dbopts, int optch, const char *optarg) -{ - struct search_ctx *ictx = (struct search_ctx *) ctx; - - switch (optch) { - case 'a': - ictx->show_all = 1; - break; - case 'd': - ictx->search_description = 1; - ictx->search_exact = 1; - ictx->show_all = 1; - break; - case 'e': - case 'x': - ictx->search_exact = 1; - break; - case 'o': - ictx->print_package = print_origin_name; - break; - case 'r': - ictx->print_result = print_rdepends; - break; - case 0x10000: - ictx->search_origin = 1; - ictx->search_exact = 1; - ictx->show_all = 1; - break; - default: - return -ENOTSUP; - } - return 0; -} - -static const struct apk_option options_applet[] = { - { 'a', "all" }, - { 'd', "description" }, - { 'x', "exact" }, - { 'e', NULL }, - { 'o', "origin" }, - { 'r', "rdepends" }, - { 0x10000, "has-origin" }, -}; - -static const struct apk_option_group optgroup_applet = { - .name = "Search", - .options = options_applet, - .num_options = ARRAY_SIZE(options_applet), - .parse = option_parse_applet, -}; - -static void print_result_pkg(struct search_ctx *ctx, struct apk_package *pkg) -{ - char **pmatch; - - if (ctx->search_description) { - foreach_array_item(pmatch, ctx->filter) { - if (strstr(pkg->description, *pmatch) != NULL || - strstr(pkg->name->name, *pmatch) != NULL) - goto match; - } - return; - } - if (ctx->search_origin) { - foreach_array_item(pmatch, ctx->filter) { - if (pkg->origin && apk_blob_compare(APK_BLOB_STR(*pmatch), *pkg->origin) == 0) - goto match; - } - return; - } -match: - ctx->print_result(ctx, pkg); -} - -static void print_result(struct apk_database *db, const char *match, struct apk_name *name, void *pctx) -{ - struct search_ctx *ctx = pctx; - struct apk_provider *p; - struct apk_package *pkg = NULL; - - if (!name) return; - - if (ctx->show_all) { - foreach_array_item(p, name->providers) - print_result_pkg(ctx, p->pkg); - } else { - foreach_array_item(p, name->providers) { - if (pkg == NULL || - apk_version_compare_blob(*p->version, *pkg->version) == APK_VERSION_GREATER) - pkg = p->pkg; - } - if (pkg) - print_result_pkg(ctx, pkg); - } -} - -static int print_pkg(apk_hash_item item, void *pctx) -{ - print_result_pkg((struct search_ctx *) pctx, (struct apk_package *) item); - return 0; -} - -static int search_main(void *pctx, struct apk_database *db, struct apk_string_array *args) -{ - struct search_ctx *ctx = (struct search_ctx *) pctx; - char *tmp, **pmatch; - - ctx->filter = args; - ctx->matches = apk_foreach_genid() | APK_DEP_SATISFIES; - if (ctx->print_package == NULL) - ctx->print_package = print_package_name; - if (ctx->print_result == NULL) - ctx->print_result = ctx->print_package; - - if (ctx->search_description || ctx->search_origin) - return apk_hash_foreach(&db->available.packages, print_pkg, ctx); - - if (!ctx->search_exact) { - foreach_array_item(pmatch, ctx->filter) { - tmp = alloca(strlen(*pmatch) + 3); - sprintf(tmp, "*%s*", *pmatch); - *pmatch = tmp; - } - } - apk_name_foreach_matching( - db, args, APK_FOREACH_NULL_MATCHES_ALL | apk_foreach_genid(), - print_result, ctx); - return 0; -} - -static struct apk_applet apk_search = { - .name = "search", - .arguments = "PATTERN", - .open_flags = APK_OPENF_READ | APK_OPENF_NO_STATE, - .command_groups = APK_COMMAND_GROUP_QUERY, - .context_size = sizeof(struct search_ctx), - .optgroups = { &optgroup_global, &optgroup_applet }, - .main = search_main, -}; - -APK_DEFINE_APPLET(apk_search); diff --git a/src/stats.c b/src/stats.c deleted file mode 100644 index 33a3285..0000000 --- a/src/stats.c +++ /dev/null @@ -1,64 +0,0 @@ -/* stats.c - Alpine Package Keeper (APK) - * - * Copyright (C) 2013 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 "apk_defines.h" -#include "apk_applet.h" -#include "apk_database.h" - -static int list_count(struct list_head *h) -{ - struct list_head *n; - int c = 0; - - list_for_each(n, h) - c++; - - return c; -} - -static int stats_main(void *ctx, struct apk_database *db, struct apk_string_array *args) -{ - extern struct apk_hash atom_hash; - - printf( - "installed:\n" - " packages: %d\n" - " dirs: %d\n" - " files: %d\n" - " bytes: %zu\n" - " triggers: %d\n" - "available:\n" - " names: %d\n" - " packages: %d\n" - "atoms:\n" - " num: %d\n" - , - db->installed.stats.packages, - db->installed.stats.dirs, - db->installed.stats.files, - db->installed.stats.bytes, - list_count(&db->installed.triggers), - db->available.names.num_items, - db->available.packages.num_items, - atom_hash.num_items - ); - return 0; -} - -static struct apk_applet stats_applet = { - .name = "stats", - .open_flags = APK_OPENF_READ, - .main = stats_main, -}; - -APK_DEFINE_APPLET(stats_applet); - - diff --git a/src/update.c b/src/update.c deleted file mode 100644 index 5742127..0000000 --- a/src/update.c +++ /dev/null @@ -1,57 +0,0 @@ -/* update.c - Alpine Package Keeper (APK) - * - * Copyright (C) 2005-2008 Natanael Copa - * Copyright (C) 2008-2011 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 "apk_defines.h" -#include "apk_applet.h" -#include "apk_database.h" -#include "apk_version.h" -#include "apk_print.h" - -static int update_main(void *ctx, struct apk_database *db, struct apk_string_array *args) -{ - struct apk_repository *repo; - int i; - char buf[32] = "OK:"; - - if (apk_verbosity < 1) - return db->repo_update_errors; - - for (i = 0; i < db->num_repos; i++) { - repo = &db->repos[i]; - - if (APK_BLOB_IS_NULL(repo->description)) - continue; - - apk_message(BLOB_FMT " [%s]", - BLOB_PRINTF(repo->description), - db->repos[i].url); - } - - if (db->repo_update_errors != 0) - snprintf(buf, sizeof(buf), "%d errors;", - db->repo_update_errors); - apk_message("%s %d distinct packages available", buf, - db->available.packages.num_items); - - return db->repo_update_errors; -} - -static struct apk_applet apk_update = { - .name = "update", - .open_flags = APK_OPENF_WRITE, - .forced_force = APK_FORCE_REFRESH, - .command_groups = APK_COMMAND_GROUP_SYSTEM, - .main = update_main, -}; - -APK_DEFINE_APPLET(apk_update); - diff --git a/src/upgrade.c b/src/upgrade.c deleted file mode 100644 index f0bf16c..0000000 --- a/src/upgrade.c +++ /dev/null @@ -1,198 +0,0 @@ -/* upgrade.c - Alpine Package Keeper (APK) - * - * Copyright (C) 2005-2008 Natanael Copa - * Copyright (C) 2008-2011 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 -#include -#include "apk_applet.h" -#include "apk_database.h" -#include "apk_print.h" -#include "apk_solver.h" - -struct upgrade_ctx { - unsigned short solver_flags; - int no_self_upgrade : 1; - int self_upgrade_only : 1; - int ignore : 1; -}; - -static int option_parse_applet(void *ctx, struct apk_db_options *dbopts, int optch, const char *optarg) -{ - struct upgrade_ctx *uctx = (struct upgrade_ctx *) ctx; - - switch (optch) { - case 0x10000: - uctx->no_self_upgrade = 1; - break; - case 0x10001: - uctx->self_upgrade_only = 1; - break; - case 0x10002: - uctx->ignore = 1; - break; - case 'a': - uctx->solver_flags |= APK_SOLVERF_AVAILABLE; - break; - case 'l': - uctx->solver_flags |= APK_SOLVERF_LATEST; - break; - default: - return -ENOTSUP; - } - return 0; -} - -static const struct apk_option options_applet[] = { - { 'a', "available" }, - { 'l', "latest" }, - { 0x10000, "no-self-upgrade" }, - { 0x10001, "self-upgrade-only" }, - { 0x10002, "ignore" }, -}; - -static const struct apk_option_group optgroup_applet = { - .name = "Upgrade", - .options = options_applet, - .num_options = ARRAY_SIZE(options_applet), - .parse = option_parse_applet, -}; - -int apk_do_self_upgrade(struct apk_database *db, unsigned short solver_flags, unsigned int self_upgrade_only) -{ - struct apk_name *name; - struct apk_package *pkg; - struct apk_provider *p0; - struct apk_changeset changeset = {}; - int r; - - name = apk_db_get_name(db, APK_BLOB_STR("apk-tools")); - - /* First check if new version is even available */ - r = 0; - pkg = apk_pkg_get_installed(name); - if (!pkg) goto ret; - - foreach_array_item(p0, name->providers) { - struct apk_package *pkg0 = p0->pkg; - if (pkg0->name != name || pkg0->repos == 0) - continue; - if (apk_version_compare_blob(*pkg0->version, *pkg->version) == APK_VERSION_GREATER) { - r = 1; - break; - } - } - - if (r == 0) goto ret; - - /* Create new commit upgrading apk-tools only with minimal other changes */ - db->performing_self_upgrade = 1; - apk_solver_set_name_flags(name, solver_flags, 0); - - r = apk_solver_solve(db, 0, db->world, &changeset); - if (r != 0) { - apk_warning("Failed to perform initial self-upgrade, continuing with full upgrade."); - r = 0; - goto ret; - } - - if (changeset.num_total_changes == 0) - goto ret; - - if (!self_upgrade_only && apk_flags & APK_SIMULATE) { - apk_warning("This simulation is not reliable as apk-tools upgrade is available."); - goto ret; - } - - apk_message("Upgrading critical system libraries and apk-tools:"); - apk_solver_commit_changeset(db, &changeset, db->world); - if (self_upgrade_only) goto ret; - - apk_db_close(db); - - apk_message("Continuing the upgrade transaction with new apk-tools:"); - for (r = 0; apk_argv[r] != NULL; r++) - ; - apk_argv[r] = "--no-self-upgrade"; - execvp(apk_argv[0], apk_argv); - - apk_error("PANIC! Failed to re-execute new apk-tools!"); - exit(1); - -ret: - apk_change_array_free(&changeset.changes); - db->performing_self_upgrade = 0; - return r; -} - -static int upgrade_main(void *ctx, struct apk_database *db, struct apk_string_array *args) -{ - struct upgrade_ctx *uctx = (struct upgrade_ctx *) ctx; - unsigned short solver_flags; - struct apk_dependency *dep; - struct apk_dependency_array *world = NULL; - int r = 0; - - if (apk_db_check_world(db, db->world) != 0) { - apk_error("Not continuing with upgrade due to missing repository tags. " - "Use --force-broken-world to override."); - return -1; - } - - solver_flags = APK_SOLVERF_UPGRADE | uctx->solver_flags; - if (!uctx->no_self_upgrade) { - r = apk_do_self_upgrade(db, solver_flags, uctx->self_upgrade_only); - if (r != 0) - return r; - } - if (uctx->self_upgrade_only) - return 0; - - if (uctx->ignore) { - char **pkg_name; - struct apk_name *name; - foreach_array_item(pkg_name, args) { - name = apk_db_get_name(db, APK_BLOB_STR(*pkg_name)); - apk_solver_set_name_flags(name, solver_flags | APK_SOLVERF_IGNORE_UPGRADE, 0); - } - } - - if (solver_flags & APK_SOLVERF_AVAILABLE) { - apk_dependency_array_copy(&world, db->world); - foreach_array_item(dep, world) { - if (dep->result_mask == APK_DEPMASK_CHECKSUM) { - dep->result_mask = APK_DEPMASK_ANY; - dep->version = apk_blob_atomize(APK_BLOB_NULL); - } - } - } else { - world = db->world; - } - - r = apk_solver_commit(db, solver_flags, world); - - if (solver_flags & APK_SOLVERF_AVAILABLE) - apk_dependency_array_free(&world); - - return r; -} - -static struct apk_applet apk_upgrade = { - .name = "upgrade", - .open_flags = APK_OPENF_WRITE, - .command_groups = APK_COMMAND_GROUP_SYSTEM, - .context_size = sizeof(struct upgrade_ctx), - .optgroups = { &optgroup_global, &optgroup_commit, &optgroup_applet }, - .main = upgrade_main, -}; - -APK_DEFINE_APPLET(apk_upgrade); - diff --git a/src/ver.c b/src/ver.c deleted file mode 100644 index e3508a2..0000000 --- a/src/ver.c +++ /dev/null @@ -1,207 +0,0 @@ -/* ver.c - Alpine Package Keeper (APK) - * - * Copyright (C) 2005-2008 Natanael Copa - * Copyright (C) 2008-2011 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 "apk_defines.h" -#include "apk_applet.h" -#include "apk_database.h" -#include "apk_version.h" -#include "apk_print.h" - -struct ver_ctx { - int (*action)(struct apk_database *db, struct apk_string_array *args); - const char *limchars; - int all_tags : 1; -}; - -static int ver_indexes(struct apk_database *db, struct apk_string_array *args) -{ - struct apk_repository *repo; - int i; - - for (i = 0; i < db->num_repos; i++) { - repo = &db->repos[i]; - - if (APK_BLOB_IS_NULL(repo->description)) - continue; - - printf(BLOB_FMT " [%s]\n", - BLOB_PRINTF(repo->description), - db->repos[i].url); - } - - return 0; -} - -static int ver_test(struct apk_database *db, struct apk_string_array *args) -{ - int r; - - if (args->num != 2) - return 1; - - r = apk_version_compare(args->item[0], args->item[1]); - printf("%s\n", apk_version_op_string(r)); - return 0; -} - -static int ver_validate(struct apk_database *db, struct apk_string_array *args) -{ - char **parg; - int errors = 0; - - foreach_array_item(parg, args) { - if (!apk_version_validate(APK_BLOB_STR(*parg))) { - if (apk_verbosity > 0) - printf("%s\n", *parg); - errors++; - } - } - return errors; -} - -static int option_parse_applet(void *ctx, struct apk_db_options *dbopts, int optch, const char *optarg) -{ - struct ver_ctx *ictx = (struct ver_ctx *) ctx; - switch (optch) { - case 'I': - ictx->action = ver_indexes; - break; - case 't': - ictx->action = ver_test; - dbopts->open_flags |= APK_OPENF_NO_STATE | APK_OPENF_NO_REPOS; - break; - case 'c': - ictx->action = ver_validate; - dbopts->open_flags |= APK_OPENF_NO_STATE | APK_OPENF_NO_REPOS; - break; - case 'l': - ictx->limchars = optarg; - break; - case 'a': - ictx->all_tags = 1; - break; - default: - return -ENOTSUP; - } - return 0; -} - -static const struct apk_option options_applet[] = { - { 'I', "indexes" }, - { 't', "test" }, - { 'c', "check" }, - { 'a', "all" }, - { 'l', "limit", required_argument, "LIMCHARs" }, -}; - -static const struct apk_option_group optgroup_applet = { - .name = "Version", - .options = options_applet, - .num_options = ARRAY_SIZE(options_applet), - .parse = option_parse_applet, -}; - -static void ver_print_package_status(struct apk_database *db, const char *match, struct apk_name *name, void *pctx) -{ - struct ver_ctx *ctx = (struct ver_ctx *) pctx; - struct apk_package *pkg; - struct apk_provider *p0; - char pkgname[41]; - const char *opstr; - apk_blob_t *latest = apk_blob_atomize(APK_BLOB_STR("")); - unsigned int latest_repos = 0; - int i, r = -1; - unsigned short tag, allowed_repos; - - if (!name) return; - - pkg = apk_pkg_get_installed(name); - if (!pkg) return; - - tag = pkg->ipkg->repository_tag; - allowed_repos = db->repo_tags[tag].allowed_repos; - - foreach_array_item(p0, name->providers) { - struct apk_package *pkg0 = p0->pkg; - if (pkg0->name != name || pkg0->repos == 0) - continue; - if (!(ctx->all_tags || (pkg0->repos & allowed_repos))) - continue; - r = apk_version_compare_blob(*pkg0->version, *latest); - switch (r) { - case APK_VERSION_GREATER: - latest = pkg0->version; - latest_repos = pkg0->repos; - break; - case APK_VERSION_EQUAL: - latest_repos |= pkg0->repos; - break; - } - } - r = latest->len ? apk_version_compare_blob(*pkg->version, *latest) - : APK_VERSION_UNKNOWN; - opstr = apk_version_op_string(r); - if ((ctx->limchars != NULL) && (strchr(ctx->limchars, *opstr) == NULL)) - return; - if (apk_verbosity <= 0) { - printf("%s\n", pkg->name->name); - return; - } - - tag = APK_DEFAULT_REPOSITORY_TAG; - for (i = 1; i < db->num_repo_tags; i++) { - if (latest_repos & db->repo_tags[i].allowed_repos) { - tag = i; - break; - } - } - - snprintf(pkgname, sizeof(pkgname), PKG_VER_FMT, PKG_VER_PRINTF(pkg)); - printf("%-40s%s " BLOB_FMT " " BLOB_FMT "\n", - pkgname, opstr, - BLOB_PRINTF(*latest), - BLOB_PRINTF(db->repo_tags[tag].tag)); -} - -static int ver_main(void *pctx, struct apk_database *db, struct apk_string_array *args) -{ - struct ver_ctx *ctx = (struct ver_ctx *) pctx; - - if (ctx->limchars) { - if (strlen(ctx->limchars) == 0) - ctx->limchars = NULL; - } else if (args->num == 0 && apk_verbosity == 1) { - ctx->limchars = "<"; - } - - if (ctx->action != NULL) - return ctx->action(db, args); - - if (apk_verbosity > 0) - printf("%-42sAvailable:\n", "Installed:"); - - apk_name_foreach_matching( - db, args, APK_FOREACH_NULL_MATCHES_ALL | apk_foreach_genid(), - ver_print_package_status, ctx); - - return 0; -} - -static struct apk_applet apk_ver = { - .name = "version", - .open_flags = APK_OPENF_READ, - .context_size = sizeof(struct ver_ctx), - .optgroups = { &optgroup_global, &optgroup_applet }, - .main = ver_main, -}; - -APK_DEFINE_APPLET(apk_ver); diff --git a/src/verify.c b/src/verify.c deleted file mode 100644 index 098e23c..0000000 --- a/src/verify.c +++ /dev/null @@ -1,59 +0,0 @@ -/* verify.c - Alpine Package Keeper (APK) - * - * Copyright (C) 2008-2011 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 -#include - -#include "apk_applet.h" -#include "apk_database.h" -#include "apk_print.h" - -static int verify_main(void *ctx, struct apk_database *db, struct apk_string_array *args) -{ - struct apk_sign_ctx sctx; - char **parg; - int r, ok, rc = 0; - - foreach_array_item(parg, args) { - apk_sign_ctx_init(&sctx, APK_SIGN_VERIFY, NULL, db->keys_fd); - r = apk_tar_parse( - apk_istream_gunzip_mpart(apk_istream_from_file(AT_FDCWD, *parg), - apk_sign_ctx_mpart_cb, &sctx), - apk_sign_ctx_verify_tar, &sctx, &db->id_cache); - ok = sctx.control_verified && sctx.data_verified; - if (apk_verbosity >= 1) - apk_message("%s: %d - %s", *parg, r, - r < 0 ? apk_error_str(r) : - ok ? "OK" : - !sctx.control_verified ? "UNTRUSTED" : "FAILED"); - else if (!ok) - printf("%s\n", *parg); - if (!ok) - rc++; - - apk_sign_ctx_free(&sctx); - } - - return rc; -} - -static struct apk_applet apk_verify = { - .name = "verify", - .arguments = "FILE...", - .open_flags = APK_OPENF_READ | APK_OPENF_NO_STATE, - .command_groups = APK_COMMAND_GROUP_REPO, - .forced_flags = APK_ALLOW_UNTRUSTED, - .main = verify_main, -}; - -APK_DEFINE_APPLET(apk_verify); - -- cgit v1.2.3