[libvirt] [PATCH 05/14] Introduce basic infrastructure for virtlockd daemon

Daniel P. Berrange berrange at redhat.com
Tue Dec 11 20:41:39 UTC 2012


From: "Daniel P. Berrange" <berrange at redhat.com>

The virtlockd daemon will maintain locks on behalf of libvirtd.
There are two reasons for it to be separate

 - Avoid risk of other libvirtd threads accidentally
   releasing fcntl() locks by opening + closing a file
   that is locked
 - Ensure locks can be preserved across libvirtd restarts.
   virtlockd will need to be able to re-exec itself while
   maintaining locks. This is simpler to achieve if its
   sole job is maintaining locks

Signed-off-by: Daniel P. Berrange <berrange at redhat.com>
---
 .gitignore                       |   2 +
 cfg.mk                           |   6 +-
 libvirt.spec.in                  |   7 +
 po/POTFILES.in                   |   2 +
 src/Makefile.am                  |  89 +++-
 src/locking/lock_daemon.c        | 850 +++++++++++++++++++++++++++++++++++++++
 src/locking/lock_daemon.h        |  43 ++
 src/locking/lock_daemon_config.c | 193 +++++++++
 src/locking/lock_daemon_config.h |  50 +++
 src/locking/virtlockd.init.in    |  93 +++++
 src/locking/virtlockd.sysconf    |   3 +
 11 files changed, 1334 insertions(+), 4 deletions(-)
 create mode 100644 src/locking/lock_daemon.c
 create mode 100644 src/locking/lock_daemon.h
 create mode 100644 src/locking/lock_daemon_config.c
 create mode 100644 src/locking/lock_daemon_config.h
 create mode 100644 src/locking/virtlockd.init.in
 create mode 100644 src/locking/virtlockd.sysconf

diff --git a/.gitignore b/.gitignore
index 0dadd21..1e3a624 100644
--- a/.gitignore
+++ b/.gitignore
@@ -123,6 +123,8 @@
 /src/test_libvirt*.aug
 /src/util/virkeymaps.h
 /src/virt-aa-helper
