diff --git a/src/apk_database.h b/src/apk_database.h index 28cff04..19cabaf 100644 --- a/src/apk_database.h +++ b/src/apk_database.h @@ -219,6 +219,7 @@ int apk_db_write_config(struct apk_database *db); int apk_db_permanent(struct apk_database *db); int apk_db_check_world(struct apk_database *db, struct apk_dependency_array *world); int apk_db_fire_triggers(struct apk_database *db); +int apk_db_run_script(struct apk_database *db, char *fn, char **argv); void apk_db_update_directory_permissions(struct apk_database *db); struct apk_package *apk_db_pkg_add(struct apk_database *db, struct apk_package *pkg); diff --git a/src/audit.c b/src/audit.c index 4312fd7..0c1fbfc 100644 --- a/src/audit.c +++ b/src/audit.c @@ -179,11 +179,8 @@ static int audit_directory_tree_item(void *ctx, int dirfd, const char *name) struct apk_file_info fi; int reason = 0; - if (bdir.len + bent.len + 1 >= sizeof(atctx->path)) - return -ENOMEM; - - if (apk_fileinfo_get(dirfd, name, APK_FI_NOFOLLOW, &fi) < 0) - return -EPERM; + if (bdir.len + bent.len + 1 >= sizeof(atctx->path)) return 0; + if (apk_fileinfo_get(dirfd, name, APK_FI_NOFOLLOW, &fi) < 0) return 0; memcpy(&atctx->path[atctx->pathlen], bent.ptr, bent.len); atctx->pathlen += bent.len; @@ -273,7 +270,7 @@ done: apk_db_dir_unref(db, child, FALSE); atctx->pathlen -= bent.len; - return reason < 0 ? reason : 0; + return 0; } static int audit_directory_tree(struct audit_tree_ctx *atctx, int dirfd) diff --git a/src/commit.c b/src/commit.c index b87311d..ae43474 100644 --- a/src/commit.c +++ b/src/commit.c @@ -216,6 +216,40 @@ static void run_triggers(struct apk_database *db, struct apk_changeset *changese } } +#define PRE_COMMIT_HOOK 0 +#define POST_COMMIT_HOOK 1 + +struct apk_commit_hook { + struct apk_database *db; + int type; +}; + +static int run_commit_hook(void *ctx, int dirfd, const char *file) +{ + static char *const commit_hook_str[] = { "pre-commit", "post-commit" }; + struct apk_commit_hook *hook = (struct apk_commit_hook *) ctx; + struct apk_database *db = hook->db; + char fn[PATH_MAX], *argv[] = { fn, (char *) commit_hook_str[hook->type], NULL }; + + if ((apk_flags & (APK_NO_SCRIPTS | APK_SIMULATE)) != 0) + return 0; + + snprintf(fn, sizeof(fn), "etc/apk/commit_hooks.d" "/%s", file); + if (apk_verbosity >= 2) apk_message("Executing: %s", fn); + + if (apk_db_run_script(db, fn, argv) < 0 && hook->type == PRE_COMMIT_HOOK) + return -1; + + return 0; +} + +static int run_commit_hooks(struct apk_database *db, int type) +{ + struct apk_commit_hook hook = { .db = db, .type = type }; + return apk_dir_foreach_file(openat(db->root_fd, "etc/apk/commit_hooks.d", O_RDONLY | O_CLOEXEC), + run_commit_hook, &hook); +} + int apk_solver_commit_changeset(struct apk_database *db, struct apk_changeset *changeset, struct apk_dependency_array *world) @@ -278,6 +312,9 @@ int apk_solver_commit_changeset(struct apk_database *db, } } + if (run_commit_hooks(db, PRE_COMMIT_HOOK) < 0) + return -1; + /* Go through changes */ foreach_array_item(change, changeset->changes) { r = change->old_pkg && @@ -308,6 +345,7 @@ int apk_solver_commit_changeset(struct apk_database *db, all_done: apk_dependency_array_copy(&db->world, world); apk_db_write_config(db); + run_commit_hooks(db, POST_COMMIT_HOOK); if (!db->performing_self_upgrade) { if (errors) @@ -328,7 +366,6 @@ all_done: db->installed.stats.packages); } } - return errors; } diff --git a/src/database.c b/src/database.c index 31ac3e4..0de7490 100644 --- a/src/database.c +++ b/src/database.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -1877,6 +1878,34 @@ int apk_db_fire_triggers(struct apk_database *db) return db->pending_triggers; } +int apk_db_run_script(struct apk_database *db, char *fn, char **argv) +{ + int status; + pid_t pid; + static char * const environment[] = { + "PATH=/usr/sbin:/usr/bin:/sbin:/bin", + NULL + }; + + pid = fork(); + if (pid == -1) { + apk_error("%s: fork: %s", basename(fn), strerror(errno)); + return -2; + } + if (pid == 0) { + umask(0022); + if (fchdir(db->root_fd) == 0 && chroot(".") == 0) + execve(fn, argv, environment); + exit(127); /* should not get here */ + } + waitpid(pid, &status, 0); + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { + apk_error("%s: script exited with error %d", basename(fn), WEXITSTATUS(status)); + return -1; + } + return 0; +} + static int update_permissions(apk_hash_item item, void *ctx) { struct apk_database *db = (struct apk_database *) ctx; diff --git a/src/io.c b/src/io.c index b48f932..8cf867b 100644 --- a/src/io.c +++ b/src/io.c @@ -741,6 +741,7 @@ int apk_dir_foreach_file(int dirfd, apk_dir_file_cb cb, void *ctx) { struct dirent *de; DIR *dir; + int ret = 0; if (dirfd < 0) return -1; @@ -759,11 +760,11 @@ int apk_dir_foreach_file(int dirfd, apk_dir_file_cb cb, void *ctx) (de->d_name[1] == '.' && de->d_name[2] == 0)) continue; } - cb(ctx, dirfd, de->d_name); + ret = cb(ctx, dirfd, de->d_name); + if (ret) break; } closedir(dir); - - return 0; + return ret; } struct apk_istream *apk_istream_from_file_gz(int atfd, const char *file) diff --git a/src/package.c b/src/package.c index c6e8e48..d1c9c8b 100644 --- a/src/package.c +++ b/src/package.c @@ -979,14 +979,9 @@ void apk_ipkg_run_script(struct apk_installed_package *ipkg, struct apk_database *db, unsigned int type, char **argv) { - static char * const environment[] = { - "PATH=/usr/sbin:/usr/bin:/sbin:/bin", - NULL - }; struct apk_package *pkg = ipkg->pkg; char fn[PATH_MAX]; - int fd, status, root_fd = db->root_fd; - pid_t pid; + int fd, root_fd = db->root_fd; if (type >= APK_SCRIPT_MAX || ipkg->script[type].ptr == NULL) return; @@ -1015,23 +1010,8 @@ void apk_ipkg_run_script(struct apk_installed_package *ipkg, } close(fd); - pid = fork(); - if (pid == -1) - goto error; - if (pid == 0) { - umask(0022); - if (fchdir(root_fd) == 0 && chroot(".") == 0) - execve(fn, argv, environment); - exit(1); - } - waitpid(pid, &status, 0); - unlinkat(root_fd, fn, 0); - apk_id_cache_reset(&db->id_cache); - - if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { - apk_error("%s: script exited with error %d", &fn[15], WEXITSTATUS(status)); + if (apk_db_run_script(db, fn, argv) < 0) ipkg->broken_script = 1; - } return; error: apk_error("%s: failed to execute: %s", &fn[15], apk_error_str(errno));