2009-04-15 06:56:09 +00:00
|
|
|
/* fetch.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.
|
|
|
|
*
|
|
|
|
* 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 <stdio.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <unistd.h>
|
2009-06-09 09:06:22 +00:00
|
|
|
#include <errno.h>
|
2009-04-15 06:56:09 +00:00
|
|
|
|
|
|
|
#include "apk_applet.h"
|
|
|
|
#include "apk_database.h"
|
|
|
|
#include "apk_state.h"
|
|
|
|
#include "apk_io.h"
|
|
|
|
|
|
|
|
#define FETCH_RECURSIVE 1
|
|
|
|
#define FETCH_STDOUT 2
|
2009-06-09 09:06:22 +00:00
|
|
|
#define FETCH_LINK 4
|
2009-04-15 06:56:09 +00:00
|
|
|
|
|
|
|
struct fetch_ctx {
|
|
|
|
unsigned int flags;
|
|
|
|
const char *outdir;
|
|
|
|
};
|
|
|
|
|
|
|
|
static int fetch_parse(void *ctx, int optch, int optindex, 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;
|
2009-06-09 09:06:22 +00:00
|
|
|
case 'L':
|
|
|
|
fctx->flags |= FETCH_LINK;
|
|
|
|
break;
|
2009-04-15 06:56:09 +00:00
|
|
|
case 'o':
|
|
|
|
fctx->outdir = optarg;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int fetch_package(struct fetch_ctx *fctx,
|
|
|
|
struct apk_database *db,
|
|
|
|
struct apk_package *pkg)
|
|
|
|
{
|
|
|
|
struct apk_istream *is;
|
2009-06-09 09:06:22 +00:00
|
|
|
char infile[256];
|
|
|
|
char outfile[256];
|
2009-04-15 06:56:09 +00:00
|
|
|
int i, r, fd;
|
|
|
|
|
2009-06-09 09:06:22 +00:00
|
|
|
if (!(fctx->flags & FETCH_STDOUT)) {
|
2009-04-15 06:56:09 +00:00
|
|
|
struct apk_file_info fi;
|
|
|
|
|
2009-06-09 09:06:22 +00:00
|
|
|
snprintf(outfile, sizeof(outfile), "%s/%s-%s.apk",
|
2009-04-15 06:56:09 +00:00
|
|
|
fctx->outdir ? fctx->outdir : ".",
|
|
|
|
pkg->name->name, pkg->version);
|
|
|
|
|
2009-06-09 09:06:22 +00:00
|
|
|
if (apk_file_get_info(outfile, &fi) == 0 &&
|
2009-04-15 06:56:09 +00:00
|
|
|
fi.size == pkg->size)
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
apk_message("Downloading %s-%s", pkg->name->name, pkg->version);
|
|
|
|
|
|
|
|
for (i = 0; i < APK_MAX_REPOS; i++)
|
|
|
|
if (pkg->repos & BIT(i))
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (i >= APK_MAX_REPOS) {
|
|
|
|
apk_error("%s-%s: not present in any repository",
|
|
|
|
pkg->name->name, pkg->version);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2009-06-09 09:06:22 +00:00
|
|
|
snprintf(infile, sizeof(infile), "%s/%s-%s.apk",
|
2009-04-15 06:56:09 +00:00
|
|
|
db->repos[i].url, pkg->name->name, pkg->version);
|
2009-06-09 09:06:22 +00:00
|
|
|
|
|
|
|
if (fctx->flags & FETCH_STDOUT) {
|
|
|
|
fd = STDOUT_FILENO;
|
|
|
|
} else {
|
|
|
|
if ((fctx->flags & FETCH_LINK) && apk_url_local_file(infile)) {
|
|
|
|
if (link(infile, outfile) == 0)
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
fd = creat(outfile, 0644);
|
|
|
|
if (fd < 0) {
|
|
|
|
apk_error("%s: %s", outfile, strerror(errno));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
is = apk_istream_from_url(infile);
|
2009-04-15 06:56:09 +00:00
|
|
|
if (is == NULL) {
|
2009-06-09 09:06:22 +00:00
|
|
|
apk_error("Unable to download '%s'", infile);
|
2009-04-15 06:56:09 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = apk_istream_splice(is, fd, pkg->size, NULL, NULL);
|
2009-05-26 14:12:02 +00:00
|
|
|
is->close(is);
|
2009-04-15 09:58:47 +00:00
|
|
|
if (fd != STDOUT_FILENO)
|
|
|
|
close(fd);
|
2009-04-15 06:56:09 +00:00
|
|
|
if (r != pkg->size) {
|
2009-06-09 09:06:22 +00:00
|
|
|
apk_error("Unable to download '%s'", infile);
|
|
|
|
unlink(outfile);
|
2009-04-15 06:56:09 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int fetch_main(void *ctx, int argc, char **argv)
|
|
|
|
{
|
|
|
|
struct fetch_ctx *fctx = (struct fetch_ctx *) ctx;
|
|
|
|
struct apk_database db;
|
|
|
|
int i, j, r;
|
|
|
|
|
|
|
|
r = apk_db_open(&db, apk_root, APK_OPENF_EMPTY_STATE);
|
|
|
|
if (r != 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
for (i = 0; i < argc; i++) {
|
|
|
|
struct apk_dependency dep = (struct apk_dependency) {
|
|
|
|
.name = apk_db_get_name(&db, APK_BLOB_STR(argv[i])),
|
|
|
|
.result_mask = APK_DEPMASK_REQUIRE,
|
|
|
|
};
|
|
|
|
|
|
|
|
if (fctx->flags & FETCH_RECURSIVE) {
|
|
|
|
struct apk_state *state;
|
|
|
|
struct apk_change *change;
|
|
|
|
|
|
|
|
state = apk_state_new(&db);
|
|
|
|
r = apk_state_lock_dependency(state, &dep);
|
|
|
|
if (r != 0) {
|
|
|
|
apk_state_unref(state);
|
|
|
|
apk_error("Unable to install '%s'",
|
|
|
|
dep.name->name);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
list_for_each_entry(change, &state->change_list_head, change_list) {
|
|
|
|
r = fetch_package(fctx, &db, change->newpkg);
|
|
|
|
if (r != 0)
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
apk_state_unref(state);
|
|
|
|
} else if (dep.name->pkgs != NULL) {
|
|
|
|
struct apk_package *pkg = NULL;
|
|
|
|
|
|
|
|
for (j = 0; j < dep.name->pkgs->num; j++)
|
|
|
|
if (pkg == NULL ||
|
|
|
|
apk_version_compare(APK_BLOB_STR(dep.name->pkgs->item[j]->version),
|
|
|
|
APK_BLOB_STR(pkg->version))
|
|
|
|
== APK_VERSION_GREATER)
|
|
|
|
pkg = dep.name->pkgs->item[j];
|
|
|
|
|
|
|
|
r = fetch_package(fctx, &db, pkg);
|
|
|
|
if (r != 0)
|
|
|
|
goto err;
|
|
|
|
} else {
|
|
|
|
apk_message("Unable to get '%s'", dep.name->name);
|
|
|
|
r = -1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
err:
|
|
|
|
apk_db_close(&db);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct option fetch_options[] = {
|
|
|
|
{ "recursive", no_argument, NULL, 'R' },
|
|
|
|
{ "stdout", no_argument, NULL, 's' },
|
2009-06-09 09:06:22 +00:00
|
|
|
{ "link", no_argument, NULL, 'L' },
|
2009-04-15 06:56:09 +00:00
|
|
|
{ "output", required_argument, NULL, 'o' },
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct apk_applet apk_fetch = {
|
|
|
|
.name = "fetch",
|
2009-06-09 09:06:22 +00:00
|
|
|
.usage = "[-R|--recursive|--stdout] [--link|-L] [-o dir] apkname...",
|
2009-04-15 06:56:09 +00:00
|
|
|
.context_size = sizeof(struct fetch_ctx),
|
|
|
|
.num_options = ARRAY_SIZE(fetch_options),
|
|
|
|
.options = fetch_options,
|
|
|
|
.parse = fetch_parse,
|
|
|
|
.main = fetch_main,
|
|
|
|
};
|
|
|
|
|
|
|
|
APK_DEFINE_APPLET(apk_fetch);
|
|
|
|
|