database.c 55.8 KB
Newer Older
1 2 3
/* database.c - Alpine Package Keeper (APK)
 *
 * Copyright (C) 2005-2008 Natanael Copa <n@tanael.org>
4
 * Copyright (C) 2008-2009 Timo Teräs <timo.teras@iki.fi>
5 6
 * All rights reserved.
 *
7
 * This program is free software; you can redistribute it and/or modify it
8 9 10 11 12 13 14
 * 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 <fcntl.h>
15
#include <limits.h>
16 17 18
#include <unistd.h>
#include <malloc.h>
#include <string.h>
19
#include <stdlib.h>
20
#include <signal.h>
21
#include <fnmatch.h>
22
#include <sys/file.h>
Natanael Copa's avatar
Natanael Copa committed
23
#include <sys/stat.h>
24 25 26 27 28

#include "apk_defines.h"
#include "apk_package.h"
#include "apk_database.h"
#include "apk_state.h"
29
#include "apk_applet.h"
30
#include "apk_archive.h"
Natanael Copa's avatar
Natanael Copa committed
31 32
#include "apk_print.h"

33 34 35 36 37 38 39 40
#if defined(__x86_64__)
#define APK_DEFAULT_ARCH       "x86_64"
#elif defined(__i386__)
#define APK_DEFAULT_ARCH       "x86"
#else
#define APK_DEFAULT_ARCH       "noarch"
#endif

41 42 43 44 45
enum {
	APK_DISALLOW_RMDIR = 0,
	APK_ALLOW_RMDIR = 1
};

Natanael Copa's avatar
Natanael Copa committed
46 47
int apk_verbosity = 1;
unsigned int apk_flags = 0;
48
const char *apk_arch = APK_DEFAULT_ARCH;
49

50
const char * const apkindex_tar_gz = "APKINDEX.tar.gz";
51
const char * const apk_index_gz = "APK_INDEX.gz";
52 53 54
static const char * const apk_static_cache_dir = "var/lib/apk";
static const char * const apk_linked_cache_dir = "etc/apk/cache";

55 56 57
struct install_ctx {
	struct apk_database *db;
	struct apk_package *pkg;
58
	struct apk_installed_package *ipkg;
59 60

	int script;
61
	char **script_args;
62
	int script_pending : 1;
63

64
	struct apk_db_dir_instance *diri;
Timo Teräs's avatar
Timo Teräs committed
65
	struct apk_checksum data_csum;
66
	struct apk_sign_ctx sctx;
67
	struct apk_name_array *replaces;
68

69 70 71 72 73
	apk_progress_cb cb;
	void *cb_ctx;
	size_t installed_size;
	size_t current_file_size;

74 75
	struct hlist_node **diri_node;
	struct hlist_node **file_diri_node;
76 77
};

78
static apk_blob_t pkg_name_get_key(apk_hash_item item)
79
{
80
	return APK_BLOB_STR(((struct apk_name *) item)->name);
81 82
}

83 84 85
static void pkg_name_free(struct apk_name *name)
{
	free(name->name);
86 87
	apk_package_array_free(&name->pkgs);
	apk_name_array_free(&name->rdepends);
88 89 90
	free(name);
}

91 92 93
static const struct apk_hash_ops pkg_name_hash_ops = {
	.node_offset = offsetof(struct apk_name, hash_node),
	.get_key = pkg_name_get_key,
94 95
	.hash_key = apk_blob_hash,
	.compare = apk_blob_compare,
96
	.delete_item = (apk_hash_delete_f) pkg_name_free,
97 98
};

99
static apk_blob_t pkg_info_get_key(apk_hash_item item)
100
{
Timo Teräs's avatar
Timo Teräs committed
101
	return APK_BLOB_CSUM(((struct apk_package *) item)->csum);
102 103
}

104
static unsigned long csum_hash(apk_blob_t csum)
105
{
106 107
	/* Checksum's highest bits have the most "randomness", use that
	 * directly as hash */
108
	return *(unsigned long *) csum.ptr;
109 110 111 112 113
}

static const struct apk_hash_ops pkg_info_hash_ops = {
	.node_offset = offsetof(struct apk_package, hash_node),
	.get_key = pkg_info_get_key,
114 115
	.hash_key = csum_hash,
	.compare = apk_blob_compare,
116 117 118
	.delete_item = (apk_hash_delete_f) apk_pkg_free,
};

119
static apk_blob_t apk_db_dir_get_key(apk_hash_item item)
120
{
Timo Teräs's avatar
Timo Teräs committed
121 122
	struct apk_db_dir *dir = (struct apk_db_dir *) item;
	return APK_BLOB_PTR_LEN(dir->name, dir->namelen);
123 124 125 126 127
}

static const struct apk_hash_ops dir_hash_ops = {
	.node_offset = offsetof(struct apk_db_dir, hash_node),
	.get_key = apk_db_dir_get_key,
128 129
	.hash_key = apk_blob_hash,
	.compare = apk_blob_compare,
130 131 132
	.delete_item = (apk_hash_delete_f) free,
};

133 134 135 136 137 138
struct apk_db_file_hash_key {
	apk_blob_t dirname;
	apk_blob_t filename;
};

static unsigned long apk_db_file_hash_key(apk_blob_t _key)
139
{
140 141
	struct apk_db_file_hash_key *key = (struct apk_db_file_hash_key *) _key.ptr;

Timo Teräs's avatar
Timo Teräs committed
142
	return apk_blob_hash_seed(key->filename, apk_blob_hash(key->dirname));
143 144 145 146 147 148
}

static unsigned long apk_db_file_hash_item(apk_hash_item item)
{
	struct apk_db_file *dbf = (struct apk_db_file *) item;

Timo Teräs's avatar
Timo Teräs committed
149 150
	return apk_blob_hash_seed(APK_BLOB_PTR_LEN(dbf->name, dbf->namelen),
				  dbf->diri->dir->hash);
151 152 153 154 155 156
}

static int apk_db_file_compare_item(apk_hash_item item, apk_blob_t _key)
{
	struct apk_db_file *dbf = (struct apk_db_file *) item;
	struct apk_db_file_hash_key *key = (struct apk_db_file_hash_key *) _key.ptr;
Timo Teräs's avatar
Timo Teräs committed
157
	struct apk_db_dir *dir = dbf->diri->dir;
158 159
	int r;

Timo Teräs's avatar
Timo Teräs committed
160 161
	r = apk_blob_compare(key->filename,
			     APK_BLOB_PTR_LEN(dbf->name, dbf->namelen));
162 163 164
	if (r != 0)
		return r;

Timo Teräs's avatar
Timo Teräs committed
165 166 167
	r = apk_blob_compare(key->dirname,
			     APK_BLOB_PTR_LEN(dir->name, dir->namelen));
	return r;
168 169 170 171
}

