#############################################################################*/
#include <errno.h>
+#include <linux/sched.h>
+#include <sched.h>
+#include <signal.h>
#include <stdlib.h>
+#include <syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
#include <pakfire/logging.h>
#include <pakfire/jail.h>
char* env[ENVIRON_SIZE];
};
+static int clone3(struct clone_args* args, size_t size) {
+ return syscall(__NR_clone3, args, size);
+}
+
static void pakfire_jail_free(struct pakfire_jail* jail) {
DEBUG(jail->pakfire, "Freeing jail at %p\n", jail);
return 0;
}
+static int pakfire_jail_child(struct pakfire_jail* jail, const char* argv[]) {
+ // XXX do we have to reconfigure logging here?
+
+ DEBUG(jail->pakfire, "Launched child process in jail with PID %d\n", getpid());
+
+ return 0;
+}
+
// Run a command in the jail
int pakfire_jail_exec(struct pakfire_jail* jail, const char* argv[]) {
- return 1; // TODO
+ int r;
+
+ DEBUG(jail->pakfire, "Executing jail...\n");
+
+ // Configure child process
+ struct clone_args args = {
+ .flags =
+ CLONE_NEWCGROUP |
+ CLONE_NEWIPC |
+ CLONE_NEWNS |
+ CLONE_NEWPID |
+ CLONE_NEWUSER |
+ CLONE_NEWUTS,
+ .exit_signal = SIGCHLD,
+ };
+
+ // Fork this process
+ pid_t pid = clone3(&args, sizeof(args));
+ if (pid < 0) {
+ ERROR(jail->pakfire, "Could not clone: %m\n");
+ return -1;
+
+ // Child process
+ } else if (pid == 0) {
+ r = pakfire_jail_child(jail, argv);
+ _exit(r);
+ }
+
+ // Set some useful error code
+ int exit;
+ int status = 0;
+
+ DEBUG(jail->pakfire, "Waiting for PID %d to finish its work\n", pid);
+
+ if (!status)
+ waitpid(pid, &status, 0);
+
+ if (WIFEXITED(status)) {
+ exit = WEXITSTATUS(status);
+
+ DEBUG(jail->pakfire, "Child process exited with code: %d\n", exit);
+ } else {
+ ERROR(jail->pakfire, "Could not determine the exit status of process %d\n", pid);
+
+ errno = ESRCH;
+ exit = -1;
+ }
+
+ return exit;
}
return EXIT_FAILURE;
}
+static int test_exec(const struct test* t) {
+ struct pakfire_jail* jail = NULL;
+
+ const char* argv[] = {
+ "/does-not-exist",
+ NULL,
+ };
+
+ // Create a new jail
+ ASSERT_SUCCESS(pakfire_jail_create(&jail, t->pakfire, 0));
+
+ // Try to execute something
+ ASSERT_SUCCESS(pakfire_jail_exec(jail, argv));
+
+ // Destroy it
+ ASSERT_NULL(pakfire_jail_unref(jail));
+
+ return EXIT_SUCCESS;
+
+FAIL:
+ return EXIT_FAILURE;
+}
int main(int argc, char** argv) {
testsuite_add_test(test_create);
testsuite_add_test(test_env);
+ testsuite_add_test(test_exec);
return testsuite_run();
}