If the container is really a simple one (init is just bash and
the whole root is passed through) then virDomainReboot and
virDomainShutdown will talk to the actual init within the host.
Therefore, 'virsh shutdown $dom' will result in shutting down the
host. True, at that point the container is shut down too but
looks a bit harsh to me.
The solution is to check if the init inside the container is or
is not the same as the init running on the host.
Signed-off-by: Michal Privoznik <mprivozn(a)redhat.com>
---
src/lxc/lxc_domain.c | 77 ++++++++++++++++++++++++++++++++++++++++++++
src/lxc/lxc_domain.h | 4 +++
src/lxc/lxc_driver.c | 17 ++--------
3 files changed, 83 insertions(+), 15 deletions(-)
diff --git a/src/lxc/lxc_domain.c b/src/lxc/lxc_domain.c
index b197f9dfc2..73023c0a57 100644
--- a/src/lxc/lxc_domain.c
+++ b/src/lxc/lxc_domain.c
@@ -32,6 +32,7 @@
#include "virfile.h"
#include "virtime.h"
#include "virsystemd.h"
+#include "virinitctl.h"
#define VIR_FROM_THIS VIR_FROM_LXC
#define LXC_NAMESPACE_HREF "http://libvirt.org/schemas/domain/lxc/1.0"
@@ -416,3 +417,79 @@ virLXCDomainGetMachineName(virDomainDefPtr def, pid_t pid)
return ret;
}
+
+
+typedef struct _lxcDomainInitctlCallbackData lxcDomainInitctlCallbackData;
+struct _lxcDomainInitctlCallbackData {
+ int runlevel;
+ bool st_valid[ARRAY_CARDINALITY(virInitctlFifos)];
+ struct stat st[ARRAY_CARDINALITY(virInitctlFifos)];
+};
+
+
+static int
+lxcDomainInitctlCallback(pid_t pid ATTRIBUTE_UNUSED,
+ void *opaque)
+{
+ lxcDomainInitctlCallbackData *data = opaque;
+ size_t i;
+
+ for (i = 0; i < ARRAY_CARDINALITY(virInitctlFifos); i++) {
+ const char *fifo = virInitctlFifos[i];
+ struct stat cont_sb;
+
+ if (stat(fifo, &cont_sb) < 0) {
+ if (errno == ENOENT)
+ continue;
+
+ virReportSystemError(errno, _("Unable to stat %s"), fifo);
+ return -1;
+ }
+
+ /* Check if the init fifo is not the very one that's on
+ * the host. We don't want to change the host's runlevel.
+ */
+ if (data->st_valid[i] &&
+ data->st[i].st_dev == cont_sb.st_dev &&
+ data->st[i].st_ino == cont_sb.st_ino)
+ continue;
+
+ return virInitctlSetRunLevel(fifo, data->runlevel);
+ }
+
+ /* If no usable fifo was found then declare success. Caller
+ * will try killing the domain with signal. */
+ return 0;
+}
+
+
+int
+virLXCDomainSetRunlevel(virDomainObjPtr vm,
+ int runlevel)
+{
+ virLXCDomainObjPrivatePtr priv = vm->privateData;
+ lxcDomainInitctlCallbackData data;
+ size_t i;
+
+ memset(&data, 0, sizeof(data));
+
+ data.runlevel = runlevel;
+
+ for (i = 0; i < ARRAY_CARDINALITY(virInitctlFifos); i++) {
+ const char *fifo = virInitctlFifos[i];
+
+ if (stat(fifo, &(data.st[i])) < 0) {
+ if (errno == ENOENT)
+ continue;
+
+ virReportSystemError(errno, _("Unable to stat %s"), fifo);
+ return -1;
+ }
+
+ data.st_valid[i] = true;
+ }
+
+ return virProcessRunInMountNamespace(priv->initpid,
+ lxcDomainInitctlCallback,
+ &data);
+}
diff --git a/src/lxc/lxc_domain.h b/src/lxc/lxc_domain.h
index 364b8e5a44..c62d6d1362 100644
--- a/src/lxc/lxc_domain.h
+++ b/src/lxc/lxc_domain.h
@@ -109,4 +109,8 @@ virLXCDomainObjEndJob(virLXCDriverPtr driver,
char *
virLXCDomainGetMachineName(virDomainDefPtr def, pid_t pid);
+int
+virLXCDomainSetRunlevel(virDomainObjPtr vm,
+ int runlevel);
+
#endif /* LIBVIRT_LXC_DOMAIN_H */
diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c
index 943d199616..f0d72aa569 100644
--- a/src/lxc/lxc_driver.c
+++ b/src/lxc/lxc_driver.c
@@ -3272,15 +3272,6 @@ lxcConnectListAllDomains(virConnectPtr conn,
}
-static int
-lxcDomainInitctlCallback(pid_t pid ATTRIBUTE_UNUSED,
- void *opaque)
-{
- int *command = opaque;
- return virInitctlSetRunLevel(NULL, *command);
-}
-
-
static int
lxcDomainShutdownFlags(virDomainPtr dom,
unsigned int flags)
@@ -3318,9 +3309,7 @@ lxcDomainShutdownFlags(virDomainPtr dom,
(flags & VIR_DOMAIN_SHUTDOWN_INITCTL)) {
int command = VIR_INITCTL_RUNLEVEL_POWEROFF;
- if ((rc = virProcessRunInMountNamespace(priv->initpid,
- lxcDomainInitctlCallback,
- &command)) < 0)
+ if ((rc = virLXCDomainSetRunlevel(vm, command)) < 0)
goto endjob;
if (rc == 0 && flags != 0 &&
((flags & ~VIR_DOMAIN_SHUTDOWN_INITCTL) == 0)) {
@@ -3398,9 +3387,7 @@ lxcDomainReboot(virDomainPtr dom,
(flags & VIR_DOMAIN_REBOOT_INITCTL)) {
int command = VIR_INITCTL_RUNLEVEL_REBOOT;
- if ((rc = virProcessRunInMountNamespace(priv->initpid,
- lxcDomainInitctlCallback,
- &command)) < 0)
+ if ((rc = virLXCDomainSetRunlevel(vm, command)) < 0)
goto endjob;
if (rc == 0 && flags != 0 &&
((flags & ~VIR_DOMAIN_SHUTDOWN_INITCTL) == 0)) {
--
2.19.2