static const struct apk_hash_ops file_hash_ops = {
	.node_offset = offsetof(struct apk_db_file, hash_node),
172 173 174
	.hash_key = apk_db_file_hash_key,
	.hash_item = apk_db_file_hash_item,
	.compare_item = apk_db_file_compare_item,
175 176 177
	.delete_item = (apk_hash_delete_f) free,
};

Timo Teräs's avatar
Timo Teräs committed
178 179 180 181 182
struct apk_name *apk_db_query_name(struct apk_database *db, apk_blob_t name)
{
	return (struct apk_name *) apk_hash_get(&db->available.names, name);
}

183
struct apk_name *apk_db_get_name(struct apk_database *db, apk_blob_t name)
184 185
{
	struct apk_name *pn;
186
	unsigned long hash = apk_hash_from_key(&db->available.names, name);
187

188
	pn = (struct apk_name *) apk_hash_get_hashed(&db->available.names, name, hash);
189 190 191 192 193 194 195
	if (pn != NULL)
		return pn;

	pn = calloc(1, sizeof(struct apk_name));
	if (pn == NULL)
		return NULL;

196
	pn->name = apk_blob_cstr(name);
197
	pn->id = db->name_id++;
198 199
	apk_package_array_init(&pn->pkgs);
	apk_name_array_init(&pn->rdepends);
200
	apk_hash_insert_hashed(&db->available.names, pn, hash);
201 202 203 204

	return pn;
}

205 206
static void apk_db_dir_unref(struct apk_database *db, struct apk_db_dir *dir,
			     int allow_rmdir)
207 208 209 210 211 212
{
	dir->refs--;
	if (dir->refs > 0)
		return;

	db->installed.stats.dirs--;
213 214
	if (allow_rmdir)
		unlinkat(db->root_fd, dir->name, AT_REMOVEDIR);
215 216

	if (dir->parent != NULL)
217
		apk_db_dir_unref(db, dir->parent, allow_rmdir);
218 219
}

220
static struct apk_db_dir *apk_db_dir_ref(struct apk_db_dir *dir)
221 222 223 224 225
{
	dir->refs++;
	return dir;
}

226 227
struct apk_db_dir *apk_db_dir_query(struct apk_database *db,
				    apk_blob_t name)
228 229 230 231
{
	return (struct apk_db_dir *) apk_hash_get(&db->installed.dirs, name);
}

232 233
static struct apk_db_dir *apk_db_dir_get(struct apk_database *db,
					 apk_blob_t name)
234 235 236
{
	struct apk_db_dir *dir;
	apk_blob_t bparent;
237
	unsigned long hash = apk_hash_from_key(&db->installed.dirs, name);
238
	int i;
239

240
	if (name.len && name.ptr[name.len-1] == '/')
241 242
		name.len--;

243
	dir = (struct apk_db_dir *) apk_hash_get_hashed(&db->installed.dirs, name, hash);
244
	if (dir != NULL)
245
		return apk_db_dir_ref(dir);
246

247
	db->installed.stats.dirs++;
248 249
	dir = malloc(sizeof(*dir) + name.len + 1);
	memset(dir, 0, sizeof(*dir));
250
	dir->refs = 1;
251
	dir->rooted_name[0] = '/';
Timo Teräs's avatar
Timo Teräs committed
252 253 254 255
	memcpy(dir->name, name.ptr, name.len);
	dir->name[name.len] = 0;
	dir->namelen = name.len;
	dir->hash = hash;
256
	apk_hash_insert_hashed(&db->installed.dirs, dir, hash);
257

258 259
	if (name.len == 0)
		dir->parent = NULL;
260
	else if (apk_blob_rsplit(name, '/', &bparent, NULL))
261
		dir->parent = apk_db_dir_get(db, bparent);
262
	else
263
		dir->parent = apk_db_dir_get(db, APK_BLOB_NULL);
264

265 266 267 268
	if (dir->parent != NULL)
		dir->flags = dir->parent->flags;

	for (i = 0; i < db->protected_paths->num; i++) {
269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287
		int flags = dir->flags, j;

		flags |= APK_DBDIRF_PROTECTED;
		for (j = 0; ; j++) {
			switch (db->protected_paths->item[i][j]) {
			case '-':
				flags &= ~(APK_DBDIRF_PROTECTED |
					   APK_DBDIRF_SYMLINKS_ONLY);
				continue;
			case '*':
				flags |= APK_DBDIRF_SYMLINKS_ONLY |
					 APK_DBDIRF_PROTECTED;
				continue;
			}
			break;
		}

		if (strcmp(&db->protected_paths->item[i][j], dir->name) == 0)
			dir->flags = flags;
288 289
	}

290 291 292
	return dir;
}

293 294 295
static struct apk_db_dir_instance *apk_db_diri_new(struct apk_database *db,
						   struct apk_package *pkg,
						   apk_blob_t name,
296
						   struct hlist_node ***after)
297 298 299 300
{
	struct apk_db_dir_instance *diri;

	diri = calloc(1, sizeof(struct apk_db_dir_instance));
301
	if (diri != NULL) {
302 303
		hlist_add_after(&diri->pkg_dirs_list, *after);
		*after = &diri->pkg_dirs_list.next;
304
		diri->dir = apk_db_dir_get(db, name);
305 306
		diri->pkg = pkg;
	}
307 308 309 310 311 312 313 314 315 316 317 318

	return diri;
}

static void apk_db_diri_set(struct apk_db_dir_instance *diri, mode_t mode,
			    uid_t uid, gid_t gid)
{
	diri->mode = mode;
	diri->uid = uid;
	diri->gid = gid;
}

319
static void apk_db_diri_mkdir(struct apk_database *db, struct apk_db_dir_instance *diri)
320
{
321 322 323 324
	if (mkdirat(db->root_fd, diri->dir->name, diri->mode) == 0) {
		if (fchownat(db->root_fd, diri->dir->name, diri->uid, diri->gid, 0) != 0)
			;
	}
325 326
}

327
static void apk_db_diri_free(struct apk_database *db,
328 329
			     struct apk_db_dir_instance *diri,
			     int allow_rmdir)
330
{
331
	apk_db_dir_unref(db, diri->dir, allow_rmdir);
332 333 334
	free(diri);
}

335 336 337 338 339 340 341 342 343 344 345 346 347 348 349
struct apk_db_file *apk_db_file_query(struct apk_database *db,
				      apk_blob_t dir,
				      apk_blob_t name)
{
	struct apk_db_file_hash_key key;

	key = (struct apk_db_file_hash_key) {
		.dirname = dir,
		.filename = name,
	};

	return (struct apk_db_file *) apk_hash_get(&db->installed.files,
						   APK_BLOB_BUF(&key));
}

