2008-04-17 14:09:13 +00:00
|
|
|
/* apk.c - Alpine Package Keeper (APK)
|
|
|
|
*
|
|
|
|
* Copyright (C) 2005-2008 Natanael Copa <n@tanael.org>
|
|
|
|
* Copyright (C) 2008 Timo Teräs <timo.teras@iki.fi>
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
2009-06-25 12:14:07 +00:00
|
|
|
* This program is free software; you can redistribute it and/or modify it
|
2008-04-17 14:09:13 +00:00
|
|
|
* 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 <stdio.h>
|
2008-04-22 08:16:26 +00:00
|
|
|
#include <fcntl.h>
|
2009-01-13 12:09:45 +00:00
|
|
|
#include <ctype.h>
|
2008-04-17 14:09:13 +00:00
|
|
|
#include <stdarg.h>
|
2008-04-21 16:30:10 +00:00
|
|
|
#include <stdlib.h>
|
2008-04-17 14:09:13 +00:00
|
|
|
#include <string.h>
|
2008-04-21 16:30:10 +00:00
|
|
|
#include <getopt.h>
|
|
|
|
#include <sys/stat.h>
|
2008-04-17 14:09:13 +00:00
|
|
|
|
2009-07-08 13:19:06 +00:00
|
|
|
#include <openssl/engine.h>
|
|
|
|
|
2008-04-17 14:09:13 +00:00
|
|
|
#include "apk_defines.h"
|
|
|
|
#include "apk_applet.h"
|
2009-06-25 12:14:07 +00:00
|
|
|
#include "apk_blob.h"
|
2008-04-17 14:09:13 +00:00
|
|
|
|
2009-01-12 21:03:20 +00:00
|
|
|
const char *apk_root;
|
2009-02-17 12:23:01 +00:00
|
|
|
struct apk_repository_url apk_repository_list;
|
2009-07-07 07:30:54 +00:00
|
|
|
int apk_verbosity = 1, apk_cwd_fd, apk_wait;
|
2009-04-14 15:48:02 +00:00
|
|
|
unsigned int apk_flags = 0;
|
2008-04-21 16:30:10 +00:00
|
|
|
|
2009-06-25 12:14:07 +00:00
|
|
|
static struct apk_option generic_options[] = {
|
|
|
|
{ 'h', "help", "Show generic help or applet specific help" },
|
|
|
|
{ 'p', "root", "Install packages to DIR",
|
2009-07-07 07:30:54 +00:00
|
|
|
required_argument, "DIR" },
|
2009-06-25 12:14:07 +00:00
|
|
|
{ 'X', "repository", "Use packages from REPO",
|
2009-07-07 07:30:54 +00:00
|
|
|
required_argument, "REPO" },
|
2009-06-25 12:14:07 +00:00
|
|
|
{ 'q', "quiet", "Print less information" },
|
|
|
|
{ 'v', "verbose", "Print more information" },
|
|
|
|
{ 'V', "version", "Print program version and exit" },
|
|
|
|
{ 'f', "force", "Do what was asked even if it looks dangerous" },
|
2009-07-07 09:12:24 +00:00
|
|
|
{ 'U', "update-cache", "Update the repository cache" },
|
2009-06-25 12:14:07 +00:00
|
|
|
{ 0x101, "progress", "Show a progress bar" },
|
2009-07-07 07:30:54 +00:00
|
|
|
{ 0x102, "clean-protected", "Do not create .apk-new files to "
|
|
|
|
"configuration dirs" },
|
|
|
|
{ 0x104, "simulate", "Show what would be done without actually "
|
|
|
|
"doing it" },
|
|
|
|
{ 0x105, "wait", "Wait for TIME seconds to get an exclusive "
|
|
|
|
"repository lock before failing",
|
|
|
|
required_argument, "TIME" },
|
2009-06-25 12:14:07 +00:00
|
|
|
};
|
|
|
|
|
2008-04-17 14:09:13 +00:00
|
|
|
void apk_log(const char *prefix, const char *format, ...)
|
|
|
|
{
|
|
|
|
va_list va;
|
|
|
|
|
|
|
|
if (prefix != NULL)
|
2009-01-06 17:44:33 +00:00
|
|
|
fprintf(stderr, "%s", prefix);
|
2008-04-17 14:09:13 +00:00
|
|
|
va_start(va, format);
|
|
|
|
vfprintf(stderr, format, va);
|
|
|
|
va_end(va);
|
|
|
|
fprintf(stderr, "\n");
|
|
|
|
}
|
|
|
|
|
2009-06-25 12:14:07 +00:00
|
|
|
static int version(void)
|
2009-01-17 08:51:52 +00:00
|
|
|
{
|
|
|
|
printf("apk-tools " APK_VERSION "\n");
|
|
|
|
return 0;
|
|
|
|
}
|
2008-04-17 14:09:13 +00:00
|
|
|
|
2009-06-25 12:14:07 +00:00
|
|
|
struct apk_indent {
|
|
|
|
int x;
|
|
|
|
int indent;
|
|
|
|
};
|
|
|
|
|
|
|
|
static int print_indented(struct apk_indent *i, apk_blob_t blob)
|
2009-06-19 13:40:37 +00:00
|
|
|
{
|
2009-06-25 12:14:07 +00:00
|
|
|
static const int wrap_length = 80;
|
2008-04-17 14:09:13 +00:00
|
|
|
|
2009-06-25 12:14:07 +00:00
|
|
|
if (i->x + blob.len + 1 >= wrap_length) {
|
|
|
|
i->x = i->indent;
|
|
|
|
printf("\n%*s", i->indent - 1, "");
|
2008-04-17 14:09:13 +00:00
|
|
|
}
|
2009-06-25 12:14:07 +00:00
|
|
|
i->x += printf(" %.*s", blob.len, blob.ptr);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void print_indented_words(struct apk_indent *i, const char *text)
|
|
|
|
{
|
|
|
|
apk_blob_for_each_segment(APK_BLOB_STR(text), " ",
|
|
|
|
(apk_blob_cb) print_indented, i);
|
2009-06-19 13:40:37 +00:00
|
|
|
}
|
2008-04-17 14:09:13 +00:00
|
|
|
|
2009-06-25 12:14:07 +00:00
|
|
|
static int format_option(char *buf, size_t len, struct apk_option *o,
|
|
|
|
const char *separator)
|
2009-06-19 13:40:37 +00:00
|
|
|
{
|
2009-06-25 12:14:07 +00:00
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
if (o->val <= 0xff && isalnum(o->val)) {
|
|
|
|
i += snprintf(&buf[i], len - i, "-%c", o->val);
|
|
|
|
if (o->name != NULL)
|
|
|
|
i += snprintf(&buf[i], len - i, "%s", separator);
|
|
|
|
}
|
|
|
|
if (o->name != NULL)
|
|
|
|
i += snprintf(&buf[i], len - i, "--%s", o->name);
|
|
|
|
if (o->arg_name != NULL)
|
|
|
|
i += snprintf(&buf[i], len - i, " %s", o->arg_name);
|
|
|
|
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void print_usage(const char *cmd, const char *args, int num_opts,
|
|
|
|
struct apk_option *opts)
|
|
|
|
{
|
|
|
|
struct apk_indent indent = { 0, 11 };
|
|
|
|
char word[128];
|
|
|
|
int i, j;
|
|
|
|
|
|
|
|
indent.x = printf("\nusage: apk %s", cmd) - 1;
|
|
|
|
for (i = 0; i < num_opts; i++) {
|
|
|
|
j = 0;
|
|
|
|
word[j++] = '[';
|
|
|
|
j += format_option(&word[j], sizeof(word) - j, &opts[i], "|");
|
|
|
|
word[j++] = ']';
|
|
|
|
print_indented(&indent, APK_BLOB_PTR_LEN(word, j));
|
|
|
|
}
|
|
|
|
if (args != NULL)
|
|
|
|
print_indented(&indent, APK_BLOB_STR(args));
|
|
|
|
printf("\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void print_options(int num_opts, struct apk_option *opts)
|
|
|
|
{
|
|
|
|
struct apk_indent indent = { 0, 26 };
|
|
|
|
char word[128];
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < num_opts; i++) {
|
|
|
|
format_option(word, sizeof(word), &opts[i], ", ");
|
|
|
|
indent.x = printf(" %-*s", indent.indent - 3, word);
|
|
|
|
print_indented_words(&indent, opts[i].help);
|
|
|
|
printf("\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int usage(struct apk_applet *applet)
|
|
|
|
{
|
|
|
|
struct apk_indent indent = { 0, 2 };
|
|
|
|
|
2009-06-19 13:40:37 +00:00
|
|
|
version();
|
2009-06-25 12:14:07 +00:00
|
|
|
if (applet == NULL) {
|
|
|
|
struct apk_applet **a;
|
|
|
|
|
|
|
|
print_usage("COMMAND", "[ARGS]...",
|
|
|
|
ARRAY_SIZE(generic_options), generic_options);
|
|
|
|
|
|
|
|
printf("\navailable commands:\n ");
|
|
|
|
for (a = &__start_apkapplets; a < &__stop_apkapplets; a++)
|
|
|
|
printf("%s ", (*a)->name);
|
|
|
|
} else {
|
|
|
|
print_usage(applet->name, applet->arguments,
|
|
|
|
applet->num_options, applet->options);
|
|
|
|
printf("\ndescription:\n%*s", indent.indent - 1, "");
|
|
|
|
print_indented_words(&indent, applet->help);
|
|
|
|
}
|
|
|
|
printf("\n\ngeneric options:\n");
|
|
|
|
print_options(ARRAY_SIZE(generic_options), generic_options);
|
|
|
|
|
|
|
|
if (applet != NULL && applet->num_options > 0) {
|
|
|
|
printf("\noptions for %s command:\n", applet->name);
|
|
|
|
print_options(applet->num_options, applet->options);
|
|
|
|
}
|
|
|
|
printf("\nThis apk has coffee making abilities.\n\n");
|
|
|
|
|
2008-04-17 14:09:13 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2008-04-21 16:30:10 +00:00
|
|
|
static struct apk_applet *find_applet(const char *name)
|
|
|
|
{
|
|
|
|
struct apk_applet **a;
|
|
|
|
|
|
|
|
for (a = &__start_apkapplets; a < &__stop_apkapplets; a++) {
|
|
|
|
if (strcmp(name, (*a)->name) == 0)
|
|
|
|
return *a;
|
|
|
|
}
|
2009-06-25 12:14:07 +00:00
|
|
|
|
2008-04-21 16:30:10 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2009-01-13 12:09:45 +00:00
|
|
|
static struct apk_applet *deduce_applet(int argc, char **argv)
|
2008-04-17 14:09:13 +00:00
|
|
|
{
|
2009-01-13 12:09:45 +00:00
|
|
|
struct apk_applet *a;
|
2008-04-21 16:30:10 +00:00
|
|
|
const char *prog;
|
2009-01-13 12:09:45 +00:00
|
|
|
int i;
|
2008-04-17 14:09:13 +00:00
|
|
|
|
|
|
|
prog = strrchr(argv[0], '/');
|
|
|
|
if (prog == NULL)
|
|
|
|
prog = argv[0];
|
|
|
|
else
|
|
|
|
prog++;
|
|
|
|
|
2008-04-21 16:30:10 +00:00
|
|
|
if (strncmp(prog, "apk_", 4) == 0)
|
2009-01-13 12:09:45 +00:00
|
|
|
return find_applet(prog + 4);
|
|
|
|
|
|
|
|
for (i = 1; i < argc; i++) {
|
|
|
|
if (argv[i][0] == '-')
|
|
|
|
continue;
|
|
|
|
|
|
|
|
a = find_applet(argv[i]);
|
|
|
|
if (a != NULL)
|
|
|
|
return a;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2009-02-17 12:23:01 +00:00
|
|
|
static struct apk_repository_url *apk_repository_new(const char *url)
|
|
|
|
{
|
2009-06-25 12:14:07 +00:00
|
|
|
struct apk_repository_url *r = calloc(1,
|
2009-02-17 12:23:01 +00:00
|
|
|
sizeof(struct apk_repository_url));
|
|
|
|
if (r) {
|
|
|
|
r->url = url;
|
|
|
|
list_init(&r->list);
|
|
|
|
}
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2009-06-25 12:14:07 +00:00
|
|
|
static void merge_options(struct option *opts, struct apk_option *ao, int num)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < num; i++, opts++, ao++) {
|
|
|
|
opts->name = ao->name;
|
|
|
|
opts->has_arg = ao->has_arg;
|
|
|
|
opts->flag = NULL;
|
|
|
|
opts->val = ao->val;
|
|
|
|
}
|
|
|
|
opts->name = NULL;
|
|
|
|
}
|
2009-01-13 12:09:45 +00:00
|
|
|
|
2009-07-08 13:19:06 +00:00
|
|
|
static void fini_openssl(void)
|
|
|
|
{
|
|
|
|
EVP_cleanup();
|
|
|
|
#ifndef OPENSSL_NO_ENGINE
|
|
|
|
ENGINE_cleanup();
|
|
|
|
#endif
|
|
|
|
CRYPTO_cleanup_all_ex_data();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void init_openssl(void)
|
|
|
|
{
|
|
|
|
atexit(fini_openssl);
|
|
|
|
OpenSSL_add_all_algorithms();
|
|
|
|
#ifndef OPENSSL_NO_ENGINE
|
|
|
|
ENGINE_load_builtin_engines();
|
2009-07-13 11:28:52 +00:00
|
|
|
ENGINE_register_all_complete();
|
2009-07-08 13:19:06 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2009-01-13 12:09:45 +00:00
|
|
|
int main(int argc, char **argv)
|
|
|
|
{
|
|
|
|
struct apk_applet *applet;
|
|
|
|
char short_options[256], *sopt;
|
2009-06-25 12:14:07 +00:00
|
|
|
struct option *opt, *all_options;
|
|
|
|
int r, optindex, num_options;
|
2009-01-13 12:09:45 +00:00
|
|
|
void *ctx = NULL;
|
2009-02-17 12:23:01 +00:00
|
|
|
struct apk_repository_url *repo = NULL;
|
2008-04-17 14:09:13 +00:00
|
|
|
|
2009-01-13 12:09:45 +00:00
|
|
|
umask(0);
|
|
|
|
apk_cwd_fd = open(".", O_RDONLY);
|
|
|
|
apk_root = getenv("ROOT");
|
2009-02-17 12:23:01 +00:00
|
|
|
list_init(&apk_repository_list.list);
|
2009-01-13 12:09:45 +00:00
|
|
|
|
|
|
|
applet = deduce_applet(argc, argv);
|
2009-06-25 12:14:07 +00:00
|
|
|
num_options = ARRAY_SIZE(generic_options) + 1;
|
|
|
|
if (applet != NULL)
|
|
|
|
num_options += applet->num_options;
|
|
|
|
all_options = alloca(sizeof(struct option) * num_options);
|
|
|
|
merge_options(&all_options[0], generic_options,
|
|
|
|
ARRAY_SIZE(generic_options));
|
2009-01-17 08:51:52 +00:00
|
|
|
if (applet != NULL) {
|
2009-06-25 12:14:07 +00:00
|
|
|
merge_options(&all_options[ARRAY_SIZE(generic_options)],
|
|
|
|
applet->options, applet->num_options);
|
2009-01-17 08:51:52 +00:00
|
|
|
if (applet->context_size != 0)
|
|
|
|
ctx = calloc(1, applet->context_size);
|
2009-01-13 12:09:45 +00:00
|
|
|
}
|
2009-01-17 08:51:52 +00:00
|
|
|
|
2009-06-25 12:14:07 +00:00
|
|
|
for (opt = all_options, sopt = short_options; opt->name != NULL; opt++) {
|
2009-01-15 09:10:14 +00:00
|
|
|
if (opt->flag == NULL &&
|
|
|
|
opt->val <= 0xff && isalnum(opt->val)) {
|
2009-01-13 12:09:45 +00:00
|
|
|
*(sopt++) = opt->val;
|
|
|
|
if (opt->has_arg != no_argument)
|
|
|
|
*(sopt++) = ':';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-07-08 13:19:06 +00:00
|
|
|
init_openssl();
|
|
|
|
|
2009-01-13 12:09:45 +00:00
|
|
|
optindex = 0;
|
|
|
|
while ((r = getopt_long(argc, argv, short_options,
|
2009-06-25 12:14:07 +00:00
|
|
|
all_options, &optindex)) != -1) {
|
2008-04-21 16:30:10 +00:00
|
|
|
switch (r) {
|
2009-03-04 06:27:06 +00:00
|
|
|
case 0:
|
|
|
|
break;
|
2009-06-19 13:40:37 +00:00
|
|
|
case 'h':
|
|
|
|
return usage(applet);
|
|
|
|
break;
|
2009-01-16 09:57:53 +00:00
|
|
|
case 'p':
|
2008-04-21 16:30:10 +00:00
|
|
|
apk_root = optarg;
|
|
|
|
break;
|
|
|
|
case 'X':
|
2009-02-17 12:23:01 +00:00
|
|
|
repo = apk_repository_new(optarg);
|
|
|
|
if (repo)
|
|
|
|
list_add(&repo->list, &apk_repository_list.list);
|
2008-04-21 16:30:10 +00:00
|
|
|
break;
|
2008-04-22 06:04:20 +00:00
|
|
|
case 'q':
|
2009-01-16 09:33:55 +00:00
|
|
|
apk_verbosity--;
|
|
|
|
break;
|
|
|
|
case 'v':
|
|
|
|
apk_verbosity++;
|
2008-04-22 06:04:20 +00:00
|
|
|
break;
|
2009-01-17 08:51:52 +00:00
|
|
|
case 'V':
|
|
|
|
return version();
|
2009-04-15 10:19:36 +00:00
|
|
|
case 'f':
|
|
|
|
apk_flags |= APK_FORCE;
|
|
|
|
break;
|
2009-07-07 09:12:24 +00:00
|
|
|
case 'U':
|
|
|
|
apk_flags |= APK_UPDATE_CACHE;
|
|
|
|
break;
|
2009-04-14 15:48:02 +00:00
|
|
|
case 0x101:
|
|
|
|
apk_flags |= APK_PROGRESS;
|
|
|
|
break;
|
|
|
|
case 0x102:
|
|
|
|
apk_flags |= APK_CLEAN_PROTECTED;
|
|
|
|
break;
|
|
|
|
case 0x104:
|
|
|
|
apk_flags |= APK_SIMULATE;
|
2009-01-17 08:51:52 +00:00
|
|
|
break;
|
2009-07-07 07:30:54 +00:00
|
|
|
case 0x105:
|
|
|
|
apk_wait = atoi(optarg);
|
|
|
|
break;
|
2008-04-21 16:30:10 +00:00
|
|
|
default:
|
2009-06-19 13:40:37 +00:00
|
|
|
if (applet == NULL || applet->parse == NULL ||
|
2009-06-25 12:14:07 +00:00
|
|
|
applet->parse(ctx, r,
|
|
|
|
optindex - ARRAY_SIZE(generic_options),
|
2009-01-13 12:09:45 +00:00
|
|
|
optarg) != 0)
|
2009-06-19 13:40:37 +00:00
|
|
|
return usage(applet);
|
2009-01-13 12:09:45 +00:00
|
|
|
break;
|
2008-04-17 14:09:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-01-17 08:51:52 +00:00
|
|
|
if (applet == NULL)
|
2009-06-19 13:40:37 +00:00
|
|
|
return usage(NULL);
|
2009-01-17 08:51:52 +00:00
|
|
|
|
2009-01-12 21:03:20 +00:00
|
|
|
if (apk_root == NULL)
|
|
|
|
apk_root = "/";
|
|
|
|
|
2009-01-13 12:09:45 +00:00
|
|
|
argc -= optind;
|
|
|
|
argv += optind;
|
|
|
|
if (argc >= 1 && strcmp(argv[0], applet->name) == 0) {
|
2008-04-21 16:30:10 +00:00
|
|
|
argc--;
|
|
|
|
argv++;
|
|
|
|
}
|
|
|
|
|
2009-06-29 08:22:55 +00:00
|
|
|
r = applet->main(ctx, argc, argv);
|
|
|
|
if (r == -100)
|
|
|
|
return usage(applet);
|
|
|
|
return r;
|
2008-04-17 14:09:13 +00:00
|
|
|
}
|