From: Michael Tremer Date: Thu, 13 Jun 2019 04:11:54 +0000 (+0100) Subject: libpakfire: Add function to run commands in chroot() X-Git-Tag: 0.9.28~1285^2~929 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=55b57cf692694232c0d7b72e98fcb7a52788a83f;p=pakfire.git libpakfire: Add function to run commands in chroot() Signed-off-by: Michael Tremer --- diff --git a/.gitignore b/.gitignore index 97eb45d2d..288961565 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ /src/systemd/*.service /tests/.root /tests/libpakfire/archive +/tests/libpakfire/execute /tests/libpakfire/key /tests/libpakfire/main /tests/libpakfire/makefile diff --git a/Makefile.am b/Makefile.am index 28f900c16..4eb1437e9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -271,6 +271,7 @@ lib_LTLIBRARIES += \ libpakfire_la_SOURCES = \ src/libpakfire/archive.c \ src/libpakfire/errno.c \ + src/libpakfire/execute.c \ src/libpakfire/file.c \ src/libpakfire/filter.c \ src/libpakfire/key.c \ @@ -295,6 +296,7 @@ pkginclude_HEADERS += \ src/libpakfire/include/pakfire/archive.h \ src/libpakfire/include/pakfire/constants.h \ src/libpakfire/include/pakfire/errno.h \ + src/libpakfire/include/pakfire/execute.h \ src/libpakfire/include/pakfire/file.h \ src/libpakfire/include/pakfire/filter.h \ src/libpakfire/include/pakfire/i18n.h \ @@ -352,6 +354,7 @@ EXTRA_DIST += \ check_PROGRAMS += \ tests/libpakfire/main \ tests/libpakfire/archive \ + tests/libpakfire/execute \ tests/libpakfire/key \ tests/libpakfire/makefile \ tests/libpakfire/parser \ @@ -378,6 +381,16 @@ tests_libpakfire_archive_LDADD = \ $(TESTSUITE_LDADD) \ $(PAKFIRE_LIBS) +tests_libpakfire_execute_SOURCES = \ + tests/libpakfire/execute.c + +tests_libpakfire_execute_CPPFLAGS = \ + $(TESTSUITE_CPPFLAGS) + +tests_libpakfire_execute_LDADD = \ + $(TESTSUITE_LDADD) \ + $(PAKFIRE_LIBS) + tests_libpakfire_key_SOURCES = \ tests/libpakfire/key.c \ tests/libpakfire/key.h diff --git a/src/libpakfire/execute.c b/src/libpakfire/execute.c new file mode 100644 index 000000000..4025a2061 --- /dev/null +++ b/src/libpakfire/execute.c @@ -0,0 +1,113 @@ +/*############################################################################# +# # +# Pakfire - The IPFire package management system # +# Copyright (C) 2019 Pakfire development team # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +#############################################################################*/ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define STACK_SIZE 1024 + +struct pakfire_execute_env { + Pakfire pakfire; + const char* root; + const char* command; + char** argv; + char* envp[20]; +}; + +static int pakfire_execute_fork(Pakfire pakfire, struct pakfire_execute_env* env) { + pid_t pid = getpid(); + + DEBUG(env->pakfire, "Execution environment has been forked as PID %d\n", pid); + DEBUG(env->pakfire, " command = %s, root = %s\n", env->command, env->root); + + // Move / + int r = chroot(env->root); + if (r) { + ERROR(env->pakfire, "chroot() to %s failed: %s\n", + env->root, strerror(errno)); + return errno; + } + + // exec() command + r = execve(env->command, env->argv, env->envp); + + // We should not get here + return errno; +} + +PAKFIRE_EXPORT int pakfire_execute(Pakfire pakfire, const char* command, char** argv, int flags) { + struct pakfire_execute_env env; + + // Setup environment + env.pakfire = pakfire; + env.root = pakfire_get_path(pakfire); + + env.command = command; + env.argv = argv; + + // Reset environnment + env.envp[0] = NULL; + + // Fork this process + pid_t pid = fork(); + + if (pid < 0) { + ERROR(pakfire, "Could not fork: %s\n", strerror(errno)); + return errno; + + // Child process + } else if (pid == 0) { + int r = pakfire_execute_fork(pakfire, &env); + + ERROR(pakfire, "Forked process returned unexpectedly: %s\n", + strerror(r)); + + // Exit immediately + exit(r); + + // Parent process + } else { + DEBUG(pakfire, "Waiting for PID %d to finish its work\n", pid); + + int status; + waitpid(pid, &status, 0); + + if (WIFEXITED(status)) { + int r = WEXITSTATUS(status); + + DEBUG(pakfire, "Child process has exited with code: %d\n", r); + return r; + } + + ERROR(pakfire, "Could not determine the exit status of process %d\n", pid); + return -1; + } + + return 0; +} diff --git a/src/libpakfire/include/pakfire/execute.h b/src/libpakfire/include/pakfire/execute.h new file mode 100644 index 000000000..d15459d3f --- /dev/null +++ b/src/libpakfire/include/pakfire/execute.h @@ -0,0 +1,28 @@ +/*############################################################################# +# # +# Pakfire - The IPFire package management system # +# Copyright (C) 2019 Pakfire development team # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +#############################################################################*/ + +#ifndef PAKFIRE_EXECUTE_H +#define PAKFIRE_EXECUTE_H + +#include + +int pakfire_execute(Pakfire pakfire, const char* command, char** argv, int flags); + +#endif /* PAKFIRE_EXECUTE_H */ diff --git a/src/libpakfire/include/pakfire/util.h b/src/libpakfire/include/pakfire/util.h index 3447d5e5f..8c2a16a1d 100644 --- a/src/libpakfire/include/pakfire/util.h +++ b/src/libpakfire/include/pakfire/util.h @@ -43,6 +43,7 @@ char* pakfire_format_size(double size); char* pakfire_format_date(time_t t); char* pakfire_path_join(const char* first, const char* second); +const char* pakfire_path_relpath(const char* root, const char* path); char* pakfire_basename(const char* path); char* pakfire_dirname(const char* path); diff --git a/src/libpakfire/libpakfire.sym b/src/libpakfire/libpakfire.sym index ec4708f11..51cab4ac3 100644 --- a/src/libpakfire/libpakfire.sym +++ b/src/libpakfire/libpakfire.sym @@ -26,6 +26,7 @@ global: pakfire_cache_stat; pakfire_count_packages; pakfire_create; + pakfire_execute; pakfire_get_arch; pakfire_get_cache_path; pakfire_get_installed_repo; @@ -365,6 +366,7 @@ global: pakfire_get_errno; pakfire_partition_string; pakfire_path_join; + pakfire_path_relpath; pakfire_read_file_into_buffer; pakfire_split_string; pakfire_string_to_size; diff --git a/src/libpakfire/step.c b/src/libpakfire/step.c index e21c25291..f279cd44c 100644 --- a/src/libpakfire/step.c +++ b/src/libpakfire/step.c @@ -28,6 +28,7 @@ #include #include +#include #include #include #include @@ -310,11 +311,14 @@ static int pakfire_script_check_shell(const char* data, const size_t size) { } static int pakfire_step_run_shell_script(PakfireStep step, const char* data, const size_t size) { - // Write the scriptlet to disk - char* path = pakfire_path_join(pakfire_get_path(step->pakfire), "/tmp/.pakfire-scriptlet.XXXXXX"); + const char* root = pakfire_get_path(step->pakfire); + // Write the scriptlet to disk + char* path = pakfire_path_join(root, "tmp/.pakfire-scriptlet.XXXXXX"); int r; + DEBUG(step->pakfire, "Writing script to %s\n", path); + // Open a temporary file int fd = mkstemp(path); if (fd < 0) { @@ -354,8 +358,15 @@ static int pakfire_step_run_shell_script(PakfireStep step, const char* data, con goto out; } + const char* command = path; + if (root) + command = pakfire_path_relpath(root, path); + // Run the script - INFO(step->pakfire, "XXX Running %s\n", path); + r = pakfire_execute(step->pakfire, command, NULL, 0); + if (r) { + DEBUG(step->pakfire, "Script return code: %d\n", r); + } out: // Remove script from disk diff --git a/src/libpakfire/util.c b/src/libpakfire/util.c index 86fdc3980..24b0f9db5 100644 --- a/src/libpakfire/util.c +++ b/src/libpakfire/util.c @@ -147,6 +147,14 @@ PAKFIRE_EXPORT char* pakfire_path_join(const char* first, const char* second) { return buffer; } +PAKFIRE_EXPORT const char* pakfire_path_relpath(const char* root, const char* path) { + if (pakfire_string_startswith(path, root) == 0) { + return path + strlen(root); + } + + return NULL; +} + PAKFIRE_EXPORT char* pakfire_basename(const char* path) { char* name = pakfire_strdup(path); diff --git a/tests/libpakfire/execute.c b/tests/libpakfire/execute.c new file mode 100644 index 000000000..ea520629a --- /dev/null +++ b/tests/libpakfire/execute.c @@ -0,0 +1,45 @@ +/*############################################################################# +# # +# Pakfire - The IPFire package management system # +# Copyright (C) 2019 Pakfire development team # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +#############################################################################*/ + +#include + +#include +#include + +#include "../testsuite.h" + +int test_does_not_exist(const test_t* t) { + const char* cmd = "/usr/bin/does-not-exist"; + + int r = pakfire_execute(t->pakfire, cmd, NULL, 0); + assert_return(r != 0, EXIT_FAILURE); + + return EXIT_SUCCESS; +} + +int main(int argc, char** argv) { + testsuite_init(); + + testsuite_t* ts = testsuite_create(1); + + testsuite_add_test(ts, "test_does_not_exist", test_does_not_exist); + + return testsuite_run(ts); +}