350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371
static struct apk_db_file *apk_db_file_new(struct apk_db_dir_instance *diri,
					   apk_blob_t name,
					   struct hlist_node ***after)
{
	struct apk_db_file *file;

	file = malloc(sizeof(*file) + name.len + 1);
	if (file == NULL)
		return NULL;

	memset(file, 0, sizeof(*file));
	memcpy(file->name, name.ptr, name.len);
	file->name[name.len] = 0;
	file->namelen = name.len;

	file->diri = diri;
	hlist_add_after(&file->diri_files_list, *after);
	*after = &file->diri_files_list.next;

	return file;
}

372
static struct apk_db_file *apk_db_file_get(struct apk_database *db,
373
					   struct apk_db_dir_instance *diri,
374 375
					   apk_blob_t name,
					   struct hlist_node ***after)
376 377
{
	struct apk_db_file *file;
378
	struct apk_db_file_hash_key key;
Timo Teräs's avatar
Timo Teräs committed
379 380
	struct apk_db_dir *dir = diri->dir;
	unsigned long hash;
381 382

	key = (struct apk_db_file_hash_key) {
Timo Teräs's avatar
Timo Teräs committed
383
		.dirname = APK_BLOB_PTR_LEN(dir->name, dir->namelen),
384 385
		.filename = name,
	};
386

Timo Teräs's avatar
Timo Teräs committed
387 388 389
	hash = apk_blob_hash_seed(name, dir->hash);
	file = (struct apk_db_file *) apk_hash_get_hashed(
		&db->installed.files, APK_BLOB_BUF(&key), hash);
390 391 392
	if (file != NULL)
		return file;

393
	file = apk_db_file_new(diri, name, after);
Timo Teräs's avatar
Timo Teräs committed
394
	apk_hash_insert_hashed(&db->installed.files, file, hash);
395
	db->installed.stats.files++;
396 397 398 399

	return file;
}

400 401 402 403 404 405 406
static void apk_db_pkg_rdepends(struct apk_database *db, struct apk_package *pkg)
{
	int i, j;

	for (i = 0; i < pkg->depends->num; i++) {
		struct apk_name *rname = pkg->depends->item[i].name;

407 408 409 410
		for (j = 0; j < rname->rdepends->num; j++)
			if (rname->rdepends->item[j] == pkg->name)
				return;

411 412 413 414
		*apk_name_array_add(&rname->rdepends) = pkg->name;
	}
}

415
struct apk_package *apk_db_pkg_add(struct apk_database *db, struct apk_package *pkg)
416 417 418
{
	struct apk_package *idb;

Timo Teräs's avatar
Timo Teräs committed
419
	idb = apk_hash_get(&db->available.packages, APK_BLOB_CSUM(pkg->csum));
420 421 422 423
	if (idb == NULL) {
		idb = pkg;
		apk_hash_insert(&db->available.packages, pkg);
		*apk_package_array_add(&pkg->name->pkgs) = pkg;
424
		apk_db_pkg_rdepends(db, pkg);
425 426
	} else {
		idb->repos |= pkg->repos;
427 428 429 430
		if (idb->filename == NULL && pkg->filename != NULL) {
			idb->filename = pkg->filename;
			pkg->filename = NULL;
		}
431 432 433 434 435
		if (idb->ipkg == NULL && pkg->ipkg != NULL) {
			idb->ipkg = pkg->ipkg;
			idb->ipkg->pkg = idb;
			pkg->ipkg = NULL;
		}
436 437 438 439 440
		apk_pkg_free(pkg);
	}
	return idb;
}

441
void apk_cache_format_index(apk_blob_t to, struct apk_repository *repo, int ver)
442
{
443 444 445 446 447 448 449 450 451 452 453 454 455 456 457
	/* APKINDEX.12345678.tar.gz */
	/* APK_INDEX.12345678.gz */
	if (ver == 0)
		apk_blob_push_blob(&to, APK_BLOB_STR("APKINDEX."));
	else
		apk_blob_push_blob(&to, APK_BLOB_STR("APK_INDEX."));
	apk_blob_push_hexdump(&to, APK_BLOB_PTR_LEN((char *) repo->csum.data,
						    APK_CACHE_CSUM_BYTES));
	if (ver == 0)
		apk_blob_push_blob(&to, APK_BLOB_STR(".tar.gz"));
	else
		apk_blob_push_blob(&to, APK_BLOB_STR(".gz"));
	apk_blob_push_blob(&to, APK_BLOB_PTR_LEN("", 1));
}

458
int apk_cache_download(struct apk_database *db, const char *arch, const char *url,
459 460 461 462 463
		       const char *item, const char *cacheitem, int verify)
{
	char fullurl[PATH_MAX];
	int r;

464 465 466 467 468 469 470
	if (arch != NULL)
		snprintf(fullurl, sizeof(fullurl), "%s%s%s/%s",
			 url, url[strlen(url)-1] == '/' ? "" : "/",
			 arch, item);
	else
		snprintf(fullurl, sizeof(fullurl), "%s%s%s",
			 url, url[strlen(url)-1] == '/' ? "" : "/", item);
471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488
	apk_message("fetch %s", fullurl);

	if (apk_flags & APK_SIMULATE)
		return 0;

	r = apk_url_download(fullurl, db->cachetmp_fd, cacheitem);
	if (r < 0)
		return r;

	if (verify != APK_SIGN_NONE) {
		struct apk_istream *is;
		struct apk_sign_ctx sctx;

		apk_sign_ctx_init(&sctx, APK_SIGN_VERIFY, NULL, db->keys_fd);
		is = apk_bstream_gunzip_mpart(
			apk_bstream_from_file(db->cachetmp_fd, cacheitem),
			apk_sign_ctx_mpart_cb, &sctx);

489
		r = apk_tar_parse(is, apk_sign_ctx_verify_tar, &sctx, FALSE, &db->id_cache);
490 491 492 493 494 495 496
		is->close(is);
		apk_sign_ctx_free(&sctx);
		if (r != 0) {
			unlinkat(db->cachetmp_fd, cacheitem, 0);
			return r;
		}
	}
497

498 499
	if (renameat(db->cachetmp_fd, cacheitem, db->cache_fd, cacheitem) < 0)
		return -errno;
500

501
	return 0;
502 503
}

504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528
static struct apk_db_dir_instance *find_diri(struct apk_installed_package *ipkg,
					     apk_blob_t dirname,
					     struct apk_db_dir_instance *curdiri,
					     struct hlist_node ***tail)
{
	struct hlist_node *n;
	struct apk_db_dir_instance *diri;

