cache.c 4.18 KB
Newer Older
Timo Teräs's avatar
Timo Teräs committed
1
2
3
4
5
6
7
8
9
10
11
/* 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.
 */

Timo Teräs's avatar
Timo Teräs committed
12
13
#include <errno.h>
#include <stdio.h>
Timo Teräs's avatar
Timo Teräs committed
14
15
16
17
18
19
#include <dirent.h>
#include <unistd.h>

#include "apk_defines.h"
#include "apk_applet.h"
#include "apk_database.h"
20
#include "apk_state.h"
21
#include "apk_package.h"
Natanael Copa's avatar
Natanael Copa committed
22
#include "apk_print.h"
Timo Teräs's avatar
Timo Teräs committed
23
24
25
26
27
28

#define CACHE_CLEAN	BIT(0)
#define CACHE_DOWNLOAD	BIT(1)

static int cache_download(struct apk_database *db)
{
29
30
	struct apk_state *state;
	struct apk_change *change;
Timo Teräs's avatar
Timo Teräs committed
31
	struct apk_package *pkg;
32
	struct apk_repository *repo;
33
	char item[PATH_MAX], cacheitem[PATH_MAX];
34
	int i, r = 0;
Timo Teräs's avatar
Timo Teräs committed
35

36
	state = apk_state_new(db);
37
38
39
	if (state == NULL)
		goto err;

40
41
42
	for (i = 0; i < db->world->num; i++) {
		r = apk_state_lock_dependency(state, &db->world->item[i]);
		if (r != 0) {
43
44
			apk_error("Unable to select version for '%s': %d",
				  db->world->item[i].name->name, r);
45
46
47
48
49
50
			goto err;
		}
	}

	list_for_each_entry(change, &state->change_list_head, change_list) {
		pkg = change->newpkg;
51
52
53

		apk_pkg_format_cache(pkg, APK_BLOB_BUF(cacheitem));
		if (faccessat(db->cache_fd, cacheitem, R_OK, 0) == 0)
Timo Teräs's avatar
Timo Teräs committed
54
			continue;
55

56
		repo = apk_db_select_repo(db, pkg);
57
		if (repo == NULL || apk_url_local_file(repo->url) != NULL)
58
			continue;
Timo Teräs's avatar
Timo Teräs committed
59

60
		apk_pkg_format_plain(pkg, APK_BLOB_BUF(item));
61
62
63
		r |= apk_cache_download(db, repo->url, pkg->arch,
					item, cacheitem,
					APK_SIGN_VERIFY_IDENTITY);
Timo Teräs's avatar
Timo Teräs committed
64
	}
65
66

err:
67
68
	if (state != NULL)
		apk_state_unref(state);
69
	return r;
Timo Teräs's avatar
Timo Teräs committed
70
71
72
73
}

static int cache_clean(struct apk_database *db)
{
74
	char tmp[PATH_MAX];
Timo Teräs's avatar
Timo Teräs committed
75
76
77
	DIR *dir;
	struct dirent *de;
	int delete, i;
78
79
	apk_blob_t b, bname, bver;
	struct apk_name *name;
Timo Teräs's avatar
Timo Teräs committed
80

81
	dir = fdopendir(dup(db->cache_fd));
Timo Teräs's avatar
Timo Teräs committed
82
83
84
85
86
87
	if (dir == NULL)
		return -1;

	while ((de = readdir(dir)) != NULL) {
		if (de->d_name[0] == '.')
			continue;
88

Timo Teräs's avatar
Timo Teräs committed
89
90
		delete = TRUE;
		do {
91
92
			b = APK_BLOB_STR(de->d_name);

93
94
95
96
97
98
			if (apk_blob_compare(b, APK_BLOB_STR("installed")) == 0) {
				delete = FALSE;
				break;
			}

			if (apk_pkg_parse_name(b, &bname, &bver) < 0) {
Timo Teräs's avatar
Timo Teräs committed
99
				/* Index - check for matching repository */
100
				for (i = 0; i < db->num_repos; i++) {
101
102
103
					apk_cache_format_index(APK_BLOB_BUF(tmp), &db->repos[i]);
					if (apk_blob_compare(b, APK_BLOB_STR(tmp)) != 0)
						continue;
104
105
106
					delete = 0;
					break;
				}
107
			} else {
Timo Teräs's avatar
Timo Teräs committed
108
				/* Package - search for it */
109
				name = apk_db_get_name(db, bname);
Timo Teräs's avatar
Timo Teräs committed
110
				if (name == NULL)
111
112
113
					break;
				for (i = 0; i < name->pkgs->num; i++) {
					struct apk_package *pkg = name->pkgs->item[i];
114
115
116

					apk_pkg_format_cache(pkg, APK_BLOB_BUF(tmp));
					if (apk_blob_compare(b, APK_BLOB_STR(tmp)) != 0)
117
						continue;
118

119
120
121
					delete = 0;
					break;
				}
Timo Teräs's avatar
Timo Teräs committed
122
123
124
125
126
			}
		} while (0);

		if (delete) {
			if (apk_verbosity >= 2)
127
				apk_message("deleting %s", de->d_name);
Timo Teräs's avatar
Timo Teräs committed
128
			if (!(apk_flags & APK_SIMULATE))
129
				unlinkat(db->cache_fd, de->d_name, 0);
Timo Teräs's avatar
Timo Teräs committed
130
131
132
133
134
135
136
		}
	}

	closedir(dir);
	return 0;
}

137
static int cache_main(void *ctx, struct apk_database *db, int argc, char **argv)
Timo Teräs's avatar
Timo Teräs committed
138
{
139
	int r = 0, actions = 0;
Timo Teräs's avatar
Timo Teräs committed
140
141

	if (argc != 1)
Timo Teräs's avatar
Timo Teräs committed
142
		return -EINVAL;
Timo Teräs's avatar
Timo Teräs committed
143
144
145
146
147
148
149
150

	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
Timo Teräs's avatar
Timo Teräs committed
151
		return -EINVAL;
Timo Teräs's avatar
Timo Teräs committed
152

153
	if (!apk_db_cache_active(db)) {
Timo Teräs's avatar
Timo Teräs committed
154
155
156
157
158
159
		apk_error("Package cache is not enabled.\n");
		r = 2;
		goto err;
	}

	if (r == 0 && (actions & CACHE_CLEAN))
160
		r = cache_clean(db);
Timo Teräs's avatar
Timo Teräs committed
161
	if (r == 0 && (actions & CACHE_DOWNLOAD))
162
		r = cache_download(db);
Timo Teräs's avatar
Timo Teräs committed
163
164
165
166
167
168
169
170
171
172
173
174

err:
	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",
175
	.open_flags = APK_OPENF_READ|APK_OPENF_NO_SCRIPTS|APK_OPENF_NO_INSTALLED|APK_OPENF_CACHE_WRITE,
Timo Teräs's avatar
Timo Teräs committed
176
177
178
179
	.main = cache_main,
};

APK_DEFINE_APPLET(apk_cache);