From ea901526648c43ef8e961b3d7e051b9ca14b65ca Mon Sep 17 00:00:00 2001 From: Timo Teras Date: Fri, 31 Jul 2009 16:08:09 +0300 Subject: apk: use *at instead of chdir+normal file syscall this way we never change cwd, and relative filenames are always parsed consistently. this also helps filename construction in many places. this patch also changes '--root' to override location of all configuration to be in the new root. previously it depended on the file which one was used. --- src/Makefile | 1 + src/add.c | 2 +- src/apk.c | 3 +- src/apk_archive.h | 5 +- src/apk_database.h | 12 +- src/apk_defines.h | 2 +- src/apk_io.h | 19 +-- src/apk_package.h | 5 +- src/archive.c | 55 ++++----- src/audit.c | 7 +- src/cache.c | 63 +++++----- src/database.c | 330 ++++++++++++++++++++++++----------------------------- src/fetch.c | 54 ++++----- src/index.c | 8 +- src/io.c | 34 +++--- src/package.c | 67 ++++++++--- src/state.c | 2 +- src/url.c | 21 ++-- src/verify.c | 11 +- 19 files changed, 360 insertions(+), 341 deletions(-) diff --git a/src/Makefile b/src/Makefile index 96e36b3..e0e97f1 100644 --- a/src/Makefile +++ b/src/Makefile @@ -9,6 +9,7 @@ apk-objs := state.o database.o package.o archive.o \ version.o io.o url.o gunzip.o blob.o hash.o apk.o \ add.o del.o update.o info.o search.o upgrade.o \ cache.o ver.o index.o fetch.o audit.o verify.o +CFLAGS += -D_ATFILE_SOURCE CFLAGS_apk.o := -DAPK_VERSION=\"$(FULL_VERSION)\" progs-$(STATIC) += apk.static diff --git a/src/add.c b/src/add.c index 003fcfc..e89a4cd 100644 --- a/src/add.c +++ b/src/add.c @@ -101,7 +101,7 @@ static int add_main(void *ctx, int argc, char **argv) goto err; apk_sign_ctx_init(&sctx, APK_SIGN_VERIFY_AND_GENERATE, - NULL); + NULL, db.keys_fd); r = apk_pkg_read(&db, argv[i], &sctx, &pkg); apk_sign_ctx_free(&sctx); if (r != 0) { diff --git a/src/apk.c b/src/apk.c index a21427f..122f9a7 100644 --- a/src/apk.c +++ b/src/apk.c @@ -26,7 +26,7 @@ const char *apk_root; struct apk_repository_url apk_repository_list; -int apk_verbosity = 1, apk_cwd_fd, apk_wait; +int apk_verbosity = 1, apk_wait; unsigned int apk_flags = 0; static struct apk_option generic_options[] = { @@ -292,7 +292,6 @@ int main(int argc, char **argv) struct apk_repository_url *repo = NULL; umask(0); - apk_cwd_fd = open(".", O_RDONLY); apk_root = getenv("ROOT"); list_init(&apk_repository_list.list); diff --git a/src/apk_archive.h b/src/apk_archive.h index 320db5e..f983203 100644 --- a/src/apk_archive.h +++ b/src/apk_archive.h @@ -27,9 +27,8 @@ int apk_tar_write_entry(struct apk_ostream *, const struct apk_file_info *ae, char *data); int apk_tar_write_padding(struct apk_ostream *, const struct apk_file_info *ae); -int apk_archive_entry_extract(const struct apk_file_info *ae, - struct apk_istream *is, - const char *to, +int apk_archive_entry_extract(int atfd, const struct apk_file_info *ae, + const char *suffix, struct apk_istream *is, apk_progress_cb cb, void *cb_ctx); #endif diff --git a/src/apk_database.h b/src/apk_database.h index 241719d..094725d 100644 --- a/src/apk_database.h +++ b/src/apk_database.h @@ -80,7 +80,7 @@ struct apk_repository { struct apk_database { char *root; - int root_fd, lock_fd; + int root_fd, lock_fd, cache_fd, cachetmp_fd, keys_fd; unsigned name_id, num_repos; const char *cache_dir; int permanent; @@ -134,7 +134,6 @@ struct apk_db_file *apk_db_file_query(struct apk_database *db, int apk_db_open(struct apk_database *db, const char *root, unsigned int flags); int apk_db_write_config(struct apk_database *db); void apk_db_close(struct apk_database *db); -int apk_db_cache_active(struct apk_database *db); int apk_db_permanent(struct apk_database *db); struct apk_package *apk_db_pkg_add(struct apk_database *db, struct apk_package *pkg); @@ -147,10 +146,11 @@ 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_cache_download(struct apk_database *db, struct apk_checksum *csum, - const char *url, const char *item, int verify); -int apk_cache_exists(struct apk_database *db, struct apk_checksum *csum, - const char *item); + +int apk_db_cache_active(struct apk_database *db); +void apk_cache_format_index(apk_blob_t to, struct apk_repository *repo, int ver); +int apk_cache_download(struct apk_database *db, const char *url, + const char *item, const char *cache_item, int verify); int apk_db_install_pkg(struct apk_database *db, struct apk_package *oldpkg, diff --git a/src/apk_defines.h b/src/apk_defines.h index 2ce3535..0dc0c20 100644 --- a/src/apk_defines.h +++ b/src/apk_defines.h @@ -48,7 +48,7 @@ (type *)( (char *)__mptr - offsetof(type,member) );}) #endif -extern int apk_cwd_fd, apk_verbosity, apk_wait; +extern int apk_verbosity, apk_wait; extern unsigned int apk_flags; #define APK_FORCE 0x0001 diff --git a/src/apk_io.h b/src/apk_io.h index b76385c..759bec4 100644 --- a/src/apk_io.h +++ b/src/apk_io.h @@ -66,8 +66,8 @@ struct apk_ostream *apk_ostream_gzip(struct apk_ostream *); struct apk_ostream *apk_ostream_counter(off_t *); struct apk_istream *apk_istream_from_fd(int fd); -struct apk_istream *apk_istream_from_file(const char *file); -struct apk_istream *apk_istream_from_file_gz(const char *file); +struct apk_istream *apk_istream_from_file(int atfd, const char *file); +struct apk_istream *apk_istream_from_file_gz(int atfd, const char *file); struct apk_istream *apk_istream_from_url(const char *url); struct apk_istream *apk_istream_from_url_gz(const char *url); size_t apk_istream_skip(struct apk_istream *istream, size_t size); @@ -76,20 +76,21 @@ size_t apk_istream_splice(void *stream, int fd, size_t size, struct apk_bstream *apk_bstream_from_istream(struct apk_istream *istream); struct apk_bstream *apk_bstream_from_fd(int fd); -struct apk_bstream *apk_bstream_from_file(const char *file); +struct apk_bstream *apk_bstream_from_file(int atfd, const char *file); struct apk_bstream *apk_bstream_from_url(const char *url); -struct apk_bstream *apk_bstream_tee(struct apk_bstream *from, const char *to); +struct apk_bstream *apk_bstream_tee(struct apk_bstream *from, int atfd, const char *to); struct apk_ostream *apk_ostream_to_fd(int fd); -struct apk_ostream *apk_ostream_to_file(const char *file, mode_t mode); -struct apk_ostream *apk_ostream_to_file_gz(const char *file, mode_t mode); +struct apk_ostream *apk_ostream_to_file(int atfd, const char *file, mode_t mode); +struct apk_ostream *apk_ostream_to_file_gz(int atfd, const char *file, mode_t mode); size_t apk_ostream_write_string(struct apk_ostream *ostream, const char *string); apk_blob_t apk_blob_from_istream(struct apk_istream *istream, size_t size); -apk_blob_t apk_blob_from_file(const char *file); +apk_blob_t apk_blob_from_file(int atfd, const char *file); -int apk_file_get_info(const char *filename, int checksum, struct apk_file_info *fi); -int apk_url_download(const char *url, const char *file); +int apk_file_get_info(int atfd, const char *filename, int checksum, + struct apk_file_info *fi); +int apk_url_download(const char *url, int atfd, const char *file); const char *apk_url_local_file(const char *url); #endif diff --git a/src/apk_package.h b/src/apk_package.h index 96d7840..791df93 100644 --- a/src/apk_package.h +++ b/src/apk_package.h @@ -38,6 +38,7 @@ struct apk_name; #define APK_SIGN_VERIFY_AND_GENERATE 5 struct apk_sign_ctx { + int keys_fd; int action; const EVP_MD *md; int num_signatures; @@ -97,7 +98,7 @@ APK_ARRAY(apk_package_array, struct apk_package *); extern const char *apk_script_types[]; void apk_sign_ctx_init(struct apk_sign_ctx *ctx, int action, - struct apk_checksum *identity); + struct apk_checksum *identity, int keys_fd); void apk_sign_ctx_free(struct apk_sign_ctx *ctx); int apk_sign_ctx_process_file(struct apk_sign_ctx *ctx, const struct apk_file_info *fi, @@ -121,6 +122,8 @@ void apk_deps_parse(struct apk_database *db, int apk_deps_write(struct apk_dependency_array *deps, struct apk_ostream *os); int apk_script_type(const char *name); +void apk_pkg_format_plain(struct apk_package *pkg, apk_blob_t to); +void apk_pkg_format_cache(struct apk_package *pkg, apk_blob_t to); struct apk_package *apk_pkg_new(void); int apk_pkg_read(struct apk_database *db, const char *name, struct apk_sign_ctx *ctx, struct apk_package **pkg); diff --git a/src/archive.c b/src/archive.c index 31c0909..e20caa7 100644 --- a/src/archive.c +++ b/src/archive.c @@ -309,29 +309,28 @@ int apk_tar_write_padding(struct apk_ostream *os, const struct apk_file_info *ae return 0; } -int apk_archive_entry_extract(const struct apk_file_info *ae, - struct apk_istream *is, - const char *fn, apk_progress_cb cb, - void *cb_ctx) +int apk_archive_entry_extract(int atfd, const struct apk_file_info *ae, + const char *suffix, struct apk_istream *is, + apk_progress_cb cb, void *cb_ctx) { - struct utimbuf utb; - int r = -1, fd; + char *fn = ae->name; + int fd, r = -1, atflags = 0; - if (fn == NULL) - fn = ae->name; - - /* BIG HONKING FIXME */ - unlink(fn); + if (suffix != NULL) { + fn = alloca(PATH_MAX); + snprintf(fn, PATH_MAX, "%s%s", ae->name, suffix); + } + unlinkat(atfd, fn, 0); switch (ae->mode & S_IFMT) { case S_IFDIR: - r = mkdir(fn, ae->mode & 07777); + r = mkdirat(atfd, fn, ae->mode & 07777); if (r < 0 && errno == EEXIST) r = 0; break; case S_IFREG: if (ae->link_target == NULL) { - fd = open(fn, O_RDWR | O_CREAT, ae->mode & 07777); + fd = openat(atfd, fn, O_RDWR | O_CREAT, ae->mode & 07777); if (fd < 0) { r = -1; break; @@ -341,27 +340,28 @@ int apk_archive_entry_extract(const struct apk_file_info *ae, r = 0; close(fd); } else { - char link_target[PATH_MAX]; - snprintf(link_target, sizeof(link_target), - "%s.apk-new", ae->link_target); - r = link(link_target, fn); + char *link_target = ae->link_target; + if (suffix != NULL) { + link_target = alloca(PATH_MAX); + snprintf(link_target, PATH_MAX, "%s%s", + ae->link_target, suffix); + } + r = linkat(atfd, link_target, atfd, fn, 0); } break; case S_IFLNK: - r = symlink(ae->link_target, fn); + r = symlinkat(ae->link_target, atfd, fn); + atflags |= AT_SYMLINK_NOFOLLOW; break; case S_IFSOCK: case S_IFBLK: case S_IFCHR: case S_IFIFO: - r = mknod(fn, ae->mode & 07777, ae->device); + r = mknodat(atfd, fn, ae->mode & 07777, ae->device); break; } if (r == 0) { - if (!S_ISLNK(ae->mode)) - r = chown(fn, ae->uid, ae->gid); - else - r = lchown(fn, ae->uid, ae->gid); + r = fchownat(atfd, fn, ae->uid, ae->gid, atflags); if (r < 0) { apk_error("Failed to set ownership on %s: %s", fn, strerror(errno)); @@ -370,7 +370,7 @@ int apk_archive_entry_extract(const struct apk_file_info *ae, /* chown resets suid bit so we need set it again */ if (ae->mode & 07000) { - r = chmod(fn, ae->mode & 07777); + r = fchmodat(atfd, fn, ae->mode & 07777, atflags); if (r < 0) { apk_error("Failed to set file permissions " "on %s: %s", @@ -381,8 +381,11 @@ int apk_archive_entry_extract(const struct apk_file_info *ae, if (!S_ISLNK(ae->mode)) { /* preserve modification time */ - utb.actime = utb.modtime = ae->mtime; - r = utime(fn, &utb); + struct timespec times[2]; + + times[0].tv_sec = times[1].tv_sec = ae->mtime; + times[0].tv_nsec = times[1].tv_nsec = 0; + r = utimensat(atfd, fn, times, atflags); if (r < 0) { apk_error("Failed to preserve modification time on %s: %s", fn, strerror(errno)); diff --git a/src/audit.c b/src/audit.c index 76bd492..6191a2c 100644 --- a/src/audit.c +++ b/src/audit.c @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -42,7 +43,7 @@ static int audit_directory(apk_hash_item item, void *ctx) if (!(actx->type & AUDIT_BACKUP) && (dbd->flags & APK_DBDIRF_PROTECTED)) return 0; - dir = opendir(dbd->name); + dir = fdopendir(openat(db->root_fd, dbd->name, O_RDONLY)); if (dir == NULL) return 0; @@ -53,7 +54,7 @@ static int audit_directory(apk_hash_item item, void *ctx) snprintf(tmp, sizeof(tmp), "%s/%s", dbd->name, de->d_name); - if (apk_file_get_info(tmp, APK_CHECKSUM_NONE, &fi) < 0) + if (apk_file_get_info(db->root_fd, tmp, APK_CHECKSUM_NONE, &fi) < 0) continue; if (!(actx->type & AUDIT_SYSTEM) && @@ -70,7 +71,7 @@ static int audit_directory(apk_hash_item item, void *ctx) dbf = apk_db_file_query(db, bdir, APK_BLOB_STR(de->d_name)); if (dbf != NULL) { if (dbf->csum.type != APK_CHECKSUM_NONE && - apk_file_get_info(tmp, dbf->csum.type, &fi) == 0 && + apk_file_get_info(db->root_fd, tmp, dbf->csum.type, &fi) == 0 && apk_checksum_compare(&fi.csum, &dbf->csum) == 0) continue; diff --git a/src/cache.c b/src/cache.c index ac2281e..c961fc9 100644 --- a/src/cache.c +++ b/src/cache.c @@ -28,7 +28,7 @@ static int cache_download(struct apk_database *db) struct apk_state *state; struct apk_change *change; struct apk_package *pkg; - char pkgfile[256]; + char item[PATH_MAX], cacheitem[PATH_MAX]; int i, r; if (db->world == NULL) @@ -38,24 +38,27 @@ static int cache_download(struct apk_database *db) 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'", - db->world->item[i].name->name); + 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; - snprintf(pkgfile, sizeof(pkgfile), "%s-%s.apk", - pkg->name->name, pkg->version); - if (apk_cache_exists(db, &pkg->csum, pkgfile)) + + 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; - r = apk_cache_download(db, &pkg->csum, db->repos[i].url, - pkgfile, APK_SIGN_VERIFY_IDENTITY); + 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; } @@ -68,54 +71,54 @@ err: static int cache_clean(struct apk_database *db) { + char tmp[PATH_MAX]; DIR *dir; struct dirent *de; - char path[256], csum[APK_CACHE_CSUM_BYTES]; int delete, i; apk_blob_t b, bname, bver; struct apk_name *name; - snprintf(path, sizeof(path), "%s/%s", db->root, db->cache_dir); - if (chdir(path) != 0) - return -1; - - dir = opendir(path); + 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); - apk_blob_pull_hexdump(&b, APK_BLOB_BUF(csum)); - apk_blob_pull_char(&b, '.'); - if (apk_blob_compare(b, APK_BLOB_STR(apk_index_gz)) == 0 || - apk_blob_compare(b, APK_BLOB_STR(apkindex_tar_gz)) == 0) { + 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++) { - if (memcmp(db->repos[i].csum.data, - csum, APK_CACHE_CSUM_BYTES) != 0) - continue; + 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 if (b.len > 4 && - memcmp(b.ptr+b.len-4, ".apk", 4) == 0) { + } else { /* Package - search for it */ - if (apk_pkg_parse_name(b, &bname, &bver) < 0) - break; - 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]; - if (memcmp(pkg->csum.data, csum, APK_CACHE_CSUM_BYTES) != 0) + + apk_pkg_format_cache(pkg, APK_BLOB_BUF(tmp)); + if (apk_blob_compare(b, APK_BLOB_STR(tmp)) != 0) continue; + delete = 0; break; } @@ -126,7 +129,7 @@ static int cache_clean(struct apk_database *db) if (apk_verbosity >= 2) apk_message("deleting %s", de->d_name); if (!(apk_flags & APK_SIMULATE)) - unlink(de->d_name); + unlinkat(db->cache_fd, de->d_name, 0); } } @@ -152,7 +155,7 @@ static int cache_main(void *ctx, int argc, char **argv) else return -EINVAL; - r = apk_db_open(&db, apk_root, + r = apk_db_open(&db, apk_root, APK_OPENF_READ | APK_OPENF_NO_SCRIPTS | APK_OPENF_NO_INSTALLED); if (r != 0) return r; diff --git a/src/database.c b/src/database.c index 15e4730..e71f4c2 100644 --- a/src/database.c +++ b/src/database.c @@ -285,16 +285,16 @@ static void apk_db_diri_set(struct apk_db_dir_instance *diri, mode_t mode, diri->gid = gid; } -static void apk_db_diri_mkdir(struct apk_db_dir_instance *diri) +static void apk_db_diri_mkdir(struct apk_database *db, struct apk_db_dir_instance *diri) { - if (mkdir(diri->dir->name, diri->mode) == 0) - chown(diri->dir->name, diri->uid, diri->gid); + if (mkdirat(db->root_fd, diri->dir->name, diri->mode) == 0) + fchownat(db->root_fd, diri->dir->name, diri->uid, diri->gid, 0); } -static void apk_db_diri_rmdir(struct apk_db_dir_instance *diri) +static void apk_db_diri_rmdir(struct apk_database *db, struct apk_db_dir_instance *diri) { if (diri->dir->refs == 1) - rmdir(diri->dir->name); + unlinkat(db->root_fd, diri->dir->name, 1); } static void apk_db_diri_free(struct apk_database *db, @@ -409,21 +409,62 @@ struct apk_package *apk_db_pkg_add(struct apk_database *db, struct apk_package * return idb; } -static void apk_db_cache_get_name(char *buf, size_t bufsz, - struct apk_database *db, - struct apk_checksum *csum, - const char *file, int temp) +void apk_cache_format_index(apk_blob_t to, struct apk_repository *repo, int ver) { - char csumstr[APK_CACHE_CSUM_BYTES*2+1]; - apk_blob_t bbuf = APK_BLOB_BUF(csumstr); + /* 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)); +} + +int apk_cache_download(struct apk_database *db, const char *url, + const char *item, const char *cacheitem, int verify) +{ + char fullurl[PATH_MAX]; + int r; + + snprintf(fullurl, sizeof(fullurl), "%s%s%s", + url, url[strlen(url)-1] == '/' ? "" : "/", item); + 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); + + r = apk_tar_parse(is, apk_sign_ctx_verify_tar, &sctx, FALSE); + is->close(is); + apk_sign_ctx_free(&sctx); + if (r != 0) { + unlinkat(db->cachetmp_fd, cacheitem, 0); + return r; + } + } - apk_blob_push_hexdump(&bbuf, - APK_BLOB_PTR_LEN((char *) csum->data, - APK_CACHE_CSUM_BYTES)); - apk_blob_push_blob(&bbuf, APK_BLOB_PTR_LEN("", 1)); + if (renameat(db->cachetmp_fd, cacheitem, db->cache_fd, cacheitem) < 0) + return -errno; - snprintf(buf, bufsz, "%s/%s/%s.%s%s", - db->root, db->cache_dir, csumstr, file, temp ? ".new" : ""); + return 0; } int apk_db_index_read(struct apk_database *db, struct apk_bstream *bs, int repo) @@ -690,10 +731,8 @@ static int apk_db_read_state(struct apk_database *db, int flags) * 5. files db * 6. script db */ - fchdir(db->root_fd); - if (!(flags & APK_OPENF_NO_WORLD)) { - blob = apk_blob_from_file("var/lib/apk/world"); + blob = apk_blob_from_file(db->root_fd, "var/lib/apk/world"); if (APK_BLOB_IS_NULL(blob)) return -ENOENT; apk_deps_parse(db, &db->world, blob); @@ -704,13 +743,13 @@ static int apk_db_read_state(struct apk_database *db, int flags) } if (!(flags & APK_OPENF_NO_INSTALLED)) { - bs = apk_bstream_from_file("var/lib/apk/installed"); + bs = apk_bstream_from_file(db->root_fd, "var/lib/apk/installed"); if (bs != NULL) { apk_db_index_read(db, bs, -1); bs->close(bs, NULL); } - bs = apk_bstream_from_file("etc/apk/cache/installed"); + bs = apk_bstream_from_file(db->cache_fd, "installed"); if (bs != NULL) { apk_db_index_read(db, bs, -2); bs->close(bs, NULL); @@ -718,12 +757,12 @@ static int apk_db_read_state(struct apk_database *db, int flags) } if (!(flags & APK_OPENF_NO_SCRIPTS)) { - is = apk_istream_from_file("var/lib/apk/scripts.tar"); + is = apk_istream_from_file(db->root_fd, "var/lib/apk/scripts.tar"); if (is != NULL) { apk_tar_parse(is, apk_read_script_archive_entry, db, FALSE); } else { - is = apk_istream_from_file("var/lib/apk/scripts"); + is = apk_istream_from_file(db->root_fd, "var/lib/apk/scripts"); if (is != NULL) apk_db_scriptdb_read_v1(db, is); } @@ -772,10 +811,11 @@ static int apk_db_index_write_nr_cache(struct apk_database *db) /* Write list of installed non-repository packages to * cached index file */ - ctx.os = os = apk_ostream_to_file("etc/apk/cache/installed.new", 0644); + os = apk_ostream_to_file(db->cache_fd, "installed.new", 0644); if (os == NULL) return -1; + ctx.os = os; list_for_each_entry(pkg, &db->installed.packages, installed_pkgs_list) { if (pkg->repos != 0) continue; @@ -785,8 +825,8 @@ static int apk_db_index_write_nr_cache(struct apk_database *db) } os->close(os); - if (rename("etc/apk/cache/installed.new", - "etc/apk/cache/installed") < 0) + if (renameat(db->cache_fd, "installed.new", + db->cache_fd, "installed") < 0) return -errno; return ctx.count; @@ -815,15 +855,14 @@ static int apk_db_create(struct apk_database *db) "apk-tools alpine-conf"); int fd; - fchdir(db->root_fd); - mkdir("tmp", 01777); - mkdir("dev", 0755); - mknod("dev/null", 0666, makedev(1, 3)); - mkdir("var", 0755); - mkdir("var/lib", 0755); - mkdir("var/lib/apk", 0755); + 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); - fd = creat("var/lib/apk/world", 0644); + fd = openat(db->root_fd, "var/lib/apk/world", O_CREAT|O_RDWR|O_TRUNC, 0644); if (fd < 0) return -errno; write(fd, deps.ptr, deps.len); @@ -840,7 +879,7 @@ int apk_db_open(struct apk_database *db, const char *root, unsigned int flags) { const char *apk_repos = getenv("APK_REPOS"), *msg = NULL; struct apk_repository_url *repo = NULL; - struct stat st; + struct stat64 st; apk_blob_t blob; int r; @@ -854,27 +893,26 @@ int apk_db_open(struct apk_database *db, const char *root, unsigned int flags) db->permanent = 1; if (root != NULL) { - fchdir(apk_cwd_fd); db->root = strdup(root); - db->root_fd = open(root, O_RDONLY); + db->root_fd = openat(AT_FDCWD, db->root, O_RDONLY); if (db->root_fd < 0 && (flags & APK_OPENF_CREATE)) { - mkdir(db->root, 0755); - db->root_fd = open(root, O_RDONLY); + mkdirat(AT_FDCWD, db->root, 0755); + db->root_fd = openat(AT_FDCWD, root, O_RDONLY); } if (db->root_fd < 0) { msg = "Unable to open root"; goto ret_errno; } - if (fstat(db->root_fd, &st) != 0 || major(st.st_dev) == 0) + if (fstat64(db->root_fd, &st) != 0 || major(st.st_dev) == 0) db->permanent = 0; - fchdir(db->root_fd); - if (stat(apk_linked_cache_dir, &st) == 0 && S_ISDIR(st.st_mode)) + if (fstatat64(db->root_fd, apk_linked_cache_dir, &st, 0) == 0 && + S_ISDIR(st.st_mode)) db->cache_dir = apk_linked_cache_dir; if (flags & APK_OPENF_WRITE) { - db->lock_fd = open("var/lib/apk/lock", - O_CREAT | O_WRONLY, 0400); + db->lock_fd = openat(db->root_fd, "var/lib/apk/lock", + O_CREAT | O_RDWR, 0400); if (db->lock_fd < 0 && errno == ENOENT && (flags & APK_OPENF_CREATE)) { r = apk_db_create(db); @@ -882,8 +920,9 @@ int apk_db_open(struct apk_database *db, const char *root, unsigned int flags) msg = "Unable to create database"; goto ret_r; } - db->lock_fd = open("var/lib/apk/lock", - O_CREAT | O_WRONLY, 0400); + db->lock_fd = openat(db->root_fd, + "var/lib/apk/lock", + O_CREAT | O_RDWR, 0400); } if (db->lock_fd < 0 || flock(db->lock_fd, LOCK_EX | LOCK_NB) < 0) { @@ -912,6 +951,11 @@ int apk_db_open(struct apk_database *db, const char *root, unsigned int flags) blob = APK_BLOB_STR("etc:*etc/init.d"); apk_blob_for_each_segment(blob, ":", add_protected_path, db); + db->cache_fd = openat(db->root_fd, db->cache_dir, O_RDONLY); + mkdirat(db->cache_fd, "tmp", 0644); + db->cachetmp_fd = openat(db->cache_fd, "tmp", O_RDONLY); + db->keys_fd = openat(db->root_fd, "etc/apk/keys", O_RDONLY); + if (root != NULL) { r = apk_db_read_state(db, flags); if (r == -ENOENT && (flags & APK_OPENF_CREATE)) { @@ -929,8 +973,8 @@ int apk_db_open(struct apk_database *db, const char *root, unsigned int flags) if (!(flags & APK_OPENF_NO_REPOS)) { if (apk_repos == NULL) - apk_repos = "/etc/apk/repositories"; - blob = apk_blob_from_file(apk_repos); + apk_repos = "etc/apk/repositories"; + blob = apk_blob_from_file(db->root_fd, apk_repos); if (!APK_BLOB_IS_NULL(blob)) { apk_blob_for_each_segment(blob, "\n", apk_db_add_repository, db); @@ -947,7 +991,6 @@ int apk_db_open(struct apk_database *db, const char *root, unsigned int flags) apk_db_index_write_nr_cache(db); } - fchdir(apk_cwd_fd); return 0; ret_errno: @@ -956,7 +999,7 @@ ret_r: if (msg != NULL) apk_error("%s: %s", msg, strerror(-r)); apk_db_close(db); - fchdir(apk_cwd_fd); + return r; } @@ -977,35 +1020,36 @@ int apk_db_write_config(struct apk_database *db) return -1; } - fchdir(db->root_fd); - - os = apk_ostream_to_file("var/lib/apk/world.new", 0644); + os = apk_ostream_to_file(db->root_fd, "var/lib/apk/world.new", 0644); if (os == NULL) return -1; apk_deps_write(db->world, os); os->write(os, "\n", 1); os->close(os); - if (rename("var/lib/apk/world.new", "var/lib/apk/world") < 0) + if (renameat(db->root_fd, "var/lib/apk/world.new", + db->root_fd, "var/lib/apk/world") < 0) return -errno; - os = apk_ostream_to_file("var/lib/apk/installed.new", 0644); + os = apk_ostream_to_file(db->root_fd, "var/lib/apk/installed.new", 0644); if (os == NULL) return -1; apk_db_write_fdb(db, os); os->close(os); - if (rename("var/lib/apk/installed.new", "var/lib/apk/installed") < 0) + if (renameat(db->root_fd, "var/lib/apk/installed.new", + db->root_fd, "var/lib/apk/installed") < 0) return -errno; - os = apk_ostream_to_file("var/lib/apk/scripts.tar.new", 0644); + os = apk_ostream_to_file(db->root_fd, "var/lib/apk/scripts.tar.new", 0644); if (os == NULL) return -1; apk_db_scriptdb_write(db, os); os->close(os); - if (rename("var/lib/apk/scripts.tar.new", "var/lib/apk/scripts.tar") < 0) + if (renameat(db->root_fd, "var/lib/apk/scripts.tar.new", + db->root_fd, "var/lib/apk/scripts.tar") < 0) return -errno; - unlink("var/lib/apk/scripts"); + unlinkat(db->root_fd, "var/lib/apk/scripts", 0); apk_db_index_write_nr_cache(db); return 0; @@ -1040,6 +1084,12 @@ void apk_db_close(struct apk_database *db) apk_hash_free(&db->installed.files); apk_hash_free(&db->installed.dirs); + if (db->keys_fd) + close(db->keys_fd); + if (db->cachetmp_fd) + close(db->cachetmp_fd); + if (db->cache_fd) + close(db->cache_fd); if (db->root_fd) close(db->root_fd); if (db->lock_fd) @@ -1084,19 +1134,6 @@ struct apk_package *apk_db_get_file_owner(struct apk_database *db, return dbf->diri->pkg; } -static struct apk_bstream *apk_db_cache_open(struct apk_database *db, - struct apk_checksum *csum, - const char *file) -{ - char tmp[256]; - - if (db->root == NULL) - return NULL; - - apk_db_cache_get_name(tmp, sizeof(tmp), db, csum, file, FALSE); - return apk_bstream_from_file(tmp); -} - static struct apk_bstream *apk_repository_file_open(struct apk_repository *repo, const char *file) { @@ -1109,91 +1146,26 @@ static struct apk_bstream *apk_repository_file_open(struct apk_repository *repo, return apk_bstream_from_url(tmp); } -int apk_cache_download(struct apk_database *db, struct apk_checksum *csum, - const char *url, const char *item, int verify) -{ - char tmp[256], tmp2[256]; - int r; - - snprintf(tmp, sizeof(tmp), "%s%s%s", - url, url[strlen(url)-1] == '/' ? "" : "/", item); - apk_message("fetch %s", tmp); - - if (apk_flags & APK_SIMULATE) - return 0; - - apk_db_cache_get_name(tmp2, sizeof(tmp2), db, csum, item, TRUE); - r = apk_url_download(tmp, tmp2); - 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); - is = apk_bstream_gunzip_mpart(apk_bstream_from_file(tmp2), - apk_sign_ctx_mpart_cb, &sctx); - r = apk_tar_parse(is, apk_sign_ctx_verify_tar, &sctx, FALSE); - is->close(is); - apk_sign_ctx_free(&sctx); - if (r != 0) { - unlink(tmp2); - return r; - } - } - - apk_db_cache_get_name(tmp, sizeof(tmp), db, csum, item, FALSE); - if (rename(tmp2, tmp) < 0) - return -errno; - - return 0; -} - -int apk_cache_exists(struct apk_database *db, struct apk_checksum *csum, - const char *item) -{ - char tmp[256]; - - if (db->root == NULL) - return 0; - - apk_db_cache_get_name(tmp, sizeof(tmp), db, csum, item, FALSE); - return access(tmp, R_OK | W_OK) == 0; -} - -static int apk_cache_delete(struct apk_database *db, struct apk_checksum *csum, - const char *item) -{ - char tmp[256]; - - if (db->root == NULL) - return 0; - - apk_db_cache_get_name(tmp, sizeof(tmp), db, csum, item, FALSE); - return unlink(tmp); -} - int apk_repository_update(struct apk_database *db, struct apk_repository *repo) { + char cacheitem[PATH_MAX]; int r; if (repo->csum.type == APK_CHECKSUM_NONE) return 0; - r = apk_cache_download(db, &repo->csum, repo->url, apkindex_tar_gz, + apk_cache_format_index(APK_BLOB_BUF(cacheitem), repo, 0); + r = apk_cache_download(db, repo->url, apkindex_tar_gz, cacheitem, (apk_flags & APK_ALLOW_UNTRUSTED) ? APK_SIGN_NONE : APK_SIGN_VERIFY); if (r == 0 || r == -ENOKEY || r == -EKEYREJECTED) { - if (r == -ENOKEY) - apk_error("%s: verify: UNTRUSTED", repo->url); - else if (r == -EKEYREJECTED) - apk_error("%s: verify: FAILED", repo->url); - apk_cache_delete(db, &repo->csum, apk_index_gz); + if (r != 0) + apk_error("%s: %s", repo->url, apk_error_str(r)); return r; } - r = apk_cache_download(db, &repo->csum, repo->url, apk_index_gz, + apk_cache_format_index(APK_BLOB_BUF(cacheitem), repo, 1); + r = apk_cache_download(db, repo->url, apk_index_gz, cacheitem, APK_SIGN_NONE); if (r != 0) apk_error("Failed to update %s: download failed", repo->url); @@ -1238,7 +1210,7 @@ static int load_index(struct apk_database *db, struct apk_bstream *bs, ctx.db = db; ctx.repo = repo; ctx.found = 0; - apk_sign_ctx_init(&ctx.sctx, APK_SIGN_VERIFY, NULL); + apk_sign_ctx_init(&ctx.sctx, APK_SIGN_VERIFY, NULL, db->keys_fd); is = apk_bstream_gunzip_mpart(bs, apk_sign_ctx_mpart_cb, &ctx.sctx); r = apk_tar_parse(is, load_apkindex, &ctx, FALSE); is->close(is); @@ -1260,7 +1232,7 @@ int apk_db_index_read_file(struct apk_database *db, const char *file, int repo) if (strstr(file, ".tar.gz") == NULL && strstr(file, ".gz") != NULL) targz = 0; - return load_index(db, apk_bstream_from_file(file), targz, repo); + return load_index(db, apk_bstream_from_file(AT_FDCWD, file), targz, repo); } int apk_db_add_repository(apk_database_t _db, apk_blob_t repository) @@ -1285,14 +1257,18 @@ int apk_db_add_repository(apk_database_t _db, apk_blob_t repository) }; if (apk_url_local_file(repo->url) == NULL) { + char cacheitem[PATH_MAX]; + apk_blob_checksum(repository, apk_default_checksum(), &repo->csum); if (apk_flags & APK_UPDATE_CACHE) apk_repository_update(db, repo); - bs = apk_db_cache_open(db, &repo->csum, apkindex_tar_gz); + apk_cache_format_index(APK_BLOB_BUF(cacheitem), repo, 0); + bs = apk_bstream_from_file(db->cache_fd, cacheitem); if (bs == NULL) { - bs = apk_db_cache_open(db, &repo->csum, apk_index_gz); + apk_cache_format_index(APK_BLOB_BUF(cacheitem), repo, 1); + bs = apk_bstream_from_file(db->cache_fd, cacheitem); targz = 0; } } else { @@ -1356,7 +1332,6 @@ static int apk_db_install_archive_entry(void *_ctx, apk_blob_t name = APK_BLOB_STR(ae->name), bdir, bfile; struct apk_db_dir_instance *diri = ctx->diri; struct apk_db_file *file; - char alt_name[PATH_MAX]; const char *p; int r = 0, type = APK_SCRIPT_INVALID; @@ -1455,9 +1430,7 @@ static int apk_db_install_archive_entry(void *_ctx, apk_message("%s", ae->name); /* Extract the file as name.apk-new */ - snprintf(alt_name, sizeof(alt_name), "%s/%s.apk-new", - diri->dir->name, file->name); - r = apk_archive_entry_extract(ae, is, alt_name, + r = apk_archive_entry_extract(db->root_fd, ae, ".apk-new", is, extract_cb, ctx); memcpy(&file->csum, &ae->csum, sizeof(file->csum)); } else { @@ -1474,7 +1447,7 @@ static int apk_db_install_archive_entry(void *_ctx, ctx->file_diri_node = hlist_tail_ptr(&diri->owned_files); apk_db_diri_set(diri, ae->mode & 0777, ae->uid, ae->gid); - apk_db_diri_mkdir(diri); + apk_db_diri_mkdir(db, diri); } ctx->installed_size += ctx->current_file_size; @@ -1505,9 +1478,9 @@ static void apk_db_purge_pkg(struct apk_database *db, struct apk_package *pkg, if (!(diri->dir->flags & APK_DBDIRF_PROTECTED) || (apk_flags & APK_PURGE) || (file->csum.type != APK_CHECKSUM_NONE && - apk_file_get_info(name, file->csum.type, &fi) == 0 && + apk_file_get_info(db->root_fd, name, file->csum.type, &fi) == 0 && apk_checksum_compare(&file->csum, &fi.csum) == 0)) - unlink(name); + unlinkat(db->root_fd, name, 0); if (apk_verbosity >= 3) apk_message("%s", name); __hlist_del(fc, &diri->owned_files.first); @@ -1516,7 +1489,7 @@ static void apk_db_purge_pkg(struct apk_database *db, struct apk_package *pkg, db->installed.stats.files--; } } - apk_db_diri_rmdir(diri); + apk_db_diri_rmdir(db, diri); __hlist_del(dc, &pkg->owned_dirs.first); apk_db_diri_free(db, diri); } @@ -1564,7 +1537,7 @@ static void apk_db_migrate_files(struct apk_database *db, (diri->dir->flags & APK_DBDIRF_PROTECTED)) cstype = ofile->csum.type; - r = apk_file_get_info(name, cstype, &fi); + r = apk_file_get_info(db->root_fd, name, cstype, &fi); if ((diri->dir->flags & APK_DBDIRF_PROTECTED) && (r == 0) && (ofile == NULL || @@ -1577,14 +1550,15 @@ static void apk_db_migrate_files(struct apk_database *db, * existing file */ if (ofile == NULL || ofile->csum.type != file->csum.type) - apk_file_get_info(name, file->csum.type, &fi); + apk_file_get_info(db->root_fd, name, file->csum.type, &fi); if ((apk_flags & APK_CLEAN_PROTECTED) || (file->csum.type != APK_CHECKSUM_NONE && apk_checksum_compare(&file->csum, &fi.csum) == 0)) - unlink(tmpname); + unlinkat(db->root_fd, tmpname, 0); } else { /* Overwrite the old file */ - rename(tmpname, name); + renameat(db->root_fd, tmpname, + db->root_fd, name); } /* Claim ownership of the file in db */ @@ -1608,12 +1582,9 @@ static int apk_db_unpack_pkg(struct apk_database *db, struct install_ctx ctx; struct apk_bstream *bs = NULL; struct apk_istream *tar; - char pkgname[256], file[256]; + char file[PATH_MAX]; int r, i, need_copy = FALSE; - snprintf(pkgname, sizeof(pkgname), "%s-%s.apk", - newpkg->name->name, newpkg->version); - if (newpkg->filename == NULL) { struct apk_repository *repo; @@ -1629,24 +1600,26 @@ static int apk_db_unpack_pkg(struct apk_database *db, repo = &db->repos[i]; if (apk_db_cache_active(db) && - repo->csum.type != APK_CHECKSUM_NONE) - bs = apk_db_cache_open(db, &newpkg->csum, pkgname); + repo->csum.type != APK_CHECKSUM_NONE) { + apk_pkg_format_cache(newpkg, APK_BLOB_BUF(file)); + bs = apk_bstream_from_file(db->cache_fd, file); + } if (bs == NULL) { - bs = apk_repository_file_open(repo, pkgname); + apk_pkg_format_plain(newpkg, APK_BLOB_BUF(file)); + bs = apk_repository_file_open(repo, file); if (repo->csum.type != APK_CHECKSUM_NONE) need_copy = TRUE; } } else { - bs = apk_bstream_from_file(newpkg->filename); + bs = apk_bstream_from_file(AT_FDCWD, newpkg->filename); need_copy = TRUE; } if (!apk_db_cache_active(db)) need_copy = FALSE; if (need_copy) { - apk_db_cache_get_name(file, sizeof(file), db, &newpkg->csum, - pkgname, TRUE); - bs = apk_bstream_tee(bs, file); + apk_pkg_format_cache(newpkg, APK_BLOB_BUF(file)); + bs = apk_bstream_tee(bs, db->cachetmp_fd, file); } if (bs == NULL) { @@ -1662,7 +1635,7 @@ static int apk_db_unpack_pkg(struct apk_database *db, .cb = cb, .cb_ctx = cb_ctx, }; - apk_sign_ctx_init(&ctx.sctx, APK_SIGN_VERIFY_IDENTITY, &newpkg->csum); + apk_sign_ctx_init(&ctx.sctx, APK_SIGN_VERIFY_IDENTITY, &newpkg->csum, db->keys_fd); tar = apk_bstream_gunzip_mpart(bs, apk_sign_ctx_mpart_cb, &ctx.sctx); r = apk_tar_parse(tar, apk_db_install_archive_entry, &ctx, TRUE); apk_sign_ctx_free(&ctx.sctx); @@ -1680,12 +1653,8 @@ static int apk_db_unpack_pkg(struct apk_database *db, apk_db_migrate_files(db, newpkg); - if (need_copy) { - char file2[256]; - apk_db_cache_get_name(file2, sizeof(file2), db, - &newpkg->csum, pkgname, FALSE); - rename(file, file2); - } + if (need_copy) + renameat(db->cachetmp_fd, file, db->cache_fd, file); return 0; err: @@ -1700,9 +1669,6 @@ int apk_db_install_pkg(struct apk_database *db, { int r; - if (fchdir(db->root_fd) < 0) - return errno; - /* Just purging? */ if (oldpkg != NULL && newpkg == NULL) { r = apk_pkg_run_script(oldpkg, db->root_fd, diff --git a/src/fetch.c b/src/fetch.c index c64590e..f93e465 100644 --- a/src/fetch.c +++ b/src/fetch.c @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -26,7 +27,7 @@ struct fetch_ctx { unsigned int flags; - const char *outdir; + int outdir_fd; }; static int cup(void) @@ -80,7 +81,7 @@ static int fetch_parse(void *ctx, int optch, int optindex, const char *optarg) fctx->flags |= FETCH_LINK; break; case 'o': - fctx->outdir = optarg; + fctx->outdir_fd = openat(AT_FDCWD, optarg, O_RDONLY); break; default: return -1; @@ -93,22 +94,21 @@ static int fetch_package(struct fetch_ctx *fctx, struct apk_package *pkg) { struct apk_istream *is; - char infile[256]; - char outfile[256]; + char pkgfile[PATH_MAX], url[PATH_MAX]; int i, r, fd; - if (!(fctx->flags & FETCH_STDOUT)) { - struct stat st; + apk_pkg_format_plain(pkg, APK_BLOB_BUF(pkgfile)); - snprintf(outfile, sizeof(outfile), "%s/%s-%s.apk", - fctx->outdir ? fctx->outdir : ".", - pkg->name->name, pkg->version); + if (!(fctx->flags & FETCH_STDOUT)) { + struct apk_file_info fi; - if (lstat(outfile, &st) == 0 && st.st_size == pkg->size) + if (apk_file_get_info(fctx->outdir_fd, pkgfile, + APK_CHECKSUM_NONE, &fi) == 0 && + fi.size == pkg->size) return 0; } - apk_message("Downloading %s-%s", pkg->name->name, pkg->version); + apk_message("Downloading %s-%s", pkg->name->name, pkg->version); for (i = 0; i < APK_MAX_REPOS; i++) if (pkg->repos & BIT(i)) break; @@ -122,31 +122,30 @@ static int fetch_package(struct fetch_ctx *fctx, if (apk_flags & APK_SIMULATE) return 0; - snprintf(infile, sizeof(infile), "%s/%s-%s.apk", - db->repos[i].url, pkg->name->name, pkg->version); + snprintf(url, sizeof(url), "%s%s%s", db->repos[i].url, + db->repos[i].url[strlen(db->repos[i].url)-1] == '/' ? "" : "/", + pkgfile); if (fctx->flags & FETCH_STDOUT) { fd = STDOUT_FILENO; } else { - if ((fctx->flags & FETCH_LINK) && apk_url_local_file(infile)) { - char real_infile[256]; - int n; - n = readlink(infile, real_infile, sizeof(real_infile)); - if (n > 0 && n < sizeof(real_infile)) - real_infile[n] = '\0'; - if (link(real_infile, outfile) == 0) + if ((fctx->flags & FETCH_LINK) && apk_url_local_file(url)) { + if (linkat(AT_FDCWD, url, + fctx->outdir_fd, pkgfile, + AT_SYMLINK_FOLLOW) == 0) return 0; } - fd = creat(outfile, 0644); + fd = openat(fctx->outdir_fd, pkgfile, + O_CREAT|O_RDWR|O_TRUNC, 0644); if (fd < 0) { - apk_error("%s: %s", outfile, strerror(errno)); + apk_error("%s: %s", pkgfile, strerror(errno)); return -1; } } - is = apk_istream_from_url(infile); + is = apk_istream_from_url(url); if (is == NULL) { - apk_error("Unable to download '%s'", infile); + apk_error("Unable to download '%s'", url); return -1; } @@ -155,8 +154,8 @@ static int fetch_package(struct fetch_ctx *fctx, if (fd != STDOUT_FILENO) close(fd); if (r != pkg->size) { - apk_error("Unable to download '%s'", infile); - unlink(outfile); + apk_error("Unable to download '%s'", url); + unlinkat(fctx->outdir_fd, pkgfile, 0); return -1; } @@ -169,6 +168,9 @@ static int fetch_main(void *ctx, int argc, char **argv) struct apk_database db; int i, j, r; + if (fctx->outdir_fd == 0) + fctx->outdir_fd = AT_FDCWD; + if ((argc > 0) && (strcmp(argv[0], "coffee") == 0)) { if (apk_flags & APK_FORCE) return cup(); diff --git a/src/index.c b/src/index.c index c27d020..4ef8aef 100644 --- a/src/index.c +++ b/src/index.c @@ -55,7 +55,7 @@ static int index_read_file(struct apk_database *db, struct index_ctx *ictx) if (ictx->index == NULL) return 0; - if (apk_file_get_info(ictx->index, APK_CHECKSUM_NONE, &fi) < 0) + if (apk_file_get_info(AT_FDCWD, ictx->index, APK_CHECKSUM_NONE, &fi) < 0) return -1; ictx->index_mtime = fi.mtime; @@ -107,7 +107,7 @@ static int index_main(void *ctx, int argc, char **argv) } for (i = 0; i < argc; i++) { - if (apk_file_get_info(argv[i], APK_CHECKSUM_NONE, &fi) < 0) { + if (apk_file_get_info(AT_FDCWD, argv[i], APK_CHECKSUM_NONE, &fi) < 0) { apk_warning("File '%s' is unaccessible", argv[i]); continue; } @@ -154,7 +154,7 @@ static int index_main(void *ctx, int argc, char **argv) if (!found) { struct apk_sign_ctx sctx; - apk_sign_ctx_init(&sctx, ictx->method, NULL); + apk_sign_ctx_init(&sctx, ictx->method, NULL, db.keys_fd); if (apk_pkg_read(&db, argv[i], &sctx, NULL) == 0) newpkgs++; apk_sign_ctx_free(&sctx); @@ -171,7 +171,7 @@ static int index_main(void *ctx, int argc, char **argv) } if (ictx->output != NULL) - os = apk_ostream_to_file(ictx->output, 0644); + os = apk_ostream_to_file(AT_FDCWD, ictx->output, 0644); else os = apk_ostream_to_fd(STDOUT_FILENO); if (ictx->method == APK_SIGN_GENERATE) { diff --git a/src/io.c b/src/io.c index 3929ba1..a6cdd4d 100644 --- a/src/io.c +++ b/src/io.c @@ -77,11 +77,11 @@ struct apk_istream *apk_istream_from_fd(int fd) return &fis->is; } -struct apk_istream *apk_istream_from_file(const char *file) +struct apk_istream *apk_istream_from_file(int atfd, const char *file) { int fd; - fd = open(file, O_RDONLY); + fd = openat(atfd, file, O_RDONLY); if (fd < 0) return NULL; @@ -342,11 +342,11 @@ struct apk_bstream *apk_bstream_from_fd(int fd) return apk_bstream_from_istream(apk_istream_from_fd(fd)); } -struct apk_bstream *apk_bstream_from_file(const char *file) +struct apk_bstream *apk_bstream_from_file(int atfd, const char *file) { int fd; - fd = open(file, O_RDONLY); + fd = openat(atfd, file, O_RDONLY); if (fd < 0) return NULL; @@ -387,12 +387,13 @@ static void tee_close(void *stream, size_t *size) free(tbs); } -struct apk_bstream *apk_bstream_tee(struct apk_bstream *from, const char *to) +struct apk_bstream *apk_bstream_tee(struct apk_bstream *from, int atfd, const char *to) { struct apk_tee_bstream *tbs; int fd; - fd = creat(to, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + fd = openat(atfd, to, O_CREAT | O_RDWR | O_TRUNC, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); if (fd < 0) return NULL; @@ -433,13 +434,13 @@ apk_blob_t apk_blob_from_istream(struct apk_istream *is, size_t size) return APK_BLOB_PTR_LEN(ptr, rsize); } -apk_blob_t apk_blob_from_file(const char *file) +apk_blob_t apk_blob_from_file(int atfd, const char *file) { int fd; struct stat st; char *buf; - fd = open(file, O_RDONLY); + fd = openat(atfd, file, O_RDONLY); if (fd < 0) return APK_BLOB_NULL; @@ -462,12 +463,13 @@ err_fd: return APK_BLOB_NULL; } -int apk_file_get_info(const char *filename, int checksum, struct apk_file_info *fi) +int apk_file_get_info(int atfd, const char *filename, int checksum, + struct apk_file_info *fi) { - struct stat st; + struct stat64 st; struct apk_bstream *bs; - if (lstat(filename, &st) != 0) + if (fstatat64(atfd, filename, &st, AT_SYMLINK_NOFOLLOW) != 0) return -errno; *fi = (struct apk_file_info) { @@ -482,7 +484,7 @@ int apk_file_get_info(const char *filename, int checksum, struct apk_file_info * if (checksum == APK_CHECKSUM_NONE) return 0; - bs = apk_bstream_from_file(filename); + bs = apk_bstream_from_file(atfd, filename); if (bs != NULL) { EVP_MD_CTX mdctx; apk_blob_t blob; @@ -501,9 +503,9 @@ int apk_file_get_info(const char *filename, int checksum, struct apk_file_info * return 0; } -struct apk_istream *apk_istream_from_file_gz(const char *file) +struct apk_istream *apk_istream_from_file_gz(int atfd, const char *file) { - return apk_bstream_gunzip(apk_bstream_from_file(file)); + return apk_bstream_gunzip(apk_bstream_from_file(atfd, file)); } struct apk_fd_ostream { @@ -593,11 +595,11 @@ struct apk_ostream *apk_ostream_to_fd(int fd) return &fos->os; } -struct apk_ostream *apk_ostream_to_file(const char *file, mode_t mode) +struct apk_ostream *apk_ostream_to_file(int atfd, const char *file, mode_t mode) { int fd; - fd = creat(file, mode); + fd = openat(atfd, file, O_CREAT | O_RDWR | O_TRUNC, mode); if (fd < 0) return NULL; diff --git a/src/package.c b/src/package.c index 43ce646..152edf6 100644 --- a/src/package.c +++ b/src/package.c @@ -28,6 +28,29 @@ #include "apk_database.h" #include "apk_state.h" +void apk_pkg_format_plain(struct apk_package *pkg, apk_blob_t to) +{ + /* pkgname-1.0.apk */ + apk_blob_push_blob(&to, APK_BLOB_STR(pkg->name->name)); + apk_blob_push_blob(&to, APK_BLOB_STR("-")); + apk_blob_push_blob(&to, APK_BLOB_STR(pkg->version)); + apk_blob_push_blob(&to, APK_BLOB_STR(".apk")); + apk_blob_push_blob(&to, APK_BLOB_PTR_LEN("", 1)); +} + +void apk_pkg_format_cache(struct apk_package *pkg, apk_blob_t to) +{ + /* pkgname-1.0_alpha1.12345678.apk */ + apk_blob_push_blob(&to, APK_BLOB_STR(pkg->name->name)); + apk_blob_push_blob(&to, APK_BLOB_STR("-")); + apk_blob_push_blob(&to, APK_BLOB_STR(pkg->version)); + apk_blob_push_blob(&to, APK_BLOB_STR(".")); + apk_blob_push_hexdump(&to, APK_BLOB_PTR_LEN((char *) pkg->csum.data, + APK_CACHE_CSUM_BYTES)); + apk_blob_push_blob(&to, APK_BLOB_STR(".apk")); + apk_blob_push_blob(&to, APK_BLOB_PTR_LEN("", 1)); +} + struct apk_package *apk_pkg_new(void) { struct apk_package *pkg; @@ -56,6 +79,9 @@ int apk_pkg_parse_name(apk_blob_t apkname, if (++dash >= 2) return -1; } + if (i < 0) + return -1; + if (name != NULL) *name = APK_BLOB_PTR_LEN(apkname.ptr, i); if (version != NULL) @@ -282,9 +308,10 @@ int apk_script_type(const char *name) } void apk_sign_ctx_init(struct apk_sign_ctx *ctx, int action, - struct apk_checksum *identity) + struct apk_checksum *identity, int keys_fd) { memset(ctx, 0, sizeof(struct apk_sign_ctx)); + ctx->keys_fd = keys_fd; ctx->action = action; switch (action) { case APK_SIGN_NONE: @@ -359,14 +386,19 @@ int apk_sign_ctx_process_file(struct apk_sign_ctx *ctx, ctx->signature.pkey != NULL) return 0; + if (ctx->keys_fd < 0) + return 0; + if (strncmp(&fi->name[6], "RSA.", 4) == 0 || strncmp(&fi->name[6], "DSA.", 4) == 0) { - char file[256]; - BIO *bio = BIO_new(BIO_s_file()); - snprintf(file, sizeof(file), "/etc/apk/keys/%s", &fi->name[10]); - if (BIO_read_filename(bio, file) > 0) - ctx->signature.pkey = - PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL); + int fd = openat(ctx->keys_fd, &fi->name[10], O_RDONLY); + BIO *bio; + + if (fd < 0) + return 0; + + bio = BIO_new_fp(fdopen(fd, "r"), 0); + ctx->signature.pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL); if (ctx->signature.pkey != NULL) { if (fi->name[6] == 'R') ctx->md = EVP_sha1(); @@ -690,12 +722,9 @@ int apk_pkg_read(struct apk_database *db, const char *file, struct apk_file_info fi; struct apk_bstream *bs; struct apk_istream *tar; - char realfile[PATH_MAX]; int r; - if (realpath(file, realfile) < 0) - return -errno; - r = apk_file_get_info(realfile, APK_CHECKSUM_NONE, &fi); + r = apk_file_get_info(AT_FDCWD, file, APK_CHECKSUM_NONE, &fi); if (r != 0) return r; @@ -705,7 +734,7 @@ int apk_pkg_read(struct apk_database *db, const char *file, r = -ENOMEM; if (ctx.pkg == NULL) goto err; - bs = apk_bstream_from_file(realfile); + bs = apk_bstream_from_file(AT_FDCWD, file); if (bs == NULL) goto err; @@ -723,7 +752,7 @@ int apk_pkg_read(struct apk_database *db, const char *file, } if (sctx->action != APK_SIGN_VERIFY) ctx.pkg->csum = sctx->identity; - ctx.pkg->filename = strdup(realfile); + ctx.pkg->filename = strdup(file); ctx.pkg = apk_db_pkg_add(db, ctx.pkg); if (pkg != NULL) @@ -814,18 +843,17 @@ int apk_pkg_run_script(struct apk_package *pkg, int root_fd, struct hlist_node *c; int fd, status; pid_t pid; - char fn[1024]; + char fn[PATH_MAX]; - fchdir(root_fd); hlist_for_each_entry(script, c, &pkg->scripts, script_list) { if (script->type != type) continue; - snprintf(fn, sizeof(fn), - "tmp/%s-%s.%s", + snprintf(fn, sizeof(fn), "tmp/%s-%s.%s", pkg->name->name, pkg->version, apk_script_types[type]); - fd = creat(fn, 0777); + + fd = openat(root_fd, fn, O_CREAT|O_RDWR|O_TRUNC, 0777); if (fd < 0) return fd; write(fd, script->script, script->size); @@ -837,6 +865,7 @@ int apk_pkg_run_script(struct apk_package *pkg, int root_fd, if (pid == -1) return -1; if (pid == 0) { + fchdir(root_fd); if (chroot(".") < 0) { apk_error("chroot: %s", strerror(errno)); } else { @@ -846,7 +875,7 @@ int apk_pkg_run_script(struct apk_package *pkg, int root_fd, exit(1); } waitpid(pid, &status, 0); - unlink(fn); + unlinkat(root_fd, fn, 0); if (WIFEXITED(status)) return WEXITSTATUS(status); return -1; diff --git a/src/state.c b/src/state.c index 16acfba..c539b02 100644 --- a/src/state.c +++ b/src/state.c @@ -711,7 +711,7 @@ int apk_state_commit(struct apk_state *state, if (apk_flags & APK_PROGRESS) apk_draw_progress(20, 1); - if (!(apk_flags & APK_SIMULATE) && prog.done.packages != 0) + if (!(apk_flags & APK_SIMULATE)) apk_db_write_config(db); if (r == 0) diff --git a/src/url.c b/src/url.c index e09ec4c..be5e285 100644 --- a/src/url.c +++ b/src/url.c @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -61,7 +62,7 @@ static int fork_wget(const char *url) struct apk_istream *apk_istream_from_url(const char *url) { if (apk_url_local_file(url) != NULL) - return apk_istream_from_file(apk_url_local_file(url)); + return apk_istream_from_file(AT_FDCWD, apk_url_local_file(url)); return apk_istream_from_fd(fork_wget(url)); } @@ -74,16 +75,19 @@ struct apk_istream *apk_istream_from_url_gz(const char *file) struct apk_bstream *apk_bstream_from_url(const char *url) { if (apk_url_local_file(url)) - return apk_bstream_from_file(url); + return apk_bstream_from_file(AT_FDCWD, url); return apk_bstream_from_fd(fork_wget(url)); } -int apk_url_download(const char *url, const char *file) +int apk_url_download(const char *url, int atfd, const char *file) { pid_t pid; - int status; - char tmp[256]; + int status, fd; + + fd = openat(atfd, file, O_CREAT|O_RDWR|O_TRUNC, 0644); + if (fd < 0) + return -errno; pid = fork(); if (pid == -1) @@ -92,15 +96,14 @@ int apk_url_download(const char *url, const char *file) if (pid == 0) { setsid(); dup2(open("/dev/null", O_RDONLY), STDIN_FILENO); - snprintf(tmp, sizeof(tmp), "%s.backup", file); - rename(file, tmp); - execlp("wget", "wget", "-q", "-O", file, url, NULL); + dup2(fd, STDOUT_FILENO); + execlp("wget", "wget", "-q", "-O", "-", url, NULL); exit(0); } waitpid(pid, &status, 0); if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { - unlink(file); + unlinkat(atfd, file, 0); return -1; } diff --git a/src/verify.c b/src/verify.c index 82e9b2d..dc9ddb6 100644 --- a/src/verify.c +++ b/src/verify.c @@ -10,6 +10,7 @@ #include #include +#include #include #include "apk_applet.h" @@ -19,12 +20,17 @@ static int verify_main(void *ctx, int argc, char **argv) { struct apk_sign_ctx sctx; struct apk_istream *is; + struct apk_database db; int i, r, ok, rc = 0; apk_flags |= APK_ALLOW_UNTRUSTED; + r = apk_db_open(&db, apk_root, APK_OPENF_READ | APK_OPENF_NO_STATE); + if (r != 0) + return r; + for (i = 0; i < argc; i++) { - apk_sign_ctx_init(&sctx, APK_SIGN_VERIFY, NULL); - is = apk_bstream_gunzip_mpart(apk_bstream_from_file(argv[i]), + apk_sign_ctx_init(&sctx, APK_SIGN_VERIFY, NULL, db.keys_fd); + is = apk_bstream_gunzip_mpart(apk_bstream_from_file(AT_FDCWD, argv[i]), apk_sign_ctx_mpart_cb, &sctx); if (is == NULL) { apk_error("%s: %s", strerror(errno), argv[i]); @@ -43,6 +49,7 @@ static int verify_main(void *ctx, int argc, char **argv) rc++; apk_sign_ctx_free(&sctx); } + apk_db_close(&db); return rc; } -- cgit v1.2.3