apk-tools/src/app_add.c

214 lines
5.5 KiB
C
Raw Normal View History

2020-02-14 11:49:41 +00:00
/* app_add.c - Alpine Package Keeper (APK)
*
* Copyright (C) 2005-2008 Natanael Copa <n@tanael.org>
2011-09-13 08:53:01 +00:00
* Copyright (C) 2008-2011 Timo Teräs <timo.teras@iki.fi>
* 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.
*/
2009-01-13 18:58:08 +00:00
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include "apk_applet.h"
#include "apk_database.h"
2010-03-05 08:13:25 +00:00
#include "apk_print.h"
#include "apk_solver.h"
2009-01-13 18:58:08 +00:00
struct add_ctx {
const char *virtpkg;
unsigned short solver_flags;
unsigned short extract_flags;
2009-01-13 18:58:08 +00:00
};
static int option_parse_applet(void *ctx, struct apk_db_options *dbopts, int optch, const char *optarg)
2009-01-13 18:58:08 +00:00
{
struct add_ctx *actx = (struct add_ctx *) ctx;
switch (optch) {
case 0x10000:
dbopts->open_flags |= APK_OPENF_CREATE;
2009-01-13 18:58:08 +00:00
break;
case 0x10001:
actx->extract_flags |= APK_EXTRACTF_NO_CHOWN;
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;
2009-01-13 18:58:08 +00:00
default:
return -ENOTSUP;
2009-01-13 18:58:08 +00:00
}
return 0;
}
static const struct apk_option options_applet[] = {
{ 0x10000, "initdb" },
{ 0x10001, "no-chown" },
{ 'u', "upgrade" },
{ 'l', "latest" },
add script to autogenerate help from man pages This creates main help like: -- usage: apk [<OPTIONS>...] COMMAND [<ARGUMENTS>...] Package installation and removal: add Add packages to WORLD and commit changes del Remove packages from WORLD and commit changes System maintenance: fix Check WORLD against the system and ensure consistency update Update repository indexes upgrade Install upgrades available from repositories cache Commands related to the management of an offline package cache Querying package information: info Give detailed information about packages or repositories list List packages matching a pattern or other criteria dot Generate graphviz graphs policy Show repository policy for packages Repository maintenance: index Create repository index file from packages fetch Download packages from global repositories to a local directory manifest Show checksums of package contents verify Verify package integrity and signature Miscellaneous: audit Audit directories for changes stats Show statistics about repositories and installations version Compare package versions or perform tests on version strings This apk has coffee making abilities. -- And applet specific help like: -- usage: apk add [<OPTIONS>...] PACKAGES... Description: apk add adds the requested packages to WORLD and installs (or upgrades) them if not already present, ensuring all dependencies are met. Options: --initdb Initialize a new package database -l, --latest Disables normal heuristics for choosing which repository to install a -u, --upgrade When adding packages which are already installed, upgrade them rather -t, --virtual NAME Instead of adding the specified packages to WORLD, create a new --no-chown Do not change file owner or group --
2020-04-24 08:49:14 +00:00
{ 't', "virtual", required_argument },
};
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)
{
2009-01-13 18:58:08 +00:00
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 (getuid() != 0 || (actx->extract_flags & APK_EXTRACTF_NO_CHOWN))
db->extract_flags |= APK_EXTRACTF_NO_CHOWN;
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",
.open_flags = APK_OPENF_WRITE,
2009-01-13 18:58:08 +00:00
.context_size = sizeof(struct add_ctx),
.optgroups = { &optgroup_global, &optgroup_commit, &optgroup_applet },
.main = add_main,
};
APK_DEFINE_APPLET(apk_add);