Fix shutdown for systemd init 13/30313/2
authorPiotr Bartosiewicz <p.bartosiewi@partner.samsung.com>
Fri, 14 Nov 2014 11:20:04 +0000 (12:20 +0100)
committerPiotr Bartosiewicz <p.bartosiewi@partner.samsung.com>
Fri, 14 Nov 2014 12:57:59 +0000 (13:57 +0100)
[Bug/Feature]   Systemd does not shutdown on signal
[Cause]         N/A
[Solution]      N/A
[Verification]  Build, install, run tests, run container

Change-Id: Ic4b617c1a35a260803961fb17aba1da51c3af013

common/lxc/domain.cpp
common/lxc/domain.hpp
common/utils/initctl.cpp [new file with mode: 0644]
common/utils/initctl.hpp [new file with mode: 0644]
server/configs/lxc-templates/business.sh
server/configs/lxc-templates/private.sh
tests/unit_tests/lxc/templates/minimal-dbus1.sh
tests/unit_tests/lxc/templates/minimal-dbus2.sh
tests/unit_tests/lxc/templates/minimal-dbus3.sh
tests/unit_tests/lxc/templates/minimal.sh

index 0959959..57228c0 100644 (file)
@@ -30,6 +30,9 @@
 #include <lxc/lxccontainer.h>
 #include <sys/stat.h>
 
+#include <utils/initctl.hpp>
+#include <sys/wait.h>
+
 #include <map>
 
 namespace security_containers {
@@ -145,6 +148,26 @@ bool LxcDomain::reboot()
 
 bool LxcDomain::shutdown(int timeout)
 {
+    State state = getState();
+    if (state == State::STOPPED) {
+        return true;
+    }
+    if (state != State::RUNNING) {
+        LOGE("Could not gracefully shutdown domain " << getName());
+        return false;
+    }
+
+    // try shutdown by sending poweroff to init
+    if (setRunLevel(utils::RUNLEVEL_POWEROFF)) {
+        if (!mContainer->wait(mContainer, "STOPPED", timeout)) {
+            LOGE("Could not gracefully shutdown domain " + getName() + " in " << timeout << "s");
+            return false;
+        }
+        return true;
+    }
+    LOGW("SetRunLevel failed for domain " + getName());
+
+    // fallback for other inits like bash: lxc sends 'lxc.haltsignal' signal to init
     if (!mContainer->shutdown(mContainer, timeout)) {
         LOGE("Could not gracefully shutdown domain " + getName() + " in " << timeout << "s");
         return false;
@@ -170,6 +193,26 @@ bool LxcDomain::unfreeze()
     return true;
 }
 
+bool LxcDomain::setRunLevel(int runLevel)
+{
+    auto callback = [](void* param) {
+        utils::RunLevel runLevel = *reinterpret_cast<utils::RunLevel*>(param);
+        return utils::setRunLevel(runLevel) ? 0 : 1;
+    };
+
+    lxc_attach_options_t options = LXC_ATTACH_OPTIONS_DEFAULT;
+    pid_t pid;
+    int ret = mContainer->attach(mContainer, callback, &runLevel, &options, &pid);
+    if (ret != 0) {
+        return false;
+    }
+    int status;
+    if (waitpid(pid, &status, 0) < 0) {
+        return false;
+    }
+    return status == 0;
+}
+
 
 } // namespace lxc
 } // namespace security_containers
index 3202f54..8421d6d 100644 (file)
@@ -76,6 +76,8 @@ public:
     bool unfreeze();
 private:
     lxc_container* mContainer;
+
+    bool setRunLevel(int runLevel);
 };
 
 
