From libvir-list Thu Jul 07 14:17:29 2011 From: "Daniel P. Berrange" Date: Thu, 07 Jul 2011 14:17:29 +0000 To: libvir-list Subject: [libvirt] [PATCH 11/14] Add the virtlockd daemon for managing virtual guest locks Message-Id: <1310048252-15268-12-git-send-email-berrange () redhat ! com> X-MARC-Message: https://marc.info/?l=libvir-list&m=152445519869413 From: "Daniel P. Berrange" This adds a new daemon 'virtlockd' which will manage the locks for all running virtual machines. Communication is via a new RPC lock program. The intent is that virtlockd runs forever and if it ever crashes, the entire host should be restarted (ideally via a hardware fencing agent) to ensure maximum safety of guest disks. * cfg.mk: Ignore the lockd files * src/locking/lock_daemon.c, src/locking/lock_daemon.h: Main daemon startup code * src/locking/lock_daemon_dispatch.c, src/locking/lock_daemon_dispatch.h: RPC dispatcher for lock program * src/locking/virtlockd.init.in: Init script * src/locking/virtlockd.sysconf: Init script configuration * libvirt.spec.in: Add initscript --- cfg.mk | 4 +- libvirt.spec.in | 8 + po/POTFILES.in | 5 + src/.gitignore | 4 + src/Makefile.am | 106 +++++- src/libvirt_private.syms | 2 + src/locking/lock_daemon.c | 776 ++++++++++++++++++++++++++++++++++++ src/locking/lock_daemon_dispatch.c | 334 ++++++++++++++++ src/locking/lock_daemon_dispatch.h | 46 +++ src/locking/virtlockd.init.in | 93 +++++ src/locking/virtlockd.sysconf | 3 + 11 files changed, 1374 insertions(+), 7 deletions(-) create mode 100644 src/locking/lock_daemon.c create mode 100644 src/locking/lock_daemon.h create mode 100644 src/locking/lock_daemon_dispatch.c create mode 100644 src/locking/lock_daemon_dispatch.h create mode 100644 src/locking/virtlockd.init.in create mode 100644 src/locking/virtlockd.sysconf diff --git a/cfg.mk b/cfg.mk index b00cda3..8074b59 100644 --- a/cfg.mk +++ b/cfg.mk @@ -616,7 +616,7 @@ $(srcdir)/src/remote/remote_client_bodies.h: # List all syntax-check exemptions: exclude_file_name_regexp--sc_avoid_strcase = ^tools/virsh\.c$$ -_src1=libvirt|fdstream|qemu/qemu_monitor|util/(command|util)|xen/xend_internal|rpc/virnetsocket +_src1=libvirt|fdstream|qemu/qemu_monitor|util/(command|util)|xen/xend_internal|rpc/virnetsocket|locking/lock_daemon exclude_file_name_regexp--sc_avoid_write = \ ^(src/($(_src1))|daemon/libvirtd|tools/console)\.c$$ @@ -646,7 +646,7 @@ exclude_file_name_regexp--sc_prohibit_empty_lines_at_EOF = \ _src2=src/(util/command|libvirt|lxc/lxc_controller) exclude_file_name_regexp--sc_prohibit_fork_wrappers = \ - (^docs|^($(_src2)|tests/testutils|daemon/libvirtd)\.c$$) + (^docs|^($(_src2)|tests/testutils|daemon/libvirtd|src/locking/lock_daemon)\.c$$) exclude_file_name_regexp--sc_prohibit_gethostname = ^src/util/util\.c$$ diff --git a/libvirt.spec.in b/libvirt.spec.in index 650f0bc..7f6fd13 100644 --- a/libvirt.spec.in +++ b/libvirt.spec.in @@ -1007,11 +1007,13 @@ fi %{_sysconfdir}/libvirt/nwfilter/*.xml %{_sysconfdir}/rc.d/init.d/libvirtd +%{_sysconfdir}/rc.d/init.d/virtlockd %if %{with_systemd} %{_unitdir}/libvirtd.service %endif %doc daemon/libvirtd.upstart %config(noreplace) %{_sysconfdir}/sysconfig/libvirtd +%config(noreplace) %{_sysconfdir}/sysconfig/virtlockd %config(noreplace) %{_sysconfdir}/libvirt/libvirtd.conf %if %{with_dtrace} %{_datadir}/systemtap/tapset/libvirtd.stp @@ -1072,6 +1074,11 @@ fi %dir %attr(0755, root, root) %{_localstatedir}/lib/libvirt/dnsmasq/ %endif +%if %{with_libvirtd} +%dir %attr(0755, root, root) %{_libdir}/libvirt/lock-driver +%attr(0755, root, root) %{_libdir}/libvirt/lock-driver/lockd.so +%endif + %if %{with_qemu} %{_datadir}/augeas/lenses/libvirtd_qemu.aug %{_datadir}/augeas/lenses/tests/test_libvirtd_qemu.aug @@ -1105,6 +1112,7 @@ fi %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 32eaa2d..bb94d51 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -30,8 +30,13 @@ src/fdstream.c src/interface/netcf_driver.c src/internal.h src/libvirt.c +src/locking/lock_database.c +src/locking/lock_driver_fcntl.c +src/locking/lock_driver_lockd.c src/locking/lock_driver_sanlock.c src/locking/lock_manager.c +src/locking/lock_daemon.c +src/locking/lock_daemon_dispatch.c src/lxc/lxc_container.c src/lxc/lxc_conf.c src/lxc/lxc_controller.c diff --git a/src/.gitignore b/src/.gitignore index a619643..c499b47 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -16,3 +16,7 @@ libvirt_qemu.def *.s remote_protocol-structs-t virt-aa-helper +virtlockd +virtlockd.socket +locking/lock_daemon_dispatch_stubs.h +locking/qemu-sanlock.conf diff --git a/src/Makefile.am b/src/Makefile.am index cd8a7e9..3e2c376 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -96,8 +96,34 @@ DRIVER_SOURCES = \ libvirt.c libvirt_internal.h \ locking/lock_manager.c locking/lock_manager.h \ locking/lock_driver.h \ + locking/domain_lock.h locking/domain_lock.c \ + locking/lock_driver_nop.h locking/lock_driver_nop.c + +LOCK_PROTOCOL_GENERATED = \ + locking/lock_protocol.h \ + locking/lock_protocol.c + +EXTRA_DIST += locking/lock_protocol.x + +LOCKD_GENERATED = \ + $(LOCK_PROTOCOL_GENERATED) \ + locking/lock_daemon_dispatch_stubs.h + +BUILT_SOURCES += $(LOCKD_GENERATED) + +LOCK_DAEMON_SOURCES = \ + locking/lock_daemon.c \ + locking/lock_daemon_dispatch.h \ + locking/lock_daemon_dispatch.c \ + locking/lock_database.c locking/lock_database.h \ + locking/lock_manager.c locking/lock_manager.h \ locking/lock_driver_nop.h locking/lock_driver_nop.c \ - locking/domain_lock.h locking/domain_lock.c + locking/lock_driver_fcntl.h locking/lock_driver_fcntl.c \ + $(LOCKD_GENERATED) + +$(srcdir)/locking/lock_daemon_dispatch_stubs.h: locking/lock_protocol.x $(srcdir)/rpc/gendispatch.pl + $(AM_V_GEN)perl -w $(srcdir)/rpc/gendispatch.pl -b lock $< > $@ + LOCK_DRIVER_SANLOCK_SOURCES = \ locking/lock_driver_sanlock.c @@ -1184,12 +1210,73 @@ 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) +virtlockd_LDFLAGS = \ + $(AM_LDFLAGS) \ + $(CYGWIN_EXTRA_LDFLAGS) \ + $(MINGW_EXTRA_LDFLAGS) +virtlockd_LDADD = \ + libvirt-net-rpc-server.la \ + libvirt-net-rpc.la \ + libvirt_util.la \ + ../gnulib/lib/libgnu.la \ + $(CYGWIN_EXTRA_LIBADD) +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 sanlock_la_SOURCES = $(LOCK_DRIVER_SANLOCK_SOURCES) -sanlock_la_CFLAGS = $(AM_CLFAGS) +sanlock_la_CFLAGS = $(AM_CFLAGS) sanlock_la_LDFLAGS = -module -avoid-version sanlock_la_LIBADD = -lsanlock \ ../gnulib/lib/libgnu.la @@ -1369,7 +1456,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/boot" @@ -1411,7 +1502,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/boot" ||: @@ -1446,4 +1541,5 @@ endif CLEANFILES = *.gcov .libs/*.gcda .libs/*.gcno *.gcno *.gcda *.i *.s DISTCLEANFILES = $(GENERATED_SYM_FILES) -MAINTAINERCLEANFILES = $(REMOTE_DRIVER_GENERATED) $(VIR_NET_RPC_GENERATED) $(ESX_DRIVER_GENERATED) +MAINTAINERCLEANFILES = $(REMOTE_DRIVER_GENERATED) $(VIR_NET_RPC_GENERATED) \ + $(ESX_DRIVER_GENERATED) $(LOCKD_GENERATED) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 0746dee..ac1d3d2 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -957,6 +957,7 @@ virMutexUnlock; virOnce; virThreadCreate; virThreadID; +virThreadInitialize; virThreadIsSelf; virThreadJoin; virThreadSelf; @@ -1065,6 +1066,7 @@ virAuditSend; # virterror_internal.h virDispatchError; +virErrorInitialize; virErrorMsg; virRaiseErrorFull; virReportErrorHelper; diff --git a/src/locking/lock_daemon.c b/src/locking/lock_daemon.c new file mode 100644 index 0000000..1c20715 --- /dev/null +++ b/src/locking/lock_daemon.c @@ -0,0 +1,776 @@ +/* + * lock_daemon.c: lock management daemon + * + * Copyright (C) 2006-2011 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Daniel P. Berrange + */ + +#include + +#include +#include +#include +#include +#include +#include +#include + + +#include "util.h" +#include "files.h" +#include "virterror_internal.h" +#include "logging.h" +#include "memory.h" +#include "conf.h" +#include "rpc/virnetserver.h" +#include "threads.h" +#include "lock_daemon_dispatch.h" +#include "lock_protocol.h" +#include "lock_driver_fcntl.h" +#include "intprops.h" + +#include "configmake.h" + +#define VIR_FROM_THIS VIR_FROM_LOCKING + +#define virLockError(code, ...) \ + virReportErrorHelper(VIR_FROM_THIS, code, __FILE__, \ + __FUNCTION__, __LINE__, __VA_ARGS__) + + +static virNetServerProgramPtr lockProgram = NULL; +static bool privileged; + +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 int +virLockDaemonForkIntoBackground(const char *argv0) +{ + int statuspipe[2]; + if (pipe(statuspipe) < 0) + return -1; + + int 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 +virLockDaemonAcquirePidFile(const char *argv0, const char *pidFile) { + int fd; + char ebuf[1024]; + unsigned long long pid = (unsigned long long)getpid(); + char pidstr[INT_BUFSIZE_BOUND(pid)]; + + if (pidFile[0] == '\0') + return 0; + + while (1) { + struct stat a, b; + if ((fd = open(pidFile, O_WRONLY|O_CREAT, 0644)) < 0) { + VIR_ERROR(_("%s: Failed to open pid file '%s' : %s"), + argv0, pidFile, virStrerror(errno, ebuf, sizeof ebuf)); + return -1; + } + + if (fstat(fd, &b) < 0) { + VIR_ERROR(_("%s: Pid file '%s' disappeared: %s"), + argv0, pidFile, virStrerror(errno, ebuf, sizeof ebuf)); + VIR_FORCE_CLOSE(fd); + return -1; + } + + if (virFileLock(fd, false, 0, 1) < 0) { + VIR_ERROR(_("%s: Failed to acquire pid file '%s' : %s"), + argv0, pidFile, virStrerror(errno, ebuf, sizeof ebuf)); + VIR_FORCE_CLOSE(fd); + return -1; + } + + /* Now make sure the pidfile we locked is the same + * one that now exists on the filesystem + */ + + if (stat(pidFile, &a) < 0) { + VIR_DEBUG("%s: Pid file '%s' disappeared: %s", + argv0, pidFile, virStrerror(errno, ebuf, sizeof ebuf)); + VIR_FORCE_CLOSE(fd); + continue; + } + + if (a.st_ino == b.st_ino) + break; + + VIR_DEBUG("%s: Pid file '%s' was recreated", + argv0, pidFile); + VIR_FORCE_CLOSE(fd); + } + + snprintf(pidstr, sizeof(pidstr), "%llu", pid); + + if (safewrite(fd, pidstr, strlen(pidstr)) < 0) { + VIR_ERROR(_("Failed to write to pid file '%s' : %s"), + pidFile, virStrerror(errno, ebuf, sizeof ebuf)); + } + + return fd; +} + + +static int +virLockDaemonMakePaths(char **basedir, + char **statedir, + char **pidfile, + char **sockfile) +{ + char *userdir = NULL; + uid_t uid = geteuid(); + + *basedir = *statedir = *pidfile = *sockfile = NULL; + + if (privileged) { + if (!(*basedir = strdup(LOCALSTATEDIR "/run/libvirt"))) + goto no_memory; + } else { + if (!(userdir = virGetUserDirectory(uid))) + goto error; + + if (virAsprintf(basedir, "%s/.libvirt", userdir) < 0) + goto no_memory; + } + + if (virAsprintf(statedir, "%s/lockd", *basedir) < 0) + goto no_memory; + if (virAsprintf(pidfile, "%s/lockd.pid", *statedir) < 0) + goto no_memory; + if (virAsprintf(sockfile, "%s/lockd.sock", *statedir) < 0) + goto no_memory; + + VIR_FREE(userdir); + return 0; + +no_memory: + VIR_FREE(*basedir); + VIR_FREE(*statedir); + VIR_FREE(*pidfile); + VIR_FREE(*sockfile); +error: + VIR_FREE(userdir); + 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 syslog and the logging + * is also saved onto the logfile libvird.log, but if verbose or error + * debugging is asked for then output informations or debug. + */ +static int +virLockDaemonSetLogging(virConfPtr conf ATTRIBUTE_UNUSED, + const char *filename ATTRIBUTE_UNUSED, + int godaemon, int verbose) +{ + //int log_level = 0; + char *log_filters = NULL; + char *log_outputs = NULL; + int ret = -1; + + virLogReset(); +#if 0 + /* + * 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. + */ + GET_CONF_INT (conf, filename, log_level); + if (log_level != 0) + virLogSetDefaultPriority(log_level); + + if (virLogGetNbFilters() == 0) { + GET_CONF_STR (conf, filename, log_filters); + virLogParseFilters(log_filters); + } + + if (virLogGetNbOutputs() == 0) { + GET_CONF_STR (conf, filename, log_outputs); + virLogParseOutputs(log_outputs); + } +#endif + + virLogSetFromEnv(); + + /* + * If no defined outputs, then direct to syslog when running + * as daemon. Otherwise the default output is stderr. + */ + if (virLogGetNbOutputs() == 0) { + char *tmp = NULL; + if (godaemon) { + if (virAsprintf (&tmp, "%d:syslog:libvirtd", + virLogGetDefaultPriority()) < 0) + goto free_and_fail; + } else { + if (virAsprintf (&tmp, "%d:stderr", + virLogGetDefaultPriority()) < 0) + goto free_and_fail; + } + virLogParseOutputs(tmp); + VIR_FREE(tmp); + } + + /* + * Command line override for --verbose + */ + if ((verbose) && (virLogGetDefaultPriority() > VIR_LOG_INFO)) + virLogSetDefaultPriority(VIR_LOG_INFO); + + ret = 0; + +free_and_fail: + VIR_FREE(log_filters); + VIR_FREE(log_outputs); + return(ret); +} + +/* Read the config file if it exists. + * Only used in the remote case, hence the name. + */ +static int +virLockDaemonReadConfigFile(const char *filename, + int godaemon, int verbose) +{ + virConfPtr conf; + + if (!(conf = virConfReadFile (filename, 0))) + goto error; + + if (virLockDaemonSetLogging(conf, filename, godaemon, verbose) < 0) + goto error; + + virConfFree (conf); + return 0; + +error: + virConfFree (conf); + + 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; + + if (!(svc = virNetServerServiceNewUNIX(sock_path, 0700, 0, 0, false, 1, NULL))) + return -1; + + if (virNetServerAddService(srv, svc, NULL) < 0) { + virNetServerServiceFree(svc); + return -1; + } + return 0; +} + + +static void +virLockDaemonClientFreeFunc(void *data) +{ + virLockDaemonClientPrivatePtr priv = data; + + VIR_DEBUG("Client %p dead, freeing manager %p", + priv, priv->manager); + + virMutexLock(&priv->lock); + virLockManagerFree(priv->manager); + virMutexUnlock(&priv->lock); + virMutexDestroy(&priv->lock); + VIR_FREE(priv); +} + +static int +virLockDaemonClientInit(virNetServerPtr srv ATTRIBUTE_UNUSED, + virNetServerClientPtr client) +{ + virLockDaemonClientPrivate *priv; + + if (VIR_ALLOC(priv) < 0) { + virReportOOMError(); + return -1; + } + + if (virMutexInit(&priv->lock) < 0) { + VIR_FREE(priv); + virReportOOMError(); + return -1; + } + + if (virNetServerClientGetLocalIdentity(client, + &priv->uid, + &priv->pid) < 0) + goto error; + + VIR_DEBUG("New client %p pid %llu uid %llu", + priv, (unsigned long long)priv->pid, + (unsigned long long)priv->uid); + + if (!privileged) { + if (geteuid() != priv->uid) { + virLockError(VIR_ERR_OPERATION_DENIED, + _("Disallowing client %llu with uid %llu"), + (unsigned long long)priv->pid, + (unsigned long long)priv->uid); + + goto error; + } + } else { + if (priv->uid != 0) { + virLockError(VIR_ERR_OPERATION_DENIED, + _("Disallowing client %llu with uid %llu"), + (unsigned long long)priv->pid, + (unsigned long long)priv->uid); + goto error; + } + } + + virNetServerClientSetPrivateData(client, priv, virLockDaemonClientFreeFunc); + return 0; + +error: + virMutexDestroy(&priv->lock); + VIR_FREE(priv); + return -1; +} + + +static void +virLockDaemonUsage(const char *argv0) +{ + 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 Exit after timeout period.\n\ + -f | --config Configuration file.\n\ + | --version Display version information.\n\ + -p | --pid-file Change name of PID file.\n\ +\n\ +libvirt lock management daemon:\n\ +\n\ + Default paths:\n\ +\n\ + Configuration file (unless overridden by -f):\n\ + %s/libvirt/libvirtd.conf\n\ +\n\ + Sockets (as root):\n\ + %s/run/virtlockd.sock\n\ +\n\ + Sockets (as non-root):\n\ + $HOME/.libvirt/virtlockd.sock (in UNIX abstract namespace)\n\ +\n\ + Default PID file (as root):\ + %s/run/virtlockd.pid\n\ +\n\ + Default PID file (as non-root):\ + $HOME/.libvirt/virtlockd.pid\n\ +\n"), + argv0, + SYSCONFDIR, + LOCALSTATEDIR, + LOCALSTATEDIR); +} + +enum { + OPT_VERSION = 129 +}; + +#define MAX_LISTEN 5 +int main(int argc, char **argv) { + virNetServerPtr srv = NULL; + const char *remote_config_file = NULL; + int statuswrite = -1; + int ret = 1; + int verbose = 0; + int godaemon = 0; + int timeout = 0; + char *base_dir = NULL; + char *state_dir = NULL; + char *pid_file = NULL; + int pid_file_fd = -1; + char *sock_file = 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 || + virRandomInitialize(time(NULL) ^ getpid())) { + fprintf(stderr, _("%s: initialization failed\n"), argv[0]); + exit(EXIT_FAILURE); + } + + if (virLockDaemonMakePaths(&base_dir, &state_dir, + &pid_file, &sock_file) < 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': + remote_config_file = optarg; + break; + + case OPT_VERSION: + virLockDaemonVersion(argv[0]); + return 0; + + case '?': + virLockDaemonUsage(argv[0]); + return 2; + + default: + fprintf (stderr, _("%s: internal error: unknown flag: %c\n"), + argv[0], c); + exit (EXIT_FAILURE); + } + } + + if (remote_config_file == NULL) { + static const char *default_config_file + = SYSCONFDIR "/libvirt/virtlockd.conf"; + remote_config_file = + (access(default_config_file, R_OK) == 0 + ? default_config_file + : "/dev/null"); + } + + if (godaemon) { + char ebuf[1024]; + if ((statuswrite = virLockDaemonForkIntoBackground(argv[0])) < 0) { + VIR_ERROR(_("Failed to fork as daemon: %s"), + virStrerror(errno, ebuf, sizeof ebuf)); + goto cleanup; + } + } + + if (!(srv = virNetServerNew(1, 1, 20, NULL, + virLockDaemonClientInit))) { + ret = VIR_LOCK_DAEMON_ERR_INIT; + goto cleanup; + } + + if ((virLockDaemonSetupSignals(srv)) < 0) { + ret = VIR_LOCK_DAEMON_ERR_SIGNAL; + goto cleanup; + } + + /* Ensure the rundir exists (on tmpfs on some systems) */ + if (mkdir(base_dir, 0755)) { + if (errno != EEXIST) { + char ebuf[1024]; + VIR_ERROR(_("unable to create rundir %s: %s"), base_dir, + virStrerror(errno, ebuf, sizeof(ebuf))); + ret = VIR_LOCK_DAEMON_ERR_RUNDIR; + goto cleanup; + } + } + if (mkdir(state_dir, 0700)) { + if (errno != EEXIST) { + char ebuf[1024]; + VIR_ERROR(_("unable to create rundir %s: %s"), state_dir, + virStrerror(errno, ebuf, sizeof(ebuf))); + ret = VIR_LOCK_DAEMON_ERR_RUNDIR; + goto cleanup; + } + } + + /* If we have a pidfile set, claim it now, exiting if already taken */ + if ((pid_file_fd = virLockDaemonAcquirePidFile(argv[0], pid_file)) < 0) { + ret = VIR_LOCK_DAEMON_ERR_PIDFILE; + goto cleanup; + } + + /* Read the config file (if it exists). */ + if (virLockDaemonReadConfigFile(remote_config_file, godaemon, verbose) < 0) { + ret = VIR_LOCK_DAEMON_ERR_CONFIG; + goto cleanup; + } + + if (virLockDriverFcntl.drvInit(VIR_LOCK_MANAGER_VERSION, NULL, 0) < 0) { + ret = VIR_LOCK_DAEMON_ERR_INIT; + goto cleanup; + } + + if (!(lockProgram = virNetServerProgramNew(LOCK_PROGRAM, + LOCK_PROTOCOL_VERSION, + lockProcs, lockNProcs))) { + ret = VIR_LOCK_DAEMON_ERR_INIT; + goto cleanup; + } + if (virNetServerAddProgram(srv, lockProgram) < 0) { + ret = VIR_LOCK_DAEMON_ERR_INIT; + goto cleanup; + } + + + if (virLockDaemonSetupNetworking(srv, sock_file) < 0) { + ret = VIR_LOCK_DAEMON_ERR_NETWORK; + 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(srv, true); + virNetServerRun(srv); + ret = 0; + +cleanup: + virNetServerProgramFree(lockProgram); + virNetServerFree(srv); + 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) { + unlink(pid_file); + VIR_FORCE_CLOSE(pid_file_fd); + } + virLogShutdown(); + VIR_FREE(pid_file); + VIR_FREE(sock_file); + VIR_FREE(state_dir); + return ret; +} diff --git a/src/locking/lock_daemon.h b/src/locking/lock_daemon.h new file mode 100644 index 0000000..e69de29 diff --git a/src/locking/lock_daemon_dispatch.c b/src/locking/lock_daemon_dispatch.c new file mode 100644 index 0000000..1909b9c --- /dev/null +++ b/src/locking/lock_daemon_dispatch.c @@ -0,0 +1,334 @@ +/* + * lock_daemon_dispatch.c: lock management daemon + * + * Copyright (C) 2006-2011 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Daniel P. Berrange + */ + +#include + +#include "logging.h" +#include "virterror_internal.h" +#include "rpc/virnetserver.h" +#include "rpc/virnetserverclient.h" +#include "memory.h" +#include "lock_protocol.h" +#include "lock_daemon_dispatch.h" +#include "lock_daemon_dispatch_stubs.h" +#include "lock_driver_fcntl.h" + + +#define VIR_FROM_THIS VIR_FROM_LOCKING + +#define virLockError(code, ...) \ + virReportErrorHelper(VIR_FROM_THIS, code, __FILE__, \ + __FUNCTION__, __LINE__, __VA_ARGS__) + +static virLockManagerParamPtr lockDispatchParameters(size_t nparams, + lock_param *params) +{ + virLockManagerParamPtr ret = NULL; + int i; + + if (VIR_ALLOC_N(ret, nparams) < 0) { + virReportOOMError(); + return NULL; + } + + for (i = 0 ; i < nparams ; i++) { + ret[i].key = params[i].key; + ret[i].type = params[i].value.type; + + switch (ret[i].type) { + case VIR_LOCK_MANAGER_PARAM_TYPE_STRING: + ret[i].value.str = params[i].value.lock_param_value_u.s; + break; + case VIR_LOCK_MANAGER_PARAM_TYPE_INT: + ret[i].value.i = params[i].value.lock_param_value_u.i; + break; + case VIR_LOCK_MANAGER_PARAM_TYPE_LONG: + ret[i].value.l = params[i].value.lock_param_value_u.l; + break; + case VIR_LOCK_MANAGER_PARAM_TYPE_UINT: + ret[i].value.ui = params[i].value.lock_param_value_u.ui; + break; + case VIR_LOCK_MANAGER_PARAM_TYPE_ULONG: + ret[i].value.ul = params[i].value.lock_param_value_u.ul; + break; + case VIR_LOCK_MANAGER_PARAM_TYPE_DOUBLE: + ret[i].value.d = params[i].value.lock_param_value_u.d; + break; + case VIR_LOCK_MANAGER_PARAM_TYPE_UUID: + memcpy(ret[i].value.uuid, params[i].value.lock_param_value_u.u, VIR_UUID_BUFLEN); + break; + } + } + + return ret; +} + +static int lockDispatchRegister(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + virNetMessageErrorPtr rerr, + lock_register_args *args) +{ + int rv = -1; + virLockDaemonClientPrivate *priv = + virNetServerClientGetPrivateData(client); + virLockManagerParamPtr params = NULL; + size_t nparams; + + virMutexLock(&priv->lock); + + if (priv->manager) { + virLockError(VIR_ERR_INTERNAL_ERROR, "%s", _("lock manager already open")); + goto cleanup; + } + + if (priv->restrictAccess) { + virLockError(VIR_ERR_OPERATION_DENIED, "%s", + _("lock manager has been restricted")); + goto cleanup; + } + + if (args->params.params_len > LOCK_PARAMETERS_MAX) { + virLockError(VIR_ERR_INTERNAL_ERROR, + _("Too many parameters %u for lock program, max %u"), + args->params.params_len, LOCK_PARAMETERS_MAX); + goto cleanup; + } + + if (!(params = lockDispatchParameters(args->params.params_len, + args->params.params_val))) + goto cleanup; + + nparams = args->params.params_len; + if (VIR_EXPAND_N(params, nparams, 1) < 0) { + virReportOOMError(); + goto cleanup; + } + + params[nparams-1].type = VIR_LOCK_MANAGER_PARAM_TYPE_UINT; + params[nparams-1].key = "client-pid"; + params[nparams-1].value.i = priv->pid; + + if (!(priv->manager = virLockManagerNew(&virLockDriverFcntl, + args->type, + nparams, + params, + args->flags))) + goto cleanup; + + priv->restrictAccess = args->restrictAccess; + + rv = 0; + +cleanup: + if (rv < 0) + virNetMessageSaveError(rerr); + VIR_FREE(params); + virMutexUnlock(&priv->lock); + return rv; +} + + +static int lockDispatchAddResource(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + virNetMessageErrorPtr rerr, + lock_add_resource_args *args) +{ + int rv = -1; + virLockDaemonClientPrivate *priv = + virNetServerClientGetPrivateData(client); + virLockManagerParamPtr params = NULL; + + virMutexLock(&priv->lock); + + if (!priv->manager) { + virLockError(VIR_ERR_INTERNAL_ERROR, "%s", _("lock manager not open")); + goto cleanup; + } + + if (priv->restrictAccess) { + virLockError(VIR_ERR_OPERATION_DENIED, "%s", + _("lock manager has been restricted")); + goto cleanup; + } + + if (args->params.params_len > LOCK_PARAMETERS_MAX) { + virLockError(VIR_ERR_INTERNAL_ERROR, + _("Too many parameters %u for lock program, max %u"), + args->params.params_len, LOCK_PARAMETERS_MAX); + goto cleanup; + } + + if (!(params = lockDispatchParameters(args->params.params_len, + args->params.params_val))) + goto cleanup; + + if (virLockManagerAddResource(priv->manager, + args->type, + args->name, + args->params.params_len, + params, + args->flags) < 0) + goto cleanup; + + rv = 0; + +cleanup: + if (rv < 0) + virNetMessageSaveError(rerr); + VIR_FREE(params); + virMutexUnlock(&priv->lock); + return rv; +} + + +static int lockDispatchAcquire(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + virNetMessageErrorPtr rerr, + lock_acquire_args *args) +{ + int rv = -1; + virLockDaemonClientPrivate *priv = + virNetServerClientGetPrivateData(client); + + virMutexLock(&priv->lock); + + if (!priv->manager) { + virLockError(VIR_ERR_INTERNAL_ERROR, "%s", _("lock manager not open")); + goto cleanup; + } + + if (priv->restrictAccess) { + virLockError(VIR_ERR_OPERATION_DENIED, "%s", + _("lock manager has been restricted")); + goto cleanup; + } + + if (virLockManagerAcquire(priv->manager, + args->state ? *args->state : NULL, + args->flags, + NULL) < 0) + goto cleanup; + + rv = 0; + +cleanup: + if (rv < 0) + virNetMessageSaveError(rerr); + virMutexUnlock(&priv->lock); + return rv; +} + + +static int lockDispatchRelease(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + virNetMessageErrorPtr rerr, + lock_release_args *args, + lock_release_ret *ret) +{ + int rv = -1; + virLockDaemonClientPrivate *priv = + virNetServerClientGetPrivateData(client); + + virMutexLock(&priv->lock); + + if (!priv->manager) { + virLockError(VIR_ERR_INTERNAL_ERROR, "%s", _("lock manager not open")); + goto cleanup; + } + + if (priv->restrictAccess) { + virLockError(VIR_ERR_OPERATION_DENIED, "%s", + _("lock manager has been restricted")); + goto cleanup; + } + + if (VIR_ALLOC(ret->state) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (virLockManagerRelease(priv->manager, + ret->state, + args->flags) < 0) + goto cleanup; + + rv = 0; + +cleanup: + if (rv < 0) { + virNetMessageSaveError(rerr); + VIR_FREE(ret->state); + } + virMutexUnlock(&priv->lock); + return rv; +} + + +static int lockDispatchInquire(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + virNetMessageErrorPtr rerr, + lock_inquire_args *args, + lock_inquire_ret *ret) +{ + int rv = -1; + virLockDaemonClientPrivate *priv = + virNetServerClientGetPrivateData(client); + + virMutexLock(&priv->lock); + + if (!priv->manager) { + virLockError(VIR_ERR_INTERNAL_ERROR, "%s", _("lock manager not open")); + goto cleanup; + } + + if (priv->restrictAccess) { + virLockError(VIR_ERR_OPERATION_DENIED, "%s", + _("lock manager has been restricted")); + goto cleanup; + } + + if (VIR_ALLOC(ret->state) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (virLockManagerInquire(priv->manager, + ret->state, + args->flags) < 0) + goto cleanup; + + rv = 0; + +cleanup: + if (rv < 0) { + virNetMessageSaveError(rerr); + VIR_FREE(ret->state); + } + virMutexUnlock(&priv->lock); + return rv; +} diff --git a/src/locking/lock_daemon_dispatch.h b/src/locking/lock_daemon_dispatch.h new file mode 100644 index 0000000..601e094 --- /dev/null +++ b/src/locking/lock_daemon_dispatch.h @@ -0,0 +1,46 @@ +/* + * lock_daemon_dispatch.h: lock management daemon + * + * Copyright (C) 2006-2011 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Daniel P. Berrange + */ + +#ifndef __VIR_LOCK_DAEMON_DISPATCH_H__ +# define __VIR_LOCK_DAEMON_DISPATCH_H__ + +# include "threads.h" +# include "lock_manager.h" + +extern virNetServerProgramProc lockProcs[]; +extern size_t lockNProcs; + + +typedef struct _virLockDaemonClientPrivate virLockDaemonClientPrivate; +typedef virLockDaemonClientPrivate *virLockDaemonClientPrivatePtr; + +struct _virLockDaemonClientPrivate { + virMutex lock; + virLockManagerPtr manager; + bool restrictAccess; + uid_t uid; + pid_t pid; +}; + + +#endif /* __VIR_LOCK_DAEMON_DISPATCH_H__ */ diff --git a/src/locking/virtlockd.init.in b/src/locking/virtlockd.init.in new file mode 100644 index 0000000..1adea07 --- /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.6