	if (curdiri != NULL &&
	    apk_blob_compare(APK_BLOB_PTR_LEN(curdiri->dir->name,
					      curdiri->dir->namelen),
			     dirname) == 0)
		return curdiri;

	hlist_for_each_entry(diri, n, &ipkg->owned_dirs, pkg_dirs_list) {
		if (apk_blob_compare(APK_BLOB_PTR_LEN(diri->dir->name,
						      diri->dir->namelen), dirname) == 0) {
			if (tail != NULL)
				*tail = hlist_tail_ptr(&diri->owned_files);
			return diri;
		}
	}
	return NULL;
}

Timo Teräs's avatar
Timo Teräs committed
529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554
int apk_db_read_overlay(struct apk_database *db, struct apk_bstream *bs)
{
	struct apk_db_dir_instance *diri = NULL;
	struct hlist_node **diri_node = NULL, **file_diri_node = NULL;
	struct apk_package *pkg;
	struct apk_installed_package *ipkg;
	apk_blob_t token = APK_BLOB_STR("\n"), line, bdir, bfile;

	pkg = apk_pkg_new();
	if (pkg == NULL)
		return -1;

	ipkg = apk_pkg_install(db, pkg);
	if (ipkg == NULL)
		return -1;

	diri_node = hlist_tail_ptr(&ipkg->owned_dirs);

	while (!APK_BLOB_IS_NULL(line = bs->read(bs, token))) {
		if (!apk_blob_rsplit(line, '/', &bdir, &bfile))
			break;

		if (bfile.len == 0) {
			diri = apk_db_diri_new(db, pkg, bdir, &diri_node);
			file_diri_node = &diri->owned_files.first;
		} else {
555 556
			diri = find_diri(ipkg, bdir, diri, &file_diri_node);
			if (diri == NULL) {
557 558
				diri = apk_db_diri_new(db, pkg, bdir, &diri_node);
				file_diri_node = &diri->owned_files.first;
559
			}
560
			apk_db_file_get(db, diri, bfile, &file_diri_node);
Timo Teräs's avatar
Timo Teräs committed
561 562 563 564 565 566
		}
	}

	return 0;
}

567
int apk_db_index_read(struct apk_database *db, struct apk_bstream *bs, int repo)
568 569
{
	struct apk_package *pkg = NULL;
570
	struct apk_installed_package *ipkg = NULL;
571
	struct apk_db_dir_instance *diri = NULL;
572
	struct apk_db_file *file = NULL;
573 574
	struct hlist_node **diri_node = NULL;
	struct hlist_node **file_diri_node = NULL;
575
	apk_blob_t token = APK_BLOB_STR("\n"), l;
576
	int field, r;
577

578 579 580 581
	while (!APK_BLOB_IS_NULL(l = bs->read(bs, token))) {
		if (l.len < 2 || l.ptr[1] != ':') {
			if (pkg == NULL)
				continue;
582

583
			if (repo >= 0)
584
				pkg->repos |= BIT(repo);
585

586
			if (apk_db_pkg_add(db, pkg) == NULL) {
587 588
				apk_error("Installed database load failed");
				return -1;
589
			}
590
			pkg = NULL;
591
			ipkg = NULL;
592 593
			continue;
		}
594

595 596 597 598 599 600 601 602
		/* Get field */
		field = l.ptr[0];
		l.ptr += 2;
		l.len -= 2;

		/* If no package, create new */
		if (pkg == NULL) {
			pkg = apk_pkg_new();
603
			ipkg = NULL;
604 605 606
			diri = NULL;
			file_diri_node = NULL;
		}
607

608
		/* Standard index line? */
609 610 611 612 613 614 615 616 617
		r = apk_pkg_add_info(db, pkg, field, l);
		if (r == 0) {
			if (repo == -1 && field == 'S') {
				/* Instert to installed database; this needs to
				 * happen after package name has been read, but
				 * before first FDB entry. */
				ipkg = apk_pkg_install(db, pkg);
				diri_node = hlist_tail_ptr(&ipkg->owned_dirs);
			}
618 619
			continue;
		}
620 621
		if (repo != -1 || ipkg == NULL)
			continue;
622

623 624 625 626 627
		/* Check FDB special entries */
		switch (field) {
		case 'F':
			if (pkg->name == NULL) {
				apk_error("FDB directory entry before package entry");
628 629
				return -1;
			}
630 631 632 633 634 635 636 637
			diri = apk_db_diri_new(db, pkg, l, &diri_node);
			file_diri_node = &diri->owned_files.first;
			break;
		case 'M':
			if (diri == NULL) {
				apk_error("FDB directory metadata entry before directory entry");
				return -1;
			}
638 639 640 641 642
			diri->uid = apk_blob_pull_uint(&l, 10);
			apk_blob_pull_char(&l, ':');
			diri->gid = apk_blob_pull_uint(&l, 10);
			apk_blob_pull_char(&l, ':');
			diri->mode = apk_blob_pull_uint(&l, 8);
643 644 645 646 647 648
			break;
		case 'R':
			if (diri == NULL) {
				apk_error("FDB file entry before directory entry");
				return -1;
			}
649
			file = apk_db_file_get(db, diri, l, &file_diri_node);
650 651 652 653 654 655
			break;
		case 'Z':
			if (file == NULL) {
				apk_error("FDB checksum entry before file entry");
				return -1;
			}
Timo Teräs's avatar
Timo Teräs committed
656
			apk_blob_pull_csum(&l, &file->csum);
657 658
			break;
		default:
659 660 661 662 663 664 665 666
			if (r != 0 && !(apk_flags & APK_FORCE)) {
				/* Installed db should not have unsupported fields */
				apk_error("This apk-tools is too old to handle installed packages");
				return -1;
			}
			/* Installed. So mark the package as installable. */
			pkg->filename = NULL;
			continue;
667
		}
668 669 670 671
		if (APK_BLOB_IS_NULL(l)) {
			apk_error("FDB format error in entry '%c'", field);
			return -1;
		}
672 673
	}

674
	return 0;
675 676
}