+/src/virtlockd
+/src/virtlockd.init
 /tests/*.log
 /tests/*.pid
 /tests/*xml2*test
diff --git a/cfg.mk b/cfg.mk
index f218eb6..95a1d3a 100644
--- a/cfg.mk
+++ b/cfg.mk
@@ -655,6 +655,8 @@ sc_prohibit_cross_inclusion:
 	@for dir in $(cross_dirs); do					\
 	  case $$dir in							\
 	    util/) safe="util";;					\
+	    locking/)							\
+	      safe="($$dir|util|conf|rpc)";;				\
 	    cpu/ | locking/ | network/ | rpc/ | security/)		\
 	      safe="($$dir|util|conf)";;				\
 	    xenapi/ | xenxs/ ) safe="($$dir|util|conf|xen)";;		\
@@ -743,7 +745,7 @@ $(srcdir)/src/remote/remote_client_bodies.h: $(srcdir)/src/remote/remote_protoco
 # List all syntax-check exemptions:
 exclude_file_name_regexp--sc_avoid_strcase = ^tools/virsh\.h$$
 
-_src1=libvirt|fdstream|qemu/qemu_monitor|util/(command|util)|xen/xend_internal|rpc/virnetsocket|lxc/lxc_controller
+_src1=libvirt|fdstream|qemu/qemu_monitor|util/(command|util)|xen/xend_internal|rpc/virnetsocket|lxc/lxc_controller|locking/lock_daemon
 exclude_file_name_regexp--sc_avoid_write = \
   ^(src/($(_src1))|daemon/libvirtd|tools/console|tests/(shunload|virnettlscontext)test)\.c$$
 
@@ -776,7 +778,7 @@ exclude_file_name_regexp--sc_prohibit_close = \
 exclude_file_name_regexp--sc_prohibit_empty_lines_at_EOF = \
   (^tests/(qemuhelp|nodeinfo)data/|\.(gif|ico|png|diff)$$)
 
-_src2=src/(util/command|libvirt|lxc/lxc_controller)
+_src2=src/(util/command|libvirt|lxc/lxc_controller|locking/lock_daemon)
 exclude_file_name_regexp--sc_prohibit_fork_wrappers = \
   (^($(_src2)|tests/testutils|daemon/libvirtd)\.c$$)
 
diff --git a/libvirt.spec.in b/libvirt.spec.in
index d6e1fbe..e12fca4 100644
--- a/libvirt.spec.in
+++ b/libvirt.spec.in
@@ -1661,9 +1661,11 @@ fi
 %{_unitdir}/libvirtd.service
 %else
 %{_sysconfdir}/rc.d/init.d/libvirtd
+%{_sysconfdir}/rc.d/init.d/virtlockd
 %endif
 %doc daemon/libvirtd.upstart
 %config(noreplace) %{_sysconfdir}/sysconfig/libvirtd
+%config(noreplace) %{_sysconfdir}/sysconfig/virtlockd
 %config(noreplace) %{_sysconfdir}/libvirt/libvirtd.conf
 %if 0%{?fedora} >= 14 || 0%{?rhel} >= 6
 %config(noreplace) %{_sysconfdir}/sysctl.d/libvirtd
@@ -1730,6 +1732,10 @@ rm -f $RPM_BUILD_ROOT%{_sysconfdir}/sysctl.d/libvirtd
 %dir %attr(0755, root, root) %{_localstatedir}/lib/libvirt/dnsmasq/
 %endif
 
+%if %{with_libvirtd}
+%dir %attr(0755, root, root) %{_libdir}/libvirt/lock-driver
+%endif
+
 %if %{with_qemu}
 %{_datadir}/augeas/lenses/libvirtd_qemu.aug
 %{_datadir}/augeas/lenses/tests/test_libvirtd_qemu.aug
@@ -1763,6 +1769,7 @@ rm -f $RPM_BUILD_ROOT%{_sysconfdir}/sysctl.d/libvirtd
 
 %attr(0755, root, root) %{_libexecdir}/libvirt_iohelper
 %attr(0755, root, root) %{_sbindir}/libvirtd
+%attr(0755, root, root) %{_sbindir}/virtlockd
 
 %{_mandir}/man8/libvirtd.8*
 
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 51a1f5c..34c688c 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -48,6 +48,8 @@ src/interface/interface_backend_udev.c
 src/internal.h
 src/libvirt.c
 src/libvirt-qemu.c
+src/locking/lock_daemon.c
+src/locking/lock_daemon_config.c
 src/locking/lock_driver_sanlock.c
 src/locking/lock_manager.c
 src/locking/sanlock_helper.c
diff --git a/src/Makefile.am b/src/Makefile.am
index 6d2816d..6a66efd 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -148,6 +148,13 @@ LOCK_DRIVER_SANLOCK_SOURCES = \
 LOCK_DRIVER_SANLOCK_HELPER_SOURCES = \
 		locking/sanlock_helper.c
 
+LOCK_DAEMON_SOURCES = \
+		locking/lock_daemon.h \
+		locking/lock_daemon.c \
+		locking/lock_daemon_config.h \
+		locking/lock_daemon_config.c \
+		$(NULL)
+
 NETDEV_CONF_SOURCES =						\
 		conf/netdev_bandwidth_conf.h conf/netdev_bandwidth_conf.c \
 		conf/netdev_vport_profile_conf.h conf/netdev_vport_profile_conf.c \
@@ -1508,6 +1515,76 @@ libvirt_qemu_la_CFLAGS = $(AM_CFLAGS)
 libvirt_qemu_la_LIBADD = libvirt.la $(CYGWIN_EXTRA_LIBADD)
 EXTRA_DIST += $(LIBVIRT_QEMU_SYMBOL_FILE)
 
+if WITH_LIBVIRTD
+sbin_PROGRAMS = virtlockd
+
+virtlockd_SOURCES = $(LOCK_DAEMON_SOURCES)
+virtlockd_CFLAGS = \
+		$(AM_CFLAGS) \
+		$(NULL)
+virtlockd_LDFLAGS = \
+		$(AM_LDFLAGS) \
+		$(CYGWIN_EXTRA_LDFLAGS) \
+		$(MINGW_EXTRA_LDFLAGS) \
+		$(NULL)
+virtlockd_LDADD = \
+		libvirt-net-rpc-server.la \
+		libvirt-net-rpc.la \
+		libvirt_util.la \
+		../gnulib/lib/libgnu.la \
+		$(CYGWIN_EXTRA_LIBADD) \
+		$(NULL)
+if WITH_DTRACE_PROBES
+virtlockd_LDADD += libvirt_probes.lo
+endif
+
+else
+EXTRA_DIST += $(LOCK_DAEMON_SOURCES)
+endif
+
+EXTRA_DIST += locking/virtlockd.sysconf
+
+install-sysconfig:
+	mkdir -p $(DESTDIR)$(sysconfdir)/sysconfig
+	$(INSTALL_DATA) $(srcdir)/locking/virtlockd.sysconf \
+	  $(DESTDIR)$(sysconfdir)/sysconfig/virtlockd
+
+uninstall-sysconfig:
+	rm -f $(DESTDIR)$(sysconfdir)/sysconfig/virtlockd
+
+EXTRA_DIST += locking/virtlockd.init.in
+
+if WITH_LIBVIRTD
+if LIBVIRT_INIT_SCRIPT_RED_HAT
+install-init:: virtlockd.init install-sysconfig
+	mkdir -p $(DESTDIR)$(sysconfdir)/rc.d/init.d
+	$(INSTALL_SCRIPT) virtlockd.init \
+	  $(DESTDIR)$(sysconfdir)/rc.d/init.d/virtlockd
+
+uninstall-init:: uninstall-sysconfig
+	rm -f $(DESTDIR)$(sysconfdir)/rc.d/init.d/libvirtd
+
+BUILT_SOURCES += virtlockd.init
+else
+install-init::
+uninstall-init::
+endif
+else
+install-init::
+uninstall-init::
+endif
+
+virtlockd.init: locking/virtlockd.init.in $(top_builddir)/config.status
+	$(AM_V_GEN)sed					\
+	    -e "s!::localstatedir::!$(localstatedir)!g"	\
+	    -e "s!::sbindir::!$(sbindir)!g"		\
+	    -e "s!::sysconfdir::!$(sysconfdir)!g"	\
+	    < $< > $@-t &&				\
+	    chmod a+x $@-t &&				\
+	    mv $@-t $@
+
+
+
 if HAVE_SANLOCK
 lockdriverdir = $(libdir)/libvirt/lock-driver
 lockdriver_LTLIBRARIES = sanlock.la
@@ -1745,7 +1822,11 @@ endif
 endif
 EXTRA_DIST += $(SECURITY_DRIVER_APPARMOR_HELPER_SOURCES)
 
-install-data-local:
+install-data-local: install-init
+if WITH_LIBVIRTD
+	$(MKDIR_P) "$(DESTDIR)$(localstatedir)/lib/libvirt/lockd"
+	$(MKDIR_P) "$(DESTDIR)$(localstatedir)/run/libvirt/lockd"
+endif
 	$(MKDIR_P) "$(DESTDIR)$(localstatedir)/cache/libvirt"
 	$(MKDIR_P) "$(DESTDIR)$(localstatedir)/lib/libvirt/images"
 	$(MKDIR_P) "$(DESTDIR)$(localstatedir)/lib/libvirt/filesystems"
@@ -1794,7 +1875,11 @@ if WITH_NETWORK
 	    $(DESTDIR)$(sysconfdir)/libvirt/qemu/networks/autostart/default.xml
 endif
 
-uninstall-local::
+uninstall-local:: uninstall-init
+if WITH_LIBVIRTD
+	rmdir "$(DESTDIR)$(localstatedir)/lib/libvirt/lockd" ||:
+	rmdir "$(DESTDIR)$(localstatedir)/run/libvirt/lockd" ||:
+endif
 	rmdir "$(DESTDIR)$(localstatedir)/cache/libvirt" ||:
 	rmdir "$(DESTDIR)$(localstatedir)/lib/libvirt/images" ||:
 	rmdir "$(DESTDIR)$(localstatedir)/lib/libvirt/filesystems" ||:
diff --git a/src/locking/lock_daemon.c b/src/locking/lock_daemon.c
new file mode 100644
index 0000000..f821d2e
--- /dev/null
+++ b/src/locking/lock_daemon.c
@@ -0,0 +1,850 @@
+/*
+ * lock_daemon.c: lock management daemon
+ *
+ * Copyright (C) 2006-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/>.
+ *
+ * Author: Daniel P. Berrange <berrange at redhat.com>
+ */
+
+#include <config.h>
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <locale.h>
+
+
+#include "lock_daemon.h"
+#include "lock_daemon_config.h"
+#include "util.h"
+#include "virfile.h"
+#include "virpidfile.h"
+#include "virterror_internal.h"
+#include "logging.h"
+#include "memory.h"
+#include "conf.h"
+#include "rpc/virnetserver.h"
+#include "virrandom.h"
+#include "virhash.h"
+
+#include "configmake.h"
+
+#define VIR_FROM_THIS VIR_FROM_LOCKING
+
+struct _virLockDaemon {
+    virMutex lock;
+    virNetServerPtr srv;
+};
+
+virLockDaemonPtr lockDaemon = NULL;
+
+enum {
+    VIR_LOCK_DAEMON_ERR_NONE = 0,
+    VIR_LOCK_DAEMON_ERR_PIDFILE,
+    VIR_LOCK_DAEMON_ERR_RUNDIR,
+    VIR_LOCK_DAEMON_ERR_INIT,
+    VIR_LOCK_DAEMON_ERR_SIGNAL,
+    VIR_LOCK_DAEMON_ERR_PRIVS,
+    VIR_LOCK_DAEMON_ERR_NETWORK,
+    VIR_LOCK_DAEMON_ERR_CONFIG,
+    VIR_LOCK_DAEMON_ERR_HOOKS,
+
+    VIR_LOCK_DAEMON_ERR_LAST
+};
+
+VIR_ENUM_DECL(virDaemonErr)
+VIR_ENUM_IMPL(virDaemonErr, VIR_LOCK_DAEMON_ERR_LAST,
+              "Initialization successful",
+              "Unable to obtain pidfile",
+              "Unable to create rundir",
+              "Unable to initialize libvirt",
+              "Unable to setup signal handlers",
+              "Unable to drop privileges",
+              "Unable to initialize network sockets",
+              "Unable to load configuration file",
+              "Unable to look for hook scripts");
+
+static void *
+virLockDaemonClientNew(virNetServerClientPtr client,
+                       void *opaque);
+static void
+virLockDaemonClientFree(void *opaque);
+
+static void
+virLockDaemonFree(virLockDaemonPtr lockd)
+{
+    if (!lockd)
+        return;
+
+    virObjectUnref(lockd->srv);
+
+    VIR_FREE(lockd);
+}
+
+
+static virLockDaemonPtr
+virLockDaemonNew(bool privileged)
+{
+    virLockDaemonPtr lockd;
+
+    if (VIR_ALLOC(lockd) < 0) {
+        virReportOOMError();
+        return NULL;
+    }
+
+    if (virMutexInit(&lockd->lock) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("Unable to initialize mutex"));
+        VIR_FREE(lockd);
+        return NULL;
+    }
+
+    if (!(lockd->srv = virNetServerNew(1, 1, 0, 20,
+                                       -1, 0,
+                                       false, NULL,
+                                       virLockDaemonClientNew,
+                                       NULL,
+                                       virLockDaemonClientFree,
+                                       (void*)(intptr_t)(privileged ? 0x1 : 0x0))))
+        goto error;
+
+    return lockd;
+
+error:
+    virLockDaemonFree(lockd);
+    return NULL;
+}
+
+
+static int
+virLockDaemonForkIntoBackground(const char *argv0)
+{
+    int statuspipe[2];
+    if (pipe(statuspipe) < 0)
+        return -1;
+
+    pid_t pid = fork();
+    switch (pid) {
+    case 0:
+        {
+            int stdinfd = -1;
+            int stdoutfd = -1;
+            int nextpid;
+
+            VIR_FORCE_CLOSE(statuspipe[0]);
+
+            if ((stdinfd = open("/dev/null", O_RDONLY)) < 0)
+                goto cleanup;
+            if ((stdoutfd = open("/dev/null", O_WRONLY)) < 0)
+                goto cleanup;
+            if (dup2(stdinfd, STDIN_FILENO) != STDIN_FILENO)
+                goto cleanup;
+            if (dup2(stdoutfd, STDOUT_FILENO) != STDOUT_FILENO)
+                goto cleanup;
+            if (dup2(stdoutfd, STDERR_FILENO) != STDERR_FILENO)
+                goto cleanup;
+            if (VIR_CLOSE(stdinfd) < 0)
+                goto cleanup;
+            if (VIR_CLOSE(stdoutfd) < 0)
+                goto cleanup;
+
+            if (setsid() < 0)
+                goto cleanup;
+
+            nextpid = fork();
+            switch (nextpid) {
+            case 0:
+                return statuspipe[1];
+            case -1:
+                return -1;
+            default:
+                _exit(0);
+            }
+
+        cleanup:
+            VIR_FORCE_CLOSE(stdoutfd);
+            VIR_FORCE_CLOSE(stdinfd);
+            return -1;
+
+        }
+
+    case -1:
+        return -1;
+
+    default:
+        {
+            int got, exitstatus = 0;
+            int ret;
+            char status;
+
+            VIR_FORCE_CLOSE(statuspipe[1]);
+
+            /* We wait to make sure the first child forked successfully */
+            if ((got = waitpid(pid, &exitstatus, 0)) < 0 ||
+                got != pid ||
+                exitstatus != 0) {
+                return -1;
+            }
+
+            /* Now block until the second child initializes successfully */
+        again:
+            ret = read(statuspipe[0], &status, 1);
+            if (ret == -1 && errno == EINTR)
+                goto again;
+
+            if (ret == 1 && status != 0) {
+                fprintf(stderr,
+                        _("%s: error: %s. Check /var/log/messages or run without "
+                          "--daemon for more info.\n"), argv0,
+                        virDaemonErrTypeToString(status));
+            }
+            _exit(ret == 1 && status == 0 ? 0 : 1);
+        }
+    }
+}
+
+
+static int
+virLockDaemonPidFilePath(bool privileged,
+                         char **pidfile)
+{
+    if (privileged) {
+        if (!(*pidfile = strdup(LOCALSTATEDIR "/run/virtlockd.pid")))
+            goto no_memory;
+    } else {
+        char *rundir = NULL;
+        mode_t old_umask;
+
+        if (!(rundir = virGetUserRuntimeDirectory()))
+            goto error;
+
+        old_umask = umask(077);
+        if (virFileMakePath(rundir) < 0) {
+            umask(old_umask);
+            goto error;
+        }
+        umask(old_umask);
+
+        if (virAsprintf(pidfile, "%s/virtlockd.pid", rundir) < 0) {
+            VIR_FREE(rundir);
+            goto no_memory;
+        }
+
+        VIR_FREE(rundir);
+    }
+
+    return 0;
+
+no_memory:
+    virReportOOMError();
+error:
+    return -1;
+}
+
+
+static int
+virLockDaemonUnixSocketPaths(bool privileged,
+                             char **sockfile)
+{
+    if (privileged) {
+        if (!(*sockfile = strdup(LOCALSTATEDIR "/run/libvirt/virtlockd-sock")))
+            goto no_memory;
+    } else {
+        char *rundir = NULL;
+        mode_t old_umask;
+
+        if (!(rundir = virGetUserRuntimeDirectory()))
+            goto error;
+
+        old_umask = umask(077);
+        if (virFileMakePath(rundir) < 0) {
+            umask(old_umask);
+            goto error;
+        }
+        umask(old_umask);
+
+        if (virAsprintf(sockfile, "%s/virtlockd-sock", rundir) < 0) {
+            VIR_FREE(rundir);
+            goto no_memory;
+        }
+
+        VIR_FREE(rundir);
+    }
+    return 0;
+
+no_memory:
+    virReportOOMError();
+error:
+    return -1;
+}
+
+
+static void
+virLockDaemonErrorHandler(void *opaque ATTRIBUTE_UNUSED,
+                          virErrorPtr err ATTRIBUTE_UNUSED)
+{
+    /* Don't do anything, since logging infrastructure already
+     * took care of reporting the error */
+}
+
+
+/*
+ * Set up the logging environment
+ * By default if daemonized all errors go to the logfile libvirtd.log,
+ * but if verbose or error debugging is asked for then also output
+ * informational and debug messages. Default size if 64 kB.
+ */
+static int
+virLockDaemonSetupLogging(virLockDaemonConfigPtr config,
+                          bool privileged,
+                          bool verbose,
+                          bool godaemon)
+{
+    virLogReset();
+
+    /*
+     * Libvirtd's order of precedence is:
+     * cmdline > environment > config
+     *
+     * In order to achieve this, we must process configuration in
+     * different order for the log level versus the filters and
+     * outputs. Because filters and outputs append, we have to look at
+     * the environment first and then only check the config file if
+     * there was no result from the environment. The default output is
+     * then applied only if there was no setting from either of the
+     * first two. Because we don't have a way to determine if the log
+     * level has been set, we must process variables in the opposite
+     * order, each one overriding the previous.
+     */
+    if (config->log_level != 0)
+        virLogSetDefaultPriority(config->log_level);
+
+    virLogSetFromEnv();
+
+    virLogSetBufferSize(config->log_buffer_size);
+
+    if (virLogGetNbFilters() == 0)
+        virLogParseFilters(config->log_filters);
+
+    if (virLogGetNbOutputs() == 0)
+        virLogParseOutputs(config->log_outputs);
+
+    /*
+     * If no defined outputs, and either running
+     * as daemon or not on a tty, then first try
+     * to direct it to the systemd journal
+     * (if it exists)....
+     */
+    if (virLogGetNbOutputs() == 0 &&
+        (godaemon || !isatty(STDIN_FILENO))) {
+        char *tmp;
+        if (access("/run/systemd/journal/socket", W_OK) >= 0) {
+            if (virAsprintf(&tmp, "%d:journald", virLogGetDefaultPriority()) < 0)
+                goto no_memory;
+            virLogParseOutputs(tmp);
+            VIR_FREE(tmp);
+        }
+    }
+
+    /*
+     * otherwise direct to libvirtd.log when running
+     * as daemon. Otherwise the default output is stderr.
+     */
+    if (virLogGetNbOutputs() == 0) {
+        char *tmp = NULL;
+
+        if (godaemon) {
+            if (privileged) {
+                if (virAsprintf(&tmp, "%d:file:%s/log/libvirt/virtlockd.log",
+                                virLogGetDefaultPriority(),
+                                LOCALSTATEDIR) == -1)
+                    goto no_memory;
+            } else {
+                char *logdir = virGetUserCacheDirectory();
+                mode_t old_umask;
+
+                if (!logdir)
+                    goto error;
+
+                old_umask = umask(077);
+                if (virFileMakePath(logdir) < 0) {
+                    umask(old_umask);
+                    goto error;
+                }
+                umask(old_umask);
+
+                if (virAsprintf(&tmp, "%d:file:%s/virtlockd.log",
+                                virLogGetDefaultPriority(), logdir) == -1) {
+                    VIR_FREE(logdir);
+                    goto no_memory;
+                }
+                VIR_FREE(logdir);
+            }
+        } else {
+            if (virAsprintf(&tmp, "%d:stderr", virLogGetDefaultPriority()) < 0)
+                goto no_memory;
+        }
+        virLogParseOutputs(tmp);
+        VIR_FREE(tmp);
+    }
+
+    /*
+     * Command line override for --verbose
+     */
+    if ((verbose) && (virLogGetDefaultPriority() > VIR_LOG_INFO))
+        virLogSetDefaultPriority(VIR_LOG_INFO);
+
+    return 0;
+
+no_memory:
+    virReportOOMError();
+error:
+    return -1;
+}
+
+
+
+/* Display version information. */
+static void
+virLockDaemonVersion(const char *argv0)
+{
+    printf("%s (%s) %s\n", argv0, PACKAGE_NAME, PACKAGE_VERSION);
+}
+
+static void
+virLockDaemonShutdownHandler(virNetServerPtr srv,
+                             siginfo_t *sig ATTRIBUTE_UNUSED,
+                             void *opaque ATTRIBUTE_UNUSED)
+{
+    virNetServerQuit(srv);
+}
+
+static int
+virLockDaemonSetupSignals(virNetServerPtr srv)
+{
+    if (virNetServerAddSignalHandler(srv, SIGINT, virLockDaemonShutdownHandler, NULL) < 0)
+        return -1;
+    if (virNetServerAddSignalHandler(srv, SIGQUIT, virLockDaemonShutdownHandler, NULL) < 0)
+        return -1;
+    if (virNetServerAddSignalHandler(srv, SIGTERM, virLockDaemonShutdownHandler, NULL) < 0)
+        return -1;
+    return 0;
+}
+
+static int
+virLockDaemonSetupNetworking(virNetServerPtr srv, const char *sock_path)
+{
+    virNetServerServicePtr svc;
+
+    VIR_DEBUG("Setting up networking natively");
+
+    if (!(svc = virNetServerServiceNewUNIX(sock_path, 0700, 0, 0, false, 1, NULL)))
+        return -1;
+
+    if (virNetServerAddService(srv, svc, NULL) < 0) {
+        virObjectUnref(svc);
+        return -1;
+    }
+    return 0;
+}
+
+
+static void
+virLockDaemonClientFree(void *opaque)
+{
+    virLockDaemonClientPtr priv = opaque;
+
+    if (!priv)
+        return;
+
+    VIR_DEBUG("priv=%p client=%lld",
+              priv,
+              (unsigned long long)priv->clientPid);
+
+    virMutexDestroy(&priv->lock);
+    VIR_FREE(priv);
+}
+
+
+static void *
+virLockDaemonClientNew(virNetServerClientPtr client,
+                       void *opaque)
+{
+    virLockDaemonClientPtr priv;
+    uid_t clientuid;
+    gid_t clientgid;
+    bool privileged = opaque != NULL;
+
+    if (VIR_ALLOC(priv) < 0) {
+        virReportOOMError();
+        return NULL;
+    }
+
+    if (virMutexInit(&priv->lock) < 0) {
+        VIR_FREE(priv);
+        virReportOOMError();
+        return NULL;
+    }
+
+    if (virNetServerClientGetUNIXIdentity(client,
+                                          &clientuid,
+                                          &clientgid,
+                                          &priv->clientPid) < 0)
+        goto error;
+
+    VIR_DEBUG("New client pid %llu uid %llu",
+              (unsigned long long)priv->clientPid,
+              (unsigned long long)clientuid);
+
+    if (!privileged) {
+        if (geteuid() != clientuid) {
+            virReportError(VIR_ERR_OPERATION_DENIED,
+                           _("Disallowing client %llu with uid %llu"),
+                           (unsigned long long)priv->clientPid,
+                           (unsigned long long)clientuid);
+            goto error;
+        }
+    } else {
+        if (clientuid != 0) {
+            virReportError(VIR_ERR_OPERATION_DENIED,
+                           _("Disallowing client %llu with uid %llu"),
+                           (unsigned long long)priv->clientPid,
+                           (unsigned long long)clientuid);
+            goto error;
+        }
+    }
+
+    return priv;
+
+error:
+    virMutexDestroy(&priv->lock);
+    VIR_FREE(priv);
+    return NULL;
+}
+
+
+static void
+virLockDaemonUsage(const char *argv0, bool privileged)
+{
+    fprintf(stderr,
+            _("\n"
+              "Usage:\n"
+              "  %s [options]\n"
+              "\n"
+              "Options:\n"
+              "  -v | --verbose         Verbose messages.\n"
+              "  -d | --daemon          Run as a daemon & write PID file.\n"
+              "  -t | --timeout <secs>  Exit after timeout period.\n"
+              "  -f | --config <file>   Configuration file.\n"
+              "     | --version         Display version information.\n"
+              "  -p | --pid-file <file> Change name of PID file.\n"
+              "\n"
+              "libvirt lock management daemon:\n"), argv0);
+
+    if (privileged) {
+        fprintf(stderr,
+                _("\n"
+                  "  Default paths:\n"
+                  "\n"
+                  "    Configuration file (unless overridden by -f):\n"
+                  "      %s/libvirt/virtlockd.conf\n"
+                  "\n"
+                  "    Sockets:\n"
+                  "      %s/run/libvirt/virtlockd-sock\n"
+                  "\n"
+                  "    PID file (unless overridden by -p):\n"
+                  "      %s/run/virtlockd.pid\n"
+                  "\n"),
+                SYSCONFDIR,
+                LOCALSTATEDIR,
+                LOCALSTATEDIR);
+    } else {
+        fprintf(stderr,
+                "%s", _("\n"
+                        "  Default paths:\n"
+                        "\n"
+                        "    Configuration file (unless overridden by -f):\n"
+                        "      $XDG_CONFIG_HOME/libvirt/virtlockd.conf\n"
+                        "\n"
+                        "    Sockets:\n"
+                        "      $XDG_RUNTIME_DIR/libvirt/virtlockd-sock\n"
+                        "\n"
+                        "    PID file:\n"
+                        "      $XDG_RUNTIME_DIR/libvirt/virtlockd.pid\n"
+                        "\n"));
+    }
+}
+
+enum {
+    OPT_VERSION = 129
+};
+
+#define MAX_LISTEN 5
+int main(int argc, char **argv) {
+    char *remote_config_file = NULL;
+    int statuswrite = -1;
+    int ret = 1;
+    int verbose = 0;
+    int godaemon = 0;
+    int timeout = 0;
+    char *run_dir = NULL;
+    char *pid_file = NULL;
+    int pid_file_fd = -1;
+    char *sock_file = NULL;
+    bool implicit_conf = false;
+    mode_t old_umask;
+    bool privileged = false;
+    virLockDaemonConfigPtr config = NULL;
+
+    struct option opts[] = {
+        { "verbose", no_argument, &verbose, 1},
+        { "daemon", no_argument, &godaemon, 1},
+        { "config", required_argument, NULL, 'f'},
+        { "timeout", required_argument, NULL, 't'},
+        { "pid-file", required_argument, NULL, 'p'},
+        { "version", no_argument, NULL, OPT_VERSION },
+        { "help", no_argument, NULL, '?' },
+        {0, 0, 0, 0}
+    };
+
+    privileged = getuid() == 0;
+
+    if (setlocale(LC_ALL, "") == NULL ||
+        bindtextdomain(PACKAGE, LOCALEDIR) == NULL ||
+        textdomain(PACKAGE) == NULL ||
+        virThreadInitialize() < 0 ||
+        virErrorInitialize() < 0) {
+        fprintf(stderr, _("%s: initialization failed\n"), argv[0]);
+        exit(EXIT_FAILURE);
+    }
+
+    while (1) {
+        int optidx = 0;
+        int c;
+        char *tmp;
+
+        c = getopt_long(argc, argv, "ldf:p:t:v", opts, &optidx);
+
+        if (c == -1) {
+            break;
+        }
+
+        switch (c) {
+        case 0:
+            /* Got one of the flags */
+            break;
+        case 'v':
+            verbose = 1;
+            break;
+        case 'd':
+            godaemon = 1;
+            break;
+
+        case 't':
+            if (virStrToLong_i(optarg, &tmp, 10, &timeout) != 0
+                || timeout <= 0
+                /* Ensure that we can multiply by 1000 without overflowing.  */
+                || timeout > INT_MAX / 1000)
+                timeout = -1;
+            break;
+
+        case 'p':
+            VIR_FREE(pid_file);
+            if (!(pid_file = strdup(optarg)))
+                exit(EXIT_FAILURE);
+            break;
+
+        case 'f':
+            VIR_FREE(remote_config_file);
+            if (!(remote_config_file = strdup(optarg)))
+                exit(EXIT_FAILURE);
+            break;
+
+        case OPT_VERSION:
+            virLockDaemonVersion(argv[0]);
+            return 0;
+
+        case '?':
+            virLockDaemonUsage(argv[0], privileged);
+            return 2;
+
+        default:
+            fprintf(stderr, _("%s: internal error: unknown flag: %c\n"),
+                    argv[0], c);
+            exit(EXIT_FAILURE);
+        }
+    }
+
+    if (!(config = virLockDaemonConfigNew(privileged))) {
+        VIR_ERROR(_("Can't create initial configuration"));
+        exit(EXIT_FAILURE);
+    }
+
+    /* No explicit config, so try and find a default one */
+    if (remote_config_file == NULL) {
+        implicit_conf = true;
+        if (virLockDaemonConfigFilePath(privileged,
+                                        &remote_config_file) < 0) {
+            VIR_ERROR(_("Can't determine config path"));
+            exit(EXIT_FAILURE);
+        }
+    }
+
+    /* Read the config file if it exists*/
+    if (remote_config_file &&
+        virLockDaemonConfigLoadFile(config, remote_config_file, implicit_conf) < 0) {
+        virErrorPtr err = virGetLastError();
+        if (err && err->message)
+            VIR_ERROR(_("Can't load config file: %s: %s"),
+                      err->message, remote_config_file);
+        else
+            VIR_ERROR(_("Can't load config file: %s"), remote_config_file);
+        exit(EXIT_FAILURE);
+    }
+
+    if (virLockDaemonSetupLogging(config, privileged, verbose, godaemon) < 0) {
+        VIR_ERROR(_("Can't initialize logging"));
+        exit(EXIT_FAILURE);
+    }
+
+    if (!pid_file &&
+        virLockDaemonPidFilePath(privileged,
+                                 &pid_file) < 0) {
+        VIR_ERROR(_("Can't determine pid file path."));
+        exit(EXIT_FAILURE);
+    }
+    VIR_DEBUG("Decided on pid file path '%s'", NULLSTR(pid_file));
+
+    if (virLockDaemonUnixSocketPaths(privileged,
+                                     &sock_file) < 0) {
+        VIR_ERROR(_("Can't determine socket paths"));
+        exit(EXIT_FAILURE);
+    }
+    VIR_DEBUG("Decided on socket paths '%s'",
+              sock_file);
+
+    if (godaemon) {
+        char ebuf[1024];
+
+        if (chdir("/") < 0) {
+            VIR_ERROR(_("cannot change to root directory: %s"),
+                      virStrerror(errno, ebuf, sizeof(ebuf)));
+            goto cleanup;
+        }
+
+        if ((statuswrite = virLockDaemonForkIntoBackground(argv[0])) < 0) {
+            VIR_ERROR(_("Failed to fork as daemon: %s"),
+                      virStrerror(errno, ebuf, sizeof(ebuf)));
+            goto cleanup;
+        }
+    }
+
+    /* Ensure the rundir exists (on tmpfs on some systems) */
+    if (privileged) {
+        run_dir = strdup(LOCALSTATEDIR "/run/libvirt");
+    } else {
+        run_dir = virGetUserRuntimeDirectory();
+
+        if (!run_dir) {
+            VIR_ERROR(_("Can't determine user directory"));
+            goto cleanup;
+        }
+    }
+    if (!run_dir) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    if (privileged)
+        old_umask = umask(022);
+    else
+        old_umask = umask(077);
+    VIR_DEBUG("Ensuring run dir '%s' exists", run_dir);
+    if (virFileMakePath(run_dir) < 0) {
+        char ebuf[1024];
+        VIR_ERROR(_("unable to create rundir %s: %s"), run_dir,
+                  virStrerror(errno, ebuf, sizeof(ebuf)));
+        ret = VIR_LOCK_DAEMON_ERR_RUNDIR;
+        goto cleanup;
+    }
+    umask(old_umask);
+
+    /* If we have a pidfile set, claim it now, exiting if already taken */
+    if ((pid_file_fd = virPidFileAcquirePath(pid_file, getpid())) < 0) {
+        ret = VIR_LOCK_DAEMON_ERR_PIDFILE;
+        goto cleanup;
+    }
+
+    if (!(lockDaemon = virLockDaemonNew(privileged))) {
+        ret = VIR_LOCK_DAEMON_ERR_INIT;
+        goto cleanup;
+    }
+
+    if (virLockDaemonSetupNetworking(lockDaemon->srv, sock_file) < 0) {
+        ret = VIR_LOCK_DAEMON_ERR_NETWORK;
+        goto cleanup;
+    }
+
+    if ((virLockDaemonSetupSignals(lockDaemon->srv)) < 0) {
+        ret = VIR_LOCK_DAEMON_ERR_SIGNAL;
+        goto cleanup;
+    }
+
+    /* Disable error func, now logging is setup */
+    virSetErrorFunc(NULL, virLockDaemonErrorHandler);
+
+
+    /* Tell parent of daemon that basic initialization is complete
+     * In particular we're ready to accept net connections & have
+     * written the pidfile
+     */
+    if (statuswrite != -1) {
+        char status = 0;
+        while (write(statuswrite, &status, 1) == -1 &&
+               errno == EINTR)
+            ;
+        VIR_FORCE_CLOSE(statuswrite);
+    }
+
+    /* Start accepting new clients from network */
+
+    virNetServerUpdateServices(lockDaemon->srv, true);
+    virNetServerRun(lockDaemon->srv);
+    ret = 0;
+
+cleanup:
+    virLockDaemonFree(lockDaemon);
+    if (statuswrite != -1) {
+        if (ret != 0) {
+            /* Tell parent of daemon what failed */
+            char status = ret;
+            while (write(statuswrite, &status, 1) == -1 &&
+                   errno == EINTR)
+                ;
+        }
+        VIR_FORCE_CLOSE(statuswrite);
+    }
+    if (pid_file_fd != -1)
+        virPidFileReleasePath(pid_file, pid_file_fd);
+    VIR_FREE(pid_file);
+    VIR_FREE(sock_file);
+    VIR_FREE(run_dir);
+    return ret;
+}
diff --git a/src/locking/lock_daemon.h b/src/locking/lock_daemon.h
new file mode 100644
index 0000000..7bc8c2e
--- /dev/null
+++ b/src/locking/lock_daemon.h
@@ -0,0 +1,43 @@
+/*
+ * lock_daemon.h: lock management daemon
+ *
+ * Copyright (C) 2006-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/>.
+ *
+ * Author: Daniel P. Berrange <berrange at redhat.com>
+ */
+
+#ifndef __VIR_LOCK_DAEMON_H__
+# define __VIR_LOCK_DAEMON_H__
+
+# include "virlockspace.h"
+# include "threads.h"
+
+typedef struct _virLockDaemon virLockDaemon;
+typedef virLockDaemon *virLockDaemonPtr;
+
+typedef struct _virLockDaemonClient virLockDaemonClient;
+typedef virLockDaemonClient *virLockDaemonClientPtr;
+
+struct _virLockDaemonClient {
+    virMutex lock;
+
+    pid_t clientPid;
+};
+
+extern virLockDaemonPtr lockDaemon;
+
+#endif /* __VIR_LOCK_DAEMON_H__ */
diff --git a/src/locking/lock_daemon_config.c b/src/locking/lock_daemon_config.c
new file mode 100644
index 0000000..c64de67
--- /dev/null
+++ b/src/locking/lock_daemon_config.c
@@ -0,0 +1,193 @@
+/*
+ * lock_daemon_config.h: virtlockd config file handling
+ *
+ * Copyright (C) 2006-2012 Red Hat, Inc.
+ * Copyright (C) 2006 Daniel P. Berrange
+ *
+ * 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/>.
+ *
+ * Author: Daniel P. Berrange <berrange at redhat.com>
+ */
+
+#include <config.h>
+
+#include "lock_daemon_config.h"
+#include "conf.h"
+#include "memory.h"
+#include "virterror_internal.h"
+#include "logging.h"
+#include "rpc/virnetserver.h"
+#include "configmake.h"
+
+#define VIR_FROM_THIS VIR_FROM_CONF
+
+
+/* A helper function used by each of the following macros.  */
+static int
+checkType(virConfValuePtr p, const char *filename,
+          const char *key, virConfType required_type)
+{
+    if (p->type != required_type) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                       _("remoteReadConfigFile: %s: %s: invalid type:"
+                         " got %s; expected %s"), filename, key,
+                       virConfTypeName(p->type),
+                       virConfTypeName(required_type));
+        return -1;
+    }
+    return 0;
+}
+
+/* If there is no config data for the key, #var_name, then do nothing.
+   If there is valid data of type VIR_CONF_STRING, and strdup succeeds,
+   store the result in var_name.  Otherwise, (i.e. invalid type, or strdup
+   failure), give a diagnostic and "goto" the cleanup-and-fail label.  */
+#define GET_CONF_STR(conf, filename, var_name)                          \
+    do {                                                                \
+        virConfValuePtr p = virConfGetValue(conf, #var_name);           \
+        if (p) {                                                        \
+            if (checkType(p, filename, #var_name, VIR_CONF_STRING) < 0) \
+                goto error;                                             \
+            VIR_FREE(data->var_name);                                   \
+            if (!(data->var_name = strdup(p->str))) {                   \
+                virReportOOMError();                                    \
+                goto error;                                             \
+            }                                                           \
+        }                                                               \
+    } while (0)
+
+/* Like GET_CONF_STR, but for integral values.  */
+#define GET_CONF_INT(conf, filename, var_name)                          \
+    do {                                                                \
+        virConfValuePtr p = virConfGetValue(conf, #var_name);           \
+        if (p) {                                                        \
+            if (checkType(p, filename, #var_name, VIR_CONF_LONG) < 0)   \
+                goto error;                                             \
+            data->var_name = p->l;                                      \
+        }                                                               \
+    } while (0)
+
+int
+virLockDaemonConfigFilePath(bool privileged, char **configfile)
+{
+    if (privileged) {
+        if (!(*configfile = strdup(SYSCONFDIR "/libvirt/virtlockd.conf")))
+            goto no_memory;
+    } else {
+        char *configdir = NULL;
+
+        if (!(configdir = virGetUserConfigDirectory()))
+            goto error;
+
+        if (virAsprintf(configfile, "%s/virtlockd.conf", configdir) < 0) {
+            VIR_FREE(configdir);
+            goto no_memory;
+        }
+        VIR_FREE(configdir);
+    }
+
+    return 0;
+
+no_memory:
+    virReportOOMError();
+error:
+    return -1;
+}
+
+
+virLockDaemonConfigPtr
+virLockDaemonConfigNew(bool privileged ATTRIBUTE_UNUSED)
+{
+    virLockDaemonConfigPtr data;
+
+    if (VIR_ALLOC(data) < 0) {
+        virReportOOMError();
+        return NULL;
+    }
+
+    data->log_buffer_size = 64;
+
+    return data;
+}
+
+void
+virLockDaemonConfigFree(virLockDaemonConfigPtr data)
+{
+    if (!data)
+        return;
+
+    VIR_FREE(data->log_filters);
+    VIR_FREE(data->log_outputs);
+
+    VIR_FREE(data);
+}
+
+static int
+virLockDaemonConfigLoadOptions(virLockDaemonConfigPtr data,
+                               const char *filename,
+                               virConfPtr conf)
+{
+    GET_CONF_INT(conf, filename, log_level);
+    GET_CONF_STR(conf, filename, log_filters);
+    GET_CONF_STR(conf, filename, log_outputs);
+    GET_CONF_INT(conf, filename, log_buffer_size);
+
+    return 0;
+
+error:
+    return -1;
+}
+
+
+/* Read the config file if it exists.
+ * Only used in the remote case, hence the name.
+ */
+int
+virLockDaemonConfigLoadFile(virLockDaemonConfigPtr data,
+                            const char *filename,
+                            bool allow_missing)
+{
+    virConfPtr conf;
+    int ret;
+
+    if (allow_missing &&
+        access(filename, R_OK) == -1 &&
+        errno == ENOENT)
+        return 0;
+
+    conf = virConfReadFile(filename, 0);
+    if (!conf)
+        return -1;
+
+    ret = virLockDaemonConfigLoadOptions(data, filename, conf);
+    virConfFree(conf);
+    return ret;
+}
+
+int virLockDaemonConfigLoadData(virLockDaemonConfigPtr data,
+                                const char *filename,
+                                const char *filedata)
+{
+    virConfPtr conf;
+    int ret;
+
+    conf = virConfReadMem(filedata, strlen(filedata), 0);
+    if (!conf)
+        return -1;
+
+    ret = virLockDaemonConfigLoadOptions(data, filename, conf);
+    virConfFree(conf);
+    return ret;
+}
diff --git a/src/locking/lock_daemon_config.h b/src/locking/lock_daemon_config.h
new file mode 100644
index 0000000..8cb0e5d
--- /dev/null
+++ b/src/locking/lock_daemon_config.h
@@ -0,0 +1,50 @@
+/*
+ * lock_daemon_config.h: virtlockd config file handling
+ *
+ * Copyright (C) 2006-2012 Red Hat, Inc.
+ * Copyright (C) 2006 Daniel P. Berrange
+ *
+ * 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/>.
+ *
+ * Author: Daniel P. Berrange <berrange at redhat.com>
+ */
+
+#ifndef __VIR_LOCK_DAEMON_CONFIG_H__
+# define __VIR_LOCK_DAEMON_CONFIG_H__
+
+# include "internal.h"
+
+typedef struct _virLockDaemonConfig virLockDaemonConfig;
+typedef virLockDaemonConfig *virLockDaemonConfigPtr;
+
+struct _virLockDaemonConfig {
+    int log_level;
+    char *log_filters;
+    char *log_outputs;
+    int log_buffer_size;
+};
+
+
+int virLockDaemonConfigFilePath(bool privileged, char **configfile);
+virLockDaemonConfigPtr virLockDaemonConfigNew(bool privileged);
+void virLockDaemonConfigFree(virLockDaemonConfigPtr data);
+int virLockDaemonConfigLoadFile(virLockDaemonConfigPtr data,
+                                const char *filename,
+                         bool allow_missing);
+int virLockDaemonConfigLoadData(virLockDaemonConfigPtr data,
+                                const char *filename,
+                                const char *filedata);
+
+#endif /* __LIBVIRTD_CONFIG_H__ */
diff --git a/src/locking/virtlockd.init.in b/src/locking/virtlockd.init.in
new file mode 100644
index 0000000..e55cbf9
--- /dev/null
+++ b/src/locking/virtlockd.init.in
@@ -0,0 +1,93 @@
+#!/bin/sh
+
+# the following is the LSB init header see
+# http://www.linux-foundation.org/spec//booksets/LSB-Core-generic/LSB-Core-generic.html#INITSCRCOMCONV
+#
+### BEGIN INIT INFO
+# Provides: virtlockd
+# Default-Start: 3 4 5
+# Short-Description: virtual machine lock manager
+# Description: This is a daemon for managing locks
+#              on virtual machine disk images
+### END INIT INFO
+
+# the following is chkconfig init header
+#
+# virtlockd:   virtual machine lock manager
+#
+# chkconfig: 345 97 03
+# description:  This is a daemon for managing locks \
+#               on virtual machine disk images
+#
+# processname: virtlockd
+# pidfile: ::localstatedir::/run/libvirt/virtlockd.pid
+#
+
+# Source function library.
+. ::sysconfdir::/rc.d/init.d/functions
+
+SERVICE=virtlockd
+PROCESS=virtlockd
+PIDFILE=::localstatedir::/run/libvirt/lockd/$SERVICE.pid
+
+VIRTLOCKD_ARGS=
+
+test -f ::sysconfdir::/sysconfig/virtlockd && . ::sysconfdir::/sysconfig/virtlockd
+
+RETVAL=0
+
+start() {
+    echo -n $"Starting $SERVICE daemon: "
+    daemon --pidfile $PIDFILE --check $SERVICE $PROCESS --daemon $VIRTLOCKD_ARGS
+    RETVAL=$?
+    echo
+    [ $RETVAL -eq 0 ] && touch ::localstatedir::/lock/subsys/$SERVICE
+}
+
+stop() {
+    echo -n $"Stopping $SERVICE daemon: "
+
+    killproc -p $PIDFILE $PROCESS
+    RETVAL=$?
+    echo
+    if [ $RETVAL -eq 0 ]; then
+        rm -f ::localstatedir::/lock/subsys/$SERVICE
+        rm -f $PIDFILE
+    fi
+}
+
+restart() {
+    stop
+    start
+}
+
+reload() {
+    echo -n $"Reloading $SERVICE configuration: "
+
+    killproc -p $PIDFILE $PROCESS -HUP
+    RETVAL=$?
+    echo
+    return $RETVAL
+}
+
+# See how we were called.
+case "$1" in
+    start|stop|restart|reload)
+        $1
+        ;;
+    status)
+        status -p $PIDFILE $PROCESS
+        RETVAL=$?
+        ;;
+    force-reload)
+        reload
+        ;;
+    condrestart|try-restart)
+        [ -f ::localstatedir::/lock/subsys/$SERVICE ] && restart || :
+        ;;
+    *)
+        echo $"Usage: $0 {start|stop|status|restart|condrestart|reload|force-reload|try-restart}"
+        exit 2
+        ;;
+esac
+exit $RETVAL
diff --git a/src/locking/virtlockd.sysconf b/src/locking/virtlockd.sysconf
new file mode 100644
index 0000000..d44dc46
--- /dev/null
+++ b/src/locking/virtlockd.sysconf
@@ -0,0 +1,3 @@
+#
+# Pass extra arguments to virtlockd
+#VIRTLOCKD_ARGS=
-- 
1.7.11.7




More information about the libvir-list mailing list