diff --git a/common/utils/initctl.cpp b/common/utils/initctl.cpp
new file mode 100644 (file)
index 0000000..cfdea77
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Piotr Bartosiewicz <p.bartosiewi@partner.samsung.com>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file
+ * @author  Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com)
+ * @brief   Api for talking to init via initctl
+ */
+
+#include "config.hpp"
+#include "utils/initctl.hpp"
+
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+
+namespace security_containers {
+namespace utils {
+
+namespace {
+    struct InitctlRequest {
+        int magic;
+        int cmd;
+        int runlevel;
+        int sleeptime;
+        char data[368];
+    };
+    const int INITCTL_MAGIC = 0x03091969;
+    const int INITCTL_CMD_RUNLVL = 1;
+
+    bool write(int fd, const void* data, size_t size)
+    {
+        while (size > 0) {
+            ssize_t r = ::write(fd, data, size);
+            if (r < 0) {
+                if (errno == EINTR) {
+                    continue;
+                }
+                return false;
+            }
+            size -= r;
+            data = reinterpret_cast<const char*>(data) + r;
+        }
+        return true;
+    }
+
+    void close(int fd)
+    {
+        while (::close(fd) == -1 && errno == EINTR) {}
+    }
+}
+
+bool setRunLevel(RunLevel runLevel)
+{
+    int fd = ::open("/dev/initctl", O_WRONLY|O_NONBLOCK|O_CLOEXEC|O_NOCTTY);
+    if (fd < 0) {
+        return false;
+    }
+
+    InitctlRequest req;
+    memset(&req, 0, sizeof(req));
+    req.magic = INITCTL_MAGIC;
+    req.cmd = INITCTL_CMD_RUNLVL;
+    req.runlevel = '0' + runLevel;
+    req.sleeptime = 0;
+
+    bool ret = write(fd, &req, sizeof(req));
+    close(fd);
+    return ret;
+}
+
+
+} // namespace utils
+} // namespace security_containers
diff --git a/common/utils/initctl.hpp b/common/utils/initctl.hpp
new file mode 100644 (file)
index 0000000..2b97dd2
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Piotr Bartosiewicz <p.bartosiewi@partner.samsung.com>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file
+ * @author  Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com)
+ * @brief   Api for talking to init via initctl
+ */
+
+#ifndef COMMON_UTILS_INITCTL_HPP
+#define COMMON_UTILS_INITCTL_HPP
+
+
+namespace security_containers {
+namespace utils {
+
+enum RunLevel : int {
+    RUNLEVEL_POWEROFF = 0,
+    RUNLEVEL_REBOOT = 6
+};
+
+bool setRunLevel(RunLevel runLevel);
+
+
+} // namespace utils
+} // namespace security_containers
+
+
+#endif // COMMON_UTILS_INITCTL_HPP
index 75be9e6..09d67ca 100755 (executable)
@@ -27,7 +27,9 @@ cat <<EOF >> ${path}/config
 lxc.utsname = ${name}
 lxc.rootfs = ${rootfs}
 
-lxc.haltsignal = SIGTERM
+# userns 1-to-1 mapping
+#lxc.id_map = u 0 0 65536
+#lxc.id_map = g 0 0 65536
 
 lxc.pts = 256
 lxc.tty = 0
index 2926e55..731ff72 100755 (executable)
@@ -27,7 +27,9 @@ cat <<EOF >> ${path}/config
 lxc.utsname = ${name}
 lxc.rootfs = ${rootfs}
 
-lxc.haltsignal = SIGTERM
+# userns 1-to-1 mapping
+#lxc.id_map = u 0 0 65536
+#lxc.id_map = g 0 0 65536
 
 lxc.pts = 256
 lxc.tty = 0
index 6f967e5..35f816f 100755 (executable)
@@ -45,18 +45,23 @@ cat <<EOF >> ${path}/config
 lxc.utsname = ${name}
 lxc.rootfs = ${rootfs}
 
+# userns 1-to-1 mapping
+lxc.id_map = u 0 0 65536
+lxc.id_map = g 0 0 65536
+
 lxc.haltsignal = SIGTERM
 
 lxc.pts = 256
 lxc.tty = 0
 