Timo Teräs's avatar
Timo Teräs committed
677
static int apk_db_write_fdb(struct apk_database *db, struct apk_ostream *os)
678
{
679
	struct apk_installed_package *ipkg;
680
	struct apk_package *pkg;
681
	struct apk_db_dir_instance *diri;
682
	struct apk_db_file *file;
683
	struct hlist_node *c1, *c2;
684
	char buf[1024];
685 686
	apk_blob_t bbuf = APK_BLOB_BUF(buf);
	int r;
687

688 689
	list_for_each_entry(ipkg, &db->installed.packages, installed_pkgs_list) {
		pkg = ipkg->pkg;
690
		r = apk_pkg_write_index_entry(pkg, os, TRUE);
691 692
		if (r < 0)
			return r;
693

694
		hlist_for_each_entry(diri, c1, &ipkg->owned_dirs, pkg_dirs_list) {
695 696 697 698 699 700 701 702 703
			apk_blob_push_blob(&bbuf, APK_BLOB_STR("F:"));
			apk_blob_push_blob(&bbuf, APK_BLOB_PTR_LEN(diri->dir->name, diri->dir->namelen));
			apk_blob_push_blob(&bbuf, APK_BLOB_STR("\nM:"));
			apk_blob_push_uint(&bbuf, diri->uid, 10);
			apk_blob_push_blob(&bbuf, APK_BLOB_STR(":"));
			apk_blob_push_uint(&bbuf, diri->gid, 10);
			apk_blob_push_blob(&bbuf, APK_BLOB_STR(":"));
			apk_blob_push_uint(&bbuf, diri->mode, 8);
			apk_blob_push_blob(&bbuf, APK_BLOB_STR("\n"));
704

705
			hlist_for_each_entry(file, c2, &diri->owned_files, diri_files_list) {
706 707
				apk_blob_push_blob(&bbuf, APK_BLOB_STR("R:"));
				apk_blob_push_blob(&bbuf, APK_BLOB_PTR_LEN(file->name, file->namelen));
Timo Teräs's avatar
Timo Teräs committed
708
				if (file->csum.type != APK_CHECKSUM_NONE) {
709
					apk_blob_push_blob(&bbuf, APK_BLOB_STR("\nZ:"));
Timo Teräs's avatar
Timo Teräs committed
710
					apk_blob_push_csum(&bbuf, &file->csum);
711
				}
712
				apk_blob_push_blob(&bbuf, APK_BLOB_STR("\n"));
713

714
				if (os->write(os, buf, bbuf.ptr - buf) != bbuf.ptr - buf)
715
					return -1;
716
				bbuf = APK_BLOB_BUF(buf);
717
			}
718
			if (os->write(os, buf, bbuf.ptr - buf) != bbuf.ptr - buf)
719
				return -1;
720
			bbuf = APK_BLOB_BUF(buf);
721
		}
Timo Teräs's avatar
Timo Teräs committed
722
		os->write(os, "\n", 1);
723 724 725 726 727
	}

	return 0;
}

Timo Teräs's avatar
Timo Teräs committed
728
static int apk_db_scriptdb_write(struct apk_database *db, struct apk_ostream *os)
729
{
730
	struct apk_installed_package *ipkg;
731
	struct apk_package *pkg;
Timo Teräs's avatar
Timo Teräs committed
732 733 734
	struct apk_file_info fi;
	char filename[256];
	apk_blob_t bfn;
735
	int r, i;
736
	time_t now = time(NULL);
737 738 739 740 741 742 743

	list_for_each_entry(ipkg, &db->installed.packages, installed_pkgs_list) {
		pkg = ipkg->pkg;

		for (i = 0; i < APK_SCRIPT_MAX; i++) {
			if (ipkg->script[i].ptr == NULL)
				continue;
744

Timo Teräs's avatar
Timo Teräs committed
745 746
			fi = (struct apk_file_info) {
				.name = filename,
747
				.size = ipkg->script[i].len,
Timo Teräs's avatar
Timo Teräs committed
748
				.mode = 0755 | S_IFREG,
749
				.mtime = now,
Timo Teräs's avatar
Timo Teräs committed
750 751 752 753 754 755 756 757 758 759
			};
			/* The scripts db expects file names in format:
			 * pkg-version.<hexdump of package checksum>.action */
			bfn = APK_BLOB_BUF(filename);
			apk_blob_push_blob(&bfn, APK_BLOB_STR(pkg->name->name));
			apk_blob_push_blob(&bfn, APK_BLOB_STR("-"));
			apk_blob_push_blob(&bfn, APK_BLOB_STR(pkg->version));
			apk_blob_push_blob(&bfn, APK_BLOB_STR("."));
			apk_blob_push_csum(&bfn, &pkg->csum);
			apk_blob_push_blob(&bfn, APK_BLOB_STR("."));
760
			apk_blob_push_blob(&bfn, APK_BLOB_STR(apk_script_types[i]));
Timo Teräs's avatar
Timo Teräs committed
761 762
			apk_blob_push_blob(&bfn, APK_BLOB_PTR_LEN("", 1));

763
			r = apk_tar_write_entry(os, &fi, ipkg->script[i].ptr);
Timo Teräs's avatar
Timo Teräs committed
764 765
			if (r < 0)
				return r;
766 767 768
		}
	}

769
	return apk_tar_write_entry(os, NULL, NULL);
770 771
}

Timo Teräs's avatar
Timo Teräs committed
772
static int apk_db_scriptdb_read_v1(struct apk_database *db, struct apk_istream *is)
773 774
{
	struct apk_package *pkg;
Timo Teräs's avatar
Timo Teräs committed
775 776 777 778 779 780
	struct {
		unsigned char md5sum[16];
		unsigned int type;
		unsigned int size;
	} hdr;
	struct apk_checksum csum;
781

782
	while (is->read(is, &hdr, sizeof(hdr)) == sizeof(hdr)) {
Timo Teräs's avatar
Timo Teräs committed
783 784 785 786
		memcpy(csum.data, hdr.md5sum, sizeof(hdr.md5sum));
		csum.type = APK_CHECKSUM_MD5;

		pkg = apk_db_get_pkg(db, &csum);
787 788
		if (pkg != NULL && pkg->ipkg != NULL)
			apk_ipkg_add_script(pkg->ipkg, is, hdr.type, hdr.size);
Timo Teräs's avatar
Timo Teräs committed
789 790
		else
			apk_istream_skip(is, hdr.size);
791 792 793 794 795
	}

	return 0;
}

Timo Teräs's avatar
Timo Teräs committed
796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829
static int apk_read_script_archive_entry(void *ctx,
					 const struct apk_file_info *ae,
					 struct apk_istream *is)
{
	struct apk_database *db = (struct apk_database *) ctx;
	struct apk_package *pkg;
	char *fncsum, *fnaction;
	struct apk_checksum csum;
	apk_blob_t blob;
	int type;

	if (!S_ISREG(ae->mode))
		return 0;

	/* The scripts db expects file names in format:
	 * pkgname-version.<hexdump of package checksum>.action */
	fnaction = memrchr(ae->name, '.', strlen(ae->name));
	if (fnaction == NULL || fnaction == ae->name)
		return 0;
	fncsum = memrchr(ae->name, '.', fnaction - ae->name - 1);
	if (fncsum == NULL)
		return 0;
	fnaction++;
	fncsum++;

