mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-01-21 20:15:17 +00:00
Introduce basic infrastructure for virtlockd daemon
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@redhat.com>
This commit is contained in:
parent
f199f75e9b
commit
c57e3d8994
2
.gitignore
vendored
2
.gitignore
vendored
@ -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
|
||||
|
6
cfg.mk
6
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$$)
|
||||
|
||||
|
@ -1662,9 +1662,11 @@ fi
|
||||
%else
|
||||
%{_sysconfdir}/rc.d/init.d/libvirtd
|
||||
%{_sysconfdir}/rc.d/init.d/libvirt-guests
|
||||
%{_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
|
||||
@ -1731,6 +1733,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
|
||||
@ -1764,6 +1770,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*
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 \
|
||||
@ -1510,6 +1517,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
|
||||
@ -1747,7 +1824,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"
|
||||
@ -1796,7 +1877,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" ||:
|
||||
|
838
src/locking/lock_daemon.c
Normal file
838
src/locking/lock_daemon.c
Normal file
@ -0,0 +1,838 @@
|
||||
/*
|
||||
* 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@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"
|
||||
" -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;
|
||||
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'},
|
||||
{ "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;
|
||||
|
||||
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 '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;
|
||||
}
|
43
src/locking/lock_daemon.h
Normal file
43
src/locking/lock_daemon.h
Normal file
@ -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@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__ */
|
193
src/locking/lock_daemon_config.c
Normal file
193
src/locking/lock_daemon_config.c
Normal file
@ -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@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;
|
||||
}
|
50
src/locking/lock_daemon_config.h
Normal file
50
src/locking/lock_daemon_config.h
Normal file
@ -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@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__ */
|
93
src/locking/virtlockd.init.in
Normal file
93
src/locking/virtlockd.init.in
Normal file
@ -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
|
3
src/locking/virtlockd.sysconf
Normal file
3
src/locking/virtlockd.sysconf
Normal file
@ -0,0 +1,3 @@
|
||||
#
|
||||
# Pass extra arguments to virtlockd
|
||||
#VIRTLOCKD_ARGS=
|
Loading…
x
Reference in New Issue
Block a user