]> git.ipfire.org Git - pakfire.git/commitdiff
libpakfire: Add function to run commands in chroot()
authorMichael Tremer <michael.tremer@ipfire.org>
Thu, 13 Jun 2019 04:11:54 +0000 (05:11 +0100)
committerMichael Tremer <michael.tremer@ipfire.org>
Thu, 13 Jun 2019 04:11:54 +0000 (05:11 +0100)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
.gitignore
Makefile.am
src/libpakfire/execute.c [new file with mode: 0644]
src/libpakfire/include/pakfire/execute.h [new file with mode: 0644]
src/libpakfire/include/pakfire/util.h
src/libpakfire/libpakfire.sym
src/libpakfire/step.c
src/libpakfire/util.c
tests/libpakfire/execute.c [new file with mode: 0644]

index 97eb45d2d2f66a3e68b0eb57a2ace464eeba1e78..2889615655c6537409ca873360f312e74f84bcbe 100644 (file)
@@ -11,6 +11,7 @@
 /src/systemd/*.service
 /tests/.root
 /tests/libpakfire/archive
+/tests/libpakfire/execute
 /tests/libpakfire/key
 /tests/libpakfire/main
 /tests/libpakfire/makefile
index 28f900c16fc60f993506a04e494d3f95bd73a0ad..4eb1437e904be6ce17e978d67e3befe281870dfd 100644 (file)
@@ -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 (file)
index 0000000..4025a20
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.       #
+#                                                                             #
+#############################################################################*/
+
+#include <errno.h>
+#include <sched.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <pakfire/execute.h>
+#include <pakfire/logging.h>
+#include <pakfire/private.h>
+#include <pakfire/types.h>
+
+#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 (file)
index 0000000..d15459d
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.       #
+#                                                                             #
+#############################################################################*/
+
+#ifndef PAKFIRE_EXECUTE_H
+#define PAKFIRE_EXECUTE_H
+
+#include <pakfire/types.h>
+
+int pakfire_execute(Pakfire pakfire, const char* command, char** argv, int flags);
+
+#endif /* PAKFIRE_EXECUTE_H */
index 3447d5e5f48db06a8b209ca01c28bdea9b66b2ca..8c2a16a1d110a641e839f3971998b734bbd00ce0 100644 (file)
@@ -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);
index ec4708f11c7921ea841dc42f396ce06323f628fa..51cab4ac3cc911a25719dbc4a9c380abad2f26db 100644 (file)
@@ -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;
index e21c2529124b587a8f15d35b8e44b8e8ca9dae54..f279cd44c994b2de522f28416e6989ff6ce51e2c 100644 (file)
@@ -28,6 +28,7 @@
 
 #include <pakfire/archive.h>
 #include <pakfire/constants.h>
+#include <pakfire/execute.h>
 #include <pakfire/logging.h>
 #include <pakfire/package.h>
 #include <pakfire/pakfire.h>
@@ -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
index 86fdc3980cf66c92abb68347b071ea64495bac38..24b0f9db529d1b7b2a6fc196676f07c885c5e3d4 100644 (file)
@@ -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 (file)
index 0000000..ea52062
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.       #
+#                                                                             #
+#############################################################################*/
+
+#include <string.h>
+
+#include <pakfire/execute.h>
+#include <pakfire/util.h>
+
+#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);
+}