	/* Parse it */
	type = apk_script_type(fnaction);
	if (type == APK_SCRIPT_INVALID)
		return 0;
	blob = APK_BLOB_PTR_PTR(fncsum, fnaction - 2);
	apk_blob_pull_csum(&blob, &csum);

	/* Attach script */
	pkg = apk_db_get_pkg(db, &csum);
830 831
	if (pkg != NULL && pkg->ipkg != NULL)
		apk_ipkg_add_script(pkg->ipkg, is, type, ae->size);
Timo Teräs's avatar
Timo Teräs committed
832 833 834 835

	return 0;
}

836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856
static int parse_triggers(void *ctx, apk_blob_t blob)
{
	struct apk_installed_package *ipkg = ctx;

	if (blob.len == 0)
		return 0;

	*apk_string_array_add(&ipkg->triggers) = apk_blob_cstr(blob);
	return 0;
}

static void apk_db_triggers_write(struct apk_database *db, struct apk_ostream *os)
{
	struct apk_installed_package *ipkg;
	char buf[APK_BLOB_CHECKSUM_BUF];
	apk_blob_t bfn;
	int i;

	list_for_each_entry(ipkg, &db->installed.triggers, trigger_pkgs_list) {
		bfn = APK_BLOB_BUF(buf);
		apk_blob_push_csum(&bfn, &ipkg->pkg->csum);
857 858
		bfn = apk_blob_pushed(APK_BLOB_BUF(buf), bfn);
		os->write(os, bfn.ptr, bfn.len);
859

860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884
		for (i = 0; i < ipkg->triggers->num; i++) {
			os->write(os, " ", 1);
			apk_ostream_write_string(os, ipkg->triggers->item[i]);
		}
		os->write(os, "\n", 1);
	}
}

static void apk_db_triggers_read(struct apk_database *db, struct apk_bstream *bs)
{
	struct apk_checksum csum;
	struct apk_package *pkg;
	struct apk_installed_package *ipkg;
	apk_blob_t l;

	while (!APK_BLOB_IS_NULL(l = bs->read(bs, APK_BLOB_STR("\n")))) {
		apk_blob_pull_csum(&l, &csum);
		apk_blob_pull_char(&l, ' ');

		pkg = apk_db_get_pkg(db, &csum);
		if (pkg == NULL || pkg->ipkg == NULL)
			continue;

		ipkg = pkg->ipkg;
		apk_blob_for_each_segment(l, " ", parse_triggers, ipkg);
885 886
		if (ipkg->triggers->num != 0 &&
		    !list_hashed(&ipkg->trigger_pkgs_list))
887 888 889 890 891
			list_add_tail(&ipkg->trigger_pkgs_list,
				      &db->installed.triggers);
	}
}

Timo Teräs's avatar
Timo Teräs committed
892
static int apk_db_read_state(struct apk_database *db, int flags)
893
{
894
	struct apk_istream *is;
895
	struct apk_bstream *bs;
896
	apk_blob_t blob;
897
	int i, r;
898 899 900 901 902 903 904 905 906

	/* Read:
	 * 1. installed repository
	 * 2. source repositories
	 * 3. master dependencies
	 * 4. package statuses
	 * 5. files db
	 * 6. script db
	 */
Timo Teräs's avatar
Timo Teräs committed
907
	if (!(flags & APK_OPENF_NO_WORLD)) {
908
		blob = apk_blob_from_file(db->root_fd, "var/lib/apk/world");
Timo Teräs's avatar
Timo Teräs committed
909 910 911 912
		if (APK_BLOB_IS_NULL(blob))
			return -ENOENT;
		apk_deps_parse(db, &db->world, blob);
		free(blob.ptr);
913

914
		for (i = 0; i < db->world->num; i++)
Timo Teräs's avatar
Timo Teräs committed
915 916
			db->world->item[i].name->flags |= APK_NAME_TOPLEVEL;
	}
917

Timo Teräs's avatar
Timo Teräs committed
918
	if (!(flags & APK_OPENF_NO_INSTALLED)) {
919
		bs = apk_bstream_from_file(db->root_fd, "var/lib/apk/installed");
920
		if (bs != NULL) {
921
			r = apk_db_index_read(db, bs, -1);
922
			bs->close(bs, NULL);
923 924
			if (r != 0)
				return -1;
Timo Teräs's avatar
Timo Teräs committed
925
		}
926

927 928 929 930 931
		bs = apk_bstream_from_file(db->root_fd, "var/lib/apk/triggers");
		if (bs != NULL) {
			apk_db_triggers_read(db, bs);
			bs->close(bs, NULL);
		}
932 933
	}

Timo Teräs's avatar
Timo Teräs committed
934
	if (!(flags & APK_OPENF_NO_SCRIPTS)) {
935
		is = apk_istream_from_file(db->root_fd, "var/lib/apk/scripts.tar");
Timo Teräs's avatar
Timo Teräs committed
936
		if (is != NULL) {
937
			apk_tar_parse(is, apk_read_script_archive_entry, db,
938
				      FALSE, &db->id_cache);
Timo Teräs's avatar
Timo Teräs committed
939
		} else {
940
			is = apk_istream_from_file(db->root_fd, "var/lib/apk/scripts");
Timo Teräs's avatar
Timo Teräs committed
941 942
			if (is != NULL)
				apk_db_scriptdb_read_v1(db, is);
Timo Teräs's avatar
Timo Teräs committed
943
		}
Timo Teräs's avatar
Timo Teräs committed
944 945
		if (is != NULL)
			is->close(is);
946 947 948 949 950
	}

	return 0;
}

951 952 953 954
struct index_write_ctx {
	struct apk_ostream *os;
	int count;
	int force;
955
	int write_arch;
956 957 958 959 960 961 962 963 964 965 966
};

static int write_index_entry(apk_hash_item item, void *ctx)
{
	struct index_write_ctx *iwctx = (struct index_write_ctx *) ctx;
	struct apk_package *pkg = (struct apk_package *) item;
	int r;

	if (!iwctx->force && pkg->filename == NULL)
		return 0;

967
	r = apk_pkg_write_index_entry(pkg, iwctx->os, iwctx->write_arch);
968 969 970 971 972 973 974 975 976 977 978 979
	if (r < 0)
		return r;

	if (iwctx->os->write(iwctx->os, "\n", 1) != 1)
		return -1;

	iwctx->count++;
	return 0;
}

