194 lines
4.4 KiB
C
194 lines
4.4 KiB
C
/* cache.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 <errno.h>
|
|
#include <stdio.h>
|
|
#include <dirent.h>
|
|
#include <unistd.h>
|
|
|
|
#include "apk_defines.h"
|
|
#include "apk_applet.h"
|
|
#include "apk_database.h"
|
|
#include "apk_state.h"
|
|
#include "apk_package.h"
|
|
|
|
#define CACHE_CLEAN BIT(0)
|
|
#define CACHE_DOWNLOAD BIT(1)
|
|
|
|
static int cache_download(struct apk_database *db)
|
|
{
|
|
struct apk_state *state;
|
|
struct apk_change *change;
|
|
struct apk_package *pkg;
|
|
char item[PATH_MAX], cacheitem[PATH_MAX];
|
|
int i, r = 0;
|
|
|
|
if (db->world == NULL)
|
|
return 0;
|
|
|
|
state = apk_state_new(db);
|
|
if (state == NULL)
|
|
goto err;
|
|
|
|
for (i = 0; i < db->world->num; i++) {
|
|
r = apk_state_lock_dependency(state, &db->world->item[i]);
|
|
if (r != 0) {
|
|
apk_error("Unable to select version for '%s': %d",
|
|
db->world->item[i].name->name, r);
|
|
goto err;
|
|
}
|
|
}
|
|
|
|
list_for_each_entry(change, &state->change_list_head, change_list) {
|
|
pkg = change->newpkg;
|
|
|
|
apk_pkg_format_cache(pkg, APK_BLOB_BUF(cacheitem));
|
|
if (faccessat(db->cache_fd, cacheitem, R_OK, 0) == 0)
|
|
continue;
|
|
|
|
for (i = 0; i < db->num_repos; i++) {
|
|
if (!(pkg->repos & BIT(i)))
|
|
continue;
|
|
|
|
apk_pkg_format_plain(pkg, APK_BLOB_BUF(item));
|
|
r = apk_cache_download(db, db->repos[i].url,
|
|
item, cacheitem,
|
|
APK_SIGN_VERIFY_IDENTITY);
|
|
if (r != 0)
|
|
return r;
|
|
}
|
|
}
|
|
|
|
err:
|
|
if (state != NULL)
|
|
apk_state_unref(state);
|
|
return r;
|
|
}
|
|
|
|
static int cache_clean(struct apk_database *db)
|
|
{
|
|
char tmp[PATH_MAX];
|
|
DIR *dir;
|
|
struct dirent *de;
|
|
int delete, i;
|
|
apk_blob_t b, bname, bver;
|
|
struct apk_name *name;
|
|
|
|
dir = fdopendir(dup(db->cache_fd));
|
|
if (dir == NULL)
|
|
return -1;
|
|
|
|
while ((de = readdir(dir)) != NULL) {
|
|
if (de->d_name[0] == '.')
|
|
continue;
|
|
|
|
delete = TRUE;
|
|
do {
|
|
b = APK_BLOB_STR(de->d_name);
|
|
|
|
if (apk_blob_compare(b, APK_BLOB_STR("installed")) == 0) {
|
|
delete = FALSE;
|
|
break;
|
|
}
|
|
|
|
if (apk_pkg_parse_name(b, &bname, &bver) < 0) {
|
|
/* Index - check for matching repository */
|
|
for (i = 0; i < db->num_repos; i++) {
|
|
apk_cache_format_index(APK_BLOB_BUF(tmp), &db->repos[i], 0);
|
|
if (apk_blob_compare(b, APK_BLOB_STR(tmp)) != 0) {
|
|
apk_cache_format_index(APK_BLOB_BUF(tmp), &db->repos[i], 1);
|
|
if (apk_blob_compare(b, APK_BLOB_STR(tmp)) != 0)
|
|
continue;
|
|
}
|
|
delete = 0;
|
|
break;
|
|
}
|
|
} else {
|
|
/* Package - search for it */
|
|
name = apk_db_get_name(db, bname);
|
|
if (name == NULL || name->pkgs == NULL)
|
|
break;
|
|
for (i = 0; i < name->pkgs->num; i++) {
|
|
struct apk_package *pkg = name->pkgs->item[i];
|
|
|
|
apk_pkg_format_cache(pkg, APK_BLOB_BUF(tmp));
|
|
if (apk_blob_compare(b, APK_BLOB_STR(tmp)) != 0)
|
|
continue;
|
|
|
|
delete = 0;
|
|
break;
|
|
}
|
|
}
|
|
} while (0);
|
|
|
|
if (delete) {
|
|
if (apk_verbosity >= 2)
|
|
apk_message("deleting %s", de->d_name);
|
|
if (!(apk_flags & APK_SIMULATE))
|
|
unlinkat(db->cache_fd, de->d_name, 0);
|
|
}
|
|
}
|
|
|
|
closedir(dir);
|
|
return 0;
|
|
}
|
|
|
|
static int cache_main(void *ctx, int argc, char **argv)
|
|
{
|
|
struct apk_database db;
|
|
int actions = 0;
|
|
int r;
|
|
|
|
if (argc != 1)
|
|
return -EINVAL;
|
|
|
|
if (strcmp(argv[0], "sync") == 0)
|
|
actions = CACHE_CLEAN | CACHE_DOWNLOAD;
|
|
else if (strcmp(argv[0], "clean") == 0)
|
|
actions = CACHE_CLEAN;
|
|
else if (strcmp(argv[0], "download") == 0)
|
|
actions = CACHE_DOWNLOAD;
|
|
else
|
|
return -EINVAL;
|
|
|
|
r = apk_db_open(&db, apk_root, APK_OPENF_READ |
|
|
APK_OPENF_NO_SCRIPTS | APK_OPENF_NO_INSTALLED);
|
|
if (r != 0)
|
|
return r;
|
|
|
|
if (!apk_db_cache_active(&db)) {
|
|
apk_error("Package cache is not enabled.\n");
|
|
r = 2;
|
|
goto err;
|
|
}
|
|
|
|
if (r == 0 && (actions & CACHE_CLEAN))
|
|
r = cache_clean(&db);
|
|
if (r == 0 && (actions & CACHE_DOWNLOAD))
|
|
r = cache_download(&db);
|
|
|
|
err:
|
|
apk_db_close(&db);
|
|
return r;
|
|
}
|
|
|
|
static struct apk_applet apk_cache = {
|
|
.name = "cache",
|
|
.help = "Download missing PACKAGEs to cache directory, or delete "
|
|
"files no longer required. Package caching is enabled by "
|
|
"making /etc/apk/cache a symlink to the directory (on boot "
|
|
"media) that will be used as package cache.",
|
|
.arguments = "sync | clean | download",
|
|
.main = cache_main,
|
|
};
|
|
|
|
APK_DEFINE_APPLET(apk_cache);
|