From 60b87557e57ca4e23126bf8c25b1cb978e380dfd Mon Sep 17 00:00:00 2001 From: Timo Teräs Date: Fri, 14 Feb 2020 13:49:41 +0200 Subject: rename all applets sources to app_*.c --- src/app_info.c | 488 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 488 insertions(+) create mode 100644 src/app_info.c (limited to 'src/app_info.c') 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); + -- cgit v1.2.3-60-g2f50