static int apk_db_index_write_nr_cache(struct apk_database *db)
{
980
	struct index_write_ctx ctx = { NULL, 0, TRUE, TRUE };
981
	struct apk_installed_package *ipkg;
982 983 984 985 986 987 988 989
	struct apk_ostream *os;
	int r;

	if (!apk_db_cache_active(db))
		return 0;

	/* Write list of installed non-repository packages to
	 * cached index file */
990 991 992 993
	os = apk_ostream_to_file(db->cache_fd,
				 "installed",
				 "installed.new",
				 0644);
994 995 996
	if (os == NULL)
		return -1;

997
	ctx.os = os;
998 999
	list_for_each_entry(ipkg, &db->installed.packages, installed_pkgs_list) {
		if (ipkg->pkg->repos != 0)
1000
			continue;
1001
		r = write_index_entry(ipkg->pkg, &ctx);
1002 1003 1004
		if (r != 0)
			return r;
	}
1005 1006 1007
	r = os->close(os);
	if (r < 0)
		return r;
1008 1009 1010 1011 1012 1013

	return ctx.count;
}

int apk_db_index_write(struct apk_database *db, struct apk_ostream *os)
{
1014
	struct index_write_ctx ctx = { os, 0, FALSE, FALSE };
1015 1016 1017 1018 1019 1020

	apk_hash_foreach(&db->available.packages, write_index_entry, &ctx);

	return ctx.count;
}

1021 1022 1023 1024 1025 1026 1027 1028
static int add_protected_path(void *ctx, apk_blob_t blob)
{
	struct apk_database *db = (struct apk_database *) ctx;

	*apk_string_array_add(&db->protected_paths) = apk_blob_cstr(blob);
	return 0;
}

1029 1030 1031 1032
static int apk_db_create(struct apk_database *db)
{
	int fd;

1033 1034 1035 1036 1037 1038
	mkdirat(db->root_fd, "tmp", 01777);
	mkdirat(db->root_fd, "dev", 0755);
	mknodat(db->root_fd, "dev/null", 0666, makedev(1, 3));
	mkdirat(db->root_fd, "var", 0755);
	mkdirat(db->root_fd, "var/lib", 0755);
	mkdirat(db->root_fd, "var/lib/apk", 0755);
1039 1040
	mkdirat(db->root_fd, "var/cache", 0755);
	mkdirat(db->root_fd, "var/cache/misc", 0755);
1041

1042
	fd = openat(db->root_fd, "var/lib/apk/world", O_CREAT|O_RDWR|O_TRUNC|O_CLOEXEC, 0644);
1043 1044 1045 1046 1047 1048 1049
	if (fd < 0)
		return -errno;
	close(fd);

	return 0;
}

1050 1051 1052 1053
static void handle_alarm(int sig)
{
}

1054
int apk_db_open(struct apk_database *db, struct apk_db_options *dbopts)
1055
{
1056 1057
	const char *msg = NULL;
	struct apk_repository_list *repo = NULL;
Timo Teräs's avatar
Timo Teräs committed
1058
	struct apk_bstream *bs;
1059
	struct stat64 st;
1060
	apk_blob_t blob;
1061
	int r;
1062

1063
	memset(db, 0, sizeof(*db));
1064 1065 1066 1067
	if (apk_flags & APK_SIMULATE) {
		dbopts->open_flags &= ~(APK_OPENF_CREATE | APK_OPENF_WRITE);
		dbopts->open_flags |= APK_OPENF_READ;
	}
1068 1069 1070 1071 1072 1073
	if (dbopts->open_flags == 0) {
		msg = "Invalid open flags (internal error)";
		r = -1;
		goto ret_r;
	}

1074 1075
	apk_hash_init(&db->available.names, &pkg_name_hash_ops, 1000);
	apk_hash_init(&db->available.packages, &pkg_info_hash_ops, 4000);
1076 1077
	apk_hash_init(&db->installed.dirs, &dir_hash_ops, 2000);
	apk_hash_init(&db->installed.files, &file_hash_ops, 10000);
1078
	list_init(&db->installed.packages);
1079
	list_init(&db->installed.triggers);
1080 1081
	apk_dependency_array_init(&db->world);
	apk_string_array_init(&db->protected_paths);
1082
	db->cache_dir = apk_static_cache_dir;
1083
	db->permanent = 1;
1084

1085
	db->root = strdup(dbopts->root ?: "/");
1086
	db->root_fd = openat(AT_FDCWD, db->root, O_RDONLY | O_CLOEXEC);
1087
	if (db->root_fd < 0 && (dbopts->open_flags & APK_OPENF_CREATE)) {
1088
		mkdirat(AT_FDCWD, db->root, 0755);
1089
		db->root_fd = openat(AT_FDCWD, db->root, O_RDONLY | O_CLOEXEC);
1090 1091 1092 1093 1094 1095 1096 1097 1098
	}
	if (db->root_fd < 0) {
		msg = "Unable to open root";
		goto ret_errno;
	}
	if (fstat64(db->root_fd, &st) != 0 || major(st.st_dev) == 0)
		db->permanent = 0;

	if (fstatat64(db->root_fd, apk_linked_cache_dir, &st, 0) == 0 &&
1099
	    S_ISDIR(st.st_mode) && major(st.st_dev) != 0)
1100 1101
		db->cache_dir = apk_linked_cache_dir;

1102 1103
	apk_id_cache_init(&db->id_cache, db->root_fd);

1104
	if (dbopts->open_flags & APK_OPENF_WRITE) {
1105
		db->lock_fd = openat(db->root_fd, "var/lib/apk/lock",
1106
				     O_CREAT | O_RDWR | O_CLOEXEC, 0400);
1107
		if (db->lock_fd < 0 && errno == ENOENT &&
1108
		    (dbopts->open_flags & APK_OPENF_CREATE)) {
1109 1110 1111 1112 1113
			r = apk_db_create(db);
			if (r != 0) {
				msg = "Unable to create database";
				goto ret_r;
			}
1114
			db->lock_fd = openat(db->root_fd, "var/lib/apk/lock",
1115
					     O_CREAT | O_RDWR | O_CLOEXEC, 0400);
1116 1117 1118 1119
		}
		if (db->lock_fd < 0 ||
		    flock(db->lock_fd, LOCK_EX | LOCK_NB) < 0) {
			msg = "Unable to lock database";
1120
			if (dbopts->lock_wait) {
1121 1122 1123 1124 1125 1126 1127 1128
				struct sigaction sa, old_sa;

				apk_message("Waiting for repository lock");
				memset(&sa, 0, sizeof sa);
				sa.sa_handler = handle_alarm;
				sa.sa_flags   = SA_ONESHOT;
				sigaction(SIGALRM, &sa, &old_sa);

1129
				alarm(dbopts->lock_wait);
1130
				if (flock(db->lock_fd, LOCK_EX) < 0)
1131
					goto ret_errno;
1132 1133 1134 1135 1136

				alarm(0);
				sigaction(SIGALRM, &old_sa, NULL);
			} else
				goto ret_errno;
1137 1138
		}
	}
1139

1140
	blob = APK_BLOB_STR("etc:*etc/init.d");
1141 1142
	apk_blob_for_each_segment(blob, ":", add_protected_path, db);

1143 1144
	db->arch = apk_arch;

1145
	db->cache_fd = openat(db->root_fd, db->cache_dir, O_RDONLY | O_CLOEXEC);
1146
	mkdirat(db->cache_fd, "tmp", 0644);
1147
	db->cachetmp_fd = openat(db->cache_fd, "tmp", O_RDONLY | O_CLOEXEC);
1148 1149
	db->keys_fd = openat(db->root_fd,
			     dbopts->keys_dir ?: "etc/apk/keys",
1150
			     O_RDONLY | O_CLOEXEC);
1151

Timo Teräs's avatar
Timo Teräs committed
1152 1153 1154 1155 1156 1157
	if (apk_flags & APK_OVERLAY_FROM_STDIN) {
		apk_flags &= ~APK_OVERLAY_FROM_STDIN;
		apk_db_read_overlay(db, apk_bstream_from_istream(
				apk_istream_from_fd(STDIN_FILENO)));
	}

1158 1159
	r = apk_db_read_state(db, dbopts->open_flags);
	if (r == -ENOENT && (dbopts->open_flags & APK_OPENF_CREATE)) {
1160
		r = apk_db_create(db);
Timo Teräs's avatar
Timo Teräs committed
1161
		if (r != 0) {
1162
			msg = "Unable to create database";
Timo Teräs's avatar
Timo Teräs committed
1163
			goto ret_r;
1164
		}
1165
		r = apk_db_read_state(db, dbopts->open_flags);
1166 1167 1168 1169
	}
	if (r != 0) {
		msg = "Unable to read database state";
		goto ret_r;
1170 1171
	}

1172
	if (!(dbopts->open_flags & APK_OPENF_NO_INSTALLED_REPO)) {
1173 1174 1175 1176 1177 1178 1179
		if (apk_db_cache_active(db)) {
			bs = apk_bstream_from_file(db->cache_fd, "installed");
			if (bs != NULL) {
				apk_db_index_read(db, bs, -2);
				bs->close(bs, NULL);
			}
		}
1180 1181
	}
	if (!(dbopts->open_flags & APK_OPENF_NO_SYS_REPOS)) {
1182 1183
		list_for_each_entry(repo, &dbopts->repository_list, list)
			apk_db_add_repository(db, APK_BLOB_STR(repo->url));
1184 1185 1186
		blob = apk_blob_from_file(
			db->root_fd,
			dbopts->repositories_file ?: "etc/apk/repositories");
1187
		if (!APK_BLOB_IS_NULL(blob)) {
1188
			apk_blob_for_each_segment(
1189 1190 1191 1192
				blob, "\n",
				apk_db_add_repository, db);
			free(blob.ptr);
		}
1193 1194
		if (apk_flags & APK_UPDATE_CACHE)
			apk_db_index_write_nr_cache(db);
1195
	}
1196 1197 1198
	if (db->bad_repos && !(apk_flags & APK_FORCE)) {
		apk_error("Aborting due to some repositories failed to load. Use --force to ignore this error.");
		r = -EBADMSG;
1199 1200
		goto ret_r;
	}
1201

1202 1203 1204 1205 1206 1207 1208
	if (db->compat_newfeatures) {
		apk_warning("This apk-tools is OLD! Some packages %s.",
			    db->compat_notinstallable ?
			    "are not installable" :
			    "might not function properly");
	}

1209
	return 0;
1210 1211 1212 1213

ret_errno:
	r = -errno;
ret_r:
1214 1215
	if (msg != NULL)
		apk_error("%s: %s", msg, strerror(-r));
1216
	apk_db_close(db);
1217

1218
	return r;
1219 1220
}

