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/test_libvirt*.aug
|
||||||
/src/util/virkeymaps.h
|
/src/util/virkeymaps.h
|
||||||
/src/virt-aa-helper
|
/src/virt-aa-helper
|
||||||
|
/src/virtlockd
|
||||||
|
/src/virtlockd.init
|
||||||
/tests/*.log
|
/tests/*.log
|
||||||
/tests/*.pid
|
/tests/*.pid
|
||||||
/tests/*xml2*test
|
/tests/*xml2*test
|
||||||
|
6
cfg.mk
6
cfg.mk
@ -655,6 +655,8 @@ sc_prohibit_cross_inclusion:
|
|||||||
@for dir in $(cross_dirs); do \
|
@for dir in $(cross_dirs); do \
|
||||||
case $$dir in \
|
case $$dir in \
|
||||||
util/) safe="util";; \
|
util/) safe="util";; \
|
||||||
|
locking/) \
|
||||||
|
safe="($$dir|util|conf|rpc)";; \
|
||||||
cpu/ | locking/ | network/ | rpc/ | security/) \
|
cpu/ | locking/ | network/ | rpc/ | security/) \
|
||||||
safe="($$dir|util|conf)";; \
|
safe="($$dir|util|conf)";; \
|
||||||
xenapi/ | xenxs/ ) safe="($$dir|util|conf|xen)";; \
|
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:
|
# List all syntax-check exemptions:
|
||||||
exclude_file_name_regexp--sc_avoid_strcase = ^tools/virsh\.h$$
|
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 = \
|
exclude_file_name_regexp--sc_avoid_write = \
|
||||||
^(src/($(_src1))|daemon/libvirtd|tools/console|tests/(shunload|virnettlscontext)test)\.c$$
|
^(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 = \
|
exclude_file_name_regexp--sc_prohibit_empty_lines_at_EOF = \
|
||||||
(^tests/(qemuhelp|nodeinfo)data/|\.(gif|ico|png|diff)$$)
|
(^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 = \
|
exclude_file_name_regexp--sc_prohibit_fork_wrappers = \
|
||||||
(^($(_src2)|tests/testutils|daemon/libvirtd)\.c$$)
|
(^($(_src2)|tests/testutils|daemon/libvirtd)\.c$$)
|
||||||
|
|
||||||
|
@ -1662,9 +1662,11 @@ fi
|
|||||||
%else
|
%else
|
||||||
%{_sysconfdir}/rc.d/init.d/libvirtd
|
%{_sysconfdir}/rc.d/init.d/libvirtd
|
||||||
%{_sysconfdir}/rc.d/init.d/libvirt-guests
|
%{_sysconfdir}/rc.d/init.d/libvirt-guests
|
||||||
|
%{_sysconfdir}/rc.d/init.d/virtlockd
|
||||||
%endif
|
%endif
|
||||||
%doc daemon/libvirtd.upstart
|
%doc daemon/libvirtd.upstart
|
||||||
%config(noreplace) %{_sysconfdir}/sysconfig/libvirtd
|
%config(noreplace) %{_sysconfdir}/sysconfig/libvirtd
|
||||||
|
%config(noreplace) %{_sysconfdir}/sysconfig/virtlockd
|
||||||
%config(noreplace) %{_sysconfdir}/libvirt/libvirtd.conf
|
%config(noreplace) %{_sysconfdir}/libvirt/libvirtd.conf
|
||||||
%if 0%{?fedora} >= 14 || 0%{?rhel} >= 6
|
%if 0%{?fedora} >= 14 || 0%{?rhel} >= 6
|
||||||
%config(noreplace) %{_sysconfdir}/sysctl.d/libvirtd
|
%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/
|
%dir %attr(0755, root, root) %{_localstatedir}/lib/libvirt/dnsmasq/
|
||||||
%endif
|
%endif
|
||||||
|
|
||||||
|
%if %{with_libvirtd}
|
||||||
|
%dir %attr(0755, root, root) %{_libdir}/libvirt/lock-driver
|
||||||
|
%endif
|
||||||
|
|
||||||
%if %{with_qemu}
|
%if %{with_qemu}
|
||||||
%{_datadir}/augeas/lenses/libvirtd_qemu.aug
|
%{_datadir}/augeas/lenses/libvirtd_qemu.aug
|
||||||
%{_datadir}/augeas/lenses/tests/test_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) %{_libexecdir}/libvirt_iohelper
|
||||||
%attr(0755, root, root) %{_sbindir}/libvirtd
|
%attr(0755, root, root) %{_sbindir}/libvirtd
|
||||||
|
%attr(0755, root, root) %{_sbindir}/virtlockd
|
||||||
|
|
||||||
%{_mandir}/man8/libvirtd.8*
|
%{_mandir}/man8/libvirtd.8*
|
||||||
|
|
||||||
|
@ -48,6 +48,8 @@ src/interface/interface_backend_udev.c
|
|||||||
src/internal.h
|
src/internal.h
|
||||||
src/libvirt.c
|
src/libvirt.c
|
||||||
src/libvirt-qemu.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_driver_sanlock.c
|
||||||
src/locking/lock_manager.c
|
src/locking/lock_manager.c
|
||||||
src/locking/sanlock_helper.c
|
src/locking/sanlock_helper.c
|
||||||
|
@ -148,6 +148,13 @@ LOCK_DRIVER_SANLOCK_SOURCES = \
|
|||||||
LOCK_DRIVER_SANLOCK_HELPER_SOURCES = \
|
LOCK_DRIVER_SANLOCK_HELPER_SOURCES = \
|
||||||
locking/sanlock_helper.c
|
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 = \
|
NETDEV_CONF_SOURCES = \
|
||||||
conf/netdev_bandwidth_conf.h conf/netdev_bandwidth_conf.c \
|
conf/netdev_bandwidth_conf.h conf/netdev_bandwidth_conf.c \
|
||||||
conf/netdev_vport_profile_conf.h conf/netdev_vport_profile_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)
|
libvirt_qemu_la_LIBADD = libvirt.la $(CYGWIN_EXTRA_LIBADD)
|
||||||
EXTRA_DIST += $(LIBVIRT_QEMU_SYMBOL_FILE)
|
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
|
if HAVE_SANLOCK
|
||||||
lockdriverdir = $(libdir)/libvirt/lock-driver
|
lockdriverdir = $(libdir)/libvirt/lock-driver
|
||||||
lockdriver_LTLIBRARIES = sanlock.la
|
lockdriver_LTLIBRARIES = sanlock.la
|
||||||
@ -1747,7 +1824,11 @@ endif
|
|||||||
endif
|
endif
|
||||||
EXTRA_DIST += $(SECURITY_DRIVER_APPARMOR_HELPER_SOURCES)
|
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)/cache/libvirt"
|
||||||
$(MKDIR_P) "$(DESTDIR)$(localstatedir)/lib/libvirt/images"
|
$(MKDIR_P) "$(DESTDIR)$(localstatedir)/lib/libvirt/images"
|
||||||
$(MKDIR_P) "$(DESTDIR)$(localstatedir)/lib/libvirt/filesystems"
|
$(MKDIR_P) "$(DESTDIR)$(localstatedir)/lib/libvirt/filesystems"
|
||||||
@ -1796,7 +1877,11 @@ if WITH_NETWORK
|
|||||||
$(DESTDIR)$(sysconfdir)/libvirt/qemu/networks/autostart/default.xml
|
$(DESTDIR)$(sysconfdir)/libvirt/qemu/networks/autostart/default.xml
|
||||||
endif
|
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)/cache/libvirt" ||:
|
||||||
rmdir "$(DESTDIR)$(localstatedir)/lib/libvirt/images" ||:
|
rmdir "$(DESTDIR)$(localstatedir)/lib/libvirt/images" ||:
|
||||||
rmdir "$(DESTDIR)$(localstatedir)/lib/libvirt/filesystems" ||:
|
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