+lxc.cgroup.devices.deny = a
+
 lxc.mount.auto = proc sys cgroup
 lxc.mount.entry = /bin bin none ro,bind 0 0
 lxc.mount.entry = /etc etc none ro,bind 0 0
 lxc.mount.entry = /lib lib none ro,bind 0 0
 lxc.mount.entry = /sbin sbin none ro,bind 0 0
 lxc.mount.entry = /usr usr none ro,rbind 0 0
-lxc.mount.entry = devtmpfs dev devtmpfs rw,relatime,mode=755 0 0
 lxc.mount.entry = /tmp/ut-run1 var/run none rw,bind 0 0
 EOF
 
index 1b5bf57..f8f963e 100755 (executable)
@@ -45,18 +45,23 @@ cat <<EOF >> ${path}/config
 lxc.utsname = ${name}
 lxc.rootfs = ${rootfs}
 
+# userns 1-to-1 mapping
+lxc.id_map = u 0 0 65536
+lxc.id_map = g 0 0 65536
+
 lxc.haltsignal = SIGTERM
 
 lxc.pts = 256
 lxc.tty = 0
 
+lxc.cgroup.devices.deny = a
+
 lxc.mount.auto = proc sys cgroup
 lxc.mount.entry = /bin bin none ro,bind 0 0
 lxc.mount.entry = /etc etc none ro,bind 0 0
 lxc.mount.entry = /lib lib none ro,bind 0 0
 lxc.mount.entry = /sbin sbin none ro,bind 0 0
 lxc.mount.entry = /usr usr none ro,rbind 0 0
-lxc.mount.entry = devtmpfs dev devtmpfs rw,relatime,mode=755 0 0
 lxc.mount.entry = /tmp/ut-run2 var/run none rw,bind 0 0
 EOF
 
index 9ace1c6..68f4f11 100755 (executable)
@@ -45,18 +45,23 @@ cat <<EOF >> ${path}/config
 lxc.utsname = ${name}
 lxc.rootfs = ${rootfs}
 
+# userns 1-to-1 mapping
+lxc.id_map = u 0 0 65536
+lxc.id_map = g 0 0 65536
+
 lxc.haltsignal = SIGTERM
 
 lxc.pts = 256
 lxc.tty = 0
 
+lxc.cgroup.devices.deny = a
+
 lxc.mount.auto = proc sys cgroup
 lxc.mount.entry = /bin bin none ro,bind 0 0
 lxc.mount.entry = /etc etc none ro,bind 0 0
 lxc.mount.entry = /lib lib none ro,bind 0 0
 lxc.mount.entry = /sbin sbin none ro,bind 0 0
 lxc.mount.entry = /usr usr none ro,rbind 0 0
-lxc.mount.entry = devtmpfs dev devtmpfs rw,relatime,mode=755 0 0
 lxc.mount.entry = /tmp/ut-run3 var/run none rw,bind 0 0
 EOF
 
index 64f6da7..547661e 100755 (executable)
@@ -43,18 +43,23 @@ cat <<EOF >> ${path}/config
 lxc.utsname = ${name}
 lxc.rootfs = ${rootfs}
 
+# userns 1-to-1 mapping
+lxc.id_map = u 0 0 65536
+lxc.id_map = g 0 0 65536
+
 lxc.haltsignal = SIGTERM
 
 lxc.pts = 256
 lxc.tty = 0
 
+lxc.cgroup.devices.deny = a
+
 lxc.mount.auto = proc sys cgroup
 lxc.mount.entry = /bin bin none ro,bind 0 0
 lxc.mount.entry = /etc etc none ro,bind 0 0
 lxc.mount.entry = /lib lib none ro,bind 0 0
 lxc.mount.entry = /sbin sbin none ro,bind 0 0
 lxc.mount.entry = /usr usr none ro,rbind 0 0
-lxc.mount.entry = devtmpfs dev devtmpfs rw,relatime,mode=755 0 0
 EOF
 
 if [ "$(uname -m)" = "x86_64" ]; then