1221 1222 1223 1224 1225
struct write_ctx {
	struct apk_database *db;
	int fd;
};

1226
int apk_db_write_config(struct apk_database *db)
1227
{
Timo Teräs's avatar
Timo Teräs committed
1228
	struct apk_ostream *os;
1229
	int r;
1230

1231
	if ((apk_flags & APK_SIMULATE) || db->root == NULL)
1232
		return 0;
1233

1234 1235 1236 1237 1238
	if (db->lock_fd == 0) {
		apk_error("Refusing to write db without write lock!");
		return -1;
	}

1239 1240 1241 1242
	os = apk_ostream_to_file(db->root_fd,
				 "var/lib/apk/world",
				 "var/lib/apk/world.new",
				 0644);
Timo Teräs's avatar
Timo Teräs committed
1243
	if (os == NULL)
1244
		return -1;
1245

1246 1247
	apk_deps_write(db->world, os);
	os->write(os, "\n", 1);
1248 1249 1250
	r = os->close(os);
	if (r < 0)
		return r;
1251

1252 1253 1254 1255
	os = apk_ostream_to_file(db->root_fd,
				 "var/lib/apk/installed",
				 "var/lib/apk/installed.new",
				 0644);
Timo Teräs's avatar
Timo Teräs committed
1256
	if (os == NULL)
1257
		return -1;
Timo Teräs's avatar
Timo Teräs committed
1258
	apk_db_write_fdb(db, os);
1259 1260 1261
	r = os->close(os);
	if (r < 0)
		return r;
1262

1263 1264 1265 1266
	os = apk_ostream_to_file(db->root_fd,
				 "var/lib/apk/scripts.tar",
				 "var/lib/apk/scripts.tar.new",
				 0644);
Timo Teräs's avatar
Timo Teräs committed
1267
	if (os == NULL)
1268
		return -1;
Timo Teräs's avatar
Timo Teräs committed
1269
	apk_db_scriptdb_write(db, os);
1270 1271 1272
	r = os->close(os);
	if (r < 0)
		return r;
Timo Teräs's avatar
Timo Teräs committed
1273

1274
	unlinkat(db->root_fd, "var/lib/apk/scripts", 0);
1275
	apk_db_index_write_nr_cache(db);
1276

1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287
	os = apk_ostream_to_file(db->root_fd,
				 "var/lib/apk/triggers",
				 "var/lib/apk/triggers.new",
				 0644);
	if (os == NULL)
		return -1;
	apk_db_triggers_write(db, os);
	r = os->close(os);
	if (r < 0)
		return r;

1288 1289 1290
	return 0;
}

1291
void apk_db_close(struct apk_database *db)
1292
{