summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/Makefile4
-rw-r--r--src/apk_database.h3
-rw-r--r--src/apk_io.h2
-rw-r--r--src/database.c108
-rw-r--r--src/update.c41
-rw-r--r--src/url.c34
6 files changed, 177 insertions, 15 deletions
diff --git a/src/Makefile b/src/Makefile
index 993ca91..a25eb84 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -2,8 +2,8 @@ progs-y += apk
apk-objs := state.o database.o package.o archive.o \
version.o io.o url.o gunzip.o blob.o \
hash.o md5.o apk.o \
- add.o del.o ver.o index.o info.o search.o \
- fetch.o audit.o
+ add.o del.o update.o info.o search.o \
+ ver.o index.o fetch.o audit.o
CFLAGS_apk.o := -DAPK_VERSION=\"$(FULL_VERSION)\"
progs-$(STATIC) += apk.static
diff --git a/src/apk_database.h b/src/apk_database.h
index 6ca630b..db8a019 100644
--- a/src/apk_database.h
+++ b/src/apk_database.h
@@ -67,6 +67,7 @@ struct apk_name {
struct apk_repository {
char *url;
+ char *cache;
};
struct apk_database {
@@ -124,6 +125,8 @@ struct apk_package *apk_db_get_file_owner(struct apk_database *db, apk_blob_t fi
int apk_db_index_write(struct apk_database *db, struct apk_ostream *os);
int apk_db_add_repository(apk_database_t db, apk_blob_t repository);
+int apk_repository_update(struct apk_database *db, struct apk_repository *repo);
+
int apk_db_install_pkg(struct apk_database *db,
struct apk_package *oldpkg,
struct apk_package *newpkg,
diff --git a/src/apk_io.h b/src/apk_io.h
index a0d9049..e0d9629 100644
--- a/src/apk_io.h
+++ b/src/apk_io.h
@@ -69,5 +69,7 @@ apk_blob_t apk_blob_from_istream(struct apk_istream *istream, size_t size);
apk_blob_t apk_blob_from_file(const char *file);
int apk_file_get_info(const char *filename, struct apk_file_info *fi);
+int apk_url_download(const char *url, const char *file);
+const char *apk_url_local_file(const char *url);
#endif
diff --git a/src/database.c b/src/database.c
index 195f653..0957d2d 100644
--- a/src/database.c
+++ b/src/database.c
@@ -803,8 +803,11 @@ void apk_db_close(struct apk_database *db)
}
}
- for (i = 0; i < db->num_repos; i++)
+ for (i = 0; i < db->num_repos; i++) {
free(db->repos[i].url);
+ if (db->repos[i].cache != NULL)
+ free(db->repos[i].cache);
+ }
if (db->protected_paths) {
for (i = 0; i < db->protected_paths->num; i++)
free(db->protected_paths->item[i]);
@@ -896,13 +899,77 @@ int apk_db_index_write(struct apk_database *db, struct apk_ostream *os)
return ctx.count;
}
-int apk_db_add_repository(apk_database_t _db, apk_blob_t repository)
+static struct apk_bstream *apk_db_cache_open(struct apk_database *db,
+ const char *file)
{
- struct apk_database *db = _db.db;
- struct apk_istream *is;
char tmp[256];
+
+ if (db->root == NULL)
+ return NULL;
+
+ snprintf(tmp, sizeof(tmp), "%svar/lib/apk/%s", db->root, file);
+ return apk_bstream_from_file(tmp);
+}
+
+static int apk_db_cache_has(struct apk_database *db, const char *file)
+{
+ char tmp[256];
+ struct apk_file_info fi;
+ int r;
+
+ if (db->root == NULL)
+ return FALSE;
+
+ snprintf(tmp, sizeof(tmp), "%svar/lib/apk/%s", db->root, file);
+ r = apk_file_get_info(tmp, &fi);
+ if (r < 0)
+ return FALSE;
+
+ return TRUE;
+}
+
+static struct apk_bstream *apk_repository_file_open(struct apk_repository *repo,
+ const char *file)
+{
+ char tmp[256];
+
+ snprintf(tmp, sizeof(tmp), "%s/%s", repo->url, file);
+
+ return apk_bstream_from_url(tmp);
+}
+
+int apk_repository_update(struct apk_database *db, struct apk_repository *repo)
+{
+ char tmp[256], tmp2[256];
int r;
+ if (repo->cache == NULL)
+ return 0;
+
+ apk_message("fetch index %s", repo->url);
+
+ snprintf(tmp, sizeof(tmp), "%s/APK_INDEX.gz", repo->url);
+ snprintf(tmp2, sizeof(tmp2), "%svar/lib/apk/%s.new",
+ db->root, repo->cache);
+ r = apk_url_download(tmp, tmp2);
+ if (r < 0)
+ return r;
+
+ snprintf(tmp2, sizeof(tmp2), "%svar/lib/apk/%s",
+ db->root, repo->cache);
+ if (rename(tmp2, tmp) < 0)
+ return -errno;
+
+ return 0;
+}
+
+int apk_db_add_repository(apk_database_t _db, apk_blob_t repository)
+{
+ struct apk_database *db = _db.db;
+ struct apk_istream *is = NULL;
+ char buf[2*sizeof(csum_t)+32], *name;
+ int r, n;
+
if (repository.ptr == NULL || *repository.ptr == '\0'
|| *repository.ptr == '#')
return 0;
@@ -911,14 +978,37 @@ int apk_db_add_repository(apk_database_t _db, apk_blob_t repository)
return -1;
r = db->num_repos++;
- db->repos[r] = (struct apk_repository){
- .url = apk_blob_cstr(repository)
+ db->repos[r] = (struct apk_repository) {
+ .url = apk_blob_cstr(repository),
+ .cache = NULL,
};
- snprintf(tmp, sizeof(tmp), "%s/APK_INDEX.gz", db->repos[r].url);
- is = apk_istream_from_url_gz(tmp);
+ if (apk_url_local_file(db->repos[r].url) == NULL) {
+ csum_ctx_t csum;
+ csum_t res;
+
+ csum_init(&csum);
+ csum_process(&csum, repository.ptr, repository.len);
+ csum_finish(&csum, res);
+
+ n = apk_hexdump_format(sizeof(buf), buf, APK_BLOB_BUF(res)) - 1;
+ snprintf(&buf[n], sizeof(buf) - n, ".index.gz");
+
+ db->repos[r].cache = strdup(buf);
+
+ if (!apk_db_cache_has(db, db->repos[r].cache)) {
+ n = apk_repository_update(db, &db->repos[r]);
+ if (n < 0)
+ return n;
+ }
+ name = db->repos[r].cache;
+ is = apk_bstream_gunzip(apk_db_cache_open(db, db->repos[r].cache), 1);
+ } else {
+ name = "APK_INDEX.gz";
+ is = apk_bstream_gunzip(apk_repository_file_open(&db->repos[r], name), 1);
+ }
if (is == NULL) {
- apk_error("Failed to open index file %s", tmp);
+ apk_error("Failed to open index file %s", name);
return -1;
}
apk_db_index_read(db, is, r);
diff --git a/src/update.c b/src/update.c
new file mode 100644
index 0000000..4351653
--- /dev/null
+++ b/src/update.c
@@ -0,0 +1,41 @@
+/* update.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 "apk_defines.h"
+#include "apk_applet.h"
+#include "apk_database.h"
+#include "apk_version.h"
+
+static int update_main(void *ctx, int argc, char **argv)
+{
+ struct apk_database db;
+ int i;
+
+ if (apk_db_open(&db, apk_root, APK_OPENF_READ) < 0)
+ return -1;
+
+ for (i = 0; i < db.num_repos; i++)
+ apk_repository_update(&db, &db.repos[i]);
+
+ apk_db_close(&db);
+
+ return 0;
+}
+
+static struct apk_applet apk_update = {
+ .name = "update",
+ .usage = "",
+ .main = update_main,
+};
+
+APK_DEFINE_APPLET(apk_update);
+
diff --git a/src/url.c b/src/url.c
index 656aef6..8502b28 100644
--- a/src/url.c
+++ b/src/url.c
@@ -13,10 +13,11 @@
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
+#include <sys/wait.h>
#include "apk_io.h"
-static const char *url_is_file(const char *url)
+const char *apk_url_local_file(const char *url)
{
if (strncmp(url, "file:", 5) == 0)
return &url[5];
@@ -59,8 +60,8 @@ static int fork_wget(const char *url)
struct apk_istream *apk_istream_from_url(const char *url)
{
- if (url_is_file(url) != NULL)
- return apk_istream_from_file(url_is_file(url));
+ if (apk_url_local_file(url) != NULL)
+ return apk_istream_from_file(apk_url_local_file(url));
return apk_istream_from_fd(fork_wget(url));
}
@@ -72,9 +73,34 @@ struct apk_istream *apk_istream_from_url_gz(const char *file)
struct apk_bstream *apk_bstream_from_url(const char *url)
{
- if (url_is_file(url))
+ if (apk_url_local_file(url))
return apk_bstream_from_file(url);
return apk_bstream_from_fd(fork_wget(url));
}
+int apk_url_download(const char *url, const char *file)
+{
+ pid_t pid;
+ int status;
+
+ pid = fork();
+ if (pid == -1)
+ return -1;
+
+ if (pid == 0) {
+ setsid();
+ dup2(open("/dev/null", O_RDONLY), STDIN_FILENO);
+ execlp("wget", "wget", "-q", "-O", file, url, NULL);
+ exit(0);
+ }
+
+ waitpid(pid, &status, 0);
+ if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
+ unlink(file);
+ return -1;
+ }
+
+ return 0;
+}
+