On 12.09.2012 18:29, Daniel P. Berrange wrote: > From: "Daniel P. Berrange" <berrange@xxxxxxxxxx> > > 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@xxxxxxxxxx> > --- > .gitignore | 2 + > cfg.mk | 6 +- > libvirt.spec.in | 7 + > po/POTFILES.in | 1 + > src/Makefile.am | 86 ++++- > src/locking/lock_daemon.c | 750 ++++++++++++++++++++++++++++++++++++++++++ > src/locking/lock_daemon.h | 43 +++ > src/locking/virtlockd.init.in | 93 ++++++ > src/locking/virtlockd.sysconf | 3 + > 9 files changed, 987 insertions(+), 4 deletions(-) > create mode 100644 src/locking/lock_daemon.c > create mode 100644 src/locking/lock_daemon.h > create mode 100644 src/locking/virtlockd.init.in > create mode 100644 src/locking/virtlockd.sysconf ACK but see my comments below > > diff --git a/.gitignore b/.gitignore > index 7919f74..619d481 100644 > --- a/.gitignore > +++ b/.gitignore > @@ -118,6 +118,8 @@ > /src/test_libvirt*.aug > /src/util/virkeymaps.h > /src/virt-aa-helper > +/src/virtlockd > +/src/virtlockd.init > /tests/*.log > /tests/*.pid > /tests/*xml2*test > diff --git a/cfg.mk b/cfg.mk > index bca363c..087bd74 100644 > --- a/cfg.mk > +++ b/cfg.mk > @@ -641,6 +641,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)";; \ > @@ -734,7 +736,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$$ > > @@ -767,7 +769,7 @@ exclude_file_name_regexp--sc_prohibit_close = \ > exclude_file_name_regexp--sc_prohibit_empty_lines_at_EOF = \ > (^tests/(qemuhelp|nodeinfo)data/|\.(gif|ico|png|diff)$$) > > -_src2=src/(util/command|libvirt|lxc/lxc_controller) > +_src2=src/(util/command|libvirt|lxc/lxc_controller|locking/lock_daemon) > exclude_file_name_regexp--sc_prohibit_fork_wrappers = \ > (^($(_src2)|tests/testutils|daemon/libvirtd)\.c$$) > > diff --git a/libvirt.spec.in b/libvirt.spec.in > index 8c4c08d..69d8c58 100644 > --- a/libvirt.spec.in > +++ b/libvirt.spec.in > @@ -1562,11 +1562,13 @@ fi > %dir %attr(0700, root, root) %{_sysconfdir}/libvirt/nwfilter/ > > %{_sysconfdir}/rc.d/init.d/libvirtd > +%{_sysconfdir}/rc.d/init.d/virtlockd > %if %{with_systemd} > %{_unitdir}/libvirtd.service > %endif > %doc daemon/libvirtd.upstart > %config(noreplace) %{_sysconfdir}/sysconfig/libvirtd > +%config(noreplace) %{_sysconfdir}/sysconfig/virtlockd > %config(noreplace) %{_sysconfdir}/libvirt/libvirtd.conf > %if 0%{?fedora} >= 14 || 0%{?rhel} >= 6 > %config(noreplace) %{_sysconfdir}/sysctl.d/libvirtd > @@ -1630,6 +1632,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 > @@ -1663,6 +1669,7 @@ rm -f $RPM_BUILD_ROOT%{_sysconfdir}/sysctl.d/libvirtd > > %attr(0755, root, root) %{_libexecdir}/libvirt_iohelper > %attr(0755, root, root) %{_sbindir}/libvirtd > +%attr(0755, root, root) %{_sbindir}/virtlockd > > %{_mandir}/man8/libvirtd.8* > > diff --git a/po/POTFILES.in b/po/POTFILES.in > index e8101a4..78f71f5 100644 > --- a/po/POTFILES.in > +++ b/po/POTFILES.in > @@ -44,6 +44,7 @@ src/interface/netcf_driver.c > src/internal.h > src/libvirt.c > src/libvirt-qemu.c > +src/locking/lock_daemon.c > src/locking/lock_driver_sanlock.c > src/locking/lock_manager.c > src/lxc/lxc_cgroup.c > diff --git a/src/Makefile.am b/src/Makefile.am > index 6860e7f..a60a772 100644 > --- a/src/Makefile.am > +++ b/src/Makefile.am > @@ -142,6 +142,10 @@ DRIVER_SOURCES = \ > LOCK_DRIVER_SANLOCK_SOURCES = \ > locking/lock_driver_sanlock.c > > +LOCK_DAEMON_SOURCES = \ > + locking/lock_daemon.h \ > + locking/lock_daemon.c \ > + $(NULL) > > NETDEV_CONF_SOURCES = \ > conf/netdev_bandwidth_conf.h conf/netdev_bandwidth_conf.c \ > @@ -1475,6 +1479,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 > @@ -1693,7 +1767,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" > @@ -1739,7 +1817,11 @@ if WITH_NETWORK > $(DESTDIR)$(sysconfdir)/libvirt/qemu/networks/autostart/default.xml > endif > > -uninstall-local:: > +uninstall-local:: uninstall-init > +if WITH_LIBVIRTD > + rmdir "$(DESTDIR)$(localstatedir)/lib/libvirt/lockd" ||: > + rmdir "$(DESTDIR)$(localstatedir)/run/libvirt/lockd" ||: > +endif > rmdir "$(DESTDIR)$(localstatedir)/cache/libvirt" ||: > rmdir "$(DESTDIR)$(localstatedir)/lib/libvirt/images" ||: > rmdir "$(DESTDIR)$(localstatedir)/lib/libvirt/filesystems" ||: > diff --git a/src/locking/lock_daemon.c b/src/locking/lock_daemon.c > new file mode 100644 > index 0000000..287ad8c > --- /dev/null > +++ b/src/locking/lock_daemon.c > @@ -0,0 +1,750 @@ > +/* > + * 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@xxxxxxxxxx> > + */ > + > +#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 "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 > + > +#define virLockError(code, ...) \ > + virReportErrorHelper(VIR_FROM_THIS, code, __FILE__, \ > + __FUNCTION__, __LINE__, __VA_ARGS__) We need to drop this - as we did a while ago for the rest of the code. > + > +struct _virLockDaemon { > + virMutex lock; > + virNetServerPtr srv; > +}; > + > +virLockDaemonPtr lockDaemon = NULL; > + > +static bool privileged; > + > +enum { > + VIR_LOCK_DAEMON_ERR_NONE = 0, > + VIR_LOCK_DAEMON_ERR_PIDFILE, > + VIR_LOCK_DAEMON_ERR_RUNDIR, > + VIR_LOCK_DAEMON_ERR_INIT, > + VIR_LOCK_DAEMON_ERR_SIGNAL, > + VIR_LOCK_DAEMON_ERR_PRIVS, > + VIR_LOCK_DAEMON_ERR_NETWORK, > + VIR_LOCK_DAEMON_ERR_CONFIG, > + VIR_LOCK_DAEMON_ERR_HOOKS, > + > + VIR_LOCK_DAEMON_ERR_LAST > +}; > + > +VIR_ENUM_DECL(virDaemonErr) > +VIR_ENUM_IMPL(virDaemonErr, VIR_LOCK_DAEMON_ERR_LAST, > + "Initialization successful", > + "Unable to obtain pidfile", > + "Unable to create rundir", > + "Unable to initialize libvirt", > + "Unable to setup signal handlers", > + "Unable to drop privileges", > + "Unable to initialize network sockets", > + "Unable to load configuration file", > + "Unable to look for hook scripts"); > + > +static 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(void) > +{ > + 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, > + NULL, NULL, The 1st NULL is supposed to be 'false' as it is bool keepaliveRequired; > + virLockDaemonClientNew, > + NULL, > + virLockDaemonClientFree, > + NULL))) > + 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 > +virLockDaemonMakePaths(char **basedir, > + char **statedir, > + char **pidfile, > + char **sockfile) > +{ > + char *userdir = NULL; > + > + *basedir = *statedir = *pidfile = *sockfile = NULL; > + > + if (privileged) { > + if (!(*basedir = strdup(LOCALSTATEDIR "/run/libvirt"))) > + goto no_memory; > + } else { > + if (!(userdir = virGetUserDirectory())) I wonder if we should use $HOME/.config here, that is virGetUserConfigDirectory(). > + goto error; > + > + if (virAsprintf(basedir, "%s/.libvirt", userdir) < 0) > + goto no_memory; > + } > + > + if (virAsprintf(statedir, "%s/virtlockd", *basedir) < 0) > + goto no_memory; > + if (virAsprintf(pidfile, "%s/virtlockd.pid", *statedir) < 0) > + goto no_memory; > + if (virAsprintf(sockfile, "%s/virtlockd.sock", *statedir) < 0) > + goto no_memory; > + > + VIR_FREE(userdir); > + return 0; > + > +no_memory: > + VIR_FREE(*basedir); > + VIR_FREE(*statedir); > + VIR_FREE(*pidfile); > + VIR_FREE(*sockfile); > +error: > + VIR_FREE(userdir); > + return -1; > +} > + > +static void > +virLockDaemonErrorHandler(void *opaque ATTRIBUTE_UNUSED, > + virErrorPtr err ATTRIBUTE_UNUSED) > +{ > + /* Don't do anything, since logging infrastructure already > + * took care of reporting the error */ > +} > + > + > +/* > + * Set up the logging environment > + * By default if daemonized all errors go to syslog and the logging > + * is also saved onto the logfile libvird.log, but if verbose or error > + * debugging is asked for then output informations or debug. > + */ > +static int > +virLockDaemonSetLogging(virConfPtr conf ATTRIBUTE_UNUSED, > + const char *filename ATTRIBUTE_UNUSED, > + int godaemon, int verbose) > +{ > + //int log_level = 0; > + char *log_filters = NULL; > + char *log_outputs = NULL; > + int ret = -1; > + > + virLogReset(); > +#if 0 > + /* > + * Libvirtd's order of precedence is: > + * cmdline > environment > config > + * > + * In order to achieve this, we must process configuration in > + * different order for the log level versus the filters and > + * outputs. Because filters and outputs append, we have to look at > + * the environment first and then only check the config file if > + * there was no result from the environment. The default output is > + * then applied only if there was no setting from either of the > + * first two. Because we don't have a way to determine if the log > + * level has been set, we must process variables in the opposite > + * order, each one overriding the previous. > + */ > + GET_CONF_INT (conf, filename, log_level); > + if (log_level != 0) > + virLogSetDefaultPriority(log_level); > + > + if (virLogGetNbFilters() == 0) { > + GET_CONF_STR (conf, filename, log_filters); > + virLogParseFilters(log_filters); > + } > + > + if (virLogGetNbOutputs() == 0) { > + GET_CONF_STR (conf, filename, log_outputs); > + virLogParseOutputs(log_outputs); > + } > +#endif > + > + virLogSetFromEnv(); > + > + /* > + * If no defined outputs, then direct to syslog when running > + * as daemon. Otherwise the default output is stderr. > + */ > + if (virLogGetNbOutputs() == 0) { > + char *tmp = NULL; > + if (godaemon) { > + if (virAsprintf (&tmp, "%d:syslog:libvirtd", > + virLogGetDefaultPriority()) < 0) > + goto free_and_fail; > + } else { > + if (virAsprintf (&tmp, "%d:stderr", > + virLogGetDefaultPriority()) < 0) > + goto free_and_fail; > + } > + virLogParseOutputs(tmp); > + VIR_FREE(tmp); > + } > + > + /* > + * Command line override for --verbose > + */ > + if ((verbose) && (virLogGetDefaultPriority() > VIR_LOG_INFO)) > + virLogSetDefaultPriority(VIR_LOG_INFO); > + > + ret = 0; > + > +free_and_fail: > + VIR_FREE(log_filters); > + VIR_FREE(log_outputs); > + return ret; > +} > + > +/* Read the config file if it exists. > + * Only used in the remote case, hence the name. > + */ > +static int > +virLockDaemonReadConfigFile(const char *filename, > + int godaemon, int verbose) > +{ > + virConfPtr conf; > + > + if (!(conf = virConfReadFile (filename, 0))) > + goto error; > + > + if (virLockDaemonSetLogging(conf, filename, godaemon, verbose) < 0) > + goto error; > + > + virConfFree (conf); > + return 0; > + > +error: > + virConfFree (conf); > + > + return -1; > +} > + > +/* Display version information. */ > +static void > + virLockDaemonVersion(const char *argv0) > +{ > + printf ("%s (%s) %s\n", argv0, PACKAGE_NAME, PACKAGE_VERSION); > +} > + > +static void > +virLockDaemonShutdownHandler(virNetServerPtr srv, > + siginfo_t *sig ATTRIBUTE_UNUSED, > + void *opaque ATTRIBUTE_UNUSED) > +{ > + virNetServerQuit(srv); > +} > + > +static int > +virLockDaemonSetupSignals(virNetServerPtr srv) > +{ > + if (virNetServerAddSignalHandler(srv, SIGINT, virLockDaemonShutdownHandler, NULL) < 0) > + return -1; > + if (virNetServerAddSignalHandler(srv, SIGQUIT, virLockDaemonShutdownHandler, NULL) < 0) > + return -1; > + if (virNetServerAddSignalHandler(srv, SIGTERM, virLockDaemonShutdownHandler, NULL) < 0) > + return -1; > + return 0; > +} > + > +static int > +virLockDaemonSetupNetworking(virNetServerPtr srv, const char *sock_path) > +{ > + virNetServerServicePtr svc; > + > + 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 ATTRIBUTE_UNUSED) > +{ > + virLockDaemonClientPtr priv; > + uid_t clientuid; > + gid_t clientgid; > + > + 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) { > + virLockError(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) { > + virLockError(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) > +{ > + fprintf (stderr, > + _("\n\ > +Usage:\n\ > + %s [options]\n\ > +\n\ > +Options:\n\ > + -v | --verbose Verbose messages.\n\ > + -d | --daemon Run as a daemon & write PID file.\n\ > + -t | --timeout <secs> Exit after timeout period.\n\ > + -f | --config <file> Configuration file.\n\ > + | --version Display version information.\n\ > + -p | --pid-file <file> Change name of PID file.\n\ > +\n\ > +libvirt lock management daemon:\n\ > +\n\ > + Default paths:\n\ > +\n\ > + Configuration file (unless overridden by -f):\n\ > + %s/libvirt/libvirtd.conf\n\ s/libvirtd/virtlockd/ > +\n\ > + Sockets (as root):\n\ > + %s/run/virtlockd/virtlockd.sock\n\ > +\n\ > + Sockets (as non-root):\n\ > + $HOME/.libvirt/virtlockd/virtlockd.sock (in UNIX abstract namespace)\n\ > +\n\ > + Default PID file (as root):\ > + %s/run/vitlockd/virtlockd.pid\n\ > +\n\ > + Default PID file (as non-root):\ > + $HOME/.libvirt/virtlockd/virtlockd.pid\n\ > +\n"), > + argv0, > + SYSCONFDIR, > + LOCALSTATEDIR, > + LOCALSTATEDIR); > +} > + > +enum { > + OPT_VERSION = 129 > +}; > + > +#define MAX_LISTEN 5 > +int main(int argc, char **argv) { > + const char *remote_config_file = NULL; > + int statuswrite = -1; > + int ret = 1; > + int verbose = 0; > + int godaemon = 0; > + int timeout = 0; > + char *base_dir = NULL; > + char *state_dir = NULL; > + char *pid_file = NULL; > + int pid_file_fd = -1; > + char *sock_file = NULL; > + > + struct option opts[] = { > + { "verbose", no_argument, &verbose, 1}, > + { "daemon", no_argument, &godaemon, 1}, > + { "config", required_argument, NULL, 'f'}, > + { "timeout", required_argument, NULL, 't'}, > + { "pid-file", required_argument, NULL, 'p'}, > + { "version", no_argument, NULL, OPT_VERSION }, > + { "help", no_argument, NULL, '?' }, > + {0, 0, 0, 0} > + }; > + > + privileged = getuid() == 0; > + > + if (setlocale (LC_ALL, "") == NULL || > + bindtextdomain (PACKAGE, LOCALEDIR) == NULL || > + textdomain(PACKAGE) == NULL || > + virThreadInitialize() < 0 || > + virErrorInitialize() < 0) { > + fprintf(stderr, _("%s: initialization failed\n"), argv[0]); > + exit(EXIT_FAILURE); > + } > + > + if (virLockDaemonMakePaths(&base_dir, &state_dir, > + &pid_file, &sock_file) < 0) > + exit(EXIT_FAILURE); > + > + while (1) { > + int optidx = 0; > + int c; > + char *tmp; > + > + c = getopt_long(argc, argv, "ldf:p:t:v", opts, &optidx); what's 'l' here? > + > + if (c == -1) { > + break; > + } > + > + switch (c) { > + case 0: > + /* Got one of the flags */ > + break; > + case 'v': > + verbose = 1; > + break; > + case 'd': > + godaemon = 1; > + break; > + > + case 't': > + if (virStrToLong_i(optarg, &tmp, 10, &timeout) != 0 > + || timeout <= 0 > + /* Ensure that we can multiply by 1000 without overflowing. */ > + || timeout > INT_MAX / 1000) > + timeout = -1; > + break; > + > + case 'p': > + VIR_FREE(pid_file); > + if (!(pid_file = strdup(optarg))) > + exit(EXIT_FAILURE); > + break; > + > + case 'f': > + remote_config_file = optarg; > + break; > + > + case OPT_VERSION: > + virLockDaemonVersion(argv[0]); > + return 0; > + > + case '?': > + virLockDaemonUsage(argv[0]); > + return 2; > + > + default: > + fprintf (stderr, _("%s: internal error: unknown flag: %c\n"), > + argv[0], c); > + exit (EXIT_FAILURE); > + } > + } > + > + if (remote_config_file == NULL) { > + static const char *default_config_file > + = SYSCONFDIR "/libvirt/virtlockd.conf"; > + remote_config_file = > + (access(default_config_file, R_OK) == 0 > + ? default_config_file > + : "/dev/null"); > + } > + > + if (godaemon) { > + char ebuf[1024]; > + if ((statuswrite = virLockDaemonForkIntoBackground(argv[0])) < 0) { > + VIR_ERROR(_("Failed to fork as daemon: %s"), > + virStrerror(errno, ebuf, sizeof(ebuf))); > + goto cleanup; > + } > + } > + > + /* Ensure the rundir exists (on tmpfs on some systems) */ > + if (mkdir(base_dir, 0755)) { > + if (errno != EEXIST) { > + char ebuf[1024]; > + VIR_ERROR(_("unable to create rundir %s: %s"), base_dir, > + virStrerror(errno, ebuf, sizeof(ebuf))); > + ret = VIR_LOCK_DAEMON_ERR_RUNDIR; > + goto cleanup; > + } > + } > + if (mkdir(state_dir, 0700)) { > + if (errno != EEXIST) { > + char ebuf[1024]; > + VIR_ERROR(_("unable to create rundir %s: %s"), state_dir, > + virStrerror(errno, ebuf, sizeof(ebuf))); > + ret = VIR_LOCK_DAEMON_ERR_RUNDIR; > + goto cleanup; > + } > + } > + > + /* If we have a pidfile set, claim it now, exiting if already taken */ > + if ((pid_file_fd = virPidFileAcquirePath(pid_file, getpid())) < 0) { > + ret = VIR_LOCK_DAEMON_ERR_PIDFILE; > + goto cleanup; > + } > + > + /* Read the config file (if it exists). */ > + if (virLockDaemonReadConfigFile(remote_config_file, godaemon, verbose) < 0) { > + ret = VIR_LOCK_DAEMON_ERR_CONFIG; > + goto cleanup; > + } > + > + > + if (!(lockDaemon = virLockDaemonNew())) { > + 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(state_dir); > + return ret; > +} > diff --git a/src/locking/lock_daemon.h b/src/locking/lock_daemon.h > new file mode 100644 > index 0000000..7bc8c2e > --- /dev/null > +++ b/src/locking/lock_daemon.h > @@ -0,0 +1,43 @@ > +/* > + * lock_daemon.h: lock management daemon > + * > + * Copyright (C) 2006-2012 Red Hat, Inc. > + * > + * This library is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2.1 of the License, or (at your option) any later version. > + * > + * This library is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * Lesser General Public License for more details. > + * > + * You should have received a copy of the GNU Lesser General Public > + * License along with this library; If not, see > + * <http://www.gnu.org/licenses/>. > + * > + * Author: Daniel P. Berrange <berrange@xxxxxxxxxx> > + */ > + > +#ifndef __VIR_LOCK_DAEMON_H__ > +# define __VIR_LOCK_DAEMON_H__ > + > +# include "virlockspace.h" > +# include "threads.h" > + > +typedef struct _virLockDaemon virLockDaemon; > +typedef virLockDaemon *virLockDaemonPtr; > + > +typedef struct _virLockDaemonClient virLockDaemonClient; > +typedef virLockDaemonClient *virLockDaemonClientPtr; > + > +struct _virLockDaemonClient { > + virMutex lock; > + > + pid_t clientPid; > +}; > + > +extern virLockDaemonPtr lockDaemon; > + > +#endif /* __VIR_LOCK_DAEMON_H__ */ > diff --git a/src/locking/virtlockd.init.in b/src/locking/virtlockd.init.in > new file mode 100644 > index 0000000..e55cbf9 > --- /dev/null > +++ b/src/locking/virtlockd.init.in > @@ -0,0 +1,93 @@ > +#!/bin/sh > + > +# the following is the LSB init header see > +# http://www.linux-foundation.org/spec//booksets/LSB-Core-generic/LSB-Core-generic.html#INITSCRCOMCONV > +# > +### BEGIN INIT INFO > +# Provides: virtlockd > +# Default-Start: 3 4 5 > +# Short-Description: virtual machine lock manager > +# Description: This is a daemon for managing locks > +# on virtual machine disk images > +### END INIT INFO > + > +# the following is chkconfig init header > +# > +# virtlockd: virtual machine lock manager > +# > +# chkconfig: 345 97 03 > +# description: This is a daemon for managing locks \ > +# on virtual machine disk images > +# > +# processname: virtlockd > +# pidfile: ::localstatedir::/run/libvirt/virtlockd.pid > +# > + > +# Source function library. > +. ::sysconfdir::/rc.d/init.d/functions > + > +SERVICE=virtlockd > +PROCESS=virtlockd > +PIDFILE=::localstatedir::/run/libvirt/lockd/$SERVICE.pid > + > +VIRTLOCKD_ARGS= > + > +test -f ::sysconfdir::/sysconfig/virtlockd && . ::sysconfdir::/sysconfig/virtlockd > + > +RETVAL=0 > + > +start() { > + echo -n $"Starting $SERVICE daemon: " > + daemon --pidfile $PIDFILE --check $SERVICE $PROCESS --daemon $VIRTLOCKD_ARGS > + RETVAL=$? > + echo > + [ $RETVAL -eq 0 ] && touch ::localstatedir::/lock/subsys/$SERVICE > +} > + > +stop() { > + echo -n $"Stopping $SERVICE daemon: " > + > + killproc -p $PIDFILE $PROCESS > + RETVAL=$? > + echo > + if [ $RETVAL -eq 0 ]; then > + rm -f ::localstatedir::/lock/subsys/$SERVICE > + rm -f $PIDFILE > + fi > +} > + > +restart() { > + stop > + start > +} > + > +reload() { > + echo -n $"Reloading $SERVICE configuration: " > + > + killproc -p $PIDFILE $PROCESS -HUP > + RETVAL=$? > + echo > + return $RETVAL > +} > + > +# See how we were called. > +case "$1" in > + start|stop|restart|reload) > + $1 > + ;; > + status) > + status -p $PIDFILE $PROCESS > + RETVAL=$? > + ;; > + force-reload) > + reload > + ;; > + condrestart|try-restart) > + [ -f ::localstatedir::/lock/subsys/$SERVICE ] && restart || : > + ;; > + *) > + echo $"Usage: $0 {start|stop|status|restart|condrestart|reload|force-reload|try-restart}" > + exit 2 > + ;; > +esac > +exit $RETVAL > diff --git a/src/locking/virtlockd.sysconf b/src/locking/virtlockd.sysconf > new file mode 100644 > index 0000000..d44dc46 > --- /dev/null > +++ b/src/locking/virtlockd.sysconf > @@ -0,0 +1,3 @@ > +# > +# Pass extra arguments to virtlockd > +#VIRTLOCKD_ARGS= > -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list