chiark / gitweb /
Fix previous commit for !HAVE_AUDIT
[elogind.git] / src / nspawn / nspawn.c
index b59b2673cd63545116509e9bd5f4fe3cdc7878c3..33153c950777b7591c64c35536cafbf4e4072336 100644 (file)
@@ -22,7 +22,6 @@
 #include <signal.h>
 #include <sched.h>
 #include <unistd.h>
-#include <attr/xattr.h>
 #include <sys/types.h>
 #include <sys/syscall.h>
 #include <sys/mount.h>
 #include <sys/un.h>
 #include <sys/socket.h>
 
+#ifdef HAVE_XATTR
+#include <attr/xattr.h>
+#endif
+
 #include <systemd/sd-daemon.h>
 
 #include "log.h"
@@ -173,7 +176,7 @@ static int parse_argv(int argc, char *argv[]) {
         assert(argc >= 0);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "+hD:u:C:bj", options, NULL)) >= 0) {
+        while ((c = getopt_long(argc, argv, "+hD:u:C:bM:j", options, NULL)) >= 0) {
 
                 switch (c) {
 
@@ -222,6 +225,11 @@ static int parse_argv(int argc, char *argv[]) {
                         break;
 
                 case ARG_UUID:
+                        if (!id128_is_valid(optarg)) {
+                                log_error("Invalid UUID: %s", optarg);
+                                return -EINVAL;
+                        }
+
                         arg_uuid = optarg;
                         break;
 
@@ -923,20 +931,21 @@ static int setup_cgroup(const char *path) {
 }
 
 static int save_attributes(const char *cgroup, pid_t pid, const char *uuid, const char *directory) {
-        char buf[DECIMAL_STR_MAX(pid_t)], path[PATH_MAX];
+#ifdef HAVE_XATTR
+        _cleanup_free_ char *path = NULL;
+        char buf[DECIMAL_STR_MAX(pid_t)];
         int r = 0, k;
 
         assert(cgroup);
         assert(pid >= 0);
         assert(arg_directory);
 
-#ifdef HAVE_XATTR
         assert_se(snprintf(buf, sizeof(buf), "%lu", (unsigned long) pid) < (int) sizeof(buf));
 
-        r = snprintf(path, sizeof(path), "/sys/fs/cgroup/systemd/%s", cgroup);
-        if (r >= (int) sizeof(path)) {
-                log_error("cgroup name too long");
-                return -EINVAL;
+        r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, cgroup, NULL, &path);
+        if (r < 0) {
+                log_error("Failed to get path: %s", strerror(-r));
+                return r;
         }
 
         r = setxattr(path, "trusted.init_pid", buf, strlen(buf), XATTR_CREATE);
@@ -954,12 +963,14 @@ static int save_attributes(const char *cgroup, pid_t pid, const char *uuid, cons
 
         k = setxattr(path, "trusted.root_directory", directory, strlen(directory), XATTR_CREATE);
         if (k < 0) {
-                log_warning("Failed to set %s attribute on %s: %m", "trusted.machine_id", path);
+                log_warning("Failed to set %s attribute on %s: %m", "trusted.root_directory", path);
                 if (r == 0)
                         r = k;
         }
-#endif
         return r;
+#else
+        return 0;
+#endif
 }
 
 static int drop_capabilities(void) {
@@ -1208,10 +1219,23 @@ finish:
         return r;
 }
 
+static bool audit_enabled(void) {
+#ifdef HAVE_AUDIT
+        int fd;
+
+        fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_AUDIT);
+        if (fd >= 0) {
+                close_nointr_nofail(fd);
+                return true;
+        }
+#endif
+        return false;
+}
+
 int main(int argc, char *argv[]) {
         pid_t pid = 0;
         int r = EXIT_FAILURE, k;
-        _cleanup_free_ char *machine_root = NULL, *newcg = NULL;
+        _cleanup_free_ char *newcg = NULL;
         _cleanup_close_ int master = -1;
         int n_fd_passed;
         const char *console = NULL;
@@ -1225,9 +1249,13 @@ int main(int argc, char *argv[]) {
         log_parse_environment();
         log_open();
 
-        r = parse_argv(argc, argv);
-        if (r <= 0)
+        k = parse_argv(argc, argv);
+        if (k < 0)
+                goto finish;
+        else if (k == 0) {
+                r = EXIT_SUCCESS;
                 goto finish;
+        }
 
         if (arg_directory) {
                 char *p;
@@ -1252,7 +1280,7 @@ int main(int argc, char *argv[]) {
                         goto finish;
                 }
 
-                hostname_cleanup(arg_machine);
+                hostname_cleanup(arg_machine, false);
                 if (isempty(arg_machine)) {
                         log_error("Failed to determine machine name automatically, please use -M.");
                         goto finish;
@@ -1269,13 +1297,20 @@ int main(int argc, char *argv[]) {
                 goto finish;
         }
 
+        if (audit_enabled()) {
+                log_warning("The kernel auditing subsystem is known to be incompatible with containers.\n"
+                            "Please make sure to turn off auditing with 'audit=0' on the kernel command\n"
+                            "line before using systemd-nspawn. Sleeping for 5s...\n");
+                sleep(5);
+        }
+
         if (path_equal(arg_directory, "/")) {
                 log_error("Spawning container on root directory not supported.");
                 goto finish;
         }
 
         if (path_is_os_tree(arg_directory) <= 0) {
-                log_error("Directory %s doesn't look like an OS root directory. Refusing.", arg_directory);
+                log_error("Directory %s doesn't look like an OS root directory (/etc/os-release is missing). Refusing.", arg_directory);
                 goto finish;
         }
 
@@ -1291,20 +1326,14 @@ int main(int argc, char *argv[]) {
         fdset_close_others(fds);
         log_open();
 
-        k = cg_get_machine_path(&machine_root);
+        k = cg_get_machine_path(arg_machine, &newcg);
         if (k < 0) {
                 log_error("Failed to determine machine cgroup path: %s", strerror(-k));
                 goto finish;
         }
 
-        newcg = strjoin(machine_root, "/", arg_machine, NULL);
-        if (!newcg) {
-                log_error("Failed to allocate cgroup path.");
-                goto finish;
-        }
-
-        r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, newcg, false);
-        if (r <= 0 && r != -ENOENT) {
+        k = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, newcg, true);
+        if (k <= 0 && k != -ENOENT) {
                 log_error("Container already running.");
 
                 free(newcg);
@@ -1348,6 +1377,8 @@ int main(int argc, char *argv[]) {
                 goto finish;
         }
 
+        sd_notify(0, "READY=1");
+
         assert_se(sigemptyset(&mask) == 0);
         sigset_add_many(&mask, SIGCHLD, SIGWINCH, SIGTERM, SIGINT, -1);
         assert_se(sigprocmask(SIG_BLOCK, &mask, NULL) == 0);
@@ -1457,8 +1488,7 @@ int main(int argc, char *argv[]) {
                         if (setup_cgroup(newcg) < 0)
                                 goto child_fail;
 
-                        close_nointr_nofail(pipefd2[1]);
-                        close_nointr_nofail(pipefd2[0]);
+                        close_pipe(pipefd2);
 
                         /* Mark everything as slave, so that we still
                          * receive mounts from the real root, but don't
@@ -1684,16 +1714,16 @@ int main(int argc, char *argv[]) {
                 if (saved_attr_valid)
                         tcsetattr(STDIN_FILENO, TCSANOW, &saved_attr);
 
-                r = wait_for_terminate(pid, &status);
-                if (r < 0) {
+                k = wait_for_terminate(pid, &status);
+                if (k < 0) {
                         r = EXIT_FAILURE;
                         break;
                 }
 
                 if (status.si_code == CLD_EXITED) {
+                        r = status.si_status;
                         if (status.si_status != 0) {
                                 log_error("Container failed with error code %i.", status.si_status);
-                                r = status.si_status;
                                 break;
                         }