diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | src/add.c | 2 | ||||
-rw-r--r-- | src/apk.c | 27 | ||||
-rw-r--r-- | src/apk_database.h | 9 | ||||
-rw-r--r-- | src/apk_defines.h | 1 | ||||
-rw-r--r-- | src/apk_io.h | 1 | ||||
-rw-r--r-- | src/apk_package.h | 4 | ||||
-rw-r--r-- | src/apk_state.h | 2 | ||||
-rw-r--r-- | src/cache.c | 5 | ||||
-rw-r--r-- | src/database.c | 281 | ||||
-rw-r--r-- | src/del.c | 2 | ||||
-rw-r--r-- | src/fetch.c | 10 | ||||
-rw-r--r-- | src/fix.c | 2 | ||||
-rw-r--r-- | src/index.c | 15 | ||||
-rw-r--r-- | src/info.c | 80 | ||||
-rw-r--r-- | src/io.c | 31 | ||||
-rw-r--r-- | src/lua-apk.c | 82 | ||||
-rw-r--r-- | src/package.c | 34 | ||||
-rw-r--r-- | src/state.c | 235 | ||||
-rw-r--r-- | src/upgrade.c | 28 | ||||
-rw-r--r-- | src/url.c | 4 |
21 files changed, 645 insertions, 212 deletions
@@ -5,7 +5,7 @@ -include config.mk PACKAGE := apk-tools -VERSION := 2.0.7 +VERSION := 2.1.0_rc1 ## # Default directories @@ -142,7 +142,7 @@ static int add_main(void *ctx, struct apk_database *db, int argc, char **argv) apk_state_print_errors(state); r = -1; } else { - r = apk_state_commit(state, db); + r = apk_state_commit(state); } if (state != NULL) apk_state_unref(state); @@ -17,7 +17,9 @@ #include <stdlib.h> #include <string.h> #include <getopt.h> +#include <unistd.h> #include <sys/stat.h> +#include <sys/ioctl.h> #include <openssl/crypto.h> #ifndef OPENSSL_NO_ENGINE @@ -31,6 +33,7 @@ #include "apk_print.h" char **apk_argv; +int apk_screen_width; static struct apk_option generic_options[] = { { 'h', "help", "Show generic help or applet specific help" }, @@ -45,6 +48,7 @@ static struct apk_option generic_options[] = { { 'f', "force", "Do what was asked even if it looks dangerous" }, { 'U', "update-cache", "Update the repository cache" }, { 0x101, "progress", "Show a progress bar" }, + { 0x110, "no-progress", "Disable progress bar even for TTYs" }, { 0x102, "clean-protected", "Do not create .apk-new files to " "configuration dirs" }, { 0x106, "purge", "Delete also modified configuration files on " @@ -62,6 +66,8 @@ static struct apk_option generic_options[] = { required_argument, "REPOFILE" }, { 0x109, "no-network", "Do not use network (cache is still used)" }, { 0x111, "overlay-from-stdin", "Read list of overlay files from stdin" }, + { 0x112, "arch", "Use architecture with --root", + required_argument, "ARCH" }, }; static int version(void) @@ -236,6 +242,20 @@ static void init_openssl(void) #endif } +static void setup_terminal(void) +{ + struct winsize w; + + setvbuf(stderr, NULL, _IOLBF, BUFSIZ); + if (ioctl(STDERR_FILENO,TIOCGWINSZ, &w) == 0) + apk_screen_width = w.ws_col; + else + apk_screen_width = 70; + if (isatty(STDOUT_FILENO) && isatty(STDERR_FILENO) && isatty(STDIN_FILENO)) + apk_flags |= APK_PROGRESS; + +} + int main(int argc, char **argv) { struct apk_applet *applet; @@ -255,6 +275,7 @@ int main(int argc, char **argv) list_init(&dbopts.repository_list); apk_atom_init(); umask(0); + setup_terminal(); applet = deduce_applet(argc, argv); num_options = ARRAY_SIZE(generic_options) + 1; @@ -326,6 +347,9 @@ int main(int argc, char **argv) case 0x101: apk_flags |= APK_PROGRESS; break; + case 0x110: + apk_flags &= ~APK_PROGRESS; + break; case 0x102: apk_flags |= APK_CLEAN_PROTECTED; break; @@ -347,6 +371,9 @@ int main(int argc, char **argv) case 0x111: apk_flags |= APK_OVERLAY_FROM_STDIN; break; + case 0x112: + dbopts.arch = optarg; + break; default: if (applet == NULL || applet->parse == NULL || applet->parse(ctx, &dbopts, r, diff --git a/src/apk_database.h b/src/apk_database.h index b79253d..9b032e7 100644 --- a/src/apk_database.h +++ b/src/apk_database.h @@ -95,6 +95,7 @@ struct apk_db_options { int lock_wait; unsigned long open_flags; char *root; + char *arch; char *keys_dir; char *repositories_file; struct list_head repository_list; @@ -105,9 +106,11 @@ struct apk_database { int root_fd, lock_fd, cache_fd, cachetmp_fd, keys_fd; unsigned name_id, num_repos; const char *cache_dir; + char *cache_remount_dir; apk_blob_t *arch; unsigned int local_repos; int permanent : 1; + int ro_cache : 1; int compat_newfeatures : 1; int compat_notinstallable : 1; @@ -155,6 +158,7 @@ struct apk_db_file *apk_db_file_query(struct apk_database *db, #define APK_OPENF_NO_WORLD 0x0040 #define APK_OPENF_NO_SYS_REPOS 0x0100 #define APK_OPENF_NO_INSTALLED_REPO 0x0200 +#define APK_OPENF_CACHE_WRITE 0x0400 #define APK_OPENF_NO_REPOS (APK_OPENF_NO_SYS_REPOS | \ APK_OPENF_NO_INSTALLED_REPO) @@ -180,10 +184,13 @@ int apk_db_add_repository(apk_database_t db, apk_blob_t repository); struct apk_repository *apk_db_select_repo(struct apk_database *db, struct apk_package *pkg); int apk_repository_update(struct apk_database *db, struct apk_repository *repo); +int apk_repo_format_filename(char *buf, size_t len, + const char *repourl, apk_blob_t *arch, + const char *pkgfile); int apk_db_cache_active(struct apk_database *db); void apk_cache_format_index(apk_blob_t to, struct apk_repository *repo); -int apk_cache_download(struct apk_database *db, const char *url, +int apk_cache_download(struct apk_database *db, const char *url, apk_blob_t *arch, const char *item, const char *cache_item, int verify); int apk_db_install_pkg(struct apk_database *db, diff --git a/src/apk_defines.h b/src/apk_defines.h index b11d181..b5ad12e 100644 --- a/src/apk_defines.h +++ b/src/apk_defines.h @@ -51,6 +51,7 @@ extern int apk_verbosity; extern unsigned int apk_flags; extern const char *apk_arch; extern char **apk_argv; +extern int apk_screen_width; #define APK_FORCE 0x0001 #define APK_SIMULATE 0x0002 diff --git a/src/apk_io.h b/src/apk_io.h index 3845554..8cf24d8 100644 --- a/src/apk_io.h +++ b/src/apk_io.h @@ -110,6 +110,7 @@ apk_blob_t apk_blob_from_file(int atfd, const char *file); int apk_file_get_info(int atfd, const char *filename, unsigned int flags, struct apk_file_info *fi); +int apk_move_file(int atfd, const char *from, const char *to); int apk_url_download(const char *url, int atfd, const char *file); const char *apk_url_local_file(const char *url); diff --git a/src/apk_package.h b/src/apk_package.h index ed25bd4..9802dfa 100644 --- a/src/apk_package.h +++ b/src/apk_package.h @@ -83,10 +83,12 @@ struct apk_package { struct apk_name *name; struct apk_installed_package *ipkg; apk_blob_t *version, *arch, *license; - char *url, *description; + apk_blob_t *origin, *maintainer; + char *url, *description, *commit; char *filename; struct apk_dependency_array *depends, *install_if; size_t installed_size, size; + time_t build_time; unsigned repos; struct apk_checksum csum; }; diff --git a/src/apk_state.h b/src/apk_state.h index 1ac049a..e0df54e 100644 --- a/src/apk_state.h +++ b/src/apk_state.h @@ -37,7 +37,7 @@ struct apk_state *apk_state_dup(struct apk_state *state); void apk_state_unref(struct apk_state *state); void apk_state_print_errors(struct apk_state *state); -int apk_state_commit(struct apk_state *state, struct apk_database *db); +int apk_state_commit(struct apk_state *state); int apk_state_lock_dependency(struct apk_state *state, struct apk_dependency *dep); int apk_state_lock_name(struct apk_state *state, diff --git a/src/cache.c b/src/cache.c index 60c7aeb..8cee1e4 100644 --- a/src/cache.c +++ b/src/cache.c @@ -58,7 +58,8 @@ static int cache_download(struct apk_database *db) continue; apk_pkg_format_plain(pkg, APK_BLOB_BUF(item)); - apk_cache_download(db, repo->url, item, cacheitem, + apk_cache_download(db, repo->url, pkg->arch, + item, cacheitem, APK_SIGN_VERIFY_IDENTITY); } @@ -171,7 +172,7 @@ static struct apk_applet apk_cache = { "making /etc/apk/cache a symlink to the directory (on boot " "media) that will be used as package cache.", .arguments = "sync | clean | download", - .open_flags = APK_OPENF_READ|APK_OPENF_NO_SCRIPTS|APK_OPENF_NO_INSTALLED, + .open_flags = APK_OPENF_READ|APK_OPENF_NO_SCRIPTS|APK_OPENF_NO_INSTALLED|APK_OPENF_CACHE_WRITE, .main = cache_main, }; diff --git a/src/database.c b/src/database.c index 53a18c7..45960d2 100644 --- a/src/database.c +++ b/src/database.c @@ -12,6 +12,7 @@ #include <errno.h> #include <stdio.h> #include <fcntl.h> +#include <mntent.h> #include <limits.h> #include <unistd.h> #include <malloc.h> @@ -19,8 +20,11 @@ #include <stdlib.h> #include <signal.h> #include <fnmatch.h> +#include <sys/vfs.h> #include <sys/file.h> +#include <sys/wait.h> #include <sys/stat.h> +#include <sys/statvfs.h> #include "apk_defines.h" #include "apk_package.h" @@ -45,12 +49,29 @@ enum { int apk_verbosity = 1; unsigned int apk_flags = 0; -const char *apk_arch = APK_DEFAULT_ARCH; const char * const apkindex_tar_gz = "APKINDEX.tar.gz"; -static const char * const apk_static_cache_dir = "var/lib/apk"; +static const char * const apk_static_cache_dir = "var/cache/apk"; static const char * const apk_linked_cache_dir = "etc/apk/cache"; +static const char * const apk_lock_file = "var/lock/apkdb"; + +static const char * const apk_world_file = "etc/apk/world"; +static const char * const apk_world_file_tmp = "etc/apk/world.new"; +static const char * const apk_world_file_old = "var/lib/apk/world"; + +static const char * const apk_scripts_file = "lib/apk/db/scripts.tar"; +static const char * const apk_scripts_file_tmp = "lib/apk/db/scripts.tar.new"; +static const char * const apk_scripts_file_old = "var/lib/apk/scripts.tar"; + +static const char * const apk_triggers_file = "lib/apk/db/triggers"; +static const char * const apk_triggers_file_tmp = "lib/apk/db/triggers.new"; +static const char * const apk_triggers_file_old = "var/lib/apk/triggers"; + +static const char * const apk_installed_file = "lib/apk/db/installed"; +static const char * const apk_installed_file_tmp = "lib/apk/db/installed.new"; +static const char * const apk_installed_file_old = "var/lib/apk/installed"; + struct install_ctx { struct apk_database *db; struct apk_package *pkg; @@ -427,9 +448,7 @@ struct apk_package *apk_db_pkg_add(struct apk_database *db, struct apk_package * struct apk_package *idb; if (pkg->license == NULL) - pkg->license = apk_blob_atomize(APK_BLOB_NULL); - if (pkg->arch == NULL) - pkg->arch = apk_blob_atomize(APK_BLOB_STR(APK_DEFAULT_ARCH)); + pkg->license = apk_blob_atomize(APK_BLOB_NULL); idb = apk_hash_get(&db->available.packages, APK_BLOB_CSUM(pkg->csum)); if (idb == NULL) { @@ -463,15 +482,13 @@ void apk_cache_format_index(apk_blob_t to, struct apk_repository *repo) apk_blob_push_blob(&to, APK_BLOB_PTR_LEN("", 1)); } -int apk_cache_download(struct apk_database *db, const char *url, +int apk_cache_download(struct apk_database *db, const char *url, apk_blob_t *arch, const char *item, const char *cacheitem, int verify) { char fullurl[PATH_MAX]; int r; - snprintf(fullurl, sizeof(fullurl), "%s%s" BLOB_FMT "/%s", - url, url[strlen(url)-1] == '/' ? "" : "/", - BLOB_PRINTF(*db->arch), item); + apk_repo_format_filename(fullurl, sizeof(fullurl), url, arch, item); apk_message("fetch %s", fullurl); if (apk_flags & APK_SIMULATE) @@ -499,8 +516,10 @@ int apk_cache_download(struct apk_database *db, const char *url, } } - if (renameat(db->cachetmp_fd, cacheitem, db->cache_fd, cacheitem) < 0) - return -errno; + if (db->cachetmp_fd != db->cache_fd) { + if (renameat(db->cachetmp_fd, cacheitem, db->cache_fd, cacheitem) < 0) + return -errno; + } return 0; } @@ -536,7 +555,6 @@ int apk_db_read_overlay(struct apk_database *db, struct apk_bstream *bs) struct hlist_node **diri_node = NULL, **file_diri_node = NULL; struct apk_package *pkg; struct apk_installed_package *ipkg; - struct apk_db_file *file; apk_blob_t token = APK_BLOB_STR("\n"), line, bdir, bfile; pkg = apk_pkg_new(); @@ -562,7 +580,7 @@ int apk_db_read_overlay(struct apk_database *db, struct apk_bstream *bs) diri = apk_db_diri_new(db, pkg, bdir, &diri_node); file_diri_node = &diri->owned_files.first; } - file = apk_db_file_get(db, diri, bfile, &file_diri_node); + (void) apk_db_file_get(db, diri, bfile, &file_diri_node); } } @@ -774,30 +792,6 @@ static int apk_db_scriptdb_write(struct apk_database *db, struct apk_ostream *os return apk_tar_write_entry(os, NULL, NULL); } -static int apk_db_scriptdb_read_v1(struct apk_database *db, struct apk_istream *is) -{ - struct apk_package *pkg; - struct { - unsigned char md5sum[16]; - unsigned int type; - unsigned int size; - } hdr; - struct apk_checksum csum; - - while (is->read(is, &hdr, sizeof(hdr)) == sizeof(hdr)) { - memcpy(csum.data, hdr.md5sum, sizeof(hdr.md5sum)); - csum.type = APK_CHECKSUM_MD5; - - pkg = apk_db_get_pkg(db, &csum); - if (pkg != NULL && pkg->ipkg != NULL) - apk_ipkg_add_script(pkg->ipkg, is, hdr.type, hdr.size); - else - apk_istream_skip(is, hdr.size); - } - - return 0; -} - static int apk_read_script_archive_entry(void *ctx, const struct apk_file_info *ae, struct apk_istream *is) @@ -910,7 +904,7 @@ static int apk_db_read_state(struct apk_database *db, int flags) * 6. script db */ if (!(flags & APK_OPENF_NO_WORLD)) { - blob = apk_blob_from_file(db->root_fd, "var/lib/apk/world"); + blob = apk_blob_from_file(db->root_fd, apk_world_file); if (APK_BLOB_IS_NULL(blob)) return -ENOENT; apk_deps_parse(db, &db->world, blob); @@ -921,7 +915,7 @@ static int apk_db_read_state(struct apk_database *db, int flags) } if (!(flags & APK_OPENF_NO_INSTALLED)) { - bs = apk_bstream_from_file(db->root_fd, "var/lib/apk/installed"); + bs = apk_bstream_from_file(db->root_fd, apk_installed_file); if (bs != NULL) { r = apk_db_index_read(db, bs, -1); bs->close(bs, NULL); @@ -929,7 +923,7 @@ static int apk_db_read_state(struct apk_database *db, int flags) return -1; } - bs = apk_bstream_from_file(db->root_fd, "var/lib/apk/triggers"); + bs = apk_bstream_from_file(db->root_fd, apk_triggers_file); if (bs != NULL) { apk_db_triggers_read(db, bs); bs->close(bs, NULL); @@ -937,17 +931,12 @@ static int apk_db_read_state(struct apk_database *db, int flags) } if (!(flags & APK_OPENF_NO_SCRIPTS)) { - is = apk_istream_from_file(db->root_fd, "var/lib/apk/scripts.tar"); + is = apk_istream_from_file(db->root_fd, apk_scripts_file); if (is != NULL) { apk_tar_parse(is, apk_read_script_archive_entry, db, FALSE, &db->id_cache); - } else { - is = apk_istream_from_file(db->root_fd, "var/lib/apk/scripts"); - if (is != NULL) - apk_db_scriptdb_read_v1(db, is); - } - if (is != NULL) is->close(is); + } } return 0; @@ -1037,13 +1026,18 @@ static int apk_db_create(struct apk_database *db) 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, "etc", 0755); + mkdirat(db->root_fd, "etc/apk", 0755); + mkdirat(db->root_fd, "lib", 0755); + mkdirat(db->root_fd, "lib/apk", 0755); + mkdirat(db->root_fd, "lib/apk/db", 0755); mkdirat(db->root_fd, "var", 0755); - mkdirat(db->root_fd, "var/lib", 0755); - mkdirat(db->root_fd, "var/lib/apk", 0755); mkdirat(db->root_fd, "var/cache", 0755); + mkdirat(db->root_fd, "var/cache/apk", 0755); mkdirat(db->root_fd, "var/cache/misc", 0755); + mkdirat(db->root_fd, "var/lock", 0755); - fd = openat(db->root_fd, "var/lib/apk/world", O_CREAT|O_RDWR|O_TRUNC|O_CLOEXEC, 0644); + fd = openat(db->root_fd, apk_world_file, O_CREAT|O_RDWR|O_TRUNC|O_CLOEXEC, 0644); if (fd < 0) return -errno; close(fd); @@ -1055,14 +1049,83 @@ static void handle_alarm(int sig) { } +static char *find_mountpoint(int atfd, const char *rel_path) +{ + struct mntent *me; + struct stat64 st; + FILE *f; + char *ret = NULL; + dev_t dev; + + if (fstatat64(atfd, rel_path, &st, 0) != 0) + return NULL; + dev = st.st_dev; + + f = setmntent("/proc/mounts", "r"); + if (f == NULL) + return NULL; + while ((me = getmntent(f)) != NULL) { + if (strcmp(me->mnt_fsname, "rootfs") == 0) + continue; + if (fstatat64(atfd, me->mnt_dir, &st, 0) == 0 && + st.st_dev == dev) { + ret = strdup(me->mnt_dir); + break; + } + } + endmntent(f); + + return ret; +} + +static int do_remount(const char *path, const char *option) +{ + pid_t pid; + int status; + + pid = fork(); + if (pid < 0) + return -errno; + + if (pid == 0) { + execl("/bin/mount", "mount", "-o", "remount", "-o", + option, path, NULL); + return 1; + } + + waitpid(pid, &status, 0); + if (!WIFEXITED(status)) + return -1; + + return WEXITSTATUS(status); +} + +static void relocate_database(struct apk_database *db) +{ + mkdirat(db->root_fd, "etc", 0755); + mkdirat(db->root_fd, "etc/apk", 0755); + mkdirat(db->root_fd, "lib", 0755); + mkdirat(db->root_fd, "lib/apk", 0755); + mkdirat(db->root_fd, "lib/apk/db", 0755); + mkdirat(db->root_fd, "var", 0755); + mkdirat(db->root_fd, "var/cache", 0755); + mkdirat(db->root_fd, "var/cache/apk", 0755); + mkdirat(db->root_fd, "var/cache/misc", 0755); + mkdirat(db->root_fd, "var/lock", 0755); + apk_move_file(db->root_fd, apk_world_file_old, apk_world_file); + apk_move_file(db->root_fd, apk_scripts_file_old, apk_scripts_file); + apk_move_file(db->root_fd, apk_triggers_file_old, apk_triggers_file); + apk_move_file(db->root_fd, apk_installed_file_old, apk_installed_file); +} + int apk_db_open(struct apk_database *db, struct apk_db_options *dbopts) { const char *msg = NULL; struct apk_repository_list *repo = NULL; struct apk_bstream *bs; - struct stat64 st; + struct statfs stfs; apk_blob_t blob; - int r, rr = 0; + int r, fd, rr = 0; memset(db, 0, sizeof(*db)); if (apk_flags & APK_SIMULATE) { @@ -1083,9 +1146,13 @@ int apk_db_open(struct apk_database *db, struct apk_db_options *dbopts) list_init(&db->installed.triggers); apk_dependency_array_init(&db->world); apk_string_array_init(&db->protected_paths); - db->cache_dir = apk_static_cache_dir; db->permanent = 1; + if (dbopts->root && dbopts->arch) { + db->arch = apk_blob_atomize(APK_BLOB_STR(dbopts->arch)); + } else { + db->arch = apk_blob_atomize(APK_BLOB_STR(APK_DEFAULT_ARCH)); + } db->root = strdup(dbopts->root ?: "/"); db->root_fd = openat(AT_FDCWD, db->root, O_RDONLY | O_CLOEXEC); if (db->root_fd < 0 && (dbopts->open_flags & APK_OPENF_CREATE)) { @@ -1096,17 +1163,17 @@ int apk_db_open(struct apk_database *db, struct apk_db_options *dbopts) msg = "Unable to open root"; goto ret_errno; } - if (fstat64(db->root_fd, &st) != 0 || major(st.st_dev) == 0) + if (fstatfs(db->root_fd, &stfs) == 0 && + stfs.f_type == 0x01021994 /* TMPFS_MAGIC */) db->permanent = 0; - if (fstatat64(db->root_fd, apk_linked_cache_dir, &st, 0) == 0 && - S_ISDIR(st.st_mode) && major(st.st_dev) != 0) - db->cache_dir = apk_linked_cache_dir; - apk_id_cache_init(&db->id_cache, db->root_fd); if (dbopts->open_flags & APK_OPENF_WRITE) { - db->lock_fd = openat(db->root_fd, "var/lib/apk/lock", + if (faccessat(db->root_fd, apk_installed_file_old, F_OK, 0) == 0) + relocate_database(db); + + db->lock_fd = openat(db->root_fd, apk_lock_file, O_CREAT | O_RDWR | O_CLOEXEC, 0400); if (db->lock_fd < 0 && errno == ENOENT && (dbopts->open_flags & APK_OPENF_CREATE)) { @@ -1115,7 +1182,7 @@ int apk_db_open(struct apk_database *db, struct apk_db_options *dbopts) msg = "Unable to create database"; goto ret_r; } - db->lock_fd = openat(db->root_fd, "var/lib/apk/lock", + db->lock_fd = openat(db->root_fd, apk_lock_file, O_CREAT | O_RDWR | O_CLOEXEC, 0400); } if (db->lock_fd < 0 || @@ -1144,10 +1211,25 @@ int apk_db_open(struct apk_database *db, struct apk_db_options *dbopts) blob = APK_BLOB_STR("etc:*etc/init.d"); apk_blob_for_each_segment(blob, ":", add_protected_path, db); - db->arch = apk_blob_atomize(APK_BLOB_STR(apk_arch)); - db->cache_fd = openat(db->root_fd, db->cache_dir, O_RDONLY | O_CLOEXEC); - mkdirat(db->cache_fd, "tmp", 0644); - db->cachetmp_fd = openat(db->cache_fd, "tmp", O_RDONLY | O_CLOEXEC); + /* figure out where to have the cache */ + fd = openat(db->root_fd, apk_linked_cache_dir, O_RDONLY | O_CLOEXEC); + if (fd >= 0 && fstatfs(fd, &stfs) == 0 && stfs.f_type != 0x01021994 /* TMPFS_MAGIC */) { + struct statvfs stvfs; + + db->cache_dir = apk_linked_cache_dir; + db->cache_fd = fd; + mkdirat(db->cache_fd, "tmp", 0644); + db->cachetmp_fd = openat(db->cache_fd, "tmp", O_RDONLY | O_CLOEXEC); + if (fstatvfs(fd, &stvfs) == 0 && (stvfs.f_flag & ST_RDONLY) != 0) + db->ro_cache = 1; + } else { + if (fd >= 0) + close(fd); + db->cache_dir = apk_static_cache_dir; + db->cache_fd = openat(db->root_fd, db->cache_dir, O_RDONLY | O_CLOEXEC); + db->cachetmp_fd = db->cache_fd; + } + db->keys_fd = openat(db->root_fd, dbopts->keys_dir ?: "etc/apk/keys", O_RDONLY | O_CLOEXEC); @@ -1211,6 +1293,21 @@ int apk_db_open(struct apk_database *db, struct apk_db_options *dbopts) "might not function properly"); } + if ((dbopts->open_flags & (APK_OPENF_WRITE | APK_OPENF_CACHE_WRITE)) && + db->ro_cache) { + /* remount cache read-write */ + db->cache_remount_dir = find_mountpoint(db->root_fd, db->cache_dir); + if (db->cache_remount_dir == NULL) { + apk_warning("Unable to find cache directory mount point"); + } else if (do_remount(db->cache_remount_dir, "rw") != 0) { + free(db->cache_remount_dir); + db->cache_remount_dir = NULL; + apk_error("Unable to remount cache read-write"); + r = EROFS; + goto ret_r; + } + } + return rr; ret_errno: @@ -1242,8 +1339,8 @@ int apk_db_write_config(struct apk_database *db) } os = apk_ostream_to_file(db->root_fd, - "var/lib/apk/world", - "var/lib/apk/world.new", + apk_world_file, + apk_world_file_tmp, 0644); if (os == NULL) return -1; @@ -1255,8 +1352,8 @@ int apk_db_write_config(struct apk_database *db) return r; os = apk_ostream_to_file(db->root_fd, - "var/lib/apk/installed", - "var/lib/apk/installed.new", + apk_installed_file, + apk_installed_file_tmp, 0644); if (os == NULL) return -1; @@ -1266,8 +1363,8 @@ int apk_db_write_config(struct apk_database *db) return r; os = apk_ostream_to_file(db->root_fd, - "var/lib/apk/scripts.tar", - "var/lib/apk/scripts.tar.new", + apk_scripts_file, + apk_scripts_file_tmp, 0644); if (os == NULL) return -1; @@ -1276,12 +1373,11 @@ int apk_db_write_config(struct apk_database *db) if (r < 0) return r; - unlinkat(db->root_fd, "var/lib/apk/scripts", 0); apk_db_index_write_nr_cache(db); os = apk_ostream_to_file(db->root_fd, - "var/lib/apk/triggers", - "var/lib/apk/triggers.new", + apk_triggers_file, + apk_triggers_file_tmp, 0644); if (os == NULL) return -1; @@ -1300,6 +1396,12 @@ void apk_db_close(struct apk_database *db) struct hlist_node *dc, *dn; int i; + if (db->cache_remount_dir) { + do_remount(db->cache_remount_dir, "ro"); + free(db->cache_remount_dir); + db->cache_remount_dir = NULL; + } + apk_id_cache_free(&db->id_cache); list_for_each_entry(ipkg, &db->installed.packages, installed_pkgs_list) { @@ -1323,7 +1425,7 @@ void apk_db_close(struct apk_database *db) if (db->keys_fd) close(db->keys_fd); - if (db->cachetmp_fd) + if (db->cachetmp_fd && db->cachetmp_fd != db->cache_fd) close(db->cachetmp_fd); if (db->cache_fd) close(db->cache_fd); @@ -1423,21 +1525,37 @@ struct apk_package *apk_db_get_file_owner(struct apk_database *db, return dbf->diri->pkg; } +int apk_repo_format_filename(char *buf, size_t len, + const char *repourl, apk_blob_t *arch, + const char *item) +{ + int n; + + if (arch != NULL) + n = snprintf(buf, len, "%s%s" BLOB_FMT "/%s", + repourl, repourl[strlen(repourl)-1] == '/' ? "" : "/", + BLOB_PRINTF(*arch), item); + else + n = snprintf(buf, len, "%s%s%s", + repourl, repourl[strlen(repourl)-1] == '/' ? "" : "/", + item); + + return n; +} + static int apk_repo_is_remote(struct apk_repository *repo) { return repo->csum.type != APK_CHECKSUM_NONE; } static struct apk_bstream *apk_repo_file_open(struct apk_repository *repo, - apk_blob_t arch, + apk_blob_t *arch, const char *file, char *buf, int buflen) { const char *url = repo->url; - snprintf(buf, buflen, "%s%s" BLOB_FMT "/%s", - url, url[strlen(url)-1] == '/' ? "" : "/", - BLOB_PRINTF(arch), file); + apk_repo_format_filename(buf, buflen, url, arch, file); if ((apk_flags & APK_NO_NETWORK) && apk_repo_is_remote(repo)) return NULL; @@ -1497,7 +1615,7 @@ int apk_repository_update(struct apk_database *db, struct apk_repository *repo) return 0; apk_cache_format_index(APK_BLOB_BUF(cacheitem), repo); - r = apk_cache_download(db, repo->url, apkindex_tar_gz, cacheitem, + r = apk_cache_download(db, repo->url, db->arch, apkindex_tar_gz, cacheitem, (apk_flags & APK_ALLOW_UNTRUSTED) ? APK_SIGN_NONE : APK_SIGN_VERIFY); if (r != 0) @@ -1605,7 +1723,7 @@ int apk_db_add_repository(apk_database_t _db, apk_blob_t repository) bs = apk_bstream_from_file(db->cache_fd, buf); } else { db->local_repos |= BIT(r); - bs = apk_repo_file_open(repo, *db->arch, apkindex_tar_gz, buf, sizeof(buf)); + bs = apk_repo_file_open(repo, db->arch, apkindex_tar_gz, buf, sizeof(buf)); } if (bs == NULL) { apk_warning("%s: index failed to open", buf); @@ -2015,7 +2133,8 @@ static int apk_db_unpack_pkg(struct apk_database *db, if (bs == NULL) { apk_pkg_format_plain(pkg, APK_BLOB_BUF(item)); - bs = apk_repo_file_open(repo, *(pkg->arch ?: db->arch), item, file, sizeof(file)); + bs = apk_repo_file_open(repo, pkg->arch, + item, file, sizeof(file)); if (apk_repo_is_remote(repo)) need_copy = TRUE; } @@ -58,7 +58,7 @@ static int del_main(void *ctx, struct apk_database *db, int argc, char **argv) r |= apk_state_lock_dependency(state, &dep); } if (r == 0) - r = apk_state_commit(state, db); + r = apk_state_commit(state); else apk_state_print_errors(state); err: diff --git a/src/fetch.c b/src/fetch.c index b67a189..72b481d 100644 --- a/src/fetch.c +++ b/src/fetch.c @@ -109,20 +109,18 @@ static int fetch_package(struct fetch_ctx *fctx, return 0; } - apk_message("Downloading %s-%s", pkg->name->name, pkg->version); + apk_message("Downloading " PKG_VER_FMT, PKG_VER_PRINTF(pkg)); repo = apk_db_select_repo(db, pkg); if (repo == NULL) { - apk_error("%s-%s: package is not currently available", - pkg->name->name, pkg->version); + apk_error(PKG_VER_FMT ": package is not currently available", + PKG_VER_PRINTF(pkg)); return -1; } if (apk_flags & APK_SIMULATE) return 0; - snprintf(url, sizeof(url), "%s%s%s", repo->url, - repo->url[strlen(repo->url)-1] == '/' ? "" : "/", - pkgfile); + apk_repo_format_filename(url, sizeof(url), repo->url, pkg->arch, pkgfile); if (fctx->flags & FETCH_STDOUT) { fd = STDOUT_FILENO; @@ -89,7 +89,7 @@ static int fix_main(void *pctx, struct apk_database *db, int argc, char **argv) r |= apk_state_lock_dependency(state, &deps[i]); if (r == 0 || (apk_flags & APK_FORCE)) - r = apk_state_commit(state, db); + r = apk_state_commit(state); else apk_state_print_errors(state); err: diff --git a/src/index.c b/src/index.c index d2b4b01..442e98a 100644 --- a/src/index.c +++ b/src/index.c @@ -25,6 +25,7 @@ struct index_ctx { const char *index; const char *output; const char *description; + apk_blob_t *rewrite_arch; time_t index_mtime; int method; }; @@ -44,6 +45,9 @@ static int index_parse(void *ctx, struct apk_db_options *dbopts, case 'd': ictx->description = optarg; break; + case 0x10000: + ictx->rewrite_arch = apk_blob_atomize(APK_BLOB_STR(optarg)); + break; default: return -1; } @@ -88,6 +92,7 @@ static int index_main(void *ctx, struct apk_database *db, int argc, char **argv) struct apk_file_info fi; int total, r, i, j, found, newpkgs = 0; struct index_ctx *ictx = (struct index_ctx *) ctx; + struct apk_package *pkg; if (isatty(STDOUT_FILENO) && ictx->output == NULL && !(apk_flags & APK_FORCE)) { @@ -139,12 +144,14 @@ static int index_main(void *ctx, struct apk_database *db, int argc, char **argv) break; for (j = 0; j < name->pkgs->num; j++) { - struct apk_package *pkg = name->pkgs->item[j]; + pkg = name->pkgs->item[j]; if (apk_blob_compare(bver, *pkg->version) != 0) continue; if (pkg->size != fi.size) continue; pkg->filename = strdup(argv[i]); + if (ictx->rewrite_arch != NULL) + pkg->arch = ictx->rewrite_arch; found = TRUE; break; } @@ -153,8 +160,10 @@ static int index_main(void *ctx, struct apk_database *db, int argc, char **argv) if (!found) { struct apk_sign_ctx sctx; apk_sign_ctx_init(&sctx, ictx->method, NULL, db->keys_fd); - if (apk_pkg_read(db, argv[i], &sctx, NULL) == 0) + if (apk_pkg_read(db, argv[i], &sctx, &pkg) == 0) newpkgs++; + if (ictx->rewrite_arch != NULL) + pkg->arch = ictx->rewrite_arch; apk_sign_ctx_free(&sctx); } } @@ -214,6 +223,8 @@ static struct apk_option index_options[] = { { 'd', "description", "Embed TEXT as description and version " "information of the repository index", required_argument, "TEXT" }, + { 0x10000, "rewrite-arch", "Use ARCH as architery for all packages", + required_argument, "ARCH" }, }; static struct apk_applet apk_index = { @@ -33,6 +33,8 @@ struct info_ctx { #define APK_INFO_RDEPENDS 0x10 #define APK_INFO_CONTENTS 0x20 #define APK_INFO_TRIGGERS 0x40 +#define APK_INFO_INSTALL_IF 0x80 +#define APK_INFO_RINSTALL_IF 0x100 static void verbose_print_pkg(struct apk_package *pkg, int minimal_verbosity) { @@ -168,15 +170,22 @@ static void info_print_size(struct apk_package *pkg) static void info_print_depends(struct apk_package *pkg) { + apk_blob_t separator = APK_BLOB_STR(apk_verbosity > 1 ? " " : "\n"); + char dep[256]; int i; - char *separator = apk_verbosity > 1 ? " " : "\n"; + if (apk_verbosity == 1) printf(PKG_VER_FMT " depends on:\n", PKG_VER_PRINTF(pkg)); if (apk_verbosity > 1) printf("%s: ", pkg->name->name); - for (i = 0; i < pkg->depends->num; i++) - printf("%s%s", pkg->depends->item[i].name->name, separator); + for (i = 0; i < pkg->depends->num; i++) { + apk_blob_t b = APK_BLOB_BUF(dep); + apk_blob_push_dep(&b, &pkg->depends->item[i]); + apk_blob_push_blob(&b, separator); + b = apk_blob_pushed(APK_BLOB_BUF(dep), b); + fwrite(b.ptr, b.len, 1, stdout); + } } static void info_print_required_by(struct apk_package *pkg) @@ -211,6 +220,58 @@ static void info_print_required_by(struct apk_package *pkg) } } +static void info_print_install_if(struct apk_package *pkg) +{ + apk_blob_t separator = APK_BLOB_STR(apk_verbosity > 1 ? " " : "\n"); + char dep[256]; + int i; + + if (apk_verbosity == 1) + printf(PKG_VER_FMT " has auto-install rule:\n", + PKG_VER_PRINTF(pkg)); + if (apk_verbosity > 1) + printf("%s: ", pkg->name->name); + for (i = 0; i < pkg->install_if->num; i++) { + apk_blob_t b = APK_BLOB_BUF(dep); + apk_blob_push_dep(&b, &pkg->install_if->item[i]); + apk_blob_push_blob(&b, separator); + b = apk_blob_pushed(APK_BLOB_BUF(dep), b); + fwrite(b.ptr, b.len, 1, stdout); + } +} + +static void info_print_rinstall_if(struct apk_package *pkg) +{ + int i, j, k; + char *separator = apk_verbosity > 1 ? " " : "\n"; + + if (apk_verbosity == 1) + printf(PKG_VER_FMT " affects auto-installation of:\n", + PKG_VER_PRINTF(pkg)); + if (apk_verbosity > 1) + printf("%s: ", pkg->name->name); + for (i = 0; i < pkg->name->rinstall_if->num; i++) { + struct apk_name *name0 = pkg->name->rinstall_if->item[i]; + + /* Check only the package that is installed, and that + * it actually has this package in install_if. */ + for (j = 0; j < name0->pkgs->num; j++) { + struct apk_package *pkg0 = name0->pkgs->item[j]; + + if (pkg0->ipkg == NULL) + continue; + for (k = 0; k < pkg0->install_if->num; k++) { + if (pkg0->install_if->item[k].name != pkg->name) + continue; + printf(PKG_VER_FMT "%s", + PKG_VER_PRINTF(pkg0), + separator); + break; + } + } + } +} + static void info_print_contents(struct apk_package *pkg) { struct apk_installed_package *ipkg = pkg->ipkg; @@ -260,9 +321,12 @@ static void info_subaction(struct info_ctx *ctx, struct apk_package *pkg) info_print_required_by, info_print_contents, info_print_triggers, + info_print_install_if, + info_print_rinstall_if, }; const int requireipkg = - APK_INFO_CONTENTS | APK_INFO_TRIGGERS | APK_INFO_RDEPENDS; + APK_INFO_CONTENTS | APK_INFO_TRIGGERS | APK_INFO_RDEPENDS | + APK_INFO_RINSTALL_IF; int i; for (i = 0; i < ARRAY_SIZE(subactions); i++) { @@ -317,6 +381,12 @@ static int info_parse(void *ctx, struct apk_db_options *dbopts, case 'r': ictx->subaction_mask |= APK_INFO_RDEPENDS; break; + case 'I': + ictx->subaction_mask |= APK_INFO_INSTALL_IF; + break; + case 'i': + ictx->subaction_mask |= APK_INFO_RINSTALL_IF; + break; case 's': ictx->subaction_mask |= APK_INFO_SIZE; break; @@ -354,6 +424,8 @@ static struct apk_option info_options[] = { { 'W', "who-owns", "Print the package owning the specified file" }, { 'R', "depends", "List packages that the PACKAGE depends on" }, { 'r', "rdepends", "List all packages depending on PACKAGE" }, + { 'i', "install-if", "List the PACKAGE's install-if rule" }, + { 'I', "rinstall-if", "List all packages having install-if referencing PACKAGE" }, { 'w', "webpage", "Show URL for more information about PACKAGE" }, { 's', "size", "Show installed size of PACKAGE" }, { 'd', "description", "Print description for PACKAGE" }, @@ -739,6 +739,37 @@ size_t apk_ostream_write_string(struct apk_ostream *os, const char *string) return len; } +int apk_move_file(int atfd, const char *from, const char *to) +{ + struct apk_istream *is; + struct stat64 st; + int rc, tofd; + + if (renameat(atfd, from, atfd, to) == 0) + return 0; + + if (fstatat64(atfd, from, &st, 0) != 0) + return -errno; + + is = apk_istream_from_file(atfd, from); + if (is == NULL) + return -ENOENT; + + tofd = openat(atfd, to, O_CREAT | O_RDWR | O_TRUNC | O_CLOEXEC, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + if (tofd < 0) { + rc = -errno; + goto close_is; + } + + rc = apk_istream_splice(is, tofd, st.st_size, NULL, NULL); + close(tofd); + unlinkat(atfd, from, 0); +close_is: + is->close(is); + return rc; +} + struct cache_item { apk_hash_node hash_node; unsigned int genid; diff --git a/src/lua-apk.c b/src/lua-apk.c index 835d379..cb36784 100644 --- a/src/lua-apk.c +++ b/src/lua-apk.c @@ -9,7 +9,8 @@ #include "apk_database.h" #define LIBNAME "apk" -#define APKDB_META "apk_database" +#define APK_DB_META "apk_database" +#define APK_IPKG_META "apk_installed_package" int apk_verbosity; unsigned int apk_flags; @@ -131,9 +132,9 @@ static struct apk_database *checkdb(lua_State *L, int index) { struct apk_database *db; luaL_checktype(L, index, LUA_TUSERDATA); - db = (struct apk_database *) luaL_checkudata(L, index, APKDB_META); + db = (struct apk_database *) luaL_checkudata(L, index, APK_DB_META); if (db == NULL) - luaL_typerror(L, index, APKDB_META); + luaL_typerror(L, index, APK_DB_META); return db; } @@ -152,7 +153,7 @@ static int Papk_db_open(lua_State *L) opts.open_flags |= APK_OPENF_READ; db = lua_newuserdata(L, sizeof(struct apk_database)); - luaL_getmetatable(L, APKDB_META); + luaL_getmetatable(L, APK_DB_META); lua_setmetatable(L, -2); r = apk_db_open(db, &opts); @@ -168,7 +169,6 @@ static int Papk_db_close(lua_State *L) return 0; } - static int push_package(lua_State *L, struct apk_package *pkg) { if (pkg == NULL) { @@ -193,12 +193,82 @@ static int Papk_who_owns(lua_State *L) return push_package(L, pkg); } +static int Papk_exists(lua_State *L) +{ + struct apk_database *db = checkdb(L, 1); + const char *depstr = luaL_checkstring(L, 2); + struct apk_dependency dep; + struct apk_name *name; + struct apk_package *pkg; + int i, r; + + r = apk_dep_from_blob(&dep, db, APK_BLOB_STR(depstr)); + if (r != 0) + goto ret_nil; + + name = dep.name; + for (i = 0; i < name->pkgs->num; i++) { + pkg = name->pkgs->item[i]; + if (pkg->ipkg != NULL) + break; + } + if (i >= name->pkgs->num) + goto ret_nil; + + if (!apk_dep_is_satisfied(&dep, pkg)) + goto ret_nil; + + return push_package(L, pkg); +ret_nil: + lua_pushnil(L); + return 1; +} + +// Iterator of all installed packages +struct apk_installed_package_iterator { + struct list_head *end; + struct apk_installed_package *node; +}; + +static int iterate_installed(lua_State *L) +{ + struct apk_installed_package_iterator *i; + struct apk_installed_package *ipkg; + i = (struct apk_installed_package_iterator *)lua_touserdata(L, lua_upvalueindex(1)); + ipkg = i->node; + + if (&ipkg->installed_pkgs_list == i->end) + return 0; + + i->node = list_entry(ipkg->installed_pkgs_list.next, + typeof(*ipkg), installed_pkgs_list); + return push_package(L, ipkg->pkg); + +} +static int Pinstalled(lua_State *L) +{ + struct apk_database *db = checkdb(L, 1); + struct apk_installed_package_iterator *i; + + i = (struct apk_installed_package_iterator *) lua_newuserdata(L, sizeof(*i)); + i->end = &db->installed.packages; + i->node = list_entry((&db->installed.packages)->next, + struct apk_installed_package, + installed_pkgs_list); + + lua_pushcclosure(L, iterate_installed, 1); + return 1; +} + static const luaL_reg reg_apk_methods[] = { {"version_validate", Pversion_validate}, {"version_compare", Pversion_compare}, {"version_is_less", Pversion_is_less}, {"db_open", Papk_db_open}, {"who_owns", Papk_who_owns}, + {"exists", Papk_exists}, + {"is_installed", Papk_exists}, + {"installed", Pinstalled}, {NULL, NULL} }; @@ -214,7 +284,7 @@ LUALIB_API int luaopen_apk(lua_State *L) lua_pushliteral(L, APK_VERSION); lua_settable(L, -3); - luaL_newmetatable(L, APKDB_META); + luaL_newmetatable(L, APK_DB_META); luaL_register(L, NULL, reg_apk_db_meta_methods); lua_pushliteral(L, "__index"); lua_pushvalue(L, -3); diff --git a/src/package.c b/src/package.c index 1a5d502..2699420 100644 --- a/src/package.c +++ b/src/package.c @@ -659,6 +659,18 @@ int apk_pkg_add_info(struct apk_database *db, struct apk_package *pkg, case 'i': apk_deps_parse(db, &pkg->install_if, value); break; + case 'o': + pkg->origin = apk_blob_atomize_dup(value); + break; + case 'm': + pkg->maintainer = apk_blob_atomize_dup(value); + break; + case 't': + pkg->build_time = apk_blob_pull_uint(&value, 10); + break; + case 'c': + pkg->commit = apk_blob_cstr(value); + break; case 'F': case 'M': case 'R': case 'Z': /* installed db entries which are handled in database.c */ return 1; @@ -691,6 +703,10 @@ static int read_info_line(void *ctx, apk_blob_t line) { "arch", 'A' }, { "depend", 'D' }, { "install_if", 'i' }, + { "origin", 'o' }, + { "maintainer", 'm' }, + { "builddate", 't' }, + { "commit", 'c' }, }; struct read_info_ctx *ri = (struct read_info_ctx *) ctx; apk_blob_t l, r; @@ -800,6 +816,8 @@ void apk_pkg_free(struct apk_package *pkg) free(pkg->url); if (pkg->description) free(pkg->description); + if (pkg->commit) + free(pkg->commit); free(pkg); } @@ -968,6 +986,22 @@ int apk_pkg_write_index_entry(struct apk_package *info, apk_blob_push_blob(&bbuf, APK_BLOB_STR(info->url)); apk_blob_push_blob(&bbuf, APK_BLOB_STR("\nL:")); apk_blob_push_blob(&bbuf, *info->license); + if (info->origin) { + apk_blob_push_blob(&bbuf, APK_BLOB_STR("\no:")); + apk_blob_push_blob(&bbuf, *info->origin); + } + if (info->maintainer) { + apk_blob_push_blob(&bbuf, APK_BLOB_STR("\nm:")); + apk_blob_push_blob(&bbuf, *info->maintainer); + } + if (info->build_time) { + apk_blob_push_blob(&bbuf, APK_BLOB_STR("\nt:")); + apk_blob_push_uint(&bbuf, info->build_time, 10); + } + if (info->commit) { + apk_blob_push_blob(&bbuf, APK_BLOB_STR("\nc:")); + apk_blob_push_blob(&bbuf, APK_BLOB_STR(info->commit)); + } apk_blob_push_blob(&bbuf, APK_BLOB_STR("\n")); if (APK_BLOB_IS_NULL(bbuf)) diff --git a/src/state.c b/src/state.c index 4a4641d..6de3629 100644 --- a/src/state.c +++ b/src/state.c @@ -138,14 +138,20 @@ static struct apk_name_choices *name_choices_new(struct apk_database *db, if (dep->name != name) continue; - for (j = 0; j < nc->num; ) { - if (apk_dep_is_satisfied(dep, nc->pkgs[j])) { - j++; - } else { - nc->pkgs[j] = nc->pkgs[nc->num - 1]; - nc->num--; + if (apk_flags & APK_PREFER_AVAILABLE) { + dep->version = apk_blob_atomize(APK_BLOB_NULL); + dep->result_mask = APK_DEPMASK_REQUIRE; + } else { + for (j = 0; j < nc->num; ) { + if (apk_dep_is_satisfied(dep, nc->pkgs[j])) { + j++; + } else { + nc->pkgs[j] = nc->pkgs[nc->num - 1]; + nc->num--; + } } } + break; } return nc; @@ -232,6 +238,50 @@ void apk_state_unref(struct apk_state *state) free(state); } +static struct apk_package *get_locked_or_installed_package( + struct apk_state *state, + struct apk_name *name) +{ + int i; + + if (ns_locked(state->name[name->id])) + return ns_to_pkg(state->name[name->id]); + + if (!ns_empty(state->name[name->id])) { + struct apk_name_choices *ns = + ns_to_choices(state->name[name->id]); + + for (i = 0; i < ns->num; i++) { + if (ns->pkgs[i]->ipkg != NULL) + return ns->pkgs[i]; + } + return NULL; + } + + for (i = 0; i < name->pkgs->num; i++) { + if (name->pkgs->item[i]->ipkg != NULL) + return name->pkgs->item[i]; + } + return NULL; +} + +static int check_dependency_array(struct apk_state *state, + struct apk_dependency_array *da) +{ + struct apk_package *pkg; + int i; + + for (i = 0; i < da->num; i++) { + pkg = get_locked_or_installed_package(state, da->item[i].name); + if (pkg == NULL && da->item[i].result_mask != APK_DEPMASK_CONFLICT) + return 0; + if (!apk_dep_is_satisfied(&da->item[i], pkg)) + return 0; + } + + return da->num; +} + static int apk_state_add_change(struct apk_state *state, struct apk_package *oldpkg, struct apk_package *newpkg) @@ -334,20 +384,22 @@ int apk_state_prune_dependency(struct apk_state *state, return c->num; } -int apk_state_lock_dependency(struct apk_state *state, - struct apk_dependency *dep) +int apk_state_autolock_name(struct apk_state *state, struct apk_name *name, + int install_if) { - struct apk_name *name = dep->name; struct apk_name_choices *c; - struct apk_package *installed = NULL, *latest = NULL, *use; - int i, r; - - r = apk_state_prune_dependency(state, dep); - if (r <= 0) - return r; + struct apk_package *installed = NULL, *latest = NULL, *use; + int i; if (ns_pending(state->name[name->id])) return apk_state_lock_name(state, name, ns_to_pkg(state->name[name->id])); + if (ns_locked(state->name[name->id])) + return 0; + if (ns_empty(state->name[name->id])) { + /* This name has not been visited yet. + * Construct list of candidates. */ + state->name[name->id] = ns_from_choices(name_choices_new(state->db, name)); + } c = ns_to_choices(state->name[name->id]); #if 1 @@ -355,6 +407,10 @@ int apk_state_lock_dependency(struct apk_state *state, for (i = 0; i < c->num; i++) { struct apk_package *pkg = c->pkgs[i]; + if (install_if && + !check_dependency_array(state, pkg->install_if)) + continue; + if (pkg->ipkg != NULL) installed = pkg; else if (!apk_state_pkg_available(state, pkg)) @@ -396,7 +452,13 @@ int apk_state_lock_dependency(struct apk_state *state, use = latest; } if (use == NULL) - return -1; + return -2; + + /* Install_if check did not result in package selection change: + * do not lock the package yet as the preferency might change + * later. */ + if (install_if && use->ipkg != NULL) + return 0; return apk_state_lock_name(state, name, use); #else @@ -411,6 +473,18 @@ int apk_state_lock_dependency(struct apk_state *state, #endif } +int apk_state_lock_dependency(struct apk_state *state, + struct apk_dependency *dep) +{ + int r; + + r = apk_state_prune_dependency(state, dep); + if (r <= 0) + return r; + + return apk_state_autolock_name(state, dep->name, FALSE); +} + static int apk_state_fix_package(struct apk_state *state, struct apk_package *pkg) { @@ -420,12 +494,18 @@ static int apk_state_fix_package(struct apk_state *state, return 0; for (i = 0; i < pkg->depends->num; i++) { - r = apk_state_lock_dependency(state, - &pkg->depends->item[i]); - if (r != 0) - ret = -1; + if (pkg->depends->item[i].name->flags & APK_NAME_TOPLEVEL_OVERRIDE) { + r = apk_state_prune_dependency(state, + &pkg->depends->item[i]); + if (r < 0) + ret = -1; + } else { + r = apk_state_lock_dependency(state, + &pkg->depends->item[i]); + if (r != 0) + ret = -1; + } } - return ret; } @@ -467,48 +547,19 @@ static int for_each_broken_reverse_depency(struct apk_state *state, void *ctx) { struct apk_package *pkg0; - int i, j, r; + int i, r; for (i = 0; i < name->rdepends->num; i++) { struct apk_name *name0 = name->rdepends->item[i]; - if (ns_locked(state->name[name0->id])) { - pkg0 = ns_to_pkg(state->name[name0->id]); - if (pkg0 == NULL) - continue; - r = call_if_dependency_broke(state, pkg0, name, - cb, ctx); - if (r != 0) - return r; - } else if (!ns_empty(state->name[name0->id])) { - struct apk_name_choices *ns = - ns_to_choices(state->name[name0->id]); - - for (j = 0; j < ns->num; j++) { - if (ns->pkgs[j]->ipkg == NULL) - continue; - r = call_if_dependency_broke(state, - ns->pkgs[j], - name, cb, ctx); - if (r != 0) - return r; - break; - } - } else { - for (j = 0; j < name0->pkgs->num; j++) { - pkg0 = name0->pkgs->item[j]; - - if (pkg0->ipkg == NULL) - continue; + pkg0 = get_locked_or_installed_package(state, name0); + if (pkg0 == NULL) + continue; - r = call_if_dependency_broke(state, - name0->pkgs->item[j], - name, cb, ctx); - if (r != 0) - return r; - break; - } - } + r = call_if_dependency_broke(state, pkg0, name, + cb, ctx); + if (r != 0) + return r; } return 0; @@ -578,15 +629,19 @@ int apk_state_lock_name(struct apk_state *state, } /* If the chosen package is installed, all is done here */ - if (oldpkg == newpkg && - (newpkg == NULL || - !(newpkg->name->flags & APK_NAME_REINSTALL))) - return 0; + if ((oldpkg != newpkg) || + (newpkg != NULL && (newpkg->name->flags & APK_NAME_REINSTALL))) { + /* Track change */ + r = apk_state_add_change(state, oldpkg, newpkg); + if (r != 0) + return r; + } - /* Track change */ - r = apk_state_add_change(state, oldpkg, newpkg); - if (r != 0) - return r; + /* Check all reverse install_if's */ + if (newpkg != NULL) { + for (i = 0; i < newpkg->name->rinstall_if->num; i++) + apk_state_autolock_name(state, newpkg->name->rinstall_if->item[i], TRUE); + } return 0; } @@ -655,22 +710,19 @@ static void apk_count_change(struct apk_change *change, struct apk_stats *stats) stats->packages ++; } -static inline void apk_draw_progress(int percent, int last) +static void apk_draw_progress(int percent) { - char tmp[128]; - char reset[128]; + const int bar_width = (apk_screen_width - 7); int i; - snprintf(tmp, sizeof(tmp), "-[ ]- %3i%%", percent); - for (i = 0; (i < (percent/5)) && (i < (sizeof(tmp)-2)); i++) - tmp[2+i] = '#'; - memset(reset, '\b', strlen(tmp)); - fwrite(tmp, strlen(tmp), 1, stderr); - if (!last) - fwrite(reset, strlen(tmp), 1, stderr); - else if (apk_verbosity > 0) - fwrite("\n", 1, 1, stderr); + fprintf(stderr, "\e7%3i%% [", percent); + for (i = 0; i < bar_width * percent / 100; i++) + fputc('#', stderr); + for (; i < bar_width; i++) + fputc(' ', stderr); + fputc(']', stderr); fflush(stderr); + fputs("\e8\e[0K", stderr); } struct progress { @@ -692,7 +744,7 @@ static void progress_cb(void *ctx, size_t progress) prog->total.bytes + prog->total.packages); if (prog->count != count) - apk_draw_progress(count, 0); + apk_draw_progress(count); prog->count = count; } @@ -799,6 +851,23 @@ static int apk_state_autoclean(struct apk_state *state, return r; } } + + for (i = 0; i < pkg->name->rinstall_if->num; i++) { + struct apk_name *n = pkg->name->rinstall_if->item[i]; + + if (ns_locked(state->name[n->id])) + continue; + if (n->flags & APK_NAME_TOPLEVEL) + continue; + + r = apk_state_autolock_name(state, n, TRUE); + if (r == -2) { + r = apk_state_lock_name(state, n, NULL); + if (r != 0) + return r; + } + } + return 0; } @@ -874,11 +943,11 @@ void apk_state_print_errors(struct apk_state *state) printf("\n"); } -int apk_state_commit(struct apk_state *state, - struct apk_database *db) +int apk_state_commit(struct apk_state *state) { struct progress prog; struct apk_change *change; + struct apk_database *db = state->db; int n = 0, r = 0, size_diff = 0, toplevel = FALSE, deleteonly = TRUE; /* Count what needs to be done */ @@ -940,6 +1009,8 @@ int apk_state_commit(struct apk_state *state, list_for_each_entry(change, &state->change_list_head, change_list) { n++; apk_print_change(db, change->oldpkg, change->newpkg, n, state->num_changes); + if (apk_flags & APK_PROGRESS) + apk_draw_progress(prog.count); prog.pkg = change->newpkg; if (!(apk_flags & APK_SIMULATE)) { @@ -961,7 +1032,7 @@ int apk_state_commit(struct apk_state *state, apk_count_change(change, &prog.done); } if (apk_flags & APK_PROGRESS) - apk_draw_progress(100, 1); + apk_draw_progress(100); update_state: apk_db_run_triggers(db); diff --git a/src/upgrade.c b/src/upgrade.c index 795e62f..ec0dc91 100644 --- a/src/upgrade.c +++ b/src/upgrade.c @@ -33,21 +33,10 @@ static int upgrade_parse(void *ctx, struct apk_db_options *dbopts, int apk_do_self_upgrade(struct apk_database *db, struct apk_state *state) { struct apk_dependency dep; - int r, i; + int r; apk_dep_from_blob(&dep, db, APK_BLOB_STR("apk-tools")); - if (apk_flags & APK_PREFER_AVAILABLE) { - for (i = 0; i < db->world->num; i++) { - struct apk_dependency *dep0 = &db->world->item[i]; - if (dep0->name != dep.name) - continue; - dep0->version = apk_blob_atomize(APK_BLOB_NULL); - dep0->result_mask = APK_DEPMASK_REQUIRE; - break; - } - } - r = apk_state_lock_dependency(state, &dep); if (r != 0 || state->num_changes == 0) return r; @@ -57,13 +46,13 @@ int apk_do_self_upgrade(struct apk_database *db, struct apk_state *state) return 0; } - apk_message("Uprading first to new apk-tools:"); + apk_message("Upgrading critical system libraries and apk-tools:"); state->print_ok = 0; - r = apk_state_commit(state, db); + r = apk_state_commit(state); apk_state_unref(state); apk_db_close(db); - apk_message("Performing rest of the operation:"); + apk_message("Continuing the upgrade transaction with new apk-tools:"); execvp(apk_argv[0], apk_argv); apk_error("PANIC! Failed to re-execute new apk-tools!"); @@ -74,7 +63,6 @@ static int upgrade_main(void *ctx, struct apk_database *db, int argc, char **arg { struct apk_state *state = NULL; struct apk_name_array *missing; - apk_blob_t *null_atom = apk_blob_atomize(APK_BLOB_NULL); int i, r = 0; apk_flags |= APK_UPGRADE; @@ -92,11 +80,7 @@ static int upgrade_main(void *ctx, struct apk_database *db, int argc, char **arg for (i = 0; i < db->world->num; i++) { struct apk_dependency *dep = &db->world->item[i]; - if (dep->version != null_atom && - (apk_flags & APK_PREFER_AVAILABLE)) { - dep->result_mask = APK_DEPMASK_REQUIRE; - dep->version = null_atom; - } + if (dep->name->pkgs->num != 0) r |= apk_state_lock_dependency(state, dep); else @@ -117,7 +101,7 @@ static int upgrade_main(void *ctx, struct apk_database *db, int argc, char **arg if (i != 0) printf("\n"); - r = apk_state_commit(state, db); + r = apk_state_commit(state); } else apk_state_print_errors(state); err: @@ -70,6 +70,10 @@ static int fork_wget(const char *url, pid_t *ppid) close(fds[0]); dup2(open("/dev/null", O_RDONLY), STDIN_FILENO); dup2(fds[1], STDOUT_FILENO); + execlp("wget", "wget", "-q", "-O", "-", url, NULL); + /* fall back to busybox wget + * See http://redmine.alpinelinux.org/issues/347 + */ execlp("busybox", "wget", "-q", "-O", "-", url, NULL); exit(0); } |