]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
Add APIs for talking to init via /dev/initctl
authorDaniel P. Berrange <berrange@redhat.com>
Wed, 28 Nov 2012 12:17:31 +0000 (12:17 +0000)
committerDaniel P. Berrange <berrange@redhat.com>
Fri, 30 Nov 2012 19:17:30 +0000 (19:17 +0000)
To be able todo controlled shutdown/reboot of containers an
API to talk to init via /dev/initctl is required. Fortunately
this is quite straightforward to implement, and is supported
by both sysvinit and systemd. Upstart support for /dev/initctl
is unclear.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
include/libvirt/virterror.h
po/POTFILES.in
src/Makefile.am
src/libvirt_private.syms
src/util/virinitctl.c [new file with mode: 0644]
src/util/virinitctl.h [new file with mode: 0644]
src/util/virterror.c

index a87768349bc5c00cebd3550b73de7d97322238a7..4d796200f4e3d7f6bee5dc7d9192bde0ddaa6f58 100644 (file)
@@ -114,6 +114,7 @@ typedef enum {
 
     VIR_FROM_SSH = 50,          /* Error from libssh2 connection transport */
     VIR_FROM_LOCKSPACE = 51,    /* Error from lockspace */
+    VIR_FROM_INITCTL = 52,      /* Error from initctl device communication */
 
 # ifdef VIR_ENUM_SENTINELS
     VIR_ERR_DOMAIN_LAST
index ec59efbe517bbe750c00ffc1f23184c49f0f89bb..77bc04b937ec85a20592dcddb91ff81d17561b40 100644 (file)
@@ -153,6 +153,7 @@ src/util/virauthconfig.c
 src/util/virdbus.c
 src/util/virfile.c
 src/util/virhash.c
+src/util/virinitctl.c
 src/util/virkeyfile.c
 src/util/virlockspace.c
 src/util/virnetdev.c
index 627dbb5c4639fcb45e032c1fe95d17d096b3d18f..6401decdfa7a7855a9a4a86af09a454f42d8e6e5 100644 (file)
@@ -94,6 +94,7 @@ UTIL_SOURCES =                                                        \
                util/virdbus.c util/virdbus.h                   \
                util/virhash.c util/virhash.h                   \
                util/virhashcode.c util/virhashcode.h           \
+               util/virinitctl.c util/virinitctl.h             \
                util/virkeycode.c util/virkeycode.h             \
                util/virkeyfile.c util/virkeyfile.h             \
                util/virkeymaps.h                               \
index 5b056504bccbc4d1bfb9905b68fc169a81fbe623..93a21cc5ccdbfc8a2f0b6d98d96995dac4e8cee2 100644 (file)
@@ -1363,6 +1363,10 @@ virFileTouch;
 virFileUpdatePerm;
 
 
+# virinitctl.h
+virInitctlSetRunLevel;
+
+
 # virkeycode.h
 virKeycodeSetTypeFromString;
 virKeycodeSetTypeToString;
diff --git a/src/util/virinitctl.c b/src/util/virinitctl.c
new file mode 100644 (file)
index 0000000..cdd3dc0
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * virinitctl.c: API for talking to init systems via initctl
+ *
+ * Copyright (C) 2012 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ *     Daniel P. Berrange <berrange@redhat.com>
+ */
+
+#include <config.h>
+
+#include <sys/param.h>
+#include <fcntl.h>
+
+#include "internal.h"
+#include "virinitctl.h"
+#include "virterror_internal.h"
+#include "util.h"
+#include "memory.h"
+#include "virfile.h"
+
+#define VIR_FROM_THIS VIR_FROM_INITCTL
+
+/* These constants & struct definitions are taken from
+ * systemd, under terms of LGPLv2+
+ *
+ * initreq.h    Interface to talk to init through /dev/initctl.
+ *
+ *              Copyright (C) 1995-2004 Miquel van Smoorenburg
+ */
+
+#if defined(__FreeBSD_kernel__)
+# define VIR_INITCTL_FIFO  "/etc/.initctl"
+#else
+# define VIR_INITCTL_FIFO  "/dev/initctl"
+#endif
+
+#define VIR_INITCTL_MAGIC 0x03091969
+#define VIR_INITCTL_CMD_START          0
+#define VIR_INITCTL_CMD_RUNLVL         1
+#define VIR_INITCTL_CMD_POWERFAIL      2
+#define VIR_INITCTL_CMD_POWERFAILNOW   3
+#define VIR_INITCTL_CMD_POWEROK        4
+#define VIR_INITCTL_CMD_BSD            5
+#define VIR_INITCTL_CMD_SETENV         6
+#define VIR_INITCTL_CMD_UNSETENV       7
+
+#define VIR_INITCTL_CMD_CHANGECONS     12345
+
+#ifdef MAXHOSTNAMELEN
+# define VIR_INITCTL_RQ_HLEN   MAXHOSTNAMELEN
+#else
+# define VIR_INITCTL_RQ_HLEN   64
+#endif
+
+/*
+*      This is what BSD 4.4 uses when talking to init.
+*      Linux doesn't use this right now.
+*/
+struct virInitctlRequestBSD {
+    char    gen_id[8];              /* Beats me.. telnetd uses "fe" */
+    char    tty_id[16];             /* Tty name minus /dev/tty      */
+    char    host[VIR_INITCTL_RQ_HLEN]; /* Hostname                     */
+    char    term_type[16];          /* Terminal type                */
+    int     signal;                 /* Signal to send               */
+    int     pid_value;              /* Process to send to           */
+    char    exec_name[128];         /* Program to execute           */
+    char    reserved[128];          /* For future expansion.        */
+};
+
+
+/*
+ *      Because of legacy interfaces, "runlevel" and "sleeptime"
+ *      aren't in a separate struct in the union.
+ *
+ *      The weird sizes are because init expects the whole
+ *      struct to be 384 bytes.
+ */
+struct virInitctlRequest {
+    int     magic;                  /* Magic number                 */
+    int     cmd;                    /* What kind of request         */
+    int     runlevel;               /* Runlevel to change to        */
+    int     sleeptime;              /* Time between TERM and KILL   */
+    union {
+        struct virInitctlRequestBSD bsd;
+        char                     data[368];
+    } i;
+};
+
+verify(sizeof(struct virInitctlRequest) == 384);
+
+/*
+ * Send a message to init to change the runlevel
+ *
+ * Returns 1 on success, 0 if initctl does not exist, -1 on error
+ */
+int virInitctlSetRunLevel(virInitctlRunLevel level,
+                          const char *vroot)
+{
+    struct virInitctlRequest req;
+    int fd = -1;
+    char *path = NULL;
+    int ret = -1;
+
+    memset(&req, 0, sizeof(req));
+
+    req.magic = VIR_INITCTL_MAGIC;
+    req.sleeptime = 0;
+    req.cmd = VIR_INITCTL_CMD_RUNLVL;
+    /* Yes it is an 'int' field, but wants a numeric character. Go figure */
+    req.runlevel = '0' + level;
+
+    if (vroot) {
+        if (virAsprintf(&path, "%s/%s", vroot, VIR_INITCTL_FIFO) < 0) {
+            virReportOOMError();
+            return -1;
+        }
+    } else {
+        if (!(path = strdup(VIR_INITCTL_FIFO))) {
+            virReportOOMError();
+            return -1;
+        }
+    }
+
+    if ((fd = open(path, O_WRONLY|O_NONBLOCK|O_CLOEXEC|O_NOCTTY)) < 0) {
+        if (errno == ENOENT) {
+            ret = 0;
+            goto cleanup;
+        }
+        virReportSystemError(errno,
+                             _("Cannot open init control %s"),
+                             path);
+        goto cleanup;
+    }
+
+    if (safewrite(fd, &req, sizeof(req)) != sizeof(req)) {
+        virReportSystemError(errno,
+                             _("Failed to send request to init control %s"),
+                             path);
+        goto cleanup;
+    }
+
+    ret = 1;
+
+cleanup:
+    VIR_FREE(path);
+    VIR_FORCE_CLOSE(fd);
+    return ret;
+}
diff --git a/src/util/virinitctl.h b/src/util/virinitctl.h
new file mode 100644 (file)
index 0000000..862539f
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * virinitctl.h: API for talking to init systems via initctl
+ *
+ * Copyright (C) 2012 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ *     Daniel P. Berrange <berrange@redhat.com>
+ */
+
+#ifndef __VIR_INITCTL_H__
+# define __VIR_INITCTL_H__
+
+typedef enum virInitctlRunLevel virInitctlRunLevel;
+enum virInitctlRunLevel {
+    VIR_INITCTL_RUNLEVEL_POWEROFF = 0,
+    VIR_INITCTL_RUNLEVEL_1 = 1,
+    VIR_INITCTL_RUNLEVEL_2 = 2,
+    VIR_INITCTL_RUNLEVEL_3 = 3,
+    VIR_INITCTL_RUNLEVEL_4 = 4,
+    VIR_INITCTL_RUNLEVEL_5 = 5,
+    VIR_INITCTL_RUNLEVEL_REBOOT = 6,
+
+    VIR_INITCTL_RUNLEVEL_LAST
+};
+
+int virInitctlSetRunLevel(virInitctlRunLevel level,
+                          const char *vroot);
+
+#endif
index 213188e2156b3935a689f8aa0b44dd3544534ae4..1142c40a63f27711bcbc12e703b8ca94e4718fad 100644 (file)
@@ -117,6 +117,7 @@ VIR_ENUM_IMPL(virErrorDomain, VIR_ERR_DOMAIN_LAST,
 
               "SSH transport layer", /* 50 */
               "Lock Space",
+              "Init control",
     )