mirror of
https://git.proxmox.com/git/mirror_corosync-qdevice
synced 2025-04-28 12:32:27 +00:00
Initial import from corosync codebase
Used the code from corosync master (31ddba64a2726bcedf81eb84df2e2da4846832f7) Signed-off-by: Jan Friesse <jfriesse@redhat.com>
This commit is contained in:
commit
9a1955a7d6
33
.gitignore
vendored
Normal file
33
.gitignore
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
*.o
|
||||
*.a
|
||||
*.so*
|
||||
*.lo
|
||||
*.la
|
||||
.libs
|
||||
.deps
|
||||
.version
|
||||
doc
|
||||
Makefile
|
||||
Makefile.in
|
||||
corosync-qdevice.spec
|
||||
aclocal.m4
|
||||
autom4te.cache/
|
||||
compile
|
||||
config.guess
|
||||
config.log
|
||||
config.status
|
||||
config.sub
|
||||
configure
|
||||
corosync-*.tar*
|
||||
depcomp
|
||||
install-sh
|
||||
libtool
|
||||
ltmain.sh
|
||||
m4
|
||||
missing
|
||||
tags
|
||||
ID
|
||||
Doxyfile
|
||||
config.h*
|
||||
stamp-*
|
||||
test-driver
|
58
LICENSE
Normal file
58
LICENSE
Normal file
@ -0,0 +1,58 @@
|
||||
-----------------------------------------------------------------------------
|
||||
The following license applies to every file in this source distribution except
|
||||
for the files git-version-gen, and gitlog-to-changelog.
|
||||
|
||||
The git* files, which are available under GPLv3 or later, are only used by
|
||||
our release process to generate text file content and are not part of any
|
||||
generated binary.
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015-2018 Red Hat, Inc.
|
||||
|
||||
All rights reserved.
|
||||
|
||||
This software licensed under BSD license, the text of which follows:
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
- Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
- Neither the name of the Red Hat, Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from this
|
||||
software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
The corosync-qdevice project uses software for release processing which generates
|
||||
changelogs and version information for the software. These programs are not
|
||||
used by the generated binaries or libraries These files are git-version-gen
|
||||
and gitlog-to-changelog.
|
||||
-----------------------------------------------------------------------------
|
||||
The license for these files is as follows:
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
156
Makefile.am
Normal file
156
Makefile.am
Normal file
@ -0,0 +1,156 @@
|
||||
# Copyright (c) 2009 Red Hat, Inc.
|
||||
#
|
||||
# Authors: Andrew Beekhof
|
||||
# Steven Dake (sdake@redhat.com)
|
||||
#
|
||||
# This software licensed under BSD license, the text of which follows:
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# - Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# - Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from this
|
||||
# software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
# THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
SPEC = $(PACKAGE_NAME).spec
|
||||
|
||||
TARFILE = $(PACKAGE_NAME)-$(VERSION).tar.gz
|
||||
|
||||
EXTRA_DIST = autogen.sh $(SPEC).in \
|
||||
build-aux/git-version-gen \
|
||||
build-aux/gitlog-to-changelog \
|
||||
build-aux/release.mk \
|
||||
.version
|
||||
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
MAINTAINERCLEANFILES = Makefile.in aclocal.m4 configure depcomp \
|
||||
config.guess config.sub missing install-sh \
|
||||
autoheader automake autoconf \
|
||||
autoscan.log configure.scan ltmain.sh test-driver
|
||||
|
||||
dist_doc_DATA = LICENSE
|
||||
|
||||
SUBDIRS = qdevices man init
|
||||
|
||||
install-exec-local:
|
||||
if BUILD_QNETD
|
||||
$(INSTALL) -m 770 -d $(DESTDIR)/${localstatedir}/run/corosync-qnetd
|
||||
$(INSTALL) -m 770 -d $(DESTDIR)/${COROSYSCONFDIR}/qnetd
|
||||
endif
|
||||
if BUILD_QDEVICES
|
||||
$(INSTALL) -m 770 -d $(DESTDIR)/${localstatedir}/run/corosync-qdevice
|
||||
$(INSTALL) -d $(DESTDIR)/${COROSYSCONFDIR}/qdevice/
|
||||
$(INSTALL) -m 770 -d $(DESTDIR)/${COROSYSCONFDIR}/qdevice/net
|
||||
endif
|
||||
|
||||
uninstall-local:
|
||||
if BUILD_QNETD
|
||||
rmdir $(DESTDIR)/${localstatedir}/run/corosync-qnetd || :;
|
||||
rmdir $(DESTDIR)/${COROSYSCONFDIR}/qnetd || :;
|
||||
endif
|
||||
if BUILD_QDEVICES
|
||||
rmdir $(DESTDIR)/${localstatedir}/run/corosync-qdevice || :;
|
||||
rmdir $(DESTDIR)/${COROSYSCONFDIR}/qdevice/net || :;
|
||||
rmdir $(DESTDIR)/${COROSYSCONFDIR}/qdevice/ || :;
|
||||
endif
|
||||
|
||||
dist-clean-local:
|
||||
rm -f autoconf automake autoheader
|
||||
|
||||
clean-generic:
|
||||
rm -rf doc/api $(SPEC) $(TARFILE)
|
||||
|
||||
## make rpm/srpm section.
|
||||
|
||||
$(SPEC): $(SPEC).in
|
||||
rm -f $@-t $@
|
||||
date="$(shell LC_ALL=C date "+%a %b %d %Y")" && \
|
||||
if [ -f .tarball-version ]; then \
|
||||
gitver="$(shell cat .tarball-version)" && \
|
||||
rpmver=$$gitver && \
|
||||
alphatag="" && \
|
||||
dirty="" && \
|
||||
numcomm=""; \
|
||||
else \
|
||||
gitver="$(shell git describe --abbrev=4 --match='v*' HEAD 2>/dev/null)" && \
|
||||
rpmver=`echo $$gitver | sed -e "s/^v//" -e "s/-.*//g"` && \
|
||||
alphatag=`echo $$gitver | sed -e "s/.*-//" -e "s/^g//"` && \
|
||||
vtag=`echo $$gitver | sed -e "s/-.*//g"` && \
|
||||
numcomm=`git rev-list $$vtag..HEAD | wc -l` && \
|
||||
git update-index --refresh > /dev/null 2>&1 || true && \
|
||||
dirty=`git diff-index --name-only HEAD 2>/dev/null`; \
|
||||
fi && \
|
||||
if [ "$$numcomm" = "0" ]; then numcomm=""; fi && \
|
||||
if [ -n "$$numcomm" ]; then numcomm="%global numcomm $$numcomm"; fi && \
|
||||
if [ "$$alphatag" = "$$gitver" ]; then alphatag=""; fi && \
|
||||
if [ -n "$$alphatag" ]; then alphatag="%global alphatag $$alphatag"; fi && \
|
||||
if [ -n "$$dirty" ]; then dirty="%global dirty dirty"; fi && \
|
||||
sed \
|
||||
-e "s#@version@#$$rpmver#g" \
|
||||
-e "s#@ALPHATAG@#$$alphatag#g" \
|
||||
-e "s#@NUMCOMM@#$$numcomm#g" \
|
||||
-e "s#@DIRTY@#$$dirty#g" \
|
||||
-e "s#@date@#$$date#g" \
|
||||
$< > $@-t; \
|
||||
chmod a-w $@-t
|
||||
mv $@-t $@
|
||||
|
||||
$(TARFILE):
|
||||
$(MAKE) dist
|
||||
|
||||
RPMBUILDOPTS = --define "_sourcedir $(abs_builddir)" \
|
||||
--define "_specdir $(abs_builddir)" \
|
||||
--define "_builddir $(abs_builddir)" \
|
||||
--define "_srcrpmdir $(abs_builddir)" \
|
||||
--define "_rpmdir $(abs_builddir)"
|
||||
|
||||
srpm: clean
|
||||
$(MAKE) $(SPEC) $(TARFILE)
|
||||
rpmbuild $(WITH_LIST) $(RPMBUILDOPTS) --nodeps -bs $(SPEC)
|
||||
|
||||
rpm: clean _version
|
||||
$(MAKE) $(SPEC) $(TARFILE)
|
||||
rpmbuild $(WITH_LIST) $(RPMBUILDOPTS) -ba $(SPEC)
|
||||
|
||||
# release/versioning
|
||||
BUILT_SOURCES = .version
|
||||
.version:
|
||||
echo $(VERSION) > $@-t && mv $@-t $@
|
||||
|
||||
dist-hook: gen-ChangeLog
|
||||
echo $(VERSION) > $(distdir)/.tarball-version
|
||||
|
||||
gen_start_date = 2000-01-01
|
||||
.PHONY: gen-ChangeLog _version
|
||||
gen-ChangeLog:
|
||||
if test -d .git; then \
|
||||
LC_ALL=C $(top_srcdir)/build-aux/gitlog-to-changelog \
|
||||
--since=$(gen_start_date) > $(distdir)/cl-t; \
|
||||
rm -f $(distdir)/ChangeLog; \
|
||||
mv $(distdir)/cl-t $(distdir)/ChangeLog; \
|
||||
fi
|
||||
|
||||
_version:
|
||||
cd $(srcdir) && rm -rf autom4te.cache .version && autoreconf -i
|
||||
$(MAKE) $(AM_MAKEFLAGS) Makefile
|
||||
|
||||
maintainer-clean-local:
|
||||
rm -rf m4
|
33
README
Normal file
33
README
Normal file
@ -0,0 +1,33 @@
|
||||
Corosync-qdevice
|
||||
----------------
|
||||
corosync-qdevice is a daemon running on each node of a cluster. It provides
|
||||
a configured number of votes to the quorum subsystem based on a third-party
|
||||
arbitrator's decision. Its primary use is to allow a cluster to sustain more
|
||||
node failures than standard quorum rules allow. It is recommended for clusters
|
||||
with an even number of nodes and highly recommended for 2 node clusters.
|
||||
|
||||
corosync-qnetd is a daemon running outside of the cluster with the purpose
|
||||
of providing a vote to the corosync-qdevice model net. It's designed to
|
||||
support multiple clusters and be almost configuration and state free.
|
||||
New clusters are handled dynamically and no configuration file exists.
|
||||
It's also able to run as non-root user - which is recommended.
|
||||
Connection between the corosync-qdevice model net client can be optionally
|
||||
configured with TLS client certificate checking. The communication protocol
|
||||
between server and client is designed to be very simple and allow
|
||||
backwards compatibility.
|
||||
|
||||
Originally both qdevice and qnetd were part of the Corosync codebase
|
||||
(https://github.com/corosync/corosync) but because it's got quite big we
|
||||
decided to split it into it's own sub project.
|
||||
|
||||
Dependencies
|
||||
------------
|
||||
* Corosync >= 2.0
|
||||
* NSS
|
||||
|
||||
Installation
|
||||
------------
|
||||
$ ./autogen.sh
|
||||
$ ./configure
|
||||
$ make
|
||||
$ sudo make install
|
5
autogen.sh
Executable file
5
autogen.sh
Executable file
@ -0,0 +1,5 @@
|
||||
#!/bin/sh
|
||||
# Run this to generate all the initial makefiles, etc.
|
||||
mkdir -p m4
|
||||
echo Building configuration system...
|
||||
autoreconf -i && echo Now run ./configure and make
|
161
build-aux/git-version-gen
Executable file
161
build-aux/git-version-gen
Executable file
@ -0,0 +1,161 @@
|
||||
#!/bin/sh
|
||||
# Print a version string.
|
||||
scriptversion=2010-10-13.20; # UTC
|
||||
|
||||
# Copyright (C) 2007-2010 Free Software Foundation, Inc.
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program 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 General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# This script is derived from GIT-VERSION-GEN from GIT: http://git.or.cz/.
|
||||
# It may be run two ways:
|
||||
# - from a git repository in which the "git describe" command below
|
||||
# produces useful output (thus requiring at least one signed tag)
|
||||
# - from a non-git-repo directory containing a .tarball-version file, which
|
||||
# presumes this script is invoked like "./git-version-gen .tarball-version".
|
||||
|
||||
# In order to use intra-version strings in your project, you will need two
|
||||
# separate generated version string files:
|
||||
#
|
||||
# .tarball-version - present only in a distribution tarball, and not in
|
||||
# a checked-out repository. Created with contents that were learned at
|
||||
# the last time autoconf was run, and used by git-version-gen. Must not
|
||||
# be present in either $(srcdir) or $(builddir) for git-version-gen to
|
||||
# give accurate answers during normal development with a checked out tree,
|
||||
# but must be present in a tarball when there is no version control system.
|
||||
# Therefore, it cannot be used in any dependencies. GNUmakefile has
|
||||
# hooks to force a reconfigure at distribution time to get the value
|
||||
# correct, without penalizing normal development with extra reconfigures.
|
||||
#
|
||||
# .version - present in a checked-out repository and in a distribution
|
||||
# tarball. Usable in dependencies, particularly for files that don't
|
||||
# want to depend on config.h but do want to track version changes.
|
||||
# Delete this file prior to any autoconf run where you want to rebuild
|
||||
# files to pick up a version string change; and leave it stale to
|
||||
# minimize rebuild time after unrelated changes to configure sources.
|
||||
#
|
||||
# It is probably wise to add these two files to .gitignore, so that you
|
||||
# don't accidentally commit either generated file.
|
||||
#
|
||||
# Use the following line in your configure.ac, so that $(VERSION) will
|
||||
# automatically be up-to-date each time configure is run (and note that
|
||||
# since configure.ac no longer includes a version string, Makefile rules
|
||||
# should not depend on configure.ac for version updates).
|
||||
#
|
||||
# AC_INIT([GNU project],
|
||||
# m4_esyscmd([build-aux/git-version-gen .tarball-version]),
|
||||
# [bug-project@example])
|
||||
#
|
||||
# Then use the following lines in your Makefile.am, so that .version
|
||||
# will be present for dependencies, and so that .tarball-version will
|
||||
# exist in distribution tarballs.
|
||||
#
|
||||
# BUILT_SOURCES = $(top_srcdir)/.version
|
||||
# $(top_srcdir)/.version:
|
||||
# echo $(VERSION) > $@-t && mv $@-t $@
|
||||
# dist-hook:
|
||||
# echo $(VERSION) > $(distdir)/.tarball-version
|
||||
|
||||
case $# in
|
||||
1|2) ;;
|
||||
*) echo 1>&2 "Usage: $0 \$srcdir/.tarball-version" \
|
||||
'[TAG-NORMALIZATION-SED-SCRIPT]'
|
||||
exit 1;;
|
||||
esac
|
||||
|
||||
tarball_version_file=$1
|
||||
tag_sed_script="${2:-s/x/x/}"
|
||||
nl='
|
||||
'
|
||||
|
||||
# Avoid meddling by environment variable of the same name.
|
||||
v=
|
||||
|
||||
# First see if there is a tarball-only version file.
|
||||
# then try "git describe", then default.
|
||||
if test -f $tarball_version_file
|
||||
then
|
||||
v=`cat $tarball_version_file` || exit 1
|
||||
case $v in
|
||||
*$nl*) v= ;; # reject multi-line output
|
||||
[0-9]*) ;;
|
||||
*) v= ;;
|
||||
esac
|
||||
test -z "$v" \
|
||||
&& echo "$0: WARNING: $tarball_version_file seems to be damaged" 1>&2
|
||||
fi
|
||||
|
||||
if test -n "$v"
|
||||
then
|
||||
: # use $v
|
||||
# Otherwise, if there is at least one git commit involving the working
|
||||
# directory, and "git describe" output looks sensible, use that to
|
||||
# derive a version string.
|
||||
elif test "`git log -1 --pretty=format:x . 2>&1`" = x \
|
||||
&& v=`git describe --abbrev=4 --match='v*' HEAD 2>/dev/null \
|
||||
|| git describe --abbrev=4 HEAD 2>/dev/null` \
|
||||
&& v=`printf '%s\n' "$v" | sed "$tag_sed_script"` \
|
||||
&& case $v in
|
||||
v[0-9]*) ;;
|
||||
*) (exit 1) ;;
|
||||
esac
|
||||
then
|
||||
# Is this a new git that lists number of commits since the last
|
||||
# tag or the previous older version that did not?
|
||||
# Newer: v6.10-77-g0f8faeb
|
||||
# Older: v6.10-g0f8faeb
|
||||
case $v in
|
||||
*-*-*) : git describe is okay three part flavor ;;
|
||||
*-*)
|
||||
: git describe is older two part flavor
|
||||
# Recreate the number of commits and rewrite such that the
|
||||
# result is the same as if we were using the newer version
|
||||
# of git describe.
|
||||
vtag=`echo "$v" | sed 's/-.*//'`
|
||||
numcommits=`git rev-list "$vtag"..HEAD | wc -l`
|
||||
v=`echo "$v" | sed "s/\(.*\)-\(.*\)/\1-$numcommits-\2/"`;
|
||||
;;
|
||||
esac
|
||||
|
||||
# Change the first '-' to a '.', so version-comparing tools work properly.
|
||||
# Remove the "g" in git describe's output string, to save a byte.
|
||||
v=`echo "$v" | sed 's/-/./;s/\(.*\)-g/\1-/'`;
|
||||
else
|
||||
v=UNKNOWN
|
||||
fi
|
||||
|
||||
v=`echo "$v" |sed 's/^v//'`
|
||||
|
||||
# Don't declare a version "dirty" merely because a time stamp has changed.
|
||||
git update-index --refresh > /dev/null 2>&1
|
||||
|
||||
dirty=`sh -c 'git diff-index --name-only HEAD' 2>/dev/null` || dirty=
|
||||
case "$dirty" in
|
||||
'') ;;
|
||||
*) # Append the suffix only if there isn't one already.
|
||||
case $v in
|
||||
*-dirty) ;;
|
||||
*) v="$v-dirty" ;;
|
||||
esac ;;
|
||||
esac
|
||||
|
||||
# Omit the trailing newline, so that m4_esyscmd can use the result directly.
|
||||
echo "$v" | tr -d "$nl"
|
||||
|
||||
# Local variables:
|
||||
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
191
build-aux/gitlog-to-changelog
Executable file
191
build-aux/gitlog-to-changelog
Executable file
@ -0,0 +1,191 @@
|
||||
eval '(exit $?0)' && eval 'exec perl -wS "$0" ${1+"$@"}'
|
||||
& eval 'exec perl -wS "$0" $argv:q'
|
||||
if 0;
|
||||
# Convert git log output to ChangeLog format.
|
||||
|
||||
my $VERSION = '2009-10-30 13:46'; # UTC
|
||||
# The definition above must lie within the first 8 lines in order
|
||||
# for the Emacs time-stamp write hook (at end) to update it.
|
||||
# If you change this file with Emacs, please let the write hook
|
||||
# do its job. Otherwise, update this string manually.
|
||||
|
||||
# Copyright (C) 2008-2010 Free Software Foundation, Inc.
|
||||
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program 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 General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# Written by Jim Meyering
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Getopt::Long;
|
||||
use POSIX qw(strftime);
|
||||
|
||||
(my $ME = $0) =~ s|.*/||;
|
||||
|
||||
# use File::Coda; # http://meyering.net/code/Coda/
|
||||
END {
|
||||
defined fileno STDOUT or return;
|
||||
close STDOUT and return;
|
||||
warn "$ME: failed to close standard output: $!\n";
|
||||
$? ||= 1;
|
||||
}
|
||||
|
||||
sub usage ($)
|
||||
{
|
||||
my ($exit_code) = @_;
|
||||
my $STREAM = ($exit_code == 0 ? *STDOUT : *STDERR);
|
||||
if ($exit_code != 0)
|
||||
{
|
||||
print $STREAM "Try `$ME --help' for more information.\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
print $STREAM <<EOF;
|
||||
Usage: $ME [OPTIONS] [ARGS]
|
||||
|
||||
Convert git log output to ChangeLog format. If present, any ARGS
|
||||
are passed to "git log". To avoid ARGS being parsed as options to
|
||||
$ME, they may be preceded by '--'.
|
||||
|
||||
OPTIONS:
|
||||
|
||||
--since=DATE convert only the logs since DATE;
|
||||
the default is to convert all log entries.
|
||||
--format=FMT set format string for commit subject and body;
|
||||
see 'man git-log' for the list of format metacharacters;
|
||||
the default is '%s%n%b%n'
|
||||
|
||||
--help display this help and exit
|
||||
--version output version information and exit
|
||||
|
||||
EXAMPLE:
|
||||
|
||||
$ME --since=2008-01-01 > ChangeLog
|
||||
$ME -- -n 5 foo > last-5-commits-to-branch-foo
|
||||
|
||||
EOF
|
||||
}
|
||||
exit $exit_code;
|
||||
}
|
||||
|
||||
# If the string $S is a well-behaved file name, simply return it.
|
||||
# If it contains white space, quotes, etc., quote it, and return the new string.
|
||||
sub shell_quote($)
|
||||
{
|
||||
my ($s) = @_;
|
||||
if ($s =~ m![^\w+/.,-]!)
|
||||
{
|
||||
# Convert each single quote to '\''
|
||||
$s =~ s/\'/\'\\\'\'/g;
|
||||
# Then single quote the string.
|
||||
$s = "'$s'";
|
||||
}
|
||||
return $s;
|
||||
}
|
||||
|
||||
sub quoted_cmd(@)
|
||||
{
|
||||
return join (' ', map {shell_quote $_} @_);
|
||||
}
|
||||
|
||||
{
|
||||
my $since_date = '1970-01-01 UTC';
|
||||
my $format_string = '%s%n%b%n';
|
||||
GetOptions
|
||||
(
|
||||
help => sub { usage 0 },
|
||||
version => sub { print "$ME version $VERSION\n"; exit },
|
||||
'since=s' => \$since_date,
|
||||
'format=s' => \$format_string,
|
||||
) or usage 1;
|
||||
|
||||
my @cmd = (qw (git log --log-size), "--since=$since_date",
|
||||
'--pretty=format:%ct %an <%ae>%n%n'.$format_string, @ARGV);
|
||||
open PIPE, '-|', @cmd
|
||||
or die ("$ME: failed to run `". quoted_cmd (@cmd) ."': $!\n"
|
||||
. "(Is your Git too old? Version 1.5.1 or later is required.)\n");
|
||||
|
||||
my $prev_date_line = '';
|
||||
while (1)
|
||||
{
|
||||
defined (my $in = <PIPE>)
|
||||
or last;
|
||||
$in =~ /^log size (\d+)$/
|
||||
or die "$ME:$.: Invalid line (expected log size):\n$in";
|
||||
my $log_nbytes = $1;
|
||||
|
||||
my $log;
|
||||
my $n_read = read PIPE, $log, $log_nbytes;
|
||||
$n_read == $log_nbytes
|
||||
or die "$ME:$.: unexpected EOF\n";
|
||||
|
||||
my @line = split "\n", $log;
|
||||
my $author_line = shift @line;
|
||||
defined $author_line
|
||||
or die "$ME:$.: unexpected EOF\n";
|
||||
$author_line =~ /^(\d+) (.*>)$/
|
||||
or die "$ME:$.: Invalid line "
|
||||
. "(expected date/author/email):\n$author_line\n";
|
||||
|
||||
my $date_line = sprintf "%s $2\n", strftime ("%F", localtime ($1));
|
||||
# If this line would be the same as the previous date/name/email
|
||||
# line, then arrange not to print it.
|
||||
if ($date_line ne $prev_date_line)
|
||||
{
|
||||
$prev_date_line eq ''
|
||||
or print "\n";
|
||||
print $date_line;
|
||||
}
|
||||
$prev_date_line = $date_line;
|
||||
|
||||
# Omit "Signed-off-by..." lines.
|
||||
@line = grep !/^Signed-off-by: .*>$/, @line;
|
||||
|
||||
# If there were any lines
|
||||
if (@line == 0)
|
||||
{
|
||||
warn "$ME: warning: empty commit message:\n $date_line\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
# Remove leading and trailing blank lines.
|
||||
while ($line[0] =~ /^\s*$/) { shift @line; }
|
||||
while ($line[$#line] =~ /^\s*$/) { pop @line; }
|
||||
|
||||
# Prefix each non-empty line with a TAB.
|
||||
@line = map { length $_ ? "\t$_" : '' } @line;
|
||||
|
||||
print "\n", join ("\n", @line), "\n";
|
||||
}
|
||||
|
||||
defined ($in = <PIPE>)
|
||||
or last;
|
||||
$in ne "\n"
|
||||
and die "$ME:$.: unexpected line:\n$in";
|
||||
}
|
||||
|
||||
close PIPE
|
||||
or die "$ME: error closing pipe from " . quoted_cmd (@cmd) . "\n";
|
||||
# FIXME-someday: include $PROCESS_STATUS in the diagnostic
|
||||
}
|
||||
|
||||
# Local Variables:
|
||||
# mode: perl
|
||||
# indent-tabs-mode: nil
|
||||
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
||||
# time-stamp-start: "my $VERSION = '"
|
||||
# time-stamp-format: "%:y-%02m-%02d %02H:%02M"
|
||||
# time-stamp-time-zone: "UTC"
|
||||
# time-stamp-end: "'; # UTC"
|
||||
# End:
|
75
build-aux/release.mk
Normal file
75
build-aux/release.mk
Normal file
@ -0,0 +1,75 @@
|
||||
# to build official release tarballs, handle tagging and publish.
|
||||
|
||||
# signing key
|
||||
gpgsignkey=
|
||||
|
||||
project=corosync-qdevice
|
||||
|
||||
all: checks setup tag tarballs sha256 sign
|
||||
|
||||
checks:
|
||||
ifeq (,$(version))
|
||||
@echo ERROR: need to define version=
|
||||
@exit 1
|
||||
endif
|
||||
@if [ ! -d .git ]; then \
|
||||
echo This script needs to be executed from top level cluster git tree; \
|
||||
exit 1; \
|
||||
fi
|
||||
|
||||
setup: checks
|
||||
./autogen.sh
|
||||
./configure
|
||||
make maintainer-clean
|
||||
|
||||
tag: setup ./tag-$(version)
|
||||
|
||||
tag-$(version):
|
||||
ifeq (,$(release))
|
||||
@echo Building test release $(version), no tagging
|
||||
else
|
||||
git tag -a -m "v$(version) release" v$(version) HEAD
|
||||
@touch $@
|
||||
endif
|
||||
|
||||
tarballs: tag
|
||||
./autogen.sh
|
||||
./configure
|
||||
make distcheck
|
||||
|
||||
sha256: tarballs $(project)-$(version).sha256
|
||||
|
||||
$(project)-$(version).sha256:
|
||||
ifeq (,$(release))
|
||||
@echo Building test release $(version), no sha256
|
||||
else
|
||||
sha256sum $(project)-$(version)*tar* | sort -k2 > $@
|
||||
endif
|
||||
|
||||
sign: sha256 $(project)-$(version).sha256.asc
|
||||
|
||||
$(project)-$(version).sha256.asc: $(project)-$(version).sha256
|
||||
ifeq (,$(gpgsignkey))
|
||||
@echo No GPG signing key defined
|
||||
else
|
||||
ifeq (,$(release))
|
||||
@echo Building test release $(version), no sign
|
||||
else
|
||||
gpg --default-key $(gpgsignkey) \
|
||||
--detach-sign \
|
||||
--armor \
|
||||
$<
|
||||
endif
|
||||
endif
|
||||
|
||||
publish:
|
||||
ifeq (,$(release))
|
||||
@echo Building test release $(version), no publishing!
|
||||
else
|
||||
@echo CHANGEME git push --tags origin
|
||||
@echo CHANGEME scp $(project)-$(version).* \
|
||||
fedorahosted.org:$(project)
|
||||
endif
|
||||
|
||||
clean:
|
||||
rm -rf $(project)-* tag-*
|
368
configure.ac
Normal file
368
configure.ac
Normal file
@ -0,0 +1,368 @@
|
||||
# -*- Autoconf -*-
|
||||
# Process this file with autoconf to produce a configure script.
|
||||
|
||||
# bootstrap / init
|
||||
AC_PREREQ([2.61])
|
||||
|
||||
AC_INIT([corosync-qdevice],
|
||||
m4_esyscmd([build-aux/git-version-gen .tarball-version]),
|
||||
[users@clusterlabs.org])
|
||||
|
||||
AC_USE_SYSTEM_EXTENSIONS
|
||||
|
||||
AM_INIT_AUTOMAKE([foreign 1.11])
|
||||
|
||||
LT_PREREQ([2.2.6])
|
||||
LT_INIT
|
||||
|
||||
AM_SILENT_RULES([yes])
|
||||
|
||||
AC_CONFIG_SRCDIR([qdevices/corosync-qdevice.c])
|
||||
AC_CONFIG_HEADER([config.h])
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
|
||||
AC_CANONICAL_HOST
|
||||
|
||||
AC_LANG([C])
|
||||
|
||||
AC_SUBST(WITH_LIST, [""])
|
||||
|
||||
dnl Fix default variables - "prefix" variable if not specified
|
||||
if test "$prefix" = "NONE"; then
|
||||
prefix="/usr"
|
||||
|
||||
dnl Fix "localstatedir" variable if not specified
|
||||
if test "$localstatedir" = "\${prefix}/var"; then
|
||||
localstatedir="/var"
|
||||
fi
|
||||
dnl Fix "sysconfdir" variable if not specified
|
||||
if test "$sysconfdir" = "\${prefix}/etc"; then
|
||||
sysconfdir="/etc"
|
||||
fi
|
||||
dnl Fix "libdir" variable if not specified
|
||||
if test "$libdir" = "\${exec_prefix}/lib"; then
|
||||
if test -e /usr/lib64; then
|
||||
libdir="/usr/lib64"
|
||||
else
|
||||
libdir="/usr/lib"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if test "$srcdir" = "."; then
|
||||
AC_MSG_NOTICE([building in place srcdir:$srcdir])
|
||||
AC_DEFINE([BUILDING_IN_PLACE], 1, [building in place])
|
||||
else
|
||||
AC_MSG_NOTICE([building out of tree srcdir:$srcdir])
|
||||
fi
|
||||
|
||||
# Checks for programs.
|
||||
|
||||
# check stolen from gnulib/m4/gnu-make.m4
|
||||
if ! ${MAKE-make} --version /cannot/make/this >/dev/null 2>&1; then
|
||||
AC_MSG_ERROR([you don't seem to have GNU make; it is required])
|
||||
fi
|
||||
|
||||
AC_PROG_AWK
|
||||
AC_PROG_GREP
|
||||
AC_PROG_SED
|
||||
AC_PROG_CPP
|
||||
AC_PROG_CC
|
||||
AC_PROG_CC_C99
|
||||
if test "x$ac_cv_prog_cc_c99" = "xno"; then
|
||||
AC_MSG_ERROR(["C99 support is required"])
|
||||
fi
|
||||
AC_PROG_LN_S
|
||||
AC_PROG_INSTALL
|
||||
AC_PROG_MAKE_SET
|
||||
PKG_PROG_PKG_CONFIG
|
||||
AC_PATH_PROG([BASHPATH], [bash])
|
||||
AC_CHECK_PROGS([GROFF], [groff])
|
||||
|
||||
# Checks for typedefs.
|
||||
AC_TYPE_UID_T
|
||||
AC_TYPE_INT16_T
|
||||
AC_TYPE_INT32_T
|
||||
AC_TYPE_INT64_T
|
||||
AC_TYPE_INT8_T
|
||||
AC_TYPE_UINT16_T
|
||||
AC_TYPE_UINT32_T
|
||||
AC_TYPE_UINT64_T
|
||||
AC_TYPE_UINT8_T
|
||||
AC_TYPE_SIZE_T
|
||||
AC_TYPE_SSIZE_T
|
||||
|
||||
# Checks for libraries.
|
||||
PKG_CHECK_MODULES([nss],[nss])
|
||||
PKG_CHECK_MODULES([qb], [libqb])
|
||||
PKG_CHECK_MODULES([corosync_common], [libcorosync_common])
|
||||
PKG_CHECK_MODULES([cmap], [libcmap])
|
||||
PKG_CHECK_MODULES([votequorum], [libvotequorum])
|
||||
|
||||
AC_CONFIG_FILES([Makefile
|
||||
qdevices/Makefile
|
||||
man/Makefile
|
||||
init/Makefile
|
||||
])
|
||||
|
||||
# ===============================================
|
||||
# Helpers
|
||||
# ===============================================
|
||||
|
||||
## helper for CC stuff
|
||||
cc_supports_flag() {
|
||||
BACKUP="$CPPFLAGS"
|
||||
CPPFLAGS="$CPPFLAGS $@ $unknown_warnings_as_errors"
|
||||
AC_MSG_CHECKING([whether $CC supports "$@"])
|
||||
AC_PREPROC_IFELSE([AC_LANG_PROGRAM([])],
|
||||
[RC=0; AC_MSG_RESULT([yes])],
|
||||
[RC=1; AC_MSG_RESULT([no])])
|
||||
CPPFLAGS="$BACKUP"
|
||||
return $RC
|
||||
}
|
||||
|
||||
## local defines
|
||||
PACKAGE_FEATURES=""
|
||||
|
||||
# local options
|
||||
AC_ARG_ENABLE([fatal-warnings],
|
||||
[ --enable-fatal-warnings : enable fatal warnings. ],
|
||||
[ default="no" ])
|
||||
|
||||
AC_ARG_ENABLE([debug],
|
||||
[ --enable-debug : enable debug build. ],
|
||||
[ default="no" ])
|
||||
|
||||
AC_ARG_ENABLE([secure-build],
|
||||
[ --enable-secure-build : enable PIE/RELRO build. ],
|
||||
[],
|
||||
[enable_secure_build="yes"])
|
||||
|
||||
AC_ARG_ENABLE([systemd],
|
||||
[ --enable-systemd : Install systemd service files],,
|
||||
[ enable_systemd="no" ])
|
||||
AM_CONDITIONAL(INSTALL_SYSTEMD, test x$enable_systemd = xyes)
|
||||
|
||||
AC_ARG_WITH([initconfigdir],
|
||||
[AS_HELP_STRING([--with-initconfigdir=DIR],
|
||||
[configuration directory @<:@SYSCONFDIR/sysconfig@:>@])],
|
||||
[INITCONFIGDIR="$withval"],
|
||||
[INITCONFIGDIR='${sysconfdir}/sysconfig'])
|
||||
AC_SUBST([INITCONFIGDIR])
|
||||
|
||||
AC_ARG_WITH([initddir],
|
||||
[ --with-initddir=DIR : path to init script directory. ],
|
||||
[ INITDDIR="$withval" ],
|
||||
[ INITDDIR="$sysconfdir/init.d" ])
|
||||
|
||||
AC_ARG_WITH([systemddir],
|
||||
[ --with-systemddir=DIR : path to systemd unit files directory. ],
|
||||
[ SYSTEMDDIR="$withval" ],
|
||||
[ SYSTEMDDIR="/lib/systemd/system" ])
|
||||
|
||||
AC_ARG_ENABLE([qdevices],
|
||||
[ --disable-qdevices : Quorum devices support ],,
|
||||
[ enable_qdevices="yes" ])
|
||||
AM_CONDITIONAL(BUILD_QDEVICES, test x$enable_qdevices = xyes)
|
||||
AC_ARG_ENABLE([qnetd],
|
||||
[ --disable-qnetd : Quorum Net Daemon support ],,
|
||||
[ enable_qnetd="yes" ])
|
||||
AM_CONDITIONAL(BUILD_QNETD, test x$enable_qnetd = xyes)
|
||||
|
||||
# *FLAGS handling goes here
|
||||
|
||||
ENV_CFLAGS="$CFLAGS"
|
||||
ENV_CPPFLAGS="$CPPFLAGS"
|
||||
ENV_LDFLAGS="$LDFLAGS"
|
||||
|
||||
# debug build stuff
|
||||
if test "x${enable_debug}" = xyes; then
|
||||
AC_DEFINE_UNQUOTED([DEBUG], [1], [Compiling Debugging code])
|
||||
OPT_CFLAGS="-O0"
|
||||
PACKAGE_FEATURES="$PACKAGE_FEATURES debug"
|
||||
else
|
||||
OPT_CFLAGS="-O3"
|
||||
fi
|
||||
|
||||
# gdb flags
|
||||
if test "x${GCC}" = xyes; then
|
||||
GDB_FLAGS="-ggdb3"
|
||||
else
|
||||
GDB_FLAGS="-g"
|
||||
fi
|
||||
|
||||
if test "x${enable_systemd}" = xyes; then
|
||||
PKG_CHECK_MODULES([libsystemd], [libsystemd])
|
||||
AC_DEFINE([HAVE_LIBSYSTEMD], [1], [have systemd interface library])
|
||||
PACKAGE_FEATURES="$PACKAGE_FEATURES systemd"
|
||||
WITH_LIST="$WITH_LIST --with systemd"
|
||||
fi
|
||||
if test "x${enable_qdevices}" = xyes; then
|
||||
PACKAGE_FEATURES="$PACKAGE_FEATURES qdevices"
|
||||
fi
|
||||
if test "x${enable_qnetd}" = xyes; then
|
||||
PACKAGE_FEATURES="$PACKAGE_FEATURES qnetd"
|
||||
fi
|
||||
|
||||
# extra warnings
|
||||
EXTRA_WARNINGS=""
|
||||
|
||||
WARNLIST="
|
||||
all
|
||||
shadow
|
||||
missing-prototypes
|
||||
missing-declarations
|
||||
strict-prototypes
|
||||
declaration-after-statement
|
||||
pointer-arith
|
||||
write-strings
|
||||
cast-align
|
||||
bad-function-cast
|
||||
missing-format-attribute
|
||||
format=2
|
||||
format-security
|
||||
format-nonliteral
|
||||
no-long-long
|
||||
unsigned-char
|
||||
gnu89-inline
|
||||
no-strict-aliasing
|
||||
"
|
||||
|
||||
for j in $WARNLIST; do
|
||||
if cc_supports_flag -W$j; then
|
||||
EXTRA_WARNINGS="$EXTRA_WARNINGS -W$j";
|
||||
fi
|
||||
done
|
||||
|
||||
if test "x${enable_fatal_warnings}" = xyes && \
|
||||
cc_supports_flag -Werror ; then
|
||||
AC_MSG_NOTICE([Enabling Fatal Warnings (-Werror)])
|
||||
WERROR_CFLAGS="-Werror"
|
||||
PACKAGE_FEATURES="$PACKAGE_FEATURES fatal-warnings"
|
||||
else
|
||||
WERROR_CFLAGS=""
|
||||
fi
|
||||
|
||||
if test "x${enable_secure_build}" = xyes; then
|
||||
# stolen from apache configure snippet
|
||||
AC_CACHE_CHECK([whether $CC accepts PIE flags], [ap_cv_cc_pie], [
|
||||
save_CFLAGS=$CFLAGS
|
||||
save_LDFLAGS=$LDFLAGS
|
||||
CFLAGS="$CFLAGS -fPIE"
|
||||
LDFLAGS="$LDFLAGS -pie"
|
||||
AC_TRY_RUN([static int foo[30000]; int main () { return 0; }],
|
||||
[ap_cv_cc_pie=yes], [ap_cv_cc_pie=no], [ap_cv_cc_pie=yes])
|
||||
CFLAGS=$save_CFLAGS
|
||||
LDFLAGS=$save_LDFLAGS
|
||||
])
|
||||
if test "$ap_cv_cc_pie" = "yes"; then
|
||||
SEC_FLAGS="$SEC_FLAGS -fPIE"
|
||||
SEC_LDFLAGS="$SEC_LDFLAGS -pie"
|
||||
PACKAGE_FEATURES="$PACKAGE_FEATURES pie"
|
||||
fi
|
||||
|
||||
# similar to above
|
||||
AC_CACHE_CHECK([whether $CC accepts RELRO flags], [ap_cv_cc_relro], [
|
||||
save_LDFLAGS=$LDFLAGS
|
||||
LDFLAGS="$LDFLAGS -Wl,-z,relro"
|
||||
AC_TRY_RUN([static int foo[30000]; int main () { return 0; }],
|
||||
[ap_cv_cc_relro=yes], [ap_cv_cc_relro=no], [ap_cv_cc_relro=yes])
|
||||
LDFLAGS=$save_LDFLAGS
|
||||
])
|
||||
if test "$ap_cv_cc_relro" = "yes"; then
|
||||
SEC_LDFLAGS="$SEC_LDFLAGS -Wl,-z,relro"
|
||||
PACKAGE_FEATURES="$PACKAGE_FEATURES relro"
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK([whether $CC accepts BINDNOW flags], [ap_cv_cc_bindnow], [
|
||||
save_LDFLAGS=$LDFLAGS
|
||||
LDFLAGS="$LDFLAGS -Wl,-z,now"
|
||||
AC_TRY_RUN([static int foo[30000]; int main () { return 0; }],
|
||||
[ap_cv_cc_bindnow=yes], [ap_cv_cc_bindnow=no], [ap_cv_cc_bindnow=yes])
|
||||
LDFLAGS=$save_LDFLAGS
|
||||
])
|
||||
if test "$ap_cv_cc_bindnow" = "yes"; then
|
||||
SEC_LDFLAGS="$SEC_LDFLAGS -Wl,-z,now"
|
||||
PACKAGE_FEATURES="$PACKAGE_FEATURES bindnow"
|
||||
fi
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK([whether $CC accepts "--as-needed"], [ap_cv_cc_as_needed], [
|
||||
save_LDFLAGS=$LDFLAGS
|
||||
LDFLAGS="$LDFLAGS -Wl,--as-needed"
|
||||
AC_TRY_RUN([static int foo[30000]; int main () { return 0; }],
|
||||
[ap_cv_cc_as_needed=yes], [ap_cv_cc_as_needed=no], [ap_cv_cc_as_needed=yes])
|
||||
LDFLAGS=$save_LDFLAGS
|
||||
])
|
||||
|
||||
# define global include dirs
|
||||
INCLUDE_DIRS="$INCLUDE_DIRS -I\$(top_builddir)/include -I\$(top_srcdir)/include"
|
||||
|
||||
# final build of *FLAGS
|
||||
CFLAGS="$ENV_CFLAGS $lt_prog_compiler_pic $SEC_FLAGS $OPT_CFLAGS $GDB_FLAGS \
|
||||
$EXTRA_WARNINGS \
|
||||
$WERROR_CFLAGS"
|
||||
CPPFLAGS="$ENV_CPPFLAGS $INCLUDE_DIRS"
|
||||
LDFLAGS="$ENV_LDFLAGS $lt_prog_compiler_pic $SEC_LDFLAGS"
|
||||
|
||||
if test "$ap_cv_cc_as_needed" = "yes"; then
|
||||
LDFLAGS="$LDFLAGS -Wl,--as-needed"
|
||||
fi
|
||||
|
||||
# substitute what we need:
|
||||
AC_SUBST([BASHPATH])
|
||||
AC_SUBST([INITDDIR])
|
||||
AC_SUBST([SYSTEMDDIR])
|
||||
AC_SUBST([LOGDIR])
|
||||
AC_SUBST([LOGROTATEDIR])
|
||||
|
||||
AC_SUBST([SOMAJOR])
|
||||
AC_SUBST([SOMINOR])
|
||||
AC_SUBST([SOMICRO])
|
||||
AC_SUBST([SONAME])
|
||||
|
||||
AC_SUBST([NSS_LDFLAGS])
|
||||
|
||||
AM_CONDITIONAL(BUILD_HTML_DOCS, test -n "${GROFF}")
|
||||
|
||||
AC_DEFINE_UNQUOTED([LOCALSTATEDIR], "$(eval echo ${localstatedir})", [localstate directory])
|
||||
|
||||
COROSYSCONFDIR=${sysconfdir}/corosync
|
||||
AC_SUBST([COROSYSCONFDIR])
|
||||
AC_DEFINE_UNQUOTED([COROSYSCONFDIR], "$(eval echo ${COROSYSCONFDIR})", [corosync-qdevice config directory])
|
||||
|
||||
AC_DEFINE_UNQUOTED([PACKAGE_FEATURES], "${PACKAGE_FEATURES}", [corosync-qdevice built-in features])
|
||||
|
||||
AC_OUTPUT
|
||||
|
||||
AC_MSG_RESULT([])
|
||||
AC_MSG_RESULT([$PACKAGE configuration:])
|
||||
AC_MSG_RESULT([ Version = ${VERSION}])
|
||||
AC_MSG_RESULT([ Prefix = ${prefix}])
|
||||
AC_MSG_RESULT([ Executables = ${sbindir}])
|
||||
AC_MSG_RESULT([ Man pages = ${mandir}])
|
||||
AC_MSG_RESULT([ Doc dir = ${docdir}])
|
||||
AC_MSG_RESULT([ Libraries = ${libdir}])
|
||||
AC_MSG_RESULT([ Header files = ${includedir}])
|
||||
AC_MSG_RESULT([ Arch-independent files = ${datadir}])
|
||||
AC_MSG_RESULT([ State information = ${localstatedir}])
|
||||
AC_MSG_RESULT([ System configuration = ${sysconfdir}])
|
||||
AC_MSG_RESULT([ System init.d directory = ${INITDDIR}])
|
||||
AC_MSG_RESULT([ System systemd directory = ${SYSTEMDDIR}])
|
||||
AC_MSG_RESULT([ Log directory = ${LOGDIR}])
|
||||
AC_MSG_RESULT([ Log rotate directory = ${LOGROTATEDIR}])
|
||||
AC_MSG_RESULT([ corosync config dir = ${COROSYSCONFDIR}])
|
||||
AC_MSG_RESULT([ init config directory = ${INITCONFIGDIR}])
|
||||
AC_MSG_RESULT([ Features = ${PACKAGE_FEATURES}])
|
||||
AC_MSG_RESULT([])
|
||||
AC_MSG_RESULT([$PACKAGE build info:])
|
||||
AC_MSG_RESULT([ Default optimization = ${OPT_CFLAGS}])
|
||||
AC_MSG_RESULT([ Default debug options = ${GDB_CFLAGS}])
|
||||
AC_MSG_RESULT([ Extra compiler warnings = ${EXTRA_WARNING}])
|
||||
AC_MSG_RESULT([ Env. defined CFLAG = ${ENV_CFLAGS}])
|
||||
AC_MSG_RESULT([ Env. defined CPPFLAGS = ${ENV_CPPFLAGS}])
|
||||
AC_MSG_RESULT([ Env. defined LDFLAGS = ${ENV_LDFLAGS}])
|
||||
AC_MSG_RESULT([ Fatal War. CFLAGS = ${WERROR_CFLAGS}])
|
||||
AC_MSG_RESULT([ Final CFLAGS = ${CFLAGS}])
|
||||
AC_MSG_RESULT([ Final CPPFLAGS = ${CPPFLAGS}])
|
||||
AC_MSG_RESULT([ Final LDFLAGS = ${LDFLAGS}])
|
212
corosync-qdevice.spec.in
Normal file
212
corosync-qdevice.spec.in
Normal file
@ -0,0 +1,212 @@
|
||||
@ALPHATAG@
|
||||
@NUMCOMM@
|
||||
@DIRTY@
|
||||
|
||||
# Conditionals
|
||||
# Invoke "rpmbuild --without <feature>" or "rpmbuild --with <feature>"
|
||||
# to disable or enable specific features
|
||||
%bcond_with runautogen
|
||||
%bcond_with systemd
|
||||
|
||||
%global gitver %{?numcomm:.%{numcomm}}%{?alphatag:.%{alphatag}}%{?dirty:.%{dirty}}
|
||||
%global gittarver %{?numcomm:.%{numcomm}}%{?alphatag:-%{alphatag}}%{?dirty:-%{dirty}}
|
||||
|
||||
Name: corosync-qdevice
|
||||
Summary: The Corosync Cluster Engine Qdevice
|
||||
Version: @version@
|
||||
Release: 1%{?gitver}%{?dist}
|
||||
License: BSD
|
||||
Group: System Environment/Base
|
||||
URL: https://github.com/corosync/corosync-qdevice
|
||||
Source0: https://github.com/corosync/corosync-qdevice/releases/download/v%{version}%{?gittarver}/%{name}-%{version}%{?gittarver}.tar.gz
|
||||
|
||||
# Runtime bits
|
||||
Requires: corosync >= 2.4.0
|
||||
Requires: corosynclib >= 2.4.0
|
||||
Requires: nss-tools
|
||||
|
||||
%if %{with systemd}
|
||||
Requires(post): systemd
|
||||
Requires(preun): systemd
|
||||
Requires(postun): systemd
|
||||
%else
|
||||
Requires(post): /sbin/chkconfig
|
||||
Requires(preun): /sbin/chkconfig
|
||||
%endif
|
||||
|
||||
# Build bits
|
||||
BuildRequires: corosynclib-devel
|
||||
BuildRequires: groff
|
||||
BuildRequires: libqb-devel
|
||||
BuildRequires: nss-devel
|
||||
BuildRequires: sed
|
||||
|
||||
%if %{with runautogen}
|
||||
BuildRequires: autoconf automake libtool
|
||||
%endif
|
||||
%if %{with systemd}
|
||||
BuildRequires: systemd-units
|
||||
BuildRequires: systemd-devel
|
||||
%endif
|
||||
|
||||
BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX)
|
||||
|
||||
%prep
|
||||
%setup -q -n %{name}-%{version}%{?gittarver}
|
||||
|
||||
%build
|
||||
%if %{with runautogen}
|
||||
./autogen.sh
|
||||
%endif
|
||||
|
||||
%{configure} \
|
||||
%if %{with systemd}
|
||||
--enable-systemd \
|
||||
%endif
|
||||
--enable-qdevices \
|
||||
--enable-qnetd \
|
||||
--with-initddir=%{_initrddir} \
|
||||
--with-systemddir=%{_unitdir}
|
||||
|
||||
make %{_smp_mflags}
|
||||
|
||||
%install
|
||||
rm -rf %{buildroot}
|
||||
|
||||
make install DESTDIR=%{buildroot}
|
||||
|
||||
## tree fixup
|
||||
# drop docs and html docs for now
|
||||
rm -rf %{buildroot}%{_docdir}/*
|
||||
mkdir -p %{buildroot}%{_sysconfdir}/sysconfig
|
||||
# /etc/sysconfig/corosync-qdevice
|
||||
install -m 644 init/corosync-qdevice.sysconfig.example \
|
||||
%{buildroot}%{_sysconfdir}/sysconfig/corosync-qdevice
|
||||
# /etc/sysconfig/corosync-qnetd
|
||||
install -m 644 init/corosync-qnetd.sysconfig.example \
|
||||
%{buildroot}%{_sysconfdir}/sysconfig/corosync-qnetd
|
||||
|
||||
%if %{with systemd}
|
||||
sed -i -e 's/^#User=/User=/' \
|
||||
%{buildroot}%{_unitdir}/corosync-qnetd.service
|
||||
%else
|
||||
sed -i -e 's/^COROSYNC_QNETD_RUNAS=""$/COROSYNC_QNETD_RUNAS="coroqnetd"/' \
|
||||
%{buildroot}%{_sysconfdir}/sysconfig/corosync-qnetd
|
||||
%endif
|
||||
|
||||
%clean
|
||||
rm -rf %{buildroot}
|
||||
|
||||
%description
|
||||
This package contains the Corosync Cluster Engine Qdevice, script for creating
|
||||
NSS certificates and an init script.
|
||||
|
||||
%post
|
||||
%if %{with systemd} && 0%{?systemd_post:1}
|
||||
%systemd_post corosync-qdevice.service
|
||||
%else
|
||||
if [ $1 -eq 1 ]; then
|
||||
/sbin/chkconfig --add corosync-qdevice || :
|
||||
fi
|
||||
%endif
|
||||
|
||||
%preun
|
||||
%if %{with systemd} && 0%{?systemd_preun:1}
|
||||
%systemd_preun corosync-qdevice.service
|
||||
%else
|
||||
if [ $1 -eq 0 ]; then
|
||||
/sbin/service corosync-qdevice stop &>/dev/null || :
|
||||
/sbin/chkconfig --del corosync-qdevice || :
|
||||
fi
|
||||
%endif
|
||||
|
||||
%postun
|
||||
%if %{with systemd} && 0%{?systemd_postun:1}
|
||||
%systemd_postun
|
||||
%endif
|
||||
|
||||
%files
|
||||
%defattr(-,root,root,-)
|
||||
%dir %{_sysconfdir}/corosync/qdevice
|
||||
%dir %config(noreplace) %{_sysconfdir}/corosync/qdevice/net
|
||||
%dir %{_localstatedir}/run/corosync-qdevice
|
||||
%{_sbindir}/corosync-qdevice
|
||||
%{_sbindir}/corosync-qdevice-net-certutil
|
||||
%{_sbindir}/corosync-qdevice-tool
|
||||
%config(noreplace) %{_sysconfdir}/sysconfig/corosync-qdevice
|
||||
%if %{with systemd}
|
||||
%{_unitdir}/corosync-qdevice.service
|
||||
%else
|
||||
%{_initrddir}/corosync-qdevice
|
||||
%endif
|
||||
%{_mandir}/man8/corosync-qdevice-tool.8*
|
||||
%{_mandir}/man8/corosync-qdevice-net-certutil.8*
|
||||
%{_mandir}/man8/corosync-qdevice.8*
|
||||
|
||||
%package -n corosync-qnetd
|
||||
Summary: The Corosync Cluster Engine Qdevice Network Daemon
|
||||
Group: System Environment/Base
|
||||
Requires: nss-tools
|
||||
Requires(pre): shadow-utils
|
||||
Requires(pre): /usr/sbin/useradd
|
||||
|
||||
%if %{with systemd}
|
||||
Requires(post): systemd
|
||||
Requires(preun): systemd
|
||||
Requires(postun): systemd
|
||||
%endif
|
||||
|
||||
%description -n corosync-qnetd
|
||||
This package contains the Corosync Cluster Engine Qdevice Network Daemon,
|
||||
script for creating NSS certificates and an init script.
|
||||
|
||||
%pre -n corosync-qnetd
|
||||
getent group coroqnetd >/dev/null || groupadd -r coroqnetd
|
||||
getent passwd coroqnetd >/dev/null || \
|
||||
useradd -r -g coroqnetd -d / -s /sbin/nologin -c "User for corosync-qnetd" coroqnetd
|
||||
exit 0
|
||||
|
||||
%post -n corosync-qnetd
|
||||
%if %{with systemd} && 0%{?systemd_post:1}
|
||||
%systemd_post corosync-qnetd.service
|
||||
%else
|
||||
if [ $1 -eq 1 ]; then
|
||||
/sbin/chkconfig --add corosync-qnetd || :
|
||||
fi
|
||||
%endif
|
||||
|
||||
%preun -n corosync-qnetd
|
||||
%if %{with systemd} && 0%{?systemd_preun:1}
|
||||
%systemd_preun corosync-qnetd.service
|
||||
%else
|
||||
if [ $1 -eq 0 ]; then
|
||||
/sbin/service corosync-qnetd stop &>/dev/null || :
|
||||
/sbin/chkconfig --del corosync-qnetd || :
|
||||
fi
|
||||
%endif
|
||||
|
||||
%postun -n corosync-qnetd
|
||||
%if %{with systemd} && 0%{?systemd_postun:1}
|
||||
%systemd_postun
|
||||
%endif
|
||||
|
||||
%files -n corosync-qnetd
|
||||
%defattr(-,root,root,-)
|
||||
%dir %config(noreplace) %attr(770, coroqnetd, coroqnetd) %{_sysconfdir}/corosync/qnetd
|
||||
%dir %attr(770, coroqnetd, coroqnetd) %{_localstatedir}/run/corosync-qnetd
|
||||
%{_bindir}/corosync-qnetd
|
||||
%{_bindir}/corosync-qnetd-certutil
|
||||
%{_bindir}/corosync-qnetd-tool
|
||||
%config(noreplace) %{_sysconfdir}/sysconfig/corosync-qnetd
|
||||
%if %{with systemd}
|
||||
%{_unitdir}/corosync-qnetd.service
|
||||
%else
|
||||
%{_initrddir}/corosync-qnetd
|
||||
%endif
|
||||
%{_mandir}/man8/corosync-qnetd-tool.8*
|
||||
%{_mandir}/man8/corosync-qnetd-certutil.8*
|
||||
%{_mandir}/man8/corosync-qnetd.8*
|
||||
|
||||
%changelog
|
||||
* @date@ Autotools generated version <nobody@nowhere.org> - @version@-1-@numcomm@.@alphatag@.@dirty@
|
||||
- Autotools generated version
|
8
init/.gitignore
vendored
Normal file
8
init/.gitignore
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
corosync
|
||||
corosync-notifyd
|
||||
corosync.service
|
||||
corosync-notifyd.service
|
||||
corosync-qnetd
|
||||
corosync-qnetd.service
|
||||
corosync-qdevice
|
||||
corosync-qdevice.service
|
83
init/Makefile.am
Normal file
83
init/Makefile.am
Normal file
@ -0,0 +1,83 @@
|
||||
# Copyright (c) 2004 MontaVista Software, Inc.
|
||||
# Copyright (c) 2009 - 2018 Red Hat, Inc.
|
||||
#
|
||||
# Authors: Jan Friesse (jfriesse@redhat.com)
|
||||
# Steven Dake (sdake@redhat.com)
|
||||
# Fabio M. Di Nitto (fdinitto@redhat.com)
|
||||
#
|
||||
# All rights reserved.
|
||||
#
|
||||
# This software licensed under BSD license, the text of which follows:
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# - Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# - Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from this
|
||||
# software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
# THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
||||
|
||||
EXTRA_DIST = corosync-qdevice.sysconfig.example corosync-qdevice.in \
|
||||
corosync-qdevice.service.in \
|
||||
corosync-qnetd.sysconfig.example corosync-qnetd.in \
|
||||
corosync-qnetd.service.in
|
||||
|
||||
if INSTALL_SYSTEMD
|
||||
systemdconfdir = $(SYSTEMDDIR)
|
||||
systemdconf_DATA =
|
||||
else
|
||||
initscriptdir = $(INITDDIR)
|
||||
initscript_SCRIPTS =
|
||||
endif
|
||||
|
||||
if BUILD_QDEVICES
|
||||
if INSTALL_SYSTEMD
|
||||
systemdconf_DATA += corosync-qdevice.service
|
||||
else
|
||||
initscript_SCRIPTS += corosync-qdevice
|
||||
endif
|
||||
endif
|
||||
|
||||
if BUILD_QNETD
|
||||
if INSTALL_SYSTEMD
|
||||
systemdconf_DATA += corosync-qnetd.service
|
||||
else
|
||||
initscript_SCRIPTS += corosync-qnetd
|
||||
endif
|
||||
endif
|
||||
|
||||
%: %.in Makefile
|
||||
rm -f $@-t $@
|
||||
cat $< | sed \
|
||||
-e 's#@''SBINDIR@#$(sbindir)#g' \
|
||||
-e 's#@''BINDIR@#$(bindir)#g' \
|
||||
-e 's#@''SYSCONFDIR@#$(sysconfdir)#g' \
|
||||
-e 's#@''INITCONFIGDIR@#$(INITCONFIGDIR)#g' \
|
||||
-e 's#@''INITDDIR@#$(INITDDIR)#g' \
|
||||
-e 's#@''LOCALSTATEDIR@#$(localstatedir)#g' \
|
||||
-e 's#@''BASHPATH@#${BASHPATH}#g' \
|
||||
> $@-t
|
||||
mv $@-t $@
|
||||
|
||||
all-local: $(initscript_SCRIPTS) $(systemdconf_DATA) $(upstartconf_DATA)
|
||||
|
||||
clean-local:
|
||||
rm -rf $(initscript_SCRIPTS) $(systemdconf_DATA) $(upstartconf_DATA)
|
164
init/corosync-qdevice.in
Executable file
164
init/corosync-qdevice.in
Executable file
@ -0,0 +1,164 @@
|
||||
#!@BASHPATH@
|
||||
|
||||
# Authors:
|
||||
# Jan Friesse <jfriesse@redhat.com>
|
||||
#
|
||||
# License: Revised BSD
|
||||
|
||||
# chkconfig: - 20 80
|
||||
# description: Corosync Qdevice daemon
|
||||
# processname: corosync-qdevice
|
||||
#
|
||||
### BEGIN INIT INFO
|
||||
# Provides: corosync-qdevice
|
||||
# Required-Start: corosync
|
||||
# Required-Stop: corosync
|
||||
# Default-Start:
|
||||
# Default-Stop:
|
||||
# Short-Description: Starts and stops Corosync Qdevice daemon.
|
||||
# Description: Starts and stops Corosync Qdevice daemon.
|
||||
### END INIT INFO
|
||||
|
||||
desc="Corosync Qdevice daemon"
|
||||
prog="corosync-qdevice"
|
||||
|
||||
# set secure PATH
|
||||
PATH="/sbin:/bin:/usr/sbin:/usr/bin:@SBINDIR@"
|
||||
|
||||
success()
|
||||
{
|
||||
echo -ne "[ OK ]\r"
|
||||
}
|
||||
|
||||
failure()
|
||||
{
|
||||
echo -ne "[FAILED]\r"
|
||||
}
|
||||
|
||||
status()
|
||||
{
|
||||
pid=$(pidof $1 2>/dev/null)
|
||||
res=$?
|
||||
if [ $res -ne 0 ]; then
|
||||
echo "$1 is stopped"
|
||||
else
|
||||
echo "$1 (pid $pid) is running..."
|
||||
fi
|
||||
return $res
|
||||
}
|
||||
|
||||
[ -f @INITCONFIGDIR@/$prog ] && . @INITCONFIGDIR@/$prog
|
||||
|
||||
case '@INITCONFIGDIR@' in
|
||||
*/sysconfig) # rpm based distros
|
||||
[ -f @INITDDIR@/functions ] && . @INITDDIR@/functions
|
||||
[ -z "$LOCK_FILE" ] && LOCK_FILE="@LOCALSTATEDIR@/lock/subsys/$prog";;
|
||||
*/default) # deb based distros
|
||||
[ -z "$LOCK_FILE" ] && LOCK_FILE="@LOCALSTATEDIR@/lock/$prog";;
|
||||
esac
|
||||
|
||||
# The version of __pids_pidof in /etc/init.d/functions calls pidof with -x
|
||||
# This means it matches scripts, including this one.
|
||||
# Redefine it here so that status (from the same file) works.
|
||||
# Otherwise simultaneous calls to stop() will loop forever
|
||||
__pids_pidof() {
|
||||
pidof -c -o $$ -o $PPID -o %PPID "$1" || \
|
||||
pidof -c -o $$ -o $PPID -o %PPID "${1##*/}"
|
||||
}
|
||||
|
||||
cluster_disabled_at_boot()
|
||||
{
|
||||
if grep -q nocluster /proc/cmdline && \
|
||||
[ "$(tty)" = "/dev/console" ]; then
|
||||
echo -e "not configured to run at boot"
|
||||
failure
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
start()
|
||||
{
|
||||
echo -n "Starting $desc ($prog): "
|
||||
|
||||
! cluster_disabled_at_boot && return
|
||||
|
||||
# most recent distributions use tmpfs for @LOCALSTATEDIR@/run
|
||||
# to avoid to clean it up on every boot.
|
||||
# they also assume that init scripts will create
|
||||
# required subdirectories for proper operations
|
||||
if [ ! -d "@LOCALSTATEDIR@/run/corosync-qdevice" ];then
|
||||
mkdir -p "@LOCALSTATEDIR@/run/corosync-qdevice"
|
||||
chmod 0770 "@LOCALSTATEDIR@/run/corosync-qdevice"
|
||||
fi
|
||||
|
||||
if status $prog > /dev/null 2>&1; then
|
||||
success
|
||||
else
|
||||
$prog $COROSYNC_QDEVICE_OPTIONS > /dev/null 2>&1
|
||||
|
||||
if [ "$?" != 0 ]; then
|
||||
failure
|
||||
rtrn=1
|
||||
else
|
||||
touch $LOCK_FILE
|
||||
success
|
||||
fi
|
||||
fi
|
||||
echo
|
||||
}
|
||||
|
||||
stop()
|
||||
{
|
||||
! status $prog > /dev/null 2>&1 && return
|
||||
|
||||
echo -n "Signaling $desc ($prog) to terminate: "
|
||||
kill -TERM $(pidof $prog) > /dev/null 2>&1
|
||||
success
|
||||
echo
|
||||
|
||||
echo -n "Waiting for $prog services to unload:"
|
||||
while status $prog > /dev/null 2>&1; do
|
||||
sleep 1
|
||||
echo -n "."
|
||||
done
|
||||
|
||||
rm -f $LOCK_FILE
|
||||
success
|
||||
echo
|
||||
}
|
||||
|
||||
restart()
|
||||
{
|
||||
stop
|
||||
start
|
||||
}
|
||||
|
||||
rtrn=0
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
start
|
||||
;;
|
||||
restart|reload|force-reload)
|
||||
restart
|
||||
;;
|
||||
condrestart|try-restart)
|
||||
if status $prog > /dev/null 2>&1; then
|
||||
restart
|
||||
fi
|
||||
;;
|
||||
status)
|
||||
status $prog
|
||||
rtrn=$?
|
||||
;;
|
||||
stop)
|
||||
stop
|
||||
;;
|
||||
*)
|
||||
echo "usage: $0 {start|stop|restart|reload|force-reload|condrestart|try-restart|status}"
|
||||
rtrn=2
|
||||
;;
|
||||
esac
|
||||
|
||||
exit $rtrn
|
17
init/corosync-qdevice.service.in
Normal file
17
init/corosync-qdevice.service.in
Normal file
@ -0,0 +1,17 @@
|
||||
[Unit]
|
||||
Description=Corosync Qdevice daemon
|
||||
Documentation=man:corosync-qdevice
|
||||
ConditionKernelCommandLine=!nocluster
|
||||
Requires=corosync.service
|
||||
After=corosync.service
|
||||
|
||||
[Service]
|
||||
EnvironmentFile=-@INITCONFIGDIR@/corosync-qdevice
|
||||
ExecStart=@SBINDIR@/corosync-qdevice -f $COROSYNC_QDEVICE_OPTIONS
|
||||
Type=notify
|
||||
Restart=on-abnormal
|
||||
RuntimeDirectory=corosync-qdevice
|
||||
RuntimeDirectoryMode=0770
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
6
init/corosync-qdevice.sysconfig.example
Normal file
6
init/corosync-qdevice.sysconfig.example
Normal file
@ -0,0 +1,6 @@
|
||||
# Corosync Qdevice daemon init script configuration file
|
||||
|
||||
# COROSYNC_QDEVICE_OPTIONS specifies options passed to corosync-qdevice command
|
||||
# (default is no options).
|
||||
# See "man corosync-qdevice" for detailed descriptions of the options.
|
||||
COROSYNC_QDEVICE_OPTIONS=""
|
171
init/corosync-qnetd.in
Executable file
171
init/corosync-qnetd.in
Executable file
@ -0,0 +1,171 @@
|
||||
#!@BASHPATH@
|
||||
|
||||
# Authors:
|
||||
# Jan Friesse <jfriesse@redhat.com>
|
||||
#
|
||||
# License: Revised BSD
|
||||
|
||||
# chkconfig: - 20 80
|
||||
# description: Corosync Qdevice Network daemon
|
||||
# processname: corosync-qnetd
|
||||
#
|
||||
### BEGIN INIT INFO
|
||||
# Provides: corosync-qnetd
|
||||
# Required-Start: $network $syslog
|
||||
# Required-Stop: $network $syslog
|
||||
# Default-Start:
|
||||
# Default-Stop:
|
||||
# Short-Description: Starts and stops Corosync Qdevice Network daemon.
|
||||
# Description: Starts and stops Corosync Qdevice Network daemon.
|
||||
### END INIT INFO
|
||||
|
||||
desc="Corosync Qdevice Network daemon"
|
||||
prog="corosync-qnetd"
|
||||
|
||||
# set secure PATH
|
||||
PATH="/sbin:/bin:/usr/sbin:/usr/bin:@SBINDIR@"
|
||||
|
||||
success()
|
||||
{
|
||||
echo -ne "[ OK ]\r"
|
||||
}
|
||||
|
||||
failure()
|
||||
{
|
||||
echo -ne "[FAILED]\r"
|
||||
}
|
||||
|
||||
status()
|
||||
{
|
||||
pid=$(pidof $1 2>/dev/null)
|
||||
res=$?
|
||||
if [ $res -ne 0 ]; then
|
||||
echo "$1 is stopped"
|
||||
else
|
||||
echo "$1 (pid $pid) is running..."
|
||||
fi
|
||||
return $res
|
||||
}
|
||||
|
||||
[ -f @INITCONFIGDIR@/$prog ] && . @INITCONFIGDIR@/$prog
|
||||
|
||||
case '@INITCONFIGDIR@' in
|
||||
*/sysconfig) # rpm based distros
|
||||
[ -f @INITDDIR@/functions ] && . @INITDDIR@/functions
|
||||
[ -z "$LOCK_FILE" ] && LOCK_FILE="@LOCALSTATEDIR@/lock/subsys/$prog";;
|
||||
*/default) # deb based distros
|
||||
[ -z "$LOCK_FILE" ] && LOCK_FILE="@LOCALSTATEDIR@/lock/$prog";;
|
||||
esac
|
||||
|
||||
# The version of __pids_pidof in /etc/init.d/functions calls pidof with -x
|
||||
# This means it matches scripts, including this one.
|
||||
# Redefine it here so that status (from the same file) works.
|
||||
# Otherwise simultaneous calls to stop() will loop forever
|
||||
__pids_pidof() {
|
||||
pidof -c -o $$ -o $PPID -o %PPID "$1" || \
|
||||
pidof -c -o $$ -o $PPID -o %PPID "${1##*/}"
|
||||
}
|
||||
|
||||
cluster_disabled_at_boot()
|
||||
{
|
||||
if grep -q nocluster /proc/cmdline && \
|
||||
[ "$(tty)" = "/dev/console" ]; then
|
||||
echo -e "not configured to run at boot"
|
||||
failure
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
start()
|
||||
{
|
||||
echo -n "Starting $desc ($prog): "
|
||||
|
||||
! cluster_disabled_at_boot && return
|
||||
|
||||
# most recent distributions use tmpfs for @LOCALSTATEDIR@/run
|
||||
# to avoid to clean it up on every boot.
|
||||
# they also assume that init scripts will create
|
||||
# required subdirectories for proper operations
|
||||
if [ ! -d "@LOCALSTATEDIR@/run/corosync-qnetd" ];then
|
||||
mkdir -p "@LOCALSTATEDIR@/run/corosync-qnetd"
|
||||
chmod 0770 "@LOCALSTATEDIR@/run/corosync-qnetd"
|
||||
if [ ! -z "$COROSYNC_QNETD_RUNAS" ];then
|
||||
chown "$COROSYNC_QNETD_RUNAS:$COROSYNC_QNETD_RUNAS" "@LOCALSTATEDIR@/run/corosync-qnetd"
|
||||
fi
|
||||
fi
|
||||
|
||||
if status $prog > /dev/null 2>&1; then
|
||||
success
|
||||
else
|
||||
if [ -z "$COROSYNC_QNETD_RUNAS" ];then
|
||||
$prog $COROSYNC_QNETD_OPTIONS > /dev/null 2>&1
|
||||
else
|
||||
runuser -s @BASHPATH@ $COROSYNC_QNETD_RUNAS -c "$prog $COROSYNC_QNETD_OPTIONS > /dev/null 2>&1"
|
||||
fi
|
||||
|
||||
if [ "$?" != 0 ]; then
|
||||
failure
|
||||
rtrn=1
|
||||
else
|
||||
touch $LOCK_FILE
|
||||
success
|
||||
fi
|
||||
fi
|
||||
echo
|
||||
}
|
||||
|
||||
stop()
|
||||
{
|
||||
! status $prog > /dev/null 2>&1 && return
|
||||
|
||||
echo -n "Signaling $desc ($prog) to terminate: "
|
||||
kill -TERM $(pidof $prog) > /dev/null 2>&1
|
||||
success
|
||||
echo
|
||||
|
||||
echo -n "Waiting for $prog services to unload:"
|
||||
while status $prog > /dev/null 2>&1; do
|
||||
sleep 1
|
||||
echo -n "."
|
||||
done
|
||||
|
||||
rm -f $LOCK_FILE
|
||||
success
|
||||
echo
|
||||
}
|
||||
|
||||
restart()
|
||||
{
|
||||
stop
|
||||
start
|
||||
}
|
||||
|
||||
rtrn=0
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
start
|
||||
;;
|
||||
restart|reload|force-reload)
|
||||
restart
|
||||
;;
|
||||
condrestart|try-restart)
|
||||
if status $prog > /dev/null 2>&1; then
|
||||
restart
|
||||
fi
|
||||
;;
|
||||
status)
|
||||
status $prog
|
||||
rtrn=$?
|
||||
;;
|
||||
stop)
|
||||
stop
|
||||
;;
|
||||
*)
|
||||
echo "usage: $0 {start|stop|restart|reload|force-reload|condrestart|try-restart|status}"
|
||||
rtrn=2
|
||||
;;
|
||||
esac
|
||||
|
||||
exit $rtrn
|
19
init/corosync-qnetd.service.in
Normal file
19
init/corosync-qnetd.service.in
Normal file
@ -0,0 +1,19 @@
|
||||
[Unit]
|
||||
Description=Corosync Qdevice Network daemon
|
||||
Documentation=man:corosync-qnetd
|
||||
ConditionKernelCommandLine=!nocluster
|
||||
Requires=network-online.target
|
||||
After=network-online.target
|
||||
|
||||
[Service]
|
||||
EnvironmentFile=-@INITCONFIGDIR@/corosync-qnetd
|
||||
ExecStart=@BINDIR@/corosync-qnetd -f $COROSYNC_QNETD_OPTIONS
|
||||
Type=notify
|
||||
Restart=on-abnormal
|
||||
# Uncomment and set user who should be used for executing qnetd
|
||||
#User=coroqnetd
|
||||
RuntimeDirectory=corosync-qnetd
|
||||
RuntimeDirectoryMode=0770
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
13
init/corosync-qnetd.sysconfig.example
Normal file
13
init/corosync-qnetd.sysconfig.example
Normal file
@ -0,0 +1,13 @@
|
||||
# Corosync Qdevice Network daemon init script configuration file
|
||||
|
||||
# COROSYNC_QNETD_OPTIONS specifies options passed to corosync-qnetd command
|
||||
# (default is no options).
|
||||
# See "man corosync-qnetd" for detailed descriptions of the options.
|
||||
COROSYNC_QNETD_OPTIONS=""
|
||||
|
||||
# COROSYNC_QNETD_RUNAS specifies user under which qnetd daemon should be running
|
||||
# (not set or empty is default and means "user who executes init script")
|
||||
# Make sure to set correct owner of directories /etc/corosync/qnetd and
|
||||
# /var/run/corosync-qnetd
|
||||
# This has no effect if systemd unit is used (you have to change unit file)
|
||||
COROSYNC_QNETD_RUNAS=""
|
2
man/.gitignore
vendored
Normal file
2
man/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
*.html
|
||||
*.3
|
92
man/Makefile.am
Normal file
92
man/Makefile.am
Normal file
@ -0,0 +1,92 @@
|
||||
# Copyright (c) 2004 MontaVista Software, Inc.
|
||||
# Copyright (c) 2009 - 2018 Red Hat, Inc.
|
||||
#
|
||||
# Authors: Jan Friesse (jfriesse@redhat.com)
|
||||
# Steven Dake (sdake@redhat.com)
|
||||
# Fabio M. Di Nitto (fdinitto@redhat.com)
|
||||
#
|
||||
# All rights reserved.
|
||||
#
|
||||
# This software licensed under BSD license, the text of which follows:
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# - Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# - Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from this
|
||||
# software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
# THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
||||
|
||||
qnetd_man = corosync-qnetd-tool.8 \
|
||||
corosync-qnetd-certutil.8 \
|
||||
corosync-qnetd.8
|
||||
|
||||
qdevices_man = corosync-qdevice-tool.8 \
|
||||
corosync-qdevice-net-certutil.8 \
|
||||
corosync-qdevice.8
|
||||
|
||||
EXTRA_DIST = $(qnetd_man) \
|
||||
$(qdevices_man)
|
||||
|
||||
dist_man_MANS =
|
||||
|
||||
if BUILD_QNETD
|
||||
dist_man_MANS += $(qnetd_man)
|
||||
endif
|
||||
|
||||
if BUILD_QDEVICES
|
||||
dist_man_MANS += $(qdevices_man)
|
||||
endif
|
||||
|
||||
HTML_DOCS = $(dist_man_MANS:%=%.html) $(man_MANS:%=%.html)
|
||||
|
||||
# developer man page generation
|
||||
%.3: %.3.in $(autogen_common)
|
||||
@echo Generating $@ man page && \
|
||||
rm -f $@-t-t $@-t $@ && \
|
||||
date="$$(LC_ALL=C date "+%F" $${SOURCE_DATE_EPOCH+-d @$$SOURCE_DATE_EPOCH})" && \
|
||||
awk "{print}(\$$1 ~ /@COMMONIPCERRORS@/){exit 0}" ${top_srcdir}/man/$@.in > $@-t-t && \
|
||||
cat ${top_srcdir}/man/$(autogen_common) >> $@-t-t && \
|
||||
awk -v p=0 "(\$$1 ~ /@COMMONIPCERRORS@/){p = 1} {if(p==1)print}" ${top_srcdir}/man/$@.in >> $@-t-t && \
|
||||
cat $@-t-t | \
|
||||
sed -e 's#@BUILDDATE@#'$$date'#g' \
|
||||
-e 's#@COMMONIPCERRORS@##g' \
|
||||
> $@-t && \
|
||||
rm -f $@-t-t && \
|
||||
mv $@-t $@
|
||||
|
||||
clean-local:
|
||||
rm -rf $(HTML_DOCS) $(autogen_man)
|
||||
|
||||
if BUILD_HTML_DOCS
|
||||
%.html: %
|
||||
$(GROFF) -mandoc -Thtml $^ > $@
|
||||
|
||||
install-data-local:
|
||||
$(INSTALL) -d $(DESTDIR)/${docdir}/html
|
||||
$(INSTALL) -m 644 $(HTML_DOCS) $(DESTDIR)/${docdir}/html/
|
||||
|
||||
uninstall-local:
|
||||
cd $(DESTDIR)/${docdir}/html && rm -f $(HTML_DOCS)
|
||||
rmdir $(DESTDIR)/${docdir}/html 2> /dev/null || :
|
||||
|
||||
all-local: $(HTML_DOCS)
|
||||
endif
|
85
man/corosync-qdevice-net-certutil.8
Normal file
85
man/corosync-qdevice-net-certutil.8
Normal file
@ -0,0 +1,85 @@
|
||||
.\"/*
|
||||
.\" * Copyright (C) 2016 Red Hat, Inc.
|
||||
.\" *
|
||||
.\" * All rights reserved.
|
||||
.\" *
|
||||
.\" * Author: Jan Friesse <jfriesse@redhat.com>
|
||||
.\" *
|
||||
.\" * This software licensed under BSD license, the text of which follows:
|
||||
.\" *
|
||||
.\" * Redistribution and use in source and binary forms, with or without
|
||||
.\" * modification, are permitted provided that the following conditions are met:
|
||||
.\" *
|
||||
.\" * - Redistributions of source code must retain the above copyright notice,
|
||||
.\" * this list of conditions and the following disclaimer.
|
||||
.\" * - Redistributions in binary form must reproduce the above copyright notice,
|
||||
.\" * this list of conditions and the following disclaimer in the documentation
|
||||
.\" * and/or other materials provided with the distribution.
|
||||
.\" * - Neither the name of Red Hat, Inc. nor the names of its
|
||||
.\" * contributors may be used to endorse or promote products derived from this
|
||||
.\" * software without specific prior written permission.
|
||||
.\" *
|
||||
.\" * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
.\" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
.\" * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
.\" * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
.\" * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
.\" * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
.\" * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
.\" * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
.\" * THE POSSIBILITY OF SUCH DAMAGE.
|
||||
.\" */
|
||||
.TH COROSYNC-QDEVICE-NET-CERTUTIL 8 2016-06-28
|
||||
.SH NAME
|
||||
corosync-qdevice-net-certutil - tool to generate qdevice model net TLS certificates
|
||||
.SH SYNOPSIS
|
||||
.B "corosync-qdevice-net-certutil [-i|-m|-M|-r|-s|-Q] [-c certificate] [-n cluster_name]"
|
||||
.SH DESCRIPTION
|
||||
.B corosync-qdevice-net-certutil
|
||||
is a frontend for NSS certutil used for generating client certificate for the net model of
|
||||
qdevice.
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.B -i
|
||||
Initialize the QDevice Net NSS certificate database.
|
||||
The default directory for the database is /etc/corosync/qdevice/net/. This directory
|
||||
has to be writable by the current user. It needs the QNetd CA certificate passed as the
|
||||
.B -c
|
||||
parameter. This certificate can be found on the server running QNetd in the file
|
||||
/etc/corosync/qnetd/nssdb/qnetd-cacert.crt.
|
||||
.TP
|
||||
.B -m
|
||||
Import the cluster certificate and key from a pk12 file.
|
||||
.TP
|
||||
.B -r
|
||||
Generate a certificate request. The certificate request is exported into
|
||||
/etc/corosync/qdevice/net/qdevice-net-node.crq. It is necessary to
|
||||
pass the cluster name using the
|
||||
.B -n
|
||||
parameter. The cluster name has to match the one defined in /etc/corosync/corosync.conf.
|
||||
.TP
|
||||
.B -M
|
||||
Import a signed certificate and export a certificate with private key into
|
||||
pk12 file.
|
||||
.TP
|
||||
.B -Q
|
||||
Use ssh/scp to properly set both
|
||||
.B corosync-qnetd
|
||||
and
|
||||
.B corosync-qdevice
|
||||
certificates on all nodes. It's highly recommended that you use an ssh agent,
|
||||
or ssh/scp will keep asking for a password - roughly 8 times the number of nodes.
|
||||
.TP
|
||||
.B -c
|
||||
File with certificate to load.
|
||||
.TP
|
||||
.B -n
|
||||
Name of the cluster.
|
||||
.SH SEE ALSO
|
||||
.BR corosync-qnetd (8)
|
||||
.BR corosync-qdevice (8)
|
||||
.SH AUTHOR
|
||||
Jan Friesse
|
||||
.PP
|
130
man/corosync-qdevice-tool.8
Normal file
130
man/corosync-qdevice-tool.8
Normal file
@ -0,0 +1,130 @@
|
||||
.\"/*
|
||||
.\" * Copyright (C) 2016-2017 Red Hat, Inc.
|
||||
.\" *
|
||||
.\" * All rights reserved.
|
||||
.\" *
|
||||
.\" * Author: Jan Friesse <jfriesse@redhat.com>
|
||||
.\" *
|
||||
.\" * This software licensed under BSD license, the text of which follows:
|
||||
.\" *
|
||||
.\" * Redistribution and use in source and binary forms, with or without
|
||||
.\" * modification, are permitted provided that the following conditions are met:
|
||||
.\" *
|
||||
.\" * - Redistributions of source code must retain the above copyright notice,
|
||||
.\" * this list of conditions and the following disclaimer.
|
||||
.\" * - Redistributions in binary form must reproduce the above copyright notice,
|
||||
.\" * this list of conditions and the following disclaimer in the documentation
|
||||
.\" * and/or other materials provided with the distribution.
|
||||
.\" * - Neither the name of Red Hat, Inc. nor the names of its
|
||||
.\" * contributors may be used to endorse or promote products derived from this
|
||||
.\" * software without specific prior written permission.
|
||||
.\" *
|
||||
.\" * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
.\" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
.\" * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
.\" * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
.\" * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
.\" * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
.\" * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
.\" * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
.\" * THE POSSIBILITY OF SUCH DAMAGE.
|
||||
.\" */
|
||||
.TH COROSYNC-QDEVICE-TOOL 8 2017-10-17
|
||||
.SH NAME
|
||||
corosync-qdevice-tool \- corosync-qdevice control interface.
|
||||
.SH SYNOPSIS
|
||||
.B "corosync-qdevice-tool [-Hhsv] [-p qdevice_ipc_socket_path]"
|
||||
.SH DESCRIPTION
|
||||
.B corosync-qdevice-tool
|
||||
is a frontend to the internal corosync-qdevice IPC. Its main purpose is to show important
|
||||
information about the current internal state of
|
||||
.B corosync-qdevice.
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.B -H
|
||||
Properly shutdown the
|
||||
.B corosync-qdevice
|
||||
process
|
||||
.TP
|
||||
.B -h
|
||||
Display a short usage text
|
||||
.TP
|
||||
.B -s
|
||||
Display the status of the
|
||||
.B corosync-qdevice
|
||||
process. The output is described in its own section below.
|
||||
.TP
|
||||
.B -v
|
||||
Display more verbose output for the
|
||||
.B -s
|
||||
option.
|
||||
.TP
|
||||
.B -p
|
||||
Path to the
|
||||
.B corosync-qdevice
|
||||
communication socket.
|
||||
|
||||
.SH STATUS COMMAND OUTPUT
|
||||
.nf
|
||||
Qdevice information
|
||||
-------------------
|
||||
Model: Net
|
||||
Node ID: 1
|
||||
HB interval: 10000ms
|
||||
Sync HB interval: 30000ms
|
||||
Configured node list:
|
||||
0 Node ID = 1
|
||||
Heuristics: Enabled
|
||||
Ring ID: 1.a00000000021b48
|
||||
Membership node list: 1
|
||||
Quorate: Yes
|
||||
Quorum node list:
|
||||
0 Node ID = 1, State = member
|
||||
Expected votes: 2
|
||||
Last poll call: 2016-06-24T17:05:20 (cast vote)
|
||||
|
||||
Qdevice-net information
|
||||
----------------------
|
||||
Cluster name: Cluster
|
||||
QNetd host: localhost:5403
|
||||
Connect timeout: 8000ms
|
||||
HB interval: 8000ms
|
||||
VQ vote timer interval: 5000ms
|
||||
TLS: Supported
|
||||
Algorithm: Fifty-Fifty split
|
||||
Tie-breaker: Node with lowest node ID
|
||||
Poll timer running: Yes (cast vote)
|
||||
State: Connected
|
||||
Heuristics result: Pass (regular: Pass, membership: Fail, connect: Fail)
|
||||
TLS active: Yes (client certificate sent)
|
||||
Connected since: 2016-06-24T17:02:35
|
||||
Echo reply received: 2016-06-24T17:05:15
|
||||
.fi
|
||||
|
||||
The output is split into a generic qdevice section and a model specific section.
|
||||
Most of the items are just taken from corosync.conf file. It's helpful to note that the
|
||||
.I Membership node list
|
||||
is the membership list of the current node and should match the quorum node list.
|
||||
.I Last poll call
|
||||
is the timestamp (in iso format) of the last call to the votequorum_qdevice_poll
|
||||
function.
|
||||
|
||||
For model net, it's good to check the
|
||||
.I Poll timer running
|
||||
state. Internally, model net supports 3 states. Not voting (when
|
||||
.I Poll timer running
|
||||
is No, which means
|
||||
.B corosync-qdevice
|
||||
is waiting for
|
||||
.B corosync-qnetd
|
||||
to reply), voting (without cast vote, it means that the
|
||||
.B corosync-qnetd
|
||||
algorithm decides that the current node shouldn't get a vote) and voting (with cast vote).
|
||||
.SH SEE ALSO
|
||||
.BR corosync-qnetd (8)
|
||||
.BR corosync-qdevice (8)
|
||||
.SH AUTHOR
|
||||
Jan Friesse
|
||||
.PP
|
461
man/corosync-qdevice.8
Normal file
461
man/corosync-qdevice.8
Normal file
@ -0,0 +1,461 @@
|
||||
.\"/*
|
||||
.\" * Copyright (C) 2016-2017 Red Hat, Inc.
|
||||
.\" *
|
||||
.\" * All rights reserved.
|
||||
.\" *
|
||||
.\" * Author: Jan Friesse <jfriesse@redhat.com>
|
||||
.\" *
|
||||
.\" * This software licensed under BSD license, the text of which follows:
|
||||
.\" *
|
||||
.\" * Redistribution and use in source and binary forms, with or without
|
||||
.\" * modification, are permitted provided that the following conditions are met:
|
||||
.\" *
|
||||
.\" * - Redistributions of source code must retain the above copyright notice,
|
||||
.\" * this list of conditions and the following disclaimer.
|
||||
.\" * - Redistributions in binary form must reproduce the above copyright notice,
|
||||
.\" * this list of conditions and the following disclaimer in the documentation
|
||||
.\" * and/or other materials provided with the distribution.
|
||||
.\" * - Neither the name of Red Hat, Inc. nor the names of its
|
||||
.\" * contributors may be used to endorse or promote products derived from this
|
||||
.\" * software without specific prior written permission.
|
||||
.\" *
|
||||
.\" * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
.\" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
.\" * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
.\" * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
.\" * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
.\" * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
.\" * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
.\" * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
.\" * THE POSSIBILITY OF SUCH DAMAGE.
|
||||
.\" */
|
||||
.TH COROSYNC-QDEVICE 8 2017-10-17
|
||||
.SH NAME
|
||||
corosync-qdevice \- QDevice daemon
|
||||
.SH SYNOPSIS
|
||||
.B "corosync-qdevice [-dfh] [-S option=value[,option2=value2,...]]"
|
||||
|
||||
.SH DESCRIPTION
|
||||
.B corosync-qdevice
|
||||
is a daemon running on each node of a cluster. It provides a configured
|
||||
number of votes to the
|
||||
quorum subsystem based on a third-party arbitrator's decision. Its primary use
|
||||
is to allow a cluster to sustain more node failures than standard quorum rules allow.
|
||||
It is recommended for clusters with an even number of nodes and highly recommended
|
||||
for 2 node clusters.
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.B -d
|
||||
Forcefully turn on debug information without the need to change corosync.conf.
|
||||
.TP
|
||||
.B -f
|
||||
Do not daemonize, run in the foreground.
|
||||
.TP
|
||||
.B -h
|
||||
Show short help text
|
||||
.TP
|
||||
.B -S
|
||||
Set advanced settings described in its own section below. This option
|
||||
shouldn't be generally used because most of the options are
|
||||
not safe to change.
|
||||
.SH CONFIGURATION
|
||||
.B corosync-qdevice
|
||||
reads its configuration from corosync.conf file.
|
||||
|
||||
The main configuration is within
|
||||
.B quorum.device
|
||||
sub-key. Each model also has its own configuration within a
|
||||
similarly named sub-key.
|
||||
.TP
|
||||
.B model
|
||||
Specifies the model to be used. This parameter is required.
|
||||
.B corosync-qdevice
|
||||
is modular and is able to support multiple different models. The model basically
|
||||
defines what type of arbitrator is used. Currently only
|
||||
.I net
|
||||
is supported.
|
||||
.TP
|
||||
.B timeout
|
||||
Specifies how often
|
||||
.B corosync-qdevice
|
||||
should call the votequorum_poll function. It is also used by the
|
||||
.I net
|
||||
model to adjust
|
||||
its hearbeat timeout. It is recommended that you don't change this value.
|
||||
Default is
|
||||
.IR 10000 .
|
||||
.TP
|
||||
.B sync_timeout
|
||||
Specifies how often
|
||||
.B corosync-qdevice
|
||||
should call the votequorum_poll function during a sync phase. It is recommended that you don't change this value.
|
||||
Default is
|
||||
.IR 30000 .
|
||||
.TP
|
||||
.B votes
|
||||
The number of votes provided to the cluster by qdevice. Default is (number_of_nodes - 1) or generally
|
||||
sum(votes_per_node) - 1.
|
||||
|
||||
.PP
|
||||
.B quorum.device.heuristics
|
||||
subkey holds the configuration of the heuristics. Heuristics are set of commands executed locally on
|
||||
startup, cluster membership change, successful connect to
|
||||
.B corosync-qnetd
|
||||
and optionally also at regular times. Commands are executed in parallel.
|
||||
When all commands finish successfully
|
||||
(their return error code is zero) on time,
|
||||
heuristics have passed, otherwise they have failed. The heuristics result is sent to
|
||||
.B corosync-qnetd
|
||||
and there it's used in calculations to determine which partition should be quorate.
|
||||
.TP
|
||||
.B timeout
|
||||
Specifies maximum time in milliseconds how long
|
||||
.B corosync-qdevice
|
||||
waits till the heuristics commands finish. If some command doesn't finish before the timeout, it's
|
||||
killed and heuristics fail. This timeout is used for heuristics executed at regular times.
|
||||
Default value is half of the
|
||||
.BR quorum.device.timeout ", so"
|
||||
.IR 5000 .
|
||||
.TP
|
||||
.B sync_timeout
|
||||
Similar to quorum.device.heuristics.timeout but used during membership changes. Default
|
||||
value is half of the
|
||||
.BR quorum.device.sync_timeout ", so"
|
||||
.IR 15000 .
|
||||
.TP
|
||||
.B interval
|
||||
Specifies interval between two regular heuristics execution. Default value is
|
||||
3 *
|
||||
.BR quorum.device.timeout ", so"
|
||||
.IR 30000 .
|
||||
.TP
|
||||
.B mode
|
||||
Can be one of
|
||||
.IR on ", " sync " or " off
|
||||
and specifies mode of operation of heuristics. Default is
|
||||
.IR off ,
|
||||
which means heuristics are disabled. When
|
||||
.I sync
|
||||
is set, heuristics are executed only during startup, membership change and when connection
|
||||
to
|
||||
.B corosync-qnetd
|
||||
is established. When heuristics should be running also on regular basis, this option
|
||||
should be set to
|
||||
.I on
|
||||
value.
|
||||
.TP
|
||||
.B exec_NAME
|
||||
defines executables.
|
||||
.I NAME
|
||||
can be arbitrary valid cmap key name string and it has no special meaning.
|
||||
The value of this variable must contain a command to execute. The value is parsed (split)
|
||||
into arguments similarly as Bourne shell would do. Quoting is possible by
|
||||
using backslash and double quotes.
|
||||
|
||||
.PP
|
||||
.B quorum.device.net
|
||||
subkey holds the configuration for
|
||||
.B model
|
||||
.IR net .
|
||||
.TP
|
||||
.B tls
|
||||
Can be one of
|
||||
.IR on ", " off " or " required
|
||||
and specifies if tls should be used.
|
||||
.I on
|
||||
means a connection with TLS is attempted first, but if the server doesn't advertise TLS support
|
||||
then non-TLS will be used.
|
||||
.I off
|
||||
is used then TLS is not required and it's then not even tried. This mode is the
|
||||
only one which doesn't need a properly initialized NSS database.
|
||||
.I required
|
||||
means TLS is required and if the server doesn't support TLS, qdevice will
|
||||
exit with error message. Default is
|
||||
.IR on .
|
||||
.TP
|
||||
.B host
|
||||
Specifies the IP address or host name of the qnetd server to be used. This parameter
|
||||
is required.
|
||||
.TP
|
||||
.B port
|
||||
Specifies TCP port of qnetd server. Default is
|
||||
.IR 5403 .
|
||||
.TP
|
||||
.B algorithm
|
||||
Decision algorithm. Can be one of the
|
||||
.I ffsplit
|
||||
or
|
||||
.IR lms .
|
||||
(actually there are also
|
||||
.I test
|
||||
and
|
||||
.IR 2nodelms ,
|
||||
both of which are mainly for developers and shouldn't be used for production clusters).
|
||||
For a description of what each algorithm means and how the algorithms differ see their
|
||||
individual sections.
|
||||
Default value is
|
||||
.IR ffsplit .
|
||||
.TP
|
||||
.B tie_breaker
|
||||
can be one of
|
||||
.IR lowest ", " highest
|
||||
or valid_node_id (number) values. It's used as a fallback if qdevice has to decide between two or more
|
||||
equal partitions.
|
||||
.I lowest
|
||||
means the partition with the lowest node id is chosen.
|
||||
.I highest
|
||||
means the partition with highest node id is chosen. And valid_node_id means that the partition
|
||||
containing the node with the given node id is chosen.
|
||||
Default is
|
||||
.IR lowest .
|
||||
.TP
|
||||
.B connect_timeout
|
||||
Timeout when
|
||||
.B corosync-qdevice
|
||||
is trying to connect to
|
||||
.B corosync-qnetd
|
||||
host. Default is 0.8 *
|
||||
.BR quorum.sync_timeout .
|
||||
.TP
|
||||
.B force_ip_version
|
||||
can be one of
|
||||
.I 0|4|6
|
||||
and forces the software to use the given IP version.
|
||||
.I 0
|
||||
(default value) means IPv6 is preferred and IPv4 should be used as a fallback.
|
||||
|
||||
.PP
|
||||
Logging configuration is within the
|
||||
.B logging
|
||||
directive.
|
||||
.B corosync-qdevice
|
||||
parses and supports most of the options with exception of
|
||||
.BR to_logfile ", " logfile
|
||||
and
|
||||
.BR logfile_priority .
|
||||
The
|
||||
.B logger_subsys
|
||||
sub-directive can be also used if
|
||||
.B subsys
|
||||
is set to
|
||||
.IR QDEVICE .
|
||||
|
||||
.PP
|
||||
For
|
||||
.B corosync-qdevice
|
||||
to work correctly, the
|
||||
.B nodelist
|
||||
directive has to be used and properly configured. Also the
|
||||
.I net
|
||||
model requires that
|
||||
.B totem.cluster_name
|
||||
option is set.
|
||||
|
||||
.SH MODEL NET TLS CONFIGURATION
|
||||
For
|
||||
.B model
|
||||
.I net
|
||||
to work using TLS, it's necessary to create the NSS database, import Qnetd
|
||||
CA certificate, and get/distribute a valid client certificate.
|
||||
|
||||
If pcs is used (recommended) the following steps are not needed because pcs does them automatically.
|
||||
|
||||
.B corosync-qdevice-net-certutil
|
||||
is the tool to perform required actions semi-automatically. Please consult the help output of
|
||||
it and its man page. For a first time configuration it may make sense to start with the
|
||||
.B -Q
|
||||
option.
|
||||
|
||||
If TLS is not required just edit corosync.conf file and set
|
||||
.B quorum.device.net.tls
|
||||
to
|
||||
.IR off .
|
||||
|
||||
.SH MODEL NET ALGORITHMS
|
||||
Algorithms are used to change behavior of how
|
||||
.B corosync-qnetd
|
||||
provides votes to a given node/partition. Currently there are two algorithms supported.
|
||||
.TP
|
||||
.B ffsplit
|
||||
This one makes sense only for clusters with an even number of nodes. It provides exactly one
|
||||
vote to the partition with the highest number of active nodes. If there are two exactly
|
||||
similar partitions,
|
||||
it provides its vote to the partition with higher score. The score is computed
|
||||
as (number_of_connected_nodes +
|
||||
number_of_connected_nodes_with_passed_heuristics - number_of_connected_nodes_with_failed_heuristics)
|
||||
If the scores are equal, the vote is provided to partition with the most clients connected to the qnetd
|
||||
server. If this number is also equal, then the tie_breaker is used. It is able to transition
|
||||
its vote if the currently active partition becomes partitioned and a non-active partition
|
||||
still has at least 50% of the active nodes. Because of this, a vote is not provided
|
||||
if the qnetd connection is not active.
|
||||
|
||||
To use this algorithm it's required to set the number of votes per node to 1 (default)
|
||||
and the qdevice number of votes has to be also 1. This is achieved by setting
|
||||
.B quorum.device.votes
|
||||
key in corosync.conf file to 1.
|
||||
.TP
|
||||
.B lms
|
||||
Last-man-standing. If the node is the only one left in the cluster that can see the
|
||||
qnetd server then we return a vote.
|
||||
|
||||
If more than one node can see the qnetd server but some nodes can't
|
||||
see each other then the cluster is divided up into 'partitions' based on
|
||||
their ring_id and this algorithm returns a vote to the partition with highest
|
||||
heuristics score (computed the same way as for the
|
||||
.B ffsplit
|
||||
algorithm), or if there is more than 1 partition with equal scores,
|
||||
the largest active partition or,
|
||||
if there is more than 1 equal partition, the partition that contains the tie_breaker
|
||||
node (lowest, highest, etc). For LMS to work, the number
|
||||
of qdevice votes has to be set to default (so just delete
|
||||
.B quorum.device.votes
|
||||
key from corosync.conf).
|
||||
|
||||
.SH ADVANCED SETTINGS
|
||||
Set by using
|
||||
.B -S
|
||||
option. The default value is shown in parentheses) Options
|
||||
beginning with
|
||||
.B net_
|
||||
prefix are specific to
|
||||
.B model
|
||||
.IR net .
|
||||
.TP
|
||||
.B lock_file
|
||||
Lock file location. (/var/run/corosync-qdevice/corosync-qdevice.pid)
|
||||
.TP
|
||||
.B local_socket_file
|
||||
Internal IPC socket file location. (/var/run/corosync-qdevice/corosync-qdevice.sock)
|
||||
.TP
|
||||
.B local_socket_backlog
|
||||
Parameter passed to listen syscall. (10)
|
||||
.TP
|
||||
.B max_cs_try_again
|
||||
How many times to retry the call to a corosync function which has returned CS_ERR_TRY_AGAIN. (10)
|
||||
.TP
|
||||
.B votequorum_device_name
|
||||
Name used for qdevice registration. (Qdevice)
|
||||
.TP
|
||||
.B ipc_max_clients
|
||||
Maximum allowed simultaneous IPC clients. (10)
|
||||
.TP
|
||||
.B ipc_max_receive_size
|
||||
Maximum size of a message received by IPC client. (4096)
|
||||
.TP
|
||||
.B ipc_max_send_size
|
||||
Maximum size of a message allowed to be sent to an IPC client. (65536)
|
||||
.TP
|
||||
.B master_wins
|
||||
Force enable/disable master wins. (default is model)
|
||||
.TP
|
||||
.B heuristics_ipc_max_send_buffers
|
||||
Maximum number of heuristics worker send buffers. (128)
|
||||
.TP
|
||||
.B heuristics_ipc_max_send_receive_size
|
||||
Maximum size of a message allowed to be send to, or received from heuristics worker. (4096)
|
||||
.TP
|
||||
.B heuristics_min_timeout
|
||||
Minimum heuristics timeout accepted by client in ms. (1000)
|
||||
.TP
|
||||
.B heuristics_max_timeout
|
||||
Maximum heuristics timeout accepted by client in ms. (120000)
|
||||
.TP
|
||||
.B heuristics_min_interval
|
||||
Minimum heuristics interval accepted by client in ms. (1000)
|
||||
.TP
|
||||
.B heuristics_max_interval
|
||||
Maximum heuristics interval accepted by client in ms. (3600000)
|
||||
.TP
|
||||
.B heuristics_max_execs
|
||||
Maximum number of exec_ commands. (32)
|
||||
.TP
|
||||
.B heuristics_use_execvp
|
||||
Use execvp instead of execv for executing commands. (off)
|
||||
.TP
|
||||
.B heuristics_max_processes
|
||||
Maximum number of processes running at one time. (160)
|
||||
.TP
|
||||
.B heuristics_kill_list_interval
|
||||
Interval between status is gathered and eventually signal is sent
|
||||
to processes which didn't finished on time in ms. (5000)
|
||||
.TP
|
||||
.B net_nss_db_dir
|
||||
NSS database directory. (/etc/corosync/qdevice/net/nssdb)
|
||||
.TP
|
||||
.B net_initial_msg_receive_size
|
||||
Initial (used during connection parameters negotiation)
|
||||
maximum size of the receive buffer for message (maximum
|
||||
allowed message size received from qnetd). (32768)
|
||||
.TP
|
||||
.B net_initial_msg_send_size
|
||||
Initial (used during connection parameter negotiation)
|
||||
maximum size of one send buffer (message) to be sent to server. (32768)
|
||||
.TP
|
||||
.B net_min_msg_send_size
|
||||
Minimum required size of one send buffer (message) to be sent to server. (32768)
|
||||
.TP
|
||||
.B net_max_msg_receive_size
|
||||
Maximum allowed size of receive buffer for a message sent by server. (16777216)
|
||||
.TP
|
||||
.B net_max_send_buffers
|
||||
Maximum number of send buffers. (10)
|
||||
.TP
|
||||
.B net_nss_qnetd_cn
|
||||
Canonical name of qnetd server certificate. (Qnetd Server)
|
||||
.TP
|
||||
.B net_nss_client_cert_nickname
|
||||
NSS nickname of qdevice client certificate. (Cluster Cert)
|
||||
.TP
|
||||
.B net_heartbeat_interval_min
|
||||
Minimum heartbeat timeout accepted by client in ms. (1000)
|
||||
.TP
|
||||
.B net_heartbeat_interval_max
|
||||
Maximum heartbeat timeout accepted by client in ms. (120000)
|
||||
.TP
|
||||
.B net_min_connect_timeout
|
||||
Minimum connection timeout accepted by client in ms. (1000)
|
||||
.TP
|
||||
.B net_max_connect_timeout
|
||||
Maximum connection timeout accepted by client in ms. (120000)
|
||||
.TP
|
||||
.B net_test_algorithm_enabled
|
||||
Enable test algorithm. (if built with --enable-debug on, otherwise off)
|
||||
|
||||
.SH EXAMPLE
|
||||
Define qdevice with
|
||||
.I net
|
||||
model connecting to qnetd running on qnetd.example.org host, using
|
||||
.I ffsplit
|
||||
algorithm.
|
||||
Heuristics is set to
|
||||
.I sync
|
||||
mode and executes two commands.
|
||||
|
||||
.nf
|
||||
quorum {
|
||||
provider: corosync_votequorum
|
||||
device {
|
||||
votes: 1
|
||||
model: net
|
||||
net {
|
||||
tls: on
|
||||
host: qnetd.example.org
|
||||
algorithm: ffsplit
|
||||
}
|
||||
heuristics {
|
||||
mode: sync
|
||||
exec_ping: /bin/ping -q -c 1 "www.example.org"
|
||||
exec_test_txt_exists: /usr/bin/test -f /tmp/test.txt
|
||||
}
|
||||
}
|
||||
.fi
|
||||
.SH SEE ALSO
|
||||
.BR corosync-qdevice-tool (8)
|
||||
.BR corosync-qdevice-net-certutil (8)
|
||||
.BR corosync-qnetd (8)
|
||||
.BR corosync.conf (5)
|
||||
.SH AUTHOR
|
||||
Jan Friesse
|
||||
.PP
|
73
man/corosync-qnetd-certutil.8
Normal file
73
man/corosync-qnetd-certutil.8
Normal file
@ -0,0 +1,73 @@
|
||||
.\"/*
|
||||
.\" * Copyright (C) 2016 Red Hat, Inc.
|
||||
.\" *
|
||||
.\" * All rights reserved.
|
||||
.\" *
|
||||
.\" * Author: Jan Friesse <jfriesse@redhat.com>
|
||||
.\" *
|
||||
.\" * This software licensed under BSD license, the text of which follows:
|
||||
.\" *
|
||||
.\" * Redistribution and use in source and binary forms, with or without
|
||||
.\" * modification, are permitted provided that the following conditions are met:
|
||||
.\" *
|
||||
.\" * - Redistributions of source code must retain the above copyright notice,
|
||||
.\" * this list of conditions and the following disclaimer.
|
||||
.\" * - Redistributions in binary form must reproduce the above copyright notice,
|
||||
.\" * this list of conditions and the following disclaimer in the documentation
|
||||
.\" * and/or other materials provided with the distribution.
|
||||
.\" * - Neither the name of Red Hat, Inc. nor the names of its
|
||||
.\" * contributors may be used to endorse or promote products derived from this
|
||||
.\" * software without specific prior written permission.
|
||||
.\" *
|
||||
.\" * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
.\" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
.\" * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
.\" * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
.\" * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
.\" * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
.\" * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
.\" * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
.\" * THE POSSIBILITY OF SUCH DAMAGE.
|
||||
.\" */
|
||||
.TH COROSYNC-QNETD-CERTUTIL 8 2016-06-28
|
||||
.SH NAME
|
||||
corosync-qnetd-certutil - tool to generate qnetd TLS certificates
|
||||
.SH SYNOPSIS
|
||||
.B "corosync-qnetd-certutil [-i|-s] [-c certificate] [-n cluster_name]"
|
||||
.SH DESCRIPTION
|
||||
.B corosync-qnetd-certutil
|
||||
is a frontend for the NSS certutil, it is used for generating the QNetd CA (Certificate Authority),
|
||||
server certificate and signing cluster certificate used by
|
||||
.B corosync-qdevice
|
||||
when using the model 'net'.
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.B -i
|
||||
Initialize the QNetd NSS certificate database and generate the QNetd CA and server certificates.
|
||||
The default directory for the database is /etc/corosync/qnetd. This directory must be
|
||||
writeable by the current user. The QNetd CA certificate is also exported into the file
|
||||
/etc/corosync/qnetd/nssdb/qnetd-cacert.crt.
|
||||
.TP
|
||||
.B -s
|
||||
Sign the cluster certificate. It is necessary to pass the cluster name (as
|
||||
configured in corosync.conf) and the certificate request file - see options below.
|
||||
The signed certificate will be written to the
|
||||
file /etc/corosync/qnetd/nssdb/cluster-$ClusterName.crt
|
||||
.TP
|
||||
.B -c
|
||||
Certificate request file to sign.
|
||||
.TP
|
||||
.B -n
|
||||
Name of the cluster.
|
||||
.SH NOTES
|
||||
If qnetd is executed by a non root user, /etc/corosync/qnetd and its subdirectories must be owned by (or have group access for) the given user. If
|
||||
.B corosync-qnetd-certutil
|
||||
is executed as root it tries to copy the owner and group of /etc/corosync/qnetd to all of the created files.
|
||||
.SH SEE ALSO
|
||||
.BR corosync-qnetd (8)
|
||||
.BR corosync-qdevice (8)
|
||||
.SH AUTHOR
|
||||
Jan Friesse
|
||||
.PP
|
128
man/corosync-qnetd-tool.8
Normal file
128
man/corosync-qnetd-tool.8
Normal file
@ -0,0 +1,128 @@
|
||||
.\"/*
|
||||
.\" * Copyright (C) 2016 Red Hat, Inc.
|
||||
.\" *
|
||||
.\" * All rights reserved.
|
||||
.\" *
|
||||
.\" * Author: Jan Friesse <jfriesse@redhat.com>
|
||||
.\" *
|
||||
.\" * This software licensed under BSD license, the text of which follows:
|
||||
.\" *
|
||||
.\" * Redistribution and use in source and binary forms, with or without
|
||||
.\" * modification, are permitted provided that the following conditions are met:
|
||||
.\" *
|
||||
.\" * - Redistributions of source code must retain the above copyright notice,
|
||||
.\" * this list of conditions and the following disclaimer.
|
||||
.\" * - Redistributions in binary form must reproduce the above copyright notice,
|
||||
.\" * this list of conditions and the following disclaimer in the documentation
|
||||
.\" * and/or other materials provided with the distribution.
|
||||
.\" * - Neither the name of Red Hat, Inc. nor the names of its
|
||||
.\" * contributors may be used to endorse or promote products derived from this
|
||||
.\" * software without specific prior written permission.
|
||||
.\" *
|
||||
.\" * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
.\" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
.\" * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
.\" * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
.\" * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
.\" * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
.\" * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
.\" * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
.\" * THE POSSIBILITY OF SUCH DAMAGE.
|
||||
.\" */
|
||||
.TH COROSYNC-QNETD-TOOL 8 2016-06-23
|
||||
.SH NAME
|
||||
corosync-qnetd-tool \- corosync-qnetd control interface.
|
||||
.SH SYNOPSIS
|
||||
.B "corosync-qnetd-tool [-Hhlsv] [-c cluster_name] [-p qnetd_ipc_socket_path]"
|
||||
.SH DESCRIPTION
|
||||
.B corosync-qnetd-tool
|
||||
is a frontend to the internal corosync-qnetd IPC. Its main purpose is to show important
|
||||
information about the current internal state of
|
||||
.B corosync-qnetd.
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.B -H
|
||||
Properly shutdown the
|
||||
.B corosync-qnetd
|
||||
process
|
||||
.TP
|
||||
.B -h
|
||||
Display a short usage text
|
||||
.TP
|
||||
.B -l
|
||||
List all clients connected to the
|
||||
.B corosync-qnetd
|
||||
process. The output is described in its own section below.
|
||||
.TP
|
||||
.B -s
|
||||
Display status of the
|
||||
.B corosync-qnetd
|
||||
process.
|
||||
.TP
|
||||
.B -v
|
||||
Display more verbose output for options
|
||||
.B -l
|
||||
and
|
||||
.B -s
|
||||
.TP
|
||||
.B -c
|
||||
Used only with the
|
||||
.B -l
|
||||
option. By default, information about all clients from all clusters is displayed, with
|
||||
this option it's possible to filter information from a single cluster given the
|
||||
.I cluster_name.
|
||||
.TP
|
||||
.B -p
|
||||
Path to the
|
||||
.B corosync-qnetd
|
||||
communication socket.
|
||||
|
||||
.SH LIST COMMAND OUTPUT
|
||||
.nf
|
||||
Cluster "Cluster":
|
||||
Algorithm: Fifty-Fifty split
|
||||
Tie-breaker: Node with lowest node ID
|
||||
Node ID 1:
|
||||
Client address: ::ffff:127.0.0.1:52000
|
||||
HB interval: 8000ms
|
||||
Configured node list: 1, 2
|
||||
Ring ID: 1.a00000000021b40
|
||||
Membership node list: 1, 2
|
||||
TLS active: Yes (client certificate verified)
|
||||
Vote: No change (ACK)
|
||||
...
|
||||
.fi
|
||||
|
||||
The output contains a list of clusters. Each cluster has the cluster common options
|
||||
.I Algorithm
|
||||
and
|
||||
.I Tie-breaker
|
||||
as configured in the corosync.conf file. Information about nodes follows.
|
||||
.I Client address
|
||||
is the IP address and port of the client.
|
||||
.I HB interval
|
||||
is the heartbeat interval between
|
||||
.B corosync-qnetd
|
||||
and
|
||||
.B corosync-qdevice
|
||||
client. This option can be configured in corosync.conf.
|
||||
.I Configured node list
|
||||
is the list of nodes configured in corosync.conf.
|
||||
.I Ring ID
|
||||
and
|
||||
.I Membership node list
|
||||
are self-explanatory.
|
||||
.I TLS active
|
||||
describes if an encrypted transport is used between server and client.
|
||||
.I Vote
|
||||
is last vote sent to
|
||||
.B corosync-qdevice
|
||||
client. The last ACK/NACK vote (if it exists) is in parentheses.
|
||||
.SH SEE ALSO
|
||||
.BR corosync-qnetd (8)
|
||||
.BR corosync-qdevice (8)
|
||||
.SH AUTHOR
|
||||
Jan Friesse
|
||||
.PP
|
227
man/corosync-qnetd.8
Normal file
227
man/corosync-qnetd.8
Normal file
@ -0,0 +1,227 @@
|
||||
.\"/*
|
||||
.\" * Copyright (C) 2016 Red Hat, Inc.
|
||||
.\" *
|
||||
.\" * All rights reserved.
|
||||
.\" *
|
||||
.\" * Author: Jan Friesse <jfriesse@redhat.com>
|
||||
.\" *
|
||||
.\" * This software licensed under BSD license, the text of which follows:
|
||||
.\" *
|
||||
.\" * Redistribution and use in source and binary forms, with or without
|
||||
.\" * modification, are permitted provided that the following conditions are met:
|
||||
.\" *
|
||||
.\" * - Redistributions of source code must retain the above copyright notice,
|
||||
.\" * this list of conditions and the following disclaimer.
|
||||
.\" * - Redistributions in binary form must reproduce the above copyright notice,
|
||||
.\" * this list of conditions and the following disclaimer in the documentation
|
||||
.\" * and/or other materials provided with the distribution.
|
||||
.\" * - Neither the name of Red Hat, Inc. nor the names of its
|
||||
.\" * contributors may be used to endorse or promote products derived from this
|
||||
.\" * software without specific prior written permission.
|
||||
.\" *
|
||||
.\" * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
.\" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
.\" * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
.\" * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
.\" * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
.\" * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
.\" * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
.\" * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
.\" * THE POSSIBILITY OF SUCH DAMAGE.
|
||||
.\" */
|
||||
.TH COROSYNC-QNETD 8 2016-06-29
|
||||
.SH NAME
|
||||
corosync-qnetd \- QNet daemon
|
||||
.SH SYNOPSIS
|
||||
.B "corosync-qnetd [-46dfhv] [-l listen_addr] [-p listen_port] [-s tls]
|
||||
.B [-c client_cert_required] [-m max_clients] [-S option=value[,option2=value2,...]]"
|
||||
|
||||
.SH DESCRIPTION
|
||||
.B corosync-qnetd
|
||||
is a daemon running outside of the cluster with the purpose of providing a vote to the
|
||||
.B corosync-qdevice
|
||||
model net. It's designed to support multiple clusters and be almost configuration
|
||||
and state free. New clusters are handled dynamically and no configuration file exists.
|
||||
It's also able to run as non-root user - which is recommended. Connection between the
|
||||
.B corosync-qdevice
|
||||
model net client can be optionally configured with TLS client certificate checking.
|
||||
The communication protocol between server and client is designed to be very simple
|
||||
and allow backwards compatibility.
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.B -4
|
||||
and its counterpart
|
||||
.B -6
|
||||
are used to force IPv4 or IPv6 communication. The default is to listen on both address families.
|
||||
.TP
|
||||
.B -d
|
||||
Turn on debug logging. By default the messages sent to syslog are purely operational, this
|
||||
option sends additional debug messages. For even more detail use the
|
||||
.B -d
|
||||
parameter twice.
|
||||
.TP
|
||||
.B -f
|
||||
Do not daemonize, run in the foreground.
|
||||
.TP
|
||||
.B -h
|
||||
Show short help text
|
||||
.TP
|
||||
.B -v
|
||||
Show version and supported communication protocol messages/options.
|
||||
.TP
|
||||
.B -l
|
||||
IP address to listen on. By default the daemon listens on all addresses (wildcard).
|
||||
.TP
|
||||
.B -p
|
||||
TCP port to listen on. Default port is 5403.
|
||||
.TP
|
||||
.B -s
|
||||
Determines if TLS should be used and can be one of
|
||||
.I on/off/required
|
||||
(the default is
|
||||
.I on
|
||||
).
|
||||
.I on
|
||||
means TLS is enabled but the client is not required to start TLS,
|
||||
.I off
|
||||
means TLS is completely disabled, and
|
||||
.I required
|
||||
means TLS is required.
|
||||
.I on
|
||||
and
|
||||
.I required
|
||||
require the NSS database to be properly initialized by running the
|
||||
.B corosync-qnetd-certutil
|
||||
command.
|
||||
.TP
|
||||
.B -c
|
||||
can be set to
|
||||
.I on/off.
|
||||
This option only makes sense if TLS is enabled. When
|
||||
.B -c
|
||||
is
|
||||
.I on
|
||||
a client is required to send its client certificate (default).
|
||||
.TP
|
||||
.B -m
|
||||
Maximum simultaneous clients. The default is 0 which means no limit.
|
||||
.TP
|
||||
.B -S
|
||||
Set advanced settings described in its own section below. This option
|
||||
shouldn't be generally used because most of the options are
|
||||
not safe to change.
|
||||
.SH UNPRIVILEGED USER CONFIGURATION
|
||||
It's generally recommended to run
|
||||
.B corosync-qnetd
|
||||
as a non root user. If you get a package from a distribution its highly
|
||||
possible that the packager has done all the hard work for you. If the installation
|
||||
is performed from source code, a few steps have to be taken.
|
||||
|
||||
First it's necessary to create an unprivileged user/group. The following commands
|
||||
can be used (executed as root):
|
||||
|
||||
.nf
|
||||
# groupadd -r coroqnetd
|
||||
# useradd -r -g coroqnetd -d / -s /sbin/nologin -c "User for corosync-qnetd" coroqnetd
|
||||
.fi
|
||||
|
||||
The next step is to set the correct owner and group on /etc/corosync/qnetd and /var/run/corosync-qnetd
|
||||
directories.
|
||||
|
||||
.nf
|
||||
# chown -R coroqnetd:coroqnetd /etc/corosync/qnetd /var/run/corosync-qnetd
|
||||
.fi
|
||||
|
||||
Some systems have the /var/run directory on a tmpfs file system which gets discarded after
|
||||
a reboot. The solution is to use an initscript which takes care of the /var/run/corosync-qnetd
|
||||
creation and sets the correct owner and permissions. For systems with systemd it's possible
|
||||
to use a tmpfile.d configuration file (installed by default if systemd is enabled during
|
||||
corosync compilation).
|
||||
|
||||
The last step is to make sure
|
||||
.B corosync-qnetd
|
||||
is really executed as an unprivileged user. For initscript systems it's enough to set the
|
||||
line COROSYNC_QNETD_RUNAS in /etc/(sysconfig|default)/corosync-qnetd file. If the file
|
||||
is not already installed then use the one provided in the corosync source code
|
||||
(init/corosync-qnetd.sysconfig.example). For systemd, overwrite/copy the
|
||||
corosync-qnetd.service unit file and uncomment/change the "User=" directive.
|
||||
|
||||
.SH TLS CONFIGURATION
|
||||
For TLS to work its necessary to create the NSS database. If pcs is used then the following
|
||||
steps are not needed because pcs does them automatically.
|
||||
|
||||
.B corosync-qnetd-certutil
|
||||
is the tool to perform required actions. Just run:
|
||||
|
||||
.nf
|
||||
# corosync-qnetd-certutil -i
|
||||
.fi
|
||||
|
||||
If TLS is not required then simply edit /etc/(sysconfig|default)/corosync-qnetd or
|
||||
systemd unit file and add the parameter
|
||||
.B -s
|
||||
.I off
|
||||
in the proper place.
|
||||
|
||||
.SH ADVANCED SETTINGS
|
||||
Set by the
|
||||
.B -S
|
||||
option. The default value is shown in parentheses.
|
||||
.TP
|
||||
.B listen_backlog
|
||||
Parameter passed to the listen syscall on the network socket. (10)
|
||||
.TP
|
||||
.B max_client_send_buffers
|
||||
Maximum number of send buffers for one client. (32)
|
||||
.TP
|
||||
.B max_client_send_size
|
||||
Maximum size of one send buffer (message) to be sent to a client. (32768)
|
||||
.TP
|
||||
.B max_client_receive_size
|
||||
Maximum size of the receive buffer for a client message (maximum
|
||||
allowed message size received by client). (32768)
|
||||
.TP
|
||||
.B nss_db_dir
|
||||
NSS database directory. (/etc/corosync/qnetd/nssdb)
|
||||
.TP
|
||||
.B cert_nickname
|
||||
NSS nickname of qnetd server certificate. (QNetd Cert)
|
||||
.TP
|
||||
.B heartbeat_interval_min
|
||||
Minimum heartbeat timeout accepted by server in ms. (1000)
|
||||
.TP
|
||||
.B heartbeat_interval_max
|
||||
Maximum heartbeat timeout accepted by server in ms. (120000)
|
||||
.TP
|
||||
.B dpd_enabled
|
||||
Dead peer detection enabled. (on)
|
||||
.TP
|
||||
.B dpd_interval
|
||||
How often the DPD algorithm detects dead peers in ms. (10000)
|
||||
.TP
|
||||
.B lock_file
|
||||
Lock file location. (/var/run/corosync-qnetd/corosync-qnetd.pid)
|
||||
.TP
|
||||
.B local_socket_file
|
||||
Internal IPC socket file location. (/var/run/corosync-qnetd/corosync-qnetd.sock)
|
||||
.TP
|
||||
.B local_socket_backlog
|
||||
Parameter passed to listen syscall on the local socket. (10)
|
||||
.TP
|
||||
.B ipc_max_clients
|
||||
Maximum allowed simultaneous IPC clients. (10)
|
||||
.TP
|
||||
.B ipc_max_receive_size
|
||||
Maximum size of a message received by IPC client. (4096)
|
||||
.TP
|
||||
.B ipc_max_send_size
|
||||
Maximum size of a message sent to an IPC client. (10485760)
|
||||
.SH SEE ALSO
|
||||
.BR corosync-qnetd-tool (8)
|
||||
.BR corosync-qnetd-certutil (8)
|
||||
.BR corosync-qdevice (8)
|
||||
.SH AUTHOR
|
||||
Jan Friesse
|
||||
.PP
|
7
qdevices/.gitignore
vendored
Normal file
7
qdevices/.gitignore
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
corosync-qdevice
|
||||
corosync-qdevice-tool
|
||||
corosync-qnetd-certutil
|
||||
corosync-qdevice-net-certutil
|
||||
corosync-qnetd
|
||||
corosync-qnetd-tool
|
||||
*.test
|
180
qdevices/Makefile.am
Normal file
180
qdevices/Makefile.am
Normal file
@ -0,0 +1,180 @@
|
||||
# Copyright (c) 2012-2018 Red Hat, Inc.
|
||||
#
|
||||
# Authors: Jan Friesse (jfriesse@redhat.com)
|
||||
# Fabio M. Di Nitto (fdinitto@redhat.com)
|
||||
#
|
||||
# This software licensed under BSD license, the text of which follows:
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# - Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# - Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from this
|
||||
# software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
# THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
||||
|
||||
SUBDIRS =
|
||||
|
||||
bin_PROGRAMS =
|
||||
sbin_PROGRAMS =
|
||||
bin_SCRIPTS =
|
||||
sbin_SCRIPTS =
|
||||
EXTRA_DIST = corosync-qnetd-certutil.sh corosync-qdevice-net-certutil.sh
|
||||
|
||||
if BUILD_QNETD
|
||||
|
||||
bin_PROGRAMS += corosync-qnetd corosync-qnetd-tool
|
||||
|
||||
bin_SCRIPTS += corosync-qnetd-certutil
|
||||
|
||||
corosync_qnetd_SOURCES = corosync-qnetd.c \
|
||||
dynar.c dynar.h msg.c msg.h msgio.c msgio.h \
|
||||
nss-sock.c nss-sock.h qnetd-client.c qnetd-client.h \
|
||||
qnetd-client-list.c qnetd-client-list.h qnetd-log.c qnetd-log.h \
|
||||
pr-poll-array.c pr-poll-array.h timer-list.c timer-list.h tlv.c tlv.h \
|
||||
send-buffer-list.c send-buffer-list.h node-list.c node-list.h \
|
||||
qnetd-algo-test.c qnetd-algo-test.h qnetd-algorithm.c qnetd-algorithm.h \
|
||||
qnetd-algo-utils.c qnetd-algo-utils.h \
|
||||
qnetd-algo-ffsplit.c qnetd-algo-ffsplit.h \
|
||||
qnetd-cluster.c qnetd-cluster.h \
|
||||
qnetd-cluster-list.c qnetd-cluster-list.h \
|
||||
qnetd-client-send.c qnetd-client-send.h \
|
||||
qnetd-algo-2nodelms.c qnetd-algo-2nodelms.h qnetd-algo-lms.c qnetd-algo-lms.h \
|
||||
utils.c utils.h qnetd-instance.c qnetd-instance.h \
|
||||
qnetd-client-net.c qnetd-client-net.h \
|
||||
qnetd-client-msg-received.c qnetd-client-msg-received.h \
|
||||
qnetd-log-debug.c qnetd-log-debug.h \
|
||||
qnetd-client-algo-timer.c qnetd-client-algo-timer.h \
|
||||
qnetd-dpd-timer.c qnetd-dpd-timer.h \
|
||||
qnetd-ipc.c qnetd-ipc.h unix-socket-ipc.c unix-socket-ipc.h \
|
||||
dynar-simple-lex.c dynar-simple-lex.h dynar-str.c dynar-str.h \
|
||||
unix-socket-client.c unix-socket-client.h \
|
||||
unix-socket-client-list.c unix-socket-client-list.h \
|
||||
unix-socket.c unix-socket.h qnetd-ipc-cmd.c qnetd-ipc-cmd.h \
|
||||
qnetd-poll-array-user-data.h qnet-config.h dynar-getopt-lex.c \
|
||||
dynar-getopt-lex.h qnetd-advanced-settings.c qnetd-advanced-settings.h
|
||||
|
||||
corosync_qnetd_tool_SOURCES = corosync-qnetd-tool.c unix-socket.c unix-socket.h dynar.c dynar.h \
|
||||
dynar-str.c dynar-str.h utils.c utils.h
|
||||
|
||||
corosync_qnetd_CFLAGS = $(nss_CFLAGS) $(libsystemd_CFLAGS)
|
||||
corosync_qnetd_LDADD = $(nss_LIBS) $(libsystemd_LIBS)
|
||||
|
||||
corosync-qnetd-certutil: corosync-qnetd-certutil.sh
|
||||
sed -e 's#@''DATADIR@#${datadir}#g' \
|
||||
-e 's#@''BASHPATH@#${BASHPATH}#g' \
|
||||
-e 's#@''COROSYSCONFDIR@#${COROSYSCONFDIR}#g' \
|
||||
$< > $@
|
||||
|
||||
endif
|
||||
|
||||
if BUILD_QDEVICES
|
||||
|
||||
sbin_PROGRAMS += corosync-qdevice corosync-qdevice-tool
|
||||
|
||||
sbin_SCRIPTS += corosync-qdevice-net-certutil
|
||||
|
||||
corosync_qdevice_SOURCES = corosync-qdevice.c \
|
||||
qdevice-cmap.c qdevice-cmap.h \
|
||||
qdevice-instance.c qdevice-instance.h node-list.c node-list.h \
|
||||
utils.c utils.h qdevice-log.c qdevice-log.h \
|
||||
qdevice-log-debug.c qdevice-log-debug.h \
|
||||
qdevice-votequorum.c qdevice-votequorum.h \
|
||||
qdevice-model.c qdevice-model.h qdevice-model-net.c qdevice-model-net.h \
|
||||
qdevice-net-instance.c qdevice-net-instance.h dynar.c dynar.h \
|
||||
send-buffer-list.c send-buffer-list.h timer-list.c timer-list.h \
|
||||
msg.c msg.h msgio.c msgio.h nss-sock.c nss-sock.h tlv.c tlv.h \
|
||||
unix-socket.c unix-socket.h unix-socket-client.c unix-socket-client.h \
|
||||
unix-socket-client-list.c unix-socket-client-list.h \
|
||||
unix-socket-ipc.c unix-socket-ipc.h qdevice-ipc.c qdevice-ipc.h \
|
||||
pr-poll-array.c pr-poll-array.h dynar-simple-lex.c dynar-simple-lex.h \
|
||||
dynar-str.c dynar-str.h qdevice-ipc-cmd.c qdevice-ipc-cmd.h \
|
||||
qdevice-net-ipc-cmd.c qdevice-net-ipc-cmd.h \
|
||||
qdevice-net-poll.c qdevice-net-poll.h \
|
||||
qdevice-net-send.c qdevice-net-send.h \
|
||||
qdevice-net-votequorum.c qdevice-net-votequorum.h \
|
||||
qdevice-net-socket.c qdevice-net-socket.h \
|
||||
qdevice-net-nss.c qdevice-net-nss.h \
|
||||
qdevice-net-msg-received.c qdevice-net-msg-received.h \
|
||||
qdevice-net-cast-vote-timer.c qdevice-net-cast-vote-timer.h \
|
||||
qdevice-net-echo-request-timer.c qdevice-net-echo-request-timer.h \
|
||||
qdevice-net-algorithm.c qdevice-net-algorithm.h \
|
||||
qdevice-net-algo-test.c qdevice-net-algo-test.h \
|
||||
qdevice-net-algo-ffsplit.c qdevice-net-algo-ffsplit.h \
|
||||
qdevice-net-algo-2nodelms.c qdevice-net-algo-2nodelms.h \
|
||||
qdevice-net-algo-lms.c qdevice-net-algo-lms.h \
|
||||
qdevice-net-poll-array-user-data.h \
|
||||
qdevice-config.h qnet-config.h qdevice-net-disconnect-reason.h \
|
||||
qdevice-model-type.h qdevice-advanced-settings.c \
|
||||
qdevice-advanced-settings.h dynar-getopt-lex.c dynar-getopt-lex.h \
|
||||
qdevice-heuristics.h qdevice-heuristics.c \
|
||||
qdevice-heuristics-worker.h qdevice-heuristics-worker.c \
|
||||
qdevice-heuristics-io.h qdevice-heuristics-io.c \
|
||||
qdevice-heuristics-worker-instance.h \
|
||||
qdevice-heuristics-worker-log.h qdevice-heuristics-worker-log.c \
|
||||
qdevice-heuristics-log.h qdevice-heuristics-log.c \
|
||||
qdevice-heuristics-instance.h qdevice-heuristics-instance.c \
|
||||
qdevice-heuristics-mode.h qdevice-heuristics-mode.c \
|
||||
qdevice-heuristics-exec-list.c qdevice-heuristics-exec-list.h \
|
||||
qdevice-heuristics-cmd.c qdevice-heuristics-cmd.h \
|
||||
qdevice-heuristics-worker-cmd.c qdevice-heuristics-worker-cmd.h \
|
||||
qdevice-heuristics-cmd-str.h \
|
||||
qdevice-heuristics-exec-result.c qdevice-heuristics-exec-result.h \
|
||||
process-list.h process-list.c \
|
||||
qdevice-net-heuristics.c qdevice-net-heuristics.h \
|
||||
qdevice-heuristics-result-notifier.c qdevice-heuristics-result-notifier.h
|
||||
|
||||
corosync_qdevice_tool_SOURCES = corosync-qdevice-tool.c unix-socket.c unix-socket.h dynar.c dynar.h \
|
||||
dynar-str.c dynar-str.h utils.c utils.h
|
||||
|
||||
corosync_qdevice_CFLAGS = $(nss_CFLAGS) $(libsystemd_CFLAGS) $(cmap_CFLAGS) \
|
||||
$(qb_CFLAGS) $(votequorum_CFLAGS) $(corosync_common_CFLAGS)
|
||||
corosync_qdevice_LDADD = $(nss_LIBS) $(libsystemd_LIBS) $(cmap_LIBS) \
|
||||
$(qb_LIBS) $(votequorum_LIBS) $(corosync_common_LIBS)
|
||||
|
||||
corosync-qdevice-net-certutil: corosync-qdevice-net-certutil.sh
|
||||
sed -e 's#@''DATADIR@#${datadir}#g' \
|
||||
-e 's#@''BASHPATH@#${BASHPATH}#g' \
|
||||
-e 's#@''COROSYSCONFDIR@#${COROSYSCONFDIR}#g' \
|
||||
$< > $@
|
||||
|
||||
TESTS = qnetd-cluster-list.test dynar.test dynar-simple-lex.test \
|
||||
dynar-getopt-lex.test process-list.test
|
||||
check_PROGRAMS = qnetd-cluster-list.test dynar.test dynar-simple-lex.test \
|
||||
dynar-getopt-lex.test process-list.test
|
||||
|
||||
qnetd_cluster_list_test_SOURCES = qnetd-cluster-list.c test-qnetd-cluster-list.c \
|
||||
qnetd-cluster.c qnetd-cluster.h \
|
||||
qnetd-client-list.c qnetd-client.c dynar.c node-list.c \
|
||||
send-buffer-list.c
|
||||
qnetd_cluster_list_test_CFLAGS = $(nss_CFLAGS)
|
||||
qnetd_cluster_list_test_LDADD = $(nss_LIBS)
|
||||
|
||||
dynar_test_SOURCES = test-dynar.c dynar.c dynar-str.c
|
||||
dynar_simple_lex_test_SOURCES = test-dynar-simple-lex.c dynar.c dynar-str.c dynar-simple-lex.c
|
||||
dynar_getopt_lex_test_SOURCES = test-dynar-getopt-lex.c dynar.c dynar-str.c dynar-getopt-lex.c
|
||||
process_list_test_SOURCES = test-process-list.c dynar.c dynar-str.c dynar-simple-lex.c \
|
||||
process-list.c
|
||||
|
||||
endif
|
||||
|
||||
clean-local:
|
||||
rm -rf $(bin_SCRIPTS) $(sbin_SCRIPTS)
|
404
qdevices/corosync-qdevice-net-certutil.sh
Normal file
404
qdevices/corosync-qdevice-net-certutil.sh
Normal file
@ -0,0 +1,404 @@
|
||||
#!@BASHPATH@
|
||||
|
||||
#
|
||||
# Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
#
|
||||
# All rights reserved.
|
||||
#
|
||||
# Author: Jan Friesse (jfriesse@redhat.com)
|
||||
#
|
||||
# This software licensed under BSD license, the text of which follows:
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# - Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# - Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from this
|
||||
# software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
# THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
BASE_DIR="@COROSYSCONFDIR@/qdevice/net"
|
||||
DB_DIR_QNETD="@COROSYSCONFDIR@/qnetd/nssdb"
|
||||
DB_DIR_NODE="$BASE_DIR/nssdb"
|
||||
# Validity of certificate (months)
|
||||
CRT_VALIDITY=1200
|
||||
CA_NICKNAME="QNet CA"
|
||||
SERVER_NICKNAME="QNetd Cert"
|
||||
CLUSTER_NICKNAME="Cluster Cert"
|
||||
CA_SUBJECT="CN=QNet CA"
|
||||
SERVER_SUBJECT="CN=Qnetd Server"
|
||||
PWD_FILE_BASE="pwdfile.txt"
|
||||
NOISE_FILE_BASE="noise.txt"
|
||||
SERIAL_NO_FILE_BASE="serial.txt"
|
||||
CA_EXPORT_FILE="$DB_DIR_QNETD/qnetd-cacert.crt"
|
||||
CRQ_FILE_BASE="qdevice-net-node.crq"
|
||||
CRT_FILE_BASE="" # Generated from cluster name
|
||||
P12_FILE_BASE="qdevice-net-node.p12"
|
||||
QNETD_CERTUTIL_CMD="corosync-qnetd-certutil"
|
||||
|
||||
usage() {
|
||||
echo "$0: [-i|-m|-M|-r|-s|-Q] [-c certificate] [-n cluster_name]"
|
||||
echo
|
||||
echo " -i Initialize node CA. Needs CA certificate from server"
|
||||
echo " -m Import cluster certificate on node (needs pk12 certificate)"
|
||||
echo " -r Generate cluster certificate request"
|
||||
echo " -M Import signed cluster certificate and export certificate with key to pk12 file"
|
||||
echo " -Q Quick start. Uses ssh/scp to initialze both qnetd and nodes."
|
||||
echo ""
|
||||
echo " -c certificate Ether CA, CRQ, CRT or pk12 certificate (operation dependant)"
|
||||
echo " -n cluster_name Name of cluster (for -r and -s operations)"
|
||||
echo ""
|
||||
echo "Typical usage:"
|
||||
echo "- Initialize database on QNetd server by running $QNETD_CERTUTIL_CMD -i"
|
||||
echo "- Copy exported QNetd CA certificate ($CA_EXPORT_FILE) to every node"
|
||||
echo "- On one of cluster node initialize database by running $0 -i -c `basename $CA_EXPORT_FILE`"
|
||||
echo "- Generate certificate request: $0 -r -n Cluster (Cluster name must match cluster_name key in the corosync.conf)"
|
||||
echo "- Copy exported CRQ to QNetd server"
|
||||
echo "- On QNetd server sign and export cluster certificate by running $QNETD_CERTUTIL_CMD -s -c `basename $CRQ_FILE_BASE` -n Cluster"
|
||||
echo "- Copy exported CRT to node where certificate request was created"
|
||||
echo "- Import certificate on node where certificate request was created by running $0 -M -c cluster-Cluster.crt"
|
||||
echo "- Copy output $P12_FILE_BASE to all other cluster nodes"
|
||||
echo "- On all other nodes in cluster:"
|
||||
echo " - Init database by running $0 -i -c `basename $CA_EXPORT_FILE`"
|
||||
echo " - Import cluster certificate and key: $0 -m -c `basename $P12_FILE_BASE`"
|
||||
echo ""
|
||||
echo "It is also possible to use Quick start (-Q). This needs properly configured ssh."
|
||||
echo " $0 -Q -n Cluster qnetd_server node1 node2 ... nodeN"
|
||||
|
||||
exit 0
|
||||
}
|
||||
|
||||
create_new_noise_file() {
|
||||
local noise_file="$1"
|
||||
|
||||
if [ ! -e "$noise_file" ];then
|
||||
echo "Creating new noise file $noise_file"
|
||||
|
||||
(ps -elf; date; w) | sha1sum | (read sha_sum rest; echo $sha_sum) > "$noise_file"
|
||||
|
||||
chown root:root "$noise_file"
|
||||
chmod 0660 "$noise_file"
|
||||
else
|
||||
echo "Using existing noise file $noise_file"
|
||||
fi
|
||||
}
|
||||
|
||||
get_serial_no() {
|
||||
local serial_no
|
||||
|
||||
if ! [ -f "$SERIAL_NO_FILE" ];then
|
||||
echo "100" > $SERIAL_NO_FILE
|
||||
chown root:root "$DB_DIR"
|
||||
chmod 0660 "$SERIAL_NO_FILE"
|
||||
fi
|
||||
serial_no=`cat $SERIAL_NO_FILE`
|
||||
serial_no=$((serial_no+1))
|
||||
echo "$serial_no" > $SERIAL_NO_FILE
|
||||
echo "$serial_no"
|
||||
}
|
||||
|
||||
init_node_ca() {
|
||||
if [ -f "$DB_DIR/cert8.db" ];then
|
||||
echo "Certificate database already exists. Delete it to continue" >&2
|
||||
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! [ -d "$DB_DIR" ];then
|
||||
echo "Creating $DB_DIR"
|
||||
mkdir -p "$DB_DIR"
|
||||
chown root:root "$DB_DIR"
|
||||
chmod 0770 "$DB_DIR"
|
||||
fi
|
||||
|
||||
echo "Creating new key and cert db"
|
||||
echo -n "" > "$PWD_FILE"
|
||||
chown root:root "$PWD_FILE"
|
||||
chmod 0660 "$PWD_FILE"
|
||||
certutil -N -d "$DB_DIR" -f "$PWD_FILE"
|
||||
chown root:root "$DB_DIR/key3.db" "$DB_DIR/cert8.db" "$DB_DIR/secmod.db"
|
||||
chmod 0660 "$DB_DIR/key3.db" "$DB_DIR/cert8.db" "$DB_DIR/secmod.db"
|
||||
|
||||
create_new_noise_file "$NOISE_FILE"
|
||||
|
||||
echo "Importing CA"
|
||||
|
||||
certutil -d "$DB_DIR" -A -t "CT,c,c" -n "$CA_NICKNAME" -f "$PWD_FILE" \
|
||||
-i "$CERTIFICATE_FILE"
|
||||
}
|
||||
|
||||
gen_cluster_cert_req() {
|
||||
if ! [ -f "$DB_DIR/cert8.db" ];then
|
||||
echo "Certificate database doesn't exists. Use $0 -i to create it" >&2
|
||||
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Creating new certificate request"
|
||||
|
||||
certutil -R -s "CN=$CLUSTER_NAME" -o "$CRQ_FILE" -d "$DB_DIR" -f "$PWD_FILE" -z "$NOISE_FILE"
|
||||
|
||||
echo "Certificate request stored in $CRQ_FILE"
|
||||
}
|
||||
|
||||
import_signed_cert() {
|
||||
if ! [ -f "$DB_DIR/cert8.db" ];then
|
||||
echo "Certificate database doesn't exists. Use $0 -i to create it" >&2
|
||||
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Importing signed cluster certificate"
|
||||
certutil -d "$DB_DIR" -A -t "u,u,u" -n "$CLUSTER_NICKNAME" -i "$CERTIFICATE_FILE"
|
||||
|
||||
pk12util -d "$DB_DIR" -o "$P12_FILE" -W "" -n "$CLUSTER_NICKNAME"
|
||||
|
||||
echo "Certificate stored in $P12_FILE"
|
||||
}
|
||||
|
||||
import_pk12() {
|
||||
if ! [ -f "$DB_DIR/cert8.db" ];then
|
||||
echo "Certificate database doesn't exists. Use $0 -i to create it" >&2
|
||||
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Importing cluster certificate and key"
|
||||
pk12util -i "$CERTIFICATE_FILE" -d "$DB_DIR" -W ""
|
||||
}
|
||||
|
||||
quick_start() {
|
||||
qnetd_addr="$1"
|
||||
master_node="$2"
|
||||
other_nodes="$3"
|
||||
|
||||
# Sanity check
|
||||
for i in "$master_node" $other_nodes;do
|
||||
if ssh root@$i "[ -d \"$DB_DIR_NODE\" ]";then
|
||||
echo "Node $i seems to be already initialized. Please delete $DB_DIR_NODE" >&2
|
||||
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! ssh "root@$i" "$0" > /dev/null;then
|
||||
echo "Node $i doesn't have $0 installed" >&2
|
||||
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
# Initialize qnetd server (it's no problem if server is already initialized)
|
||||
ssh "root@$qnetd_addr" "$QNETD_CERTUTIL_CMD -i"
|
||||
|
||||
# Copy CA cert to all nodes and initialize them
|
||||
for node in "$master_node" $other_nodes;do
|
||||
scp "root@$qnetd_addr:$CA_EXPORT_FILE" "$node:/tmp"
|
||||
ssh "root@$node" "$0 -i -c \"/tmp/`basename $CA_EXPORT_FILE`\" && rm /tmp/`basename $CA_EXPORT_FILE`"
|
||||
done
|
||||
|
||||
# Generate cert request
|
||||
ssh "root@$master_node" "$0 -r -n \"$CLUSTER_NAME\""
|
||||
|
||||
# Copy exported cert request to qnetd server
|
||||
scp "root@$master_node:$DB_DIR_NODE/$CRQ_FILE_BASE" "root@$qnetd_addr:/tmp"
|
||||
|
||||
# Sign and export cluster certificate
|
||||
ssh "root@$qnetd_addr" "$QNETD_CERTUTIL_CMD -s -c \"/tmp/$CRQ_FILE_BASE\" -n \"$CLUSTER_NAME\""
|
||||
|
||||
# Copy exported CRT to master node
|
||||
scp "root@$qnetd_addr:$DB_DIR_QNETD/cluster-$CLUSTER_NAME.crt" "root@$master_node:$DB_DIR_NODE"
|
||||
|
||||
# Import certificate
|
||||
ssh "root@$master_node" "$0 -M -c \"$DB_DIR_NODE/cluster-$CLUSTER_NAME.crt\""
|
||||
|
||||
# Copy pk12 cert to all nodes and import it
|
||||
for node in $other_nodes;do
|
||||
scp "root@$master_node:$DB_DIR_NODE/$P12_FILE" "$node:$DB_DIR_NODE/$P12_FILE"
|
||||
ssh "root@$node" "$0 -m -c \"$DB_DIR_NODE/$P12_FILE\""
|
||||
done
|
||||
}
|
||||
|
||||
OPERATION=""
|
||||
CERTIFICATE_FILE=""
|
||||
CLUSTER_NAME=""
|
||||
|
||||
while getopts ":hiMmQrc:n:" opt; do
|
||||
case $opt in
|
||||
r)
|
||||
OPERATION=gen_cluster_cert_req
|
||||
;;
|
||||
i)
|
||||
OPERATION=init_node_ca
|
||||
;;
|
||||
m)
|
||||
OPERATION=import_pk12
|
||||
;;
|
||||
M)
|
||||
OPERATION=import_signed_cert
|
||||
;;
|
||||
Q)
|
||||
OPERATION=quick_start
|
||||
;;
|
||||
n)
|
||||
CLUSTER_NAME="$OPTARG"
|
||||
;;
|
||||
h)
|
||||
usage
|
||||
;;
|
||||
c)
|
||||
CERTIFICATE_FILE="$OPTARG"
|
||||
;;
|
||||
\?)
|
||||
echo "Invalid option: -$OPTARG" >&2
|
||||
|
||||
exit 1
|
||||
;;
|
||||
:)
|
||||
echo "Option -$OPTARG requires an argument." >&2
|
||||
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
case "$OPERATION" in
|
||||
"init_qnetd_ca")
|
||||
DB_DIR="$DB_DIR_QNETD"
|
||||
;;
|
||||
"init_node_ca")
|
||||
DB_DIR="$DB_DIR_NODE"
|
||||
;;
|
||||
"gen_cluster_cert_req")
|
||||
DB_DIR="$DB_DIR_NODE"
|
||||
;;
|
||||
"sign_cluster_cert")
|
||||
DB_DIR="$DB_DIR_QNETD"
|
||||
;;
|
||||
"import_signed_cert")
|
||||
DB_DIR="$DB_DIR_NODE"
|
||||
;;
|
||||
"import_pk12")
|
||||
DB_DIR="$DB_DIR_NODE"
|
||||
;;
|
||||
"quick_start")
|
||||
DB_DIR=""
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
;;
|
||||
esac
|
||||
|
||||
PWD_FILE="$DB_DIR/$PWD_FILE_BASE"
|
||||
NOISE_FILE="$DB_DIR/$NOISE_FILE_BASE"
|
||||
SERIAL_NO_FILE="$DB_DIR/$SERIAL_NO_FILE_BASE"
|
||||
CRQ_FILE="$DB_DIR/$CRQ_FILE_BASE"
|
||||
CRT_FILE="$DB_DIR/cluster-$CLUSTER_NAME.crt"
|
||||
P12_FILE="$DB_DIR/$P12_FILE_BASE"
|
||||
|
||||
case "$OPERATION" in
|
||||
"init_qnetd_ca")
|
||||
init_qnetd_ca
|
||||
;;
|
||||
"init_node_ca")
|
||||
if ! [ -e "$CERTIFICATE_FILE" ];then
|
||||
echo "Can't open certificate file $CERTIFICATE_FILE" >&2
|
||||
|
||||
exit 2
|
||||
fi
|
||||
|
||||
init_node_ca
|
||||
;;
|
||||
"gen_cluster_cert_req")
|
||||
if [ "$CLUSTER_NAME" == "" ];then
|
||||
echo "You have to specify cluster name" >&2
|
||||
|
||||
exit 2
|
||||
fi
|
||||
|
||||
gen_cluster_cert_req
|
||||
;;
|
||||
"sign_cluster_cert")
|
||||
if ! [ -e "$CERTIFICATE_FILE" ];then
|
||||
echo "Can't open certificate file $CERTIFICATE_FILE" >&2
|
||||
|
||||
exit 2
|
||||
fi
|
||||
|
||||
if [ "$CLUSTER_NAME" == "" ];then
|
||||
echo "You have to specify cluster name" >&2
|
||||
|
||||
exit 2
|
||||
fi
|
||||
|
||||
sign_cluster_cert
|
||||
;;
|
||||
"import_signed_cert")
|
||||
if ! [ -e "$CERTIFICATE_FILE" ];then
|
||||
echo "Can't open certificate file $CERTIFICATE_FILE" >&2
|
||||
|
||||
exit 2
|
||||
fi
|
||||
|
||||
import_signed_cert
|
||||
;;
|
||||
"import_pk12")
|
||||
if ! [ -e "$CERTIFICATE_FILE" ];then
|
||||
echo "Can't open certificate file $CERTIFICATE_FILE" >&2
|
||||
|
||||
exit 2
|
||||
fi
|
||||
|
||||
import_pk12
|
||||
;;
|
||||
"quick_start")
|
||||
shift $((OPTIND-1))
|
||||
|
||||
qnetd_addr="$1"
|
||||
|
||||
shift 1
|
||||
|
||||
master_node="$1"
|
||||
shift 1
|
||||
other_nodes="$@"
|
||||
|
||||
if [ "$CLUSTER_NAME" == "" ];then
|
||||
echo "You have to specify cluster name" >&2
|
||||
|
||||
exit 2
|
||||
fi
|
||||
|
||||
if [ "$qnetd_addr" == "" ];then
|
||||
echo "No QNetd server address provided." >&2
|
||||
|
||||
exit 2
|
||||
fi
|
||||
|
||||
if [ "$master_node" == "" ];then
|
||||
echo "No nodes provided." >&2
|
||||
|
||||
exit 2
|
||||
fi
|
||||
|
||||
quick_start "$qnetd_addr" "$master_node" "$other_nodes"
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
;;
|
||||
esac
|
281
qdevices/corosync-qdevice-tool.c
Normal file
281
qdevices/corosync-qdevice-tool.c
Normal file
@ -0,0 +1,281 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "qdevice-config.h"
|
||||
|
||||
#include "dynar.h"
|
||||
#include "dynar-str.h"
|
||||
#include "utils.h"
|
||||
#include "unix-socket.h"
|
||||
|
||||
#define IPC_READ_BUF_SIZE 512
|
||||
|
||||
enum qdevice_tool_operation {
|
||||
QDEVICE_TOOL_OPERATION_NONE,
|
||||
QDEVICE_TOOL_OPERATION_SHUTDOWN,
|
||||
QDEVICE_TOOL_OPERATION_STATUS,
|
||||
};
|
||||
|
||||
enum qdevice_tool_exit_code {
|
||||
QDEVICE_TOOL_EXIT_CODE_NO_ERROR = 0,
|
||||
QDEVICE_TOOL_EXIT_CODE_USAGE = 1,
|
||||
QDEVICE_TOOL_EXIT_CODE_INTERNAL_ERROR = 2,
|
||||
QDEVICE_TOOL_EXIT_CODE_SOCKET_CONNECT = 3,
|
||||
QDEVICE_TOOL_EXIT_CODE_QDEVICE_RETURNED_ERROR = 4,
|
||||
};
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
|
||||
printf("usage: %s [-Hhsv] [-p qdevice_ipc_socket_path]\n",
|
||||
QDEVICE_TOOL_PROGRAM_NAME);
|
||||
}
|
||||
|
||||
static void
|
||||
cli_parse(int argc, char * const argv[], enum qdevice_tool_operation *operation,
|
||||
int *verbose, char **socket_path)
|
||||
{
|
||||
int ch;
|
||||
|
||||
*operation = QDEVICE_TOOL_OPERATION_NONE;
|
||||
*verbose = 0;
|
||||
*socket_path = strdup(QDEVICE_DEFAULT_LOCAL_SOCKET_FILE);
|
||||
|
||||
if (*socket_path == NULL) {
|
||||
errx(QDEVICE_TOOL_EXIT_CODE_INTERNAL_ERROR,
|
||||
"Can't alloc memory for socket path string");
|
||||
}
|
||||
|
||||
while ((ch = getopt(argc, argv, "Hhsvp:")) != -1) {
|
||||
switch (ch) {
|
||||
case 'H':
|
||||
*operation = QDEVICE_TOOL_OPERATION_SHUTDOWN;
|
||||
break;
|
||||
case 's':
|
||||
*operation = QDEVICE_TOOL_OPERATION_STATUS;
|
||||
break;
|
||||
case 'v':
|
||||
*verbose = 1;
|
||||
break;
|
||||
case 'p':
|
||||
free(*socket_path);
|
||||
*socket_path = strdup(optarg);
|
||||
if (*socket_path == NULL) {
|
||||
errx(QDEVICE_TOOL_EXIT_CODE_INTERNAL_ERROR,
|
||||
"Can't alloc memory for socket path string");
|
||||
}
|
||||
break;
|
||||
case 'h':
|
||||
case '?':
|
||||
usage();
|
||||
exit(QDEVICE_TOOL_EXIT_CODE_USAGE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (*operation == QDEVICE_TOOL_OPERATION_NONE) {
|
||||
usage();
|
||||
exit(QDEVICE_TOOL_EXIT_CODE_USAGE);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
store_command(struct dynar *str, enum qdevice_tool_operation operation, int verbose)
|
||||
{
|
||||
const char *nline = "\n\0";
|
||||
const int nline_len = 2;
|
||||
|
||||
switch (operation) {
|
||||
case QDEVICE_TOOL_OPERATION_NONE:
|
||||
errx(QDEVICE_TOOL_EXIT_CODE_INTERNAL_ERROR, "Unhandled operation none");
|
||||
break;
|
||||
case QDEVICE_TOOL_OPERATION_SHUTDOWN:
|
||||
if (dynar_str_cat(str, "shutdown ") != 0) {
|
||||
return (-1);
|
||||
}
|
||||
break;
|
||||
case QDEVICE_TOOL_OPERATION_STATUS:
|
||||
if (dynar_str_cat(str, "status ") != 0) {
|
||||
return (-1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
if (dynar_str_cat(str, "verbose ") != 0) {
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
if (dynar_cat(str, nline, nline_len) != 0) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* -1 - Internal error (can't alloc memory)
|
||||
* 0 - No error
|
||||
* 1 - IPC returned error
|
||||
* 2 - Unknown status line
|
||||
*/
|
||||
static int
|
||||
read_ipc_reply(FILE *f)
|
||||
{
|
||||
struct dynar read_str;
|
||||
int ch;
|
||||
int status_readed;
|
||||
int res;
|
||||
static const char *ok_str = "OK";
|
||||
static const char *err_str = "Error";
|
||||
int err_set;
|
||||
char c;
|
||||
|
||||
dynar_init(&read_str, IPC_READ_BUF_SIZE);
|
||||
|
||||
status_readed = 0;
|
||||
err_set = 0;
|
||||
res = 0;
|
||||
|
||||
while ((ch = fgetc(f)) != EOF) {
|
||||
if (status_readed) {
|
||||
putc(ch, (err_set ? stderr : stdout));
|
||||
} else {
|
||||
if (ch == '\r') {
|
||||
} else if (ch == '\n') {
|
||||
status_readed = 1;
|
||||
|
||||
c = '\0';
|
||||
if (dynar_cat(&read_str, &c, sizeof(c)) != 0) {
|
||||
res = -1;
|
||||
goto exit_destroy;
|
||||
}
|
||||
|
||||
if (strcasecmp(dynar_data(&read_str), ok_str) == 0) {
|
||||
} else if (strcasecmp(dynar_data(&read_str), err_str) == 0) {
|
||||
err_set = 1;
|
||||
res = 1;
|
||||
fprintf(stderr, "Error: ");
|
||||
} else {
|
||||
res = 2;
|
||||
goto exit_destroy;
|
||||
}
|
||||
} else {
|
||||
c = ch;
|
||||
if (dynar_cat(&read_str, &c, sizeof(c)) != 0) {
|
||||
res = -1;
|
||||
goto exit_destroy;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exit_destroy:
|
||||
dynar_destroy(&read_str);
|
||||
|
||||
return (res);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char * const argv[])
|
||||
{
|
||||
enum qdevice_tool_operation operation;
|
||||
int verbose;
|
||||
char *socket_path;
|
||||
int sock_fd;
|
||||
FILE *sock;
|
||||
struct dynar send_str;
|
||||
int res;
|
||||
int exit_code;
|
||||
|
||||
exit_code = QDEVICE_TOOL_EXIT_CODE_NO_ERROR;
|
||||
|
||||
cli_parse(argc, argv, &operation, &verbose, &socket_path);
|
||||
|
||||
dynar_init(&send_str, QDEVICE_DEFAULT_IPC_MAX_RECEIVE_SIZE);
|
||||
|
||||
sock_fd = unix_socket_client_create(socket_path, 0);
|
||||
if (sock_fd == -1) {
|
||||
err(QDEVICE_TOOL_EXIT_CODE_SOCKET_CONNECT,
|
||||
"Can't connect to QDevice socket (is QDevice running?)");
|
||||
}
|
||||
|
||||
sock = fdopen(sock_fd, "w+t");
|
||||
if (sock == NULL) {
|
||||
err(QDEVICE_TOOL_EXIT_CODE_INTERNAL_ERROR, "Can't open QDevice socket fd");
|
||||
}
|
||||
|
||||
if (store_command(&send_str, operation, verbose) != 0) {
|
||||
errx(QDEVICE_TOOL_EXIT_CODE_INTERNAL_ERROR, "Can't store command");
|
||||
}
|
||||
|
||||
res = fprintf(sock, "%s", dynar_data(&send_str));
|
||||
if (res < 0 || (size_t)res != strlen(dynar_data(&send_str)) ||
|
||||
fflush(sock) != 0) {
|
||||
errx(QDEVICE_TOOL_EXIT_CODE_INTERNAL_ERROR, "Can't send command");
|
||||
}
|
||||
|
||||
res = read_ipc_reply(sock);
|
||||
switch (res) {
|
||||
case -1:
|
||||
errx(QDEVICE_TOOL_EXIT_CODE_INTERNAL_ERROR, "Internal error during IPC status line read");
|
||||
break;
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
exit_code = QDEVICE_TOOL_EXIT_CODE_QDEVICE_RETURNED_ERROR;
|
||||
break;
|
||||
case 2:
|
||||
errx(QDEVICE_TOOL_EXIT_CODE_SOCKET_CONNECT, "Unknown status line returned by IPC server");
|
||||
break;
|
||||
}
|
||||
|
||||
if (fclose(sock) != 0) {
|
||||
warn("Can't close QDevice socket");
|
||||
}
|
||||
|
||||
free(socket_path);
|
||||
dynar_destroy(&send_str);
|
||||
|
||||
return (exit_code);
|
||||
}
|
298
qdevices/corosync-qdevice.c
Normal file
298
qdevices/corosync-qdevice.c
Normal file
@ -0,0 +1,298 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2017 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <err.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "dynar.h"
|
||||
#include "dynar-str.h"
|
||||
#include "dynar-getopt-lex.h"
|
||||
#include "qdevice-advanced-settings.h"
|
||||
#include "qdevice-config.h"
|
||||
#include "qdevice-cmap.h"
|
||||
#include "qdevice-heuristics.h"
|
||||
#include "qdevice-ipc.h"
|
||||
#include "qdevice-log.h"
|
||||
#include "qdevice-model.h"
|
||||
#include "qdevice-votequorum.h"
|
||||
#include "utils.h"
|
||||
|
||||
#ifdef HAVE_LIBSYSTEMD
|
||||
#include <systemd/sd-daemon.h>
|
||||
#endif
|
||||
|
||||
struct qdevice_instance *global_instance;
|
||||
|
||||
static void
|
||||
signal_int_handler(int sig)
|
||||
{
|
||||
qdevice_log(LOG_DEBUG, "SIGINT received - closing local unix socket");
|
||||
qdevice_ipc_close(global_instance);
|
||||
}
|
||||
|
||||
static void
|
||||
signal_term_handler(int sig)
|
||||
{
|
||||
qdevice_log(LOG_DEBUG, "SIGTERM received - closing server socket");
|
||||
qdevice_ipc_close(global_instance);
|
||||
}
|
||||
|
||||
static void
|
||||
signal_handlers_register(void)
|
||||
{
|
||||
struct sigaction act;
|
||||
|
||||
act.sa_handler = signal_int_handler;
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_flags = SA_RESTART;
|
||||
|
||||
sigaction(SIGINT, &act, NULL);
|
||||
|
||||
act.sa_handler = signal_term_handler;
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_flags = SA_RESTART;
|
||||
|
||||
sigaction(SIGTERM, &act, NULL);
|
||||
|
||||
act.sa_handler = SIG_DFL;
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_flags = SA_RESTART;
|
||||
|
||||
sigaction(SIGCHLD, &act, NULL);
|
||||
|
||||
act.sa_handler = SIG_IGN;
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_flags = SA_RESTART;
|
||||
|
||||
sigaction(SIGPIPE, &act, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
|
||||
printf("usage: %s [-dfh] [-S option=value[,option2=value2,...]]\n", QDEVICE_PROGRAM_NAME);
|
||||
}
|
||||
|
||||
static void
|
||||
cli_parse_long_opt(struct qdevice_advanced_settings *advanced_settings, const char *long_opt)
|
||||
{
|
||||
struct dynar_getopt_lex lex;
|
||||
struct dynar dynar_long_opt;
|
||||
const char *opt;
|
||||
const char *val;
|
||||
int res;
|
||||
|
||||
dynar_init(&dynar_long_opt, strlen(long_opt) + 1);
|
||||
if (dynar_str_cpy(&dynar_long_opt, long_opt) != 0) {
|
||||
errx(1, "Can't alloc memory for long option");
|
||||
}
|
||||
|
||||
dynar_getopt_lex_init(&lex, &dynar_long_opt);
|
||||
|
||||
while (dynar_getopt_lex_token_next(&lex) == 0 && strcmp(dynar_data(&lex.option), "") != 0) {
|
||||
opt = dynar_data(&lex.option);
|
||||
val = dynar_data(&lex.value);
|
||||
|
||||
res = qdevice_advanced_settings_set(advanced_settings, opt, val);
|
||||
switch (res) {
|
||||
case -1:
|
||||
errx(1, "Unknown option '%s'", opt);
|
||||
break;
|
||||
case -2:
|
||||
errx(1, "Invalid value '%s' for option '%s'", val, opt);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
dynar_getopt_lex_destroy(&lex);
|
||||
dynar_destroy(&dynar_long_opt);
|
||||
}
|
||||
|
||||
static void
|
||||
cli_parse(int argc, char * const argv[], int *foreground, int *force_debug,
|
||||
struct qdevice_advanced_settings *advanced_settings)
|
||||
{
|
||||
int ch;
|
||||
|
||||
*foreground = 0;
|
||||
*force_debug = 0;
|
||||
|
||||
while ((ch = getopt(argc, argv, "dfhS:")) != -1) {
|
||||
switch (ch) {
|
||||
case 'd':
|
||||
*force_debug = 1;
|
||||
break;
|
||||
case 'f':
|
||||
*foreground = 1;
|
||||
break;
|
||||
case 'S':
|
||||
cli_parse_long_opt(advanced_settings, optarg);
|
||||
break;
|
||||
case 'h':
|
||||
case '?':
|
||||
usage();
|
||||
exit(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char * const argv[])
|
||||
{
|
||||
struct qdevice_instance instance;
|
||||
struct qdevice_advanced_settings advanced_settings;
|
||||
int foreground;
|
||||
int force_debug;
|
||||
int lock_file;
|
||||
int another_instance_running;
|
||||
|
||||
if (qdevice_advanced_settings_init(&advanced_settings) != 0) {
|
||||
errx(1, "Can't alloc memory for advanced settings");
|
||||
}
|
||||
|
||||
cli_parse(argc, argv, &foreground, &force_debug, &advanced_settings);
|
||||
|
||||
qdevice_instance_init(&instance, &advanced_settings);
|
||||
|
||||
qdevice_heuristics_init(&instance.heuristics_instance, &advanced_settings);
|
||||
instance.heuristics_instance.qdevice_instance_ptr = &instance;
|
||||
|
||||
qdevice_cmap_init(&instance);
|
||||
qdevice_log_init(&instance, force_debug);
|
||||
|
||||
/*
|
||||
* Daemonize
|
||||
*/
|
||||
if (!foreground) {
|
||||
utils_tty_detach();
|
||||
}
|
||||
|
||||
if ((lock_file = utils_flock(advanced_settings.lock_file, getpid(),
|
||||
&another_instance_running)) == -1) {
|
||||
if (another_instance_running) {
|
||||
qdevice_log(LOG_ERR, "Another instance is running");
|
||||
} else {
|
||||
qdevice_log_err(LOG_ERR, "Can't acquire lock");
|
||||
}
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
qdevice_log(LOG_DEBUG, "Initializing votequorum");
|
||||
qdevice_votequorum_init(&instance);
|
||||
|
||||
qdevice_log(LOG_DEBUG, "Initializing local socket");
|
||||
if (qdevice_ipc_init(&instance) != 0) {
|
||||
return (1);
|
||||
}
|
||||
|
||||
qdevice_log(LOG_DEBUG, "Registering qdevice models");
|
||||
qdevice_model_register_all();
|
||||
|
||||
qdevice_log(LOG_DEBUG, "Configuring qdevice");
|
||||
if (qdevice_instance_configure_from_cmap(&instance) != 0) {
|
||||
return (1);
|
||||
}
|
||||
|
||||
qdevice_log(LOG_DEBUG, "Configuring master_wins");
|
||||
if (qdevice_votequorum_master_wins(&instance, (advanced_settings.master_wins ==
|
||||
QDEVICE_ADVANCED_SETTINGS_MASTER_WINS_FORCE_ON ? 1 : 0)) != 0) {
|
||||
return (1);
|
||||
}
|
||||
|
||||
qdevice_log(LOG_DEBUG, "Getting configuration node list");
|
||||
if (qdevice_cmap_store_config_node_list(&instance) != 0) {
|
||||
return (1);
|
||||
}
|
||||
|
||||
qdevice_log(LOG_DEBUG, "Initializing qdevice model");
|
||||
if (qdevice_model_init(&instance) != 0) {
|
||||
return (1);
|
||||
}
|
||||
|
||||
qdevice_log(LOG_DEBUG, "Initializing cmap tracking");
|
||||
if (qdevice_cmap_add_track(&instance) != 0) {
|
||||
return (1);
|
||||
}
|
||||
|
||||
qdevice_log(LOG_DEBUG, "Waiting for ring id");
|
||||
if (qdevice_votequorum_wait_for_ring_id(&instance) != 0) {
|
||||
return (1);
|
||||
}
|
||||
|
||||
qdevice_log(LOG_DEBUG, "Waiting for initial heuristics exec result");
|
||||
if (qdevice_heuristics_wait_for_initial_exec_result(&instance.heuristics_instance) != 0) {
|
||||
return (1);
|
||||
}
|
||||
|
||||
global_instance = &instance;
|
||||
signal_handlers_register();
|
||||
|
||||
qdevice_log(LOG_DEBUG, "Running qdevice model");
|
||||
#ifdef HAVE_LIBSYSTEMD
|
||||
sd_notify (0, "READY=1");
|
||||
#endif
|
||||
if (qdevice_model_run(&instance) != 0) {
|
||||
return (1);
|
||||
}
|
||||
|
||||
qdevice_log(LOG_DEBUG, "Removing cmap tracking");
|
||||
if (qdevice_cmap_del_track(&instance) != 0) {
|
||||
return (1);
|
||||
}
|
||||
|
||||
qdevice_log(LOG_DEBUG, "Destroying qdevice model");
|
||||
qdevice_model_destroy(&instance);
|
||||
|
||||
qdevice_log(LOG_DEBUG, "Destroying qdevice ipc");
|
||||
qdevice_ipc_destroy(&instance);
|
||||
|
||||
qdevice_log(LOG_DEBUG, "Destroying votequorum and cmap");
|
||||
qdevice_votequorum_destroy(&instance);
|
||||
qdevice_cmap_destroy(&instance);
|
||||
|
||||
qdevice_log(LOG_DEBUG, "Destroying heuristics");
|
||||
qdevice_heuristics_destroy(&instance.heuristics_instance);
|
||||
|
||||
qdevice_log(LOG_DEBUG, "Closing log");
|
||||
qdevice_log_close(&instance);
|
||||
|
||||
qdevice_instance_destroy(&instance);
|
||||
|
||||
qdevice_advanced_settings_destroy(&advanced_settings);
|
||||
|
||||
return (0);
|
||||
}
|
215
qdevices/corosync-qnetd-certutil.sh
Normal file
215
qdevices/corosync-qnetd-certutil.sh
Normal file
@ -0,0 +1,215 @@
|
||||
#!@BASHPATH@
|
||||
|
||||
#
|
||||
# Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
#
|
||||
# All rights reserved.
|
||||
#
|
||||
# Author: Jan Friesse (jfriesse@redhat.com)
|
||||
#
|
||||
# This software licensed under BSD license, the text of which follows:
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# - Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# - Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from this
|
||||
# software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
# THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
CONFIG_DIR="@COROSYSCONFDIR@/qnetd"
|
||||
DB_DIR="$CONFIG_DIR/nssdb"
|
||||
# Validity of certificate (months)
|
||||
CRT_VALIDITY=1200
|
||||
CA_NICKNAME="QNet CA"
|
||||
SERVER_NICKNAME="QNetd Cert"
|
||||
CLUSTER_NICKNAME="Cluster Cert"
|
||||
CA_SUBJECT="CN=QNet CA"
|
||||
SERVER_SUBJECT="CN=Qnetd Server"
|
||||
PWD_FILE="$DB_DIR/pwdfile.txt"
|
||||
NOISE_FILE="$DB_DIR/noise.txt"
|
||||
SERIAL_NO_FILE="$DB_DIR/serial.txt"
|
||||
CA_EXPORT_FILE="$DB_DIR/qnetd-cacert.crt"
|
||||
CRT_FILE_BASE="" # Generated from cluster name
|
||||
|
||||
usage() {
|
||||
echo "$0: [-i|-s] [-c certificate] [-n cluster_name]"
|
||||
echo
|
||||
echo " -i Initialize QNetd CA and generate server certificate"
|
||||
echo " -s Sign cluster certificate (needs cluster certificate)"
|
||||
echo " -c certificate CRQ certificate file name"
|
||||
echo " -n cluster_name Name of cluster (for -s operation)"
|
||||
|
||||
exit 0
|
||||
}
|
||||
|
||||
chown_ref_cfgdir() {
|
||||
if [ "$UID" == "0" ];then
|
||||
chown --reference="$CONFIG_DIR" "$@" 2>/dev/null || chown `stat -f "%u:%g" "$CONFIG_DIR"` "$@" 2>/dev/null || return $?
|
||||
fi
|
||||
}
|
||||
|
||||
create_new_noise_file() {
|
||||
local noise_file="$1"
|
||||
|
||||
if [ ! -e "$noise_file" ];then
|
||||
echo "Creating new noise file $noise_file"
|
||||
|
||||
(ps -elf; date; w) | sha1sum | (read sha_sum rest; echo $sha_sum) > "$noise_file"
|
||||
|
||||
chown_ref_cfgdir "$noise_file"
|
||||
chmod 0660 "$noise_file"
|
||||
else
|
||||
echo "Using existing noise file $noise_file"
|
||||
fi
|
||||
}
|
||||
|
||||
get_serial_no() {
|
||||
local serial_no
|
||||
|
||||
if ! [ -f "$SERIAL_NO_FILE" ];then
|
||||
echo "100" > $SERIAL_NO_FILE
|
||||
chown_ref_cfgdir "$SERIAL_NO_FILE"
|
||||
chmod 0660 "$SERIAL_NO_FILE"
|
||||
fi
|
||||
serial_no=`cat $SERIAL_NO_FILE`
|
||||
serial_no=$((serial_no+1))
|
||||
echo "$serial_no" > $SERIAL_NO_FILE
|
||||
echo "$serial_no"
|
||||
}
|
||||
|
||||
init_qnetd_ca() {
|
||||
if [ -f "$DB_DIR/cert8.db" ];then
|
||||
echo "Certificate database ($DB_DIR) already exists. Delete it to initialize new db" >&2
|
||||
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! [ -d "$DB_DIR" ];then
|
||||
echo "Creating $DB_DIR"
|
||||
mkdir -p "$DB_DIR"
|
||||
chown_ref_cfgdir "$DB_DIR"
|
||||
chmod 0770 "$DB_DIR"
|
||||
fi
|
||||
|
||||
echo "Creating new key and cert db"
|
||||
echo -n "" > "$PWD_FILE"
|
||||
chown_ref_cfgdir "$PWD_FILE"
|
||||
chmod 0660 "$PWD_FILE"
|
||||
|
||||
certutil -N -d "$DB_DIR" -f "$PWD_FILE"
|
||||
chown_ref_cfgdir "$DB_DIR/key3.db" "$DB_DIR/cert8.db" "$DB_DIR/secmod.db"
|
||||
chmod 0660 "$DB_DIR/key3.db" "$DB_DIR/cert8.db" "$DB_DIR/secmod.db"
|
||||
|
||||
create_new_noise_file "$NOISE_FILE"
|
||||
|
||||
echo "Creating new CA"
|
||||
# Create self-signed certificate (CA). Asks 3 questions (is this CA, lifetime and critical extension
|
||||
echo -e "y\n0\ny\n" | certutil -S -n "$CA_NICKNAME" -s "$CA_SUBJECT" -x \
|
||||
-t "CT,," -m `get_serial_no` -v $CRT_VALIDITY -d "$DB_DIR" \
|
||||
-z "$NOISE_FILE" -f "$PWD_FILE" -2
|
||||
# Export CA certificate in ascii
|
||||
certutil -L -d "$DB_DIR" -n "$CA_NICKNAME" > "$CA_EXPORT_FILE"
|
||||
certutil -L -d "$DB_DIR" -n "$CA_NICKNAME" -a >> "$CA_EXPORT_FILE"
|
||||
chown_ref_cfgdir "$CA_EXPORT_FILE"
|
||||
|
||||
certutil -S -n "$SERVER_NICKNAME" -s "$SERVER_SUBJECT" -c "$CA_NICKNAME" -t "u,u,u" -m `get_serial_no` \
|
||||
-v $CRT_VALIDITY -d "$DB_DIR" -z "$NOISE_FILE" -f "$PWD_FILE"
|
||||
|
||||
echo "QNetd CA certificate is exported as $CA_EXPORT_FILE"
|
||||
}
|
||||
|
||||
|
||||
sign_cluster_cert() {
|
||||
if ! [ -f "$DB_DIR/cert8.db" ];then
|
||||
echo "Certificate database doesn't exists. Use $0 -I to create it" >&2
|
||||
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Signing cluster certificate"
|
||||
certutil -C -v "$CRT_VALIDITY" -m `get_serial_no` -i "$CERTIFICATE_FILE" -o "$CRT_FILE" -c "$CA_NICKNAME" -d "$DB_DIR"
|
||||
chown_ref_cfgdir "$CRT_FILE"
|
||||
|
||||
echo "Certificate stored in $CRT_FILE"
|
||||
}
|
||||
|
||||
|
||||
OPERATION=""
|
||||
CERTIFICATE_FILE=""
|
||||
CLUSTER_NAME=""
|
||||
|
||||
while getopts ":hisc:n:" opt; do
|
||||
case $opt in
|
||||
i)
|
||||
OPERATION=init_qnetd_ca
|
||||
;;
|
||||
s)
|
||||
OPERATION=sign_cluster_cert
|
||||
;;
|
||||
h)
|
||||
usage
|
||||
;;
|
||||
c)
|
||||
CERTIFICATE_FILE="$OPTARG"
|
||||
;;
|
||||
n)
|
||||
CLUSTER_NAME="$OPTARG"
|
||||
;;
|
||||
\?)
|
||||
echo "Invalid option: -$OPTARG" >&2
|
||||
|
||||
exit 1
|
||||
;;
|
||||
:)
|
||||
echo "Option -$OPTARG requires an argument." >&2
|
||||
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
[ "$OPERATION" == "" ] && usage
|
||||
|
||||
CRT_FILE="$DB_DIR/cluster-$CLUSTER_NAME.crt"
|
||||
|
||||
case "$OPERATION" in
|
||||
"init_qnetd_ca")
|
||||
init_qnetd_ca
|
||||
;;
|
||||
"sign_cluster_cert")
|
||||
if ! [ -e "$CERTIFICATE_FILE" ];then
|
||||
echo "Can't open certificate file $CERTIFICATE_FILE" >&2
|
||||
|
||||
exit 2
|
||||
fi
|
||||
|
||||
if [ "$CLUSTER_NAME" == "" ];then
|
||||
echo "You have to specify cluster name" >&2
|
||||
|
||||
exit 2
|
||||
fi
|
||||
|
||||
sign_cluster_cert
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
;;
|
||||
esac
|
310
qdevices/corosync-qnetd-tool.c
Normal file
310
qdevices/corosync-qnetd-tool.c
Normal file
@ -0,0 +1,310 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "qnet-config.h"
|
||||
|
||||
#include "dynar.h"
|
||||
#include "dynar-str.h"
|
||||
#include "utils.h"
|
||||
#include "unix-socket.h"
|
||||
|
||||
#define IPC_READ_BUF_SIZE 512
|
||||
|
||||
enum qnetd_tool_operation {
|
||||
QNETD_TOOL_OPERATION_NONE,
|
||||
QNETD_TOOL_OPERATION_SHUTDOWN,
|
||||
QNETD_TOOL_OPERATION_STATUS,
|
||||
QNETD_TOOL_OPERATION_LIST,
|
||||
};
|
||||
|
||||
enum qnetd_tool_exit_code {
|
||||
QNETD_TOOL_EXIT_CODE_NO_ERROR = 0,
|
||||
QNETD_TOOL_EXIT_CODE_USAGE = 1,
|
||||
QNETD_TOOL_EXIT_CODE_INTERNAL_ERROR = 2,
|
||||
QNETD_TOOL_EXIT_CODE_SOCKET_CONNECT = 3,
|
||||
QNETD_TOOL_EXIT_CODE_QNETD_RETURNED_ERROR = 4,
|
||||
};
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
|
||||
printf("usage: %s [-Hhlsv] [-c cluster_name] [-p qnetd_ipc_socket_path]\n",
|
||||
QNETD_TOOL_PROGRAM_NAME);
|
||||
}
|
||||
|
||||
static void
|
||||
cli_parse(int argc, char * const argv[], enum qnetd_tool_operation *operation,
|
||||
int *verbose, char **cluster_name, char **socket_path)
|
||||
{
|
||||
int ch;
|
||||
|
||||
*operation = QNETD_TOOL_OPERATION_NONE;
|
||||
*verbose = 0;
|
||||
*cluster_name = NULL;
|
||||
*socket_path = strdup(QNETD_DEFAULT_LOCAL_SOCKET_FILE);
|
||||
|
||||
if (*socket_path == NULL) {
|
||||
errx(QNETD_TOOL_EXIT_CODE_INTERNAL_ERROR,
|
||||
"Can't alloc memory for socket path string");
|
||||
}
|
||||
|
||||
while ((ch = getopt(argc, argv, "Hhlsvc:p:")) != -1) {
|
||||
switch (ch) {
|
||||
case 'H':
|
||||
*operation = QNETD_TOOL_OPERATION_SHUTDOWN;
|
||||
break;
|
||||
case 'l':
|
||||
*operation = QNETD_TOOL_OPERATION_LIST;
|
||||
break;
|
||||
case 's':
|
||||
*operation = QNETD_TOOL_OPERATION_STATUS;
|
||||
break;
|
||||
case 'v':
|
||||
*verbose = 1;
|
||||
break;
|
||||
case 'c':
|
||||
free(*cluster_name);
|
||||
*cluster_name = strdup(optarg);
|
||||
if (*cluster_name == NULL) {
|
||||
errx(QNETD_TOOL_EXIT_CODE_INTERNAL_ERROR,
|
||||
"Can't alloc memory for cluster name string");
|
||||
}
|
||||
break;
|
||||
case 'p':
|
||||
free(*socket_path);
|
||||
*socket_path = strdup(optarg);
|
||||
if (*socket_path == NULL) {
|
||||
errx(QNETD_TOOL_EXIT_CODE_INTERNAL_ERROR,
|
||||
"Can't alloc memory for socket path string");
|
||||
}
|
||||
break;
|
||||
case 'h':
|
||||
case '?':
|
||||
usage();
|
||||
exit(QNETD_TOOL_EXIT_CODE_USAGE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (*operation == QNETD_TOOL_OPERATION_NONE) {
|
||||
usage();
|
||||
exit(QNETD_TOOL_EXIT_CODE_USAGE);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
store_command(struct dynar *str, enum qnetd_tool_operation operation, int verbose,
|
||||
const char *cluster_name)
|
||||
{
|
||||
const char *nline = "\n\0";
|
||||
const int nline_len = 2;
|
||||
|
||||
switch (operation) {
|
||||
case QNETD_TOOL_OPERATION_NONE:
|
||||
errx(QNETD_TOOL_EXIT_CODE_INTERNAL_ERROR, "Unhandled operation none");
|
||||
break;
|
||||
case QNETD_TOOL_OPERATION_SHUTDOWN:
|
||||
if (dynar_str_cat(str, "shutdown ") != 0) {
|
||||
return (-1);
|
||||
}
|
||||
break;
|
||||
case QNETD_TOOL_OPERATION_STATUS:
|
||||
if (dynar_str_cat(str, "status ") != 0) {
|
||||
return (-1);
|
||||
}
|
||||
break;
|
||||
case QNETD_TOOL_OPERATION_LIST:
|
||||
if (dynar_str_cat(str, "list ") != 0) {
|
||||
return (-1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
if (dynar_str_cat(str, "verbose ") != 0) {
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
if (cluster_name != NULL) {
|
||||
if (dynar_str_cat(str, "cluster ") != 0 ||
|
||||
dynar_str_quote_cat(str, cluster_name) != 0 ||
|
||||
dynar_str_cat(str, " ") != 0) {
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
if (dynar_cat(str, nline, nline_len) != 0) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* -1 - Internal error (can't alloc memory)
|
||||
* 0 - No error
|
||||
* 1 - IPC returned error
|
||||
* 2 - Unknown status line
|
||||
*/
|
||||
static int
|
||||
read_ipc_reply(FILE *f)
|
||||
{
|
||||
struct dynar read_str;
|
||||
int ch;
|
||||
int status_readed;
|
||||
int res;
|
||||
static const char *ok_str = "OK";
|
||||
static const char *err_str = "Error";
|
||||
int err_set;
|
||||
char c;
|
||||
|
||||
dynar_init(&read_str, IPC_READ_BUF_SIZE);
|
||||
|
||||
status_readed = 0;
|
||||
err_set = 0;
|
||||
res = 0;
|
||||
|
||||
while ((ch = fgetc(f)) != EOF) {
|
||||
if (status_readed) {
|
||||
putc(ch, (err_set ? stderr : stdout));
|
||||
} else {
|
||||
if (ch == '\r') {
|
||||
} else if (ch == '\n') {
|
||||
status_readed = 1;
|
||||
|
||||
c = '\0';
|
||||
if (dynar_cat(&read_str, &c, sizeof(c)) != 0) {
|
||||
res = -1;
|
||||
goto exit_destroy;
|
||||
}
|
||||
|
||||
if (strcasecmp(dynar_data(&read_str), ok_str) == 0) {
|
||||
} else if (strcasecmp(dynar_data(&read_str), err_str) == 0) {
|
||||
err_set = 1;
|
||||
res = 1;
|
||||
fprintf(stderr, "Error: ");
|
||||
} else {
|
||||
res = 2;
|
||||
goto exit_destroy;
|
||||
}
|
||||
} else {
|
||||
c = ch;
|
||||
if (dynar_cat(&read_str, &c, sizeof(c)) != 0) {
|
||||
res = -1;
|
||||
goto exit_destroy;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exit_destroy:
|
||||
dynar_destroy(&read_str);
|
||||
|
||||
return (res);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char * const argv[])
|
||||
{
|
||||
enum qnetd_tool_operation operation;
|
||||
int verbose;
|
||||
char *cluster_name;
|
||||
char *socket_path;
|
||||
int sock_fd;
|
||||
FILE *sock;
|
||||
struct dynar send_str;
|
||||
int res;
|
||||
int exit_code;
|
||||
|
||||
exit_code = QNETD_TOOL_EXIT_CODE_NO_ERROR;
|
||||
|
||||
cli_parse(argc, argv, &operation, &verbose, &cluster_name, &socket_path);
|
||||
|
||||
dynar_init(&send_str, QNETD_DEFAULT_IPC_MAX_RECEIVE_SIZE);
|
||||
|
||||
sock_fd = unix_socket_client_create(socket_path, 0);
|
||||
if (sock_fd == -1) {
|
||||
err(QNETD_TOOL_EXIT_CODE_SOCKET_CONNECT,
|
||||
"Can't connect to qnetd socket (is QNetd running?)");
|
||||
}
|
||||
|
||||
sock = fdopen(sock_fd, "w+t");
|
||||
if (sock == NULL) {
|
||||
err(QNETD_TOOL_EXIT_CODE_INTERNAL_ERROR, "Can't open QNetd socket fd");
|
||||
}
|
||||
|
||||
if (store_command(&send_str, operation, verbose, cluster_name) != 0) {
|
||||
errx(QNETD_TOOL_EXIT_CODE_INTERNAL_ERROR, "Can't store command");
|
||||
}
|
||||
|
||||
res = fprintf(sock, "%s", dynar_data(&send_str));
|
||||
if (res < 0 || (size_t)res != strlen(dynar_data(&send_str)) ||
|
||||
fflush(sock) != 0) {
|
||||
errx(QNETD_TOOL_EXIT_CODE_INTERNAL_ERROR, "Can't send command");
|
||||
}
|
||||
|
||||
res = read_ipc_reply(sock);
|
||||
switch (res) {
|
||||
case -1:
|
||||
errx(QNETD_TOOL_EXIT_CODE_INTERNAL_ERROR, "Internal error during IPC status line read");
|
||||
break;
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
exit_code = QNETD_TOOL_EXIT_CODE_QNETD_RETURNED_ERROR;
|
||||
break;
|
||||
case 2:
|
||||
errx(QNETD_TOOL_EXIT_CODE_SOCKET_CONNECT, "Unknown status line returned by IPC server");
|
||||
break;
|
||||
}
|
||||
|
||||
if (fclose(sock) != 0) {
|
||||
warn("Can't close QNetd socket");
|
||||
}
|
||||
|
||||
free(cluster_name);
|
||||
free(socket_path);
|
||||
dynar_destroy(&send_str);
|
||||
|
||||
return (exit_code);
|
||||
}
|
662
qdevices/corosync-qnetd.c
Normal file
662
qdevices/corosync-qnetd.c
Normal file
@ -0,0 +1,662 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "qnet-config.h"
|
||||
|
||||
#include "dynar.h"
|
||||
#include "dynar-str.h"
|
||||
#include "dynar-getopt-lex.h"
|
||||
#include "nss-sock.h"
|
||||
#include "pr-poll-array.h"
|
||||
#include "qnetd-advanced-settings.h"
|
||||
#include "qnetd-algorithm.h"
|
||||
#include "qnetd-instance.h"
|
||||
#include "qnetd-ipc.h"
|
||||
#include "qnetd-log.h"
|
||||
#include "qnetd-client-net.h"
|
||||
#include "qnetd-client-msg-received.h"
|
||||
#include "qnetd-poll-array-user-data.h"
|
||||
#include "utils.h"
|
||||
#include "msg.h"
|
||||
|
||||
#ifdef HAVE_LIBSYSTEMD
|
||||
#include <systemd/sd-daemon.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This is global variable used for comunication with main loop and signal (calls close)
|
||||
*/
|
||||
struct qnetd_instance *global_instance;
|
||||
|
||||
enum tlv_decision_algorithm_type
|
||||
qnetd_static_supported_decision_algorithms[QNETD_STATIC_SUPPORTED_DECISION_ALGORITHMS_SIZE] = {
|
||||
TLV_DECISION_ALGORITHM_TYPE_TEST,
|
||||
TLV_DECISION_ALGORITHM_TYPE_FFSPLIT,
|
||||
TLV_DECISION_ALGORITHM_TYPE_2NODELMS,
|
||||
TLV_DECISION_ALGORITHM_TYPE_LMS,
|
||||
};
|
||||
|
||||
static void
|
||||
qnetd_err_nss(void)
|
||||
{
|
||||
|
||||
qnetd_log_nss(LOG_CRIT, "NSS error");
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void
|
||||
qnetd_warn_nss(void)
|
||||
{
|
||||
|
||||
qnetd_log_nss(LOG_WARNING, "NSS warning");
|
||||
}
|
||||
|
||||
static PRPollDesc *
|
||||
qnetd_pr_poll_array_create(struct qnetd_instance *instance)
|
||||
{
|
||||
struct pr_poll_array *poll_array;
|
||||
const struct qnetd_client_list *client_list;
|
||||
struct qnetd_client *client;
|
||||
PRPollDesc *poll_desc;
|
||||
struct qnetd_poll_array_user_data *user_data;
|
||||
const struct unix_socket_client_list *ipc_client_list;
|
||||
struct unix_socket_client *ipc_client;
|
||||
|
||||
poll_array = &instance->poll_array;
|
||||
client_list = &instance->clients;
|
||||
ipc_client_list = &instance->local_ipc.clients;
|
||||
|
||||
pr_poll_array_clean(poll_array);
|
||||
|
||||
if (pr_poll_array_add(poll_array, &poll_desc, (void **)&user_data) < 0) {
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
poll_desc->fd = instance->server.socket;
|
||||
poll_desc->in_flags = PR_POLL_READ;
|
||||
|
||||
user_data->type = QNETD_POLL_ARRAY_USER_DATA_TYPE_SOCKET;
|
||||
|
||||
if (qnetd_ipc_is_closed(instance)) {
|
||||
qnetd_log(LOG_DEBUG, "Listening socket is closed");
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (pr_poll_array_add(poll_array, &poll_desc, (void **)&user_data) < 0) {
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
poll_desc->fd = instance->ipc_socket_poll_fd;
|
||||
poll_desc->in_flags = PR_POLL_READ;
|
||||
user_data->type = QNETD_POLL_ARRAY_USER_DATA_TYPE_IPC_SOCKET;
|
||||
|
||||
TAILQ_FOREACH(client, client_list, entries) {
|
||||
if (pr_poll_array_add(poll_array, &poll_desc, (void **)&user_data) < 0) {
|
||||
return (NULL);
|
||||
}
|
||||
poll_desc->fd = client->socket;
|
||||
poll_desc->in_flags = PR_POLL_READ;
|
||||
|
||||
if (!send_buffer_list_empty(&client->send_buffer_list)) {
|
||||
poll_desc->in_flags |= PR_POLL_WRITE;
|
||||
}
|
||||
|
||||
user_data->type = QNETD_POLL_ARRAY_USER_DATA_TYPE_CLIENT;
|
||||
user_data->client = client;
|
||||
}
|
||||
|
||||
TAILQ_FOREACH(ipc_client, ipc_client_list, entries) {
|
||||
if (!ipc_client->reading_line && !ipc_client->writing_buffer) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pr_poll_array_add(poll_array, &poll_desc, (void **)&user_data) < 0) {
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
poll_desc->fd = ((struct qnetd_ipc_user_data *)ipc_client->user_data)->nspr_poll_fd;
|
||||
if (ipc_client->reading_line) {
|
||||
poll_desc->in_flags |= PR_POLL_READ;
|
||||
}
|
||||
|
||||
if (ipc_client->writing_buffer) {
|
||||
poll_desc->in_flags |= PR_POLL_WRITE;
|
||||
}
|
||||
|
||||
user_data->type = QNETD_POLL_ARRAY_USER_DATA_TYPE_IPC_CLIENT;
|
||||
user_data->ipc_client = ipc_client;
|
||||
}
|
||||
|
||||
pr_poll_array_gc(poll_array);
|
||||
|
||||
return (poll_array->array);
|
||||
}
|
||||
|
||||
static int
|
||||
qnetd_poll(struct qnetd_instance *instance)
|
||||
{
|
||||
struct qnetd_client *client;
|
||||
PRPollDesc *pfds;
|
||||
PRInt32 poll_res;
|
||||
ssize_t i;
|
||||
int client_disconnect;
|
||||
struct qnetd_poll_array_user_data *user_data;
|
||||
struct unix_socket_client *ipc_client;
|
||||
|
||||
client = NULL;
|
||||
client_disconnect = 0;
|
||||
|
||||
pfds = qnetd_pr_poll_array_create(instance);
|
||||
if (pfds == NULL) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if ((poll_res = PR_Poll(pfds, pr_poll_array_size(&instance->poll_array),
|
||||
timer_list_time_to_expire(&instance->main_timer_list))) >= 0) {
|
||||
timer_list_expire(&instance->main_timer_list);
|
||||
|
||||
/*
|
||||
* Walk thru pfds array and process events
|
||||
*/
|
||||
for (i = 0; i < pr_poll_array_size(&instance->poll_array); i++) {
|
||||
user_data = pr_poll_array_get_user_data(&instance->poll_array, i);
|
||||
|
||||
client = NULL;
|
||||
ipc_client = NULL;
|
||||
client_disconnect = 0;
|
||||
|
||||
switch (user_data->type) {
|
||||
case QNETD_POLL_ARRAY_USER_DATA_TYPE_SOCKET:
|
||||
break;
|
||||
case QNETD_POLL_ARRAY_USER_DATA_TYPE_CLIENT:
|
||||
client = user_data->client;
|
||||
client_disconnect = client->schedule_disconnect;
|
||||
break;
|
||||
case QNETD_POLL_ARRAY_USER_DATA_TYPE_IPC_SOCKET:
|
||||
break;
|
||||
case QNETD_POLL_ARRAY_USER_DATA_TYPE_IPC_CLIENT:
|
||||
ipc_client = user_data->ipc_client;
|
||||
client_disconnect = ipc_client->schedule_disconnect;
|
||||
}
|
||||
|
||||
if (!client_disconnect && poll_res > 0 &&
|
||||
pfds[i].out_flags & PR_POLL_READ) {
|
||||
switch (user_data->type) {
|
||||
case QNETD_POLL_ARRAY_USER_DATA_TYPE_SOCKET:
|
||||
qnetd_client_net_accept(instance);
|
||||
break;
|
||||
case QNETD_POLL_ARRAY_USER_DATA_TYPE_CLIENT:
|
||||
if (qnetd_client_net_read(instance, client) == -1) {
|
||||
client_disconnect = 1;
|
||||
}
|
||||
break;
|
||||
case QNETD_POLL_ARRAY_USER_DATA_TYPE_IPC_SOCKET:
|
||||
qnetd_ipc_accept(instance, &ipc_client);
|
||||
break;
|
||||
case QNETD_POLL_ARRAY_USER_DATA_TYPE_IPC_CLIENT:
|
||||
qnetd_ipc_io_read(instance, ipc_client);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!client_disconnect && poll_res > 0 &&
|
||||
pfds[i].out_flags & PR_POLL_WRITE) {
|
||||
switch (user_data->type) {
|
||||
case QNETD_POLL_ARRAY_USER_DATA_TYPE_SOCKET:
|
||||
/*
|
||||
* Poll write on listen socket -> fatal error
|
||||
*/
|
||||
qnetd_log(LOG_CRIT, "POLL_WRITE on listening socket");
|
||||
|
||||
return (-1);
|
||||
break;
|
||||
case QNETD_POLL_ARRAY_USER_DATA_TYPE_CLIENT:
|
||||
if (qnetd_client_net_write(instance, client) == -1) {
|
||||
client_disconnect = 1;
|
||||
}
|
||||
break;
|
||||
case QNETD_POLL_ARRAY_USER_DATA_TYPE_IPC_SOCKET:
|
||||
qnetd_log(LOG_CRIT, "POLL_WRITE on listening IPC socket");
|
||||
return (-1);
|
||||
break;
|
||||
case QNETD_POLL_ARRAY_USER_DATA_TYPE_IPC_CLIENT:
|
||||
qnetd_ipc_io_write(instance, ipc_client);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!client_disconnect && poll_res > 0 &&
|
||||
(pfds[i].out_flags & (PR_POLL_ERR|PR_POLL_NVAL|PR_POLL_HUP|PR_POLL_EXCEPT)) &&
|
||||
!(pfds[i].out_flags & (PR_POLL_READ|PR_POLL_WRITE))) {
|
||||
switch (user_data->type) {
|
||||
case QNETD_POLL_ARRAY_USER_DATA_TYPE_SOCKET:
|
||||
case QNETD_POLL_ARRAY_USER_DATA_TYPE_IPC_SOCKET:
|
||||
if (pfds[i].out_flags != PR_POLL_NVAL) {
|
||||
/*
|
||||
* Poll ERR on listening socket is fatal error.
|
||||
* POLL_NVAL is used as a signal to quit poll loop.
|
||||
*/
|
||||
qnetd_log(LOG_CRIT, "POLL_ERR (%u) on listening "
|
||||
"socket", pfds[i].out_flags);
|
||||
} else {
|
||||
qnetd_log(LOG_DEBUG, "Listening socket is closed");
|
||||
}
|
||||
|
||||
return (-1);
|
||||
break;
|
||||
case QNETD_POLL_ARRAY_USER_DATA_TYPE_CLIENT:
|
||||
qnetd_log(LOG_DEBUG, "POLL_ERR (%u) on client socket. "
|
||||
"Disconnecting.", pfds[i].out_flags);
|
||||
|
||||
client_disconnect = 1;
|
||||
break;
|
||||
case QNETD_POLL_ARRAY_USER_DATA_TYPE_IPC_CLIENT:
|
||||
qnetd_log(LOG_DEBUG, "POLL_ERR (%u) on ipc client socket."
|
||||
" Disconnecting.", pfds[i].out_flags);
|
||||
|
||||
client_disconnect = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If client is scheduled for disconnect, disconnect it
|
||||
*/
|
||||
if (user_data->type == QNETD_POLL_ARRAY_USER_DATA_TYPE_CLIENT &&
|
||||
client_disconnect) {
|
||||
qnetd_instance_client_disconnect(instance, client, 0);
|
||||
} else if (user_data->type == QNETD_POLL_ARRAY_USER_DATA_TYPE_IPC_CLIENT &&
|
||||
(client_disconnect || ipc_client->schedule_disconnect)) {
|
||||
qnetd_ipc_client_disconnect(instance, ipc_client);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
signal_int_handler(int sig)
|
||||
{
|
||||
|
||||
qnetd_log(LOG_DEBUG, "SIGINT received - closing server IPC socket");
|
||||
|
||||
qnetd_ipc_close(global_instance);
|
||||
}
|
||||
|
||||
static void
|
||||
signal_term_handler(int sig)
|
||||
{
|
||||
|
||||
qnetd_log(LOG_DEBUG, "SIGTERM received - closing server IPC socket");
|
||||
|
||||
qnetd_ipc_close(global_instance);
|
||||
}
|
||||
|
||||
static void
|
||||
signal_handlers_register(void)
|
||||
{
|
||||
struct sigaction act;
|
||||
|
||||
act.sa_handler = signal_int_handler;
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_flags = SA_RESTART;
|
||||
|
||||
sigaction(SIGINT, &act, NULL);
|
||||
|
||||
act.sa_handler = signal_term_handler;
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_flags = SA_RESTART;
|
||||
|
||||
sigaction(SIGTERM, &act, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
|
||||
printf("usage: %s [-46dfhv] [-l listen_addr] [-p listen_port] [-s tls]\n", QNETD_PROGRAM_NAME);
|
||||
printf("%14s[-c client_cert_required] [-m max_clients] [-S option=value[,option2=value2,...]]\n", "");
|
||||
}
|
||||
|
||||
static void
|
||||
display_version(void)
|
||||
{
|
||||
enum msg_type *supported_messages;
|
||||
size_t no_supported_messages;
|
||||
size_t zi;
|
||||
|
||||
msg_get_supported_messages(&supported_messages, &no_supported_messages);
|
||||
printf("Corosync Qdevice Network Daemon, version '%s'\n\n", VERSION);
|
||||
printf("Supported algorithms: ");
|
||||
for (zi = 0; zi < QNETD_STATIC_SUPPORTED_DECISION_ALGORITHMS_SIZE; zi++) {
|
||||
if (zi != 0) {
|
||||
printf(", ");
|
||||
}
|
||||
printf("%s (%u)",
|
||||
tlv_decision_algorithm_type_to_str(qnetd_static_supported_decision_algorithms[zi]),
|
||||
qnetd_static_supported_decision_algorithms[zi]);
|
||||
}
|
||||
printf("\n");
|
||||
printf("Supported message types: ");
|
||||
for (zi = 0; zi < no_supported_messages; zi++) {
|
||||
if (zi != 0) {
|
||||
printf(", ");
|
||||
}
|
||||
printf("%s (%u)", msg_type_to_str(supported_messages[zi]), supported_messages[zi]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static void
|
||||
cli_parse_long_opt(struct qnetd_advanced_settings *advanced_settings, const char *long_opt)
|
||||
{
|
||||
struct dynar_getopt_lex lex;
|
||||
struct dynar dynar_long_opt;
|
||||
const char *opt;
|
||||
const char *val;
|
||||
int res;
|
||||
|
||||
dynar_init(&dynar_long_opt, strlen(long_opt) + 1);
|
||||
if (dynar_str_cpy(&dynar_long_opt, long_opt) != 0) {
|
||||
errx(1, "Can't alloc memory for long option");
|
||||
}
|
||||
|
||||
dynar_getopt_lex_init(&lex, &dynar_long_opt);
|
||||
|
||||
while (dynar_getopt_lex_token_next(&lex) == 0 && strcmp(dynar_data(&lex.option), "") != 0) {
|
||||
opt = dynar_data(&lex.option);
|
||||
val = dynar_data(&lex.value);
|
||||
|
||||
res = qnetd_advanced_settings_set(advanced_settings, opt, val);
|
||||
switch (res) {
|
||||
case -1:
|
||||
errx(1, "Unknown option '%s'", opt);
|
||||
break;
|
||||
case -2:
|
||||
errx(1, "Invalid value '%s' for option '%s'", val, opt);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
dynar_getopt_lex_destroy(&lex);
|
||||
dynar_destroy(&dynar_long_opt);
|
||||
}
|
||||
|
||||
static void
|
||||
cli_parse(int argc, char * const argv[], char **host_addr, uint16_t *host_port, int *foreground,
|
||||
int *debug_log, int *bump_log_priority, enum tlv_tls_supported *tls_supported,
|
||||
int *client_cert_required, size_t *max_clients, PRIntn *address_family,
|
||||
struct qnetd_advanced_settings *advanced_settings)
|
||||
{
|
||||
int ch;
|
||||
char *ep;
|
||||
long long int tmpll;
|
||||
|
||||
*host_addr = NULL;
|
||||
*host_port = QNETD_DEFAULT_HOST_PORT;
|
||||
*foreground = 0;
|
||||
*debug_log = 0;
|
||||
*bump_log_priority = 0;
|
||||
*tls_supported = QNETD_DEFAULT_TLS_SUPPORTED;
|
||||
*client_cert_required = QNETD_DEFAULT_TLS_CLIENT_CERT_REQUIRED;
|
||||
*max_clients = QNETD_DEFAULT_MAX_CLIENTS;
|
||||
*address_family = PR_AF_UNSPEC;
|
||||
|
||||
while ((ch = getopt(argc, argv, "46dfhvc:l:m:p:S:s:")) != -1) {
|
||||
switch (ch) {
|
||||
case '4':
|
||||
*address_family = PR_AF_INET;
|
||||
break;
|
||||
case '6':
|
||||
*address_family = PR_AF_INET6;
|
||||
break;
|
||||
case 'f':
|
||||
*foreground = 1;
|
||||
break;
|
||||
case 'd':
|
||||
if (*debug_log) {
|
||||
*bump_log_priority = 1;
|
||||
}
|
||||
*debug_log = 1;
|
||||
break;
|
||||
case 'c':
|
||||
if ((*client_cert_required = utils_parse_bool_str(optarg)) == -1) {
|
||||
errx(1, "client_cert_required should be on/yes/1, off/no/0");
|
||||
}
|
||||
break;
|
||||
case 'l':
|
||||
free(*host_addr);
|
||||
*host_addr = strdup(optarg);
|
||||
if (*host_addr == NULL) {
|
||||
errx(1, "Can't alloc memory for host addr string");
|
||||
}
|
||||
break;
|
||||
case 'm':
|
||||
errno = 0;
|
||||
|
||||
tmpll = strtoll(optarg, &ep, 10);
|
||||
if (tmpll < 0 || errno != 0 || *ep != '\0') {
|
||||
errx(1, "max clients value %s is invalid", optarg);
|
||||
}
|
||||
*max_clients = (size_t)tmpll;
|
||||
break;
|
||||
case 'p':
|
||||
*host_port = strtol(optarg, &ep, 10);
|
||||
if (*host_port <= 0 || *host_port > ((uint16_t)~0) || *ep != '\0') {
|
||||
errx(1, "host port must be in range 0-65535");
|
||||
}
|
||||
break;
|
||||
case 'S':
|
||||
cli_parse_long_opt(advanced_settings, optarg);
|
||||
break;
|
||||
case 's':
|
||||
if (strcasecmp(optarg, "on") == 0) {
|
||||
*tls_supported = QNETD_DEFAULT_TLS_SUPPORTED;
|
||||
} else if (strcasecmp(optarg, "off") == 0) {
|
||||
*tls_supported = TLV_TLS_UNSUPPORTED;
|
||||
} else if (strcasecmp(optarg, "req") == 0) {
|
||||
*tls_supported = TLV_TLS_REQUIRED;
|
||||
} else {
|
||||
errx(1, "tls must be one of on, off, req");
|
||||
}
|
||||
break;
|
||||
case 'v':
|
||||
display_version();
|
||||
exit(1);
|
||||
break;
|
||||
case 'h':
|
||||
case '?':
|
||||
usage();
|
||||
exit(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char * const argv[])
|
||||
{
|
||||
struct qnetd_instance instance;
|
||||
struct qnetd_advanced_settings advanced_settings;
|
||||
char *host_addr;
|
||||
uint16_t host_port;
|
||||
int foreground;
|
||||
int debug_log;
|
||||
int bump_log_priority;
|
||||
enum tlv_tls_supported tls_supported;
|
||||
int client_cert_required;
|
||||
size_t max_clients;
|
||||
PRIntn address_family;
|
||||
int lock_file;
|
||||
int another_instance_running;
|
||||
|
||||
if (qnetd_advanced_settings_init(&advanced_settings) != 0) {
|
||||
errx(1, "Can't alloc memory for advanced settings");
|
||||
}
|
||||
|
||||
cli_parse(argc, argv, &host_addr, &host_port, &foreground, &debug_log, &bump_log_priority,
|
||||
&tls_supported, &client_cert_required, &max_clients, &address_family, &advanced_settings);
|
||||
|
||||
if (foreground) {
|
||||
qnetd_log_init(QNETD_LOG_TARGET_STDERR);
|
||||
} else {
|
||||
qnetd_log_init(QNETD_LOG_TARGET_SYSLOG);
|
||||
}
|
||||
|
||||
qnetd_log_set_debug(debug_log);
|
||||
qnetd_log_set_priority_bump(bump_log_priority);
|
||||
|
||||
/*
|
||||
* Daemonize
|
||||
*/
|
||||
if (!foreground) {
|
||||
utils_tty_detach();
|
||||
}
|
||||
|
||||
if ((lock_file = utils_flock(advanced_settings.lock_file, getpid(),
|
||||
&another_instance_running)) == -1) {
|
||||
if (another_instance_running) {
|
||||
qnetd_log(LOG_ERR, "Another instance is running");
|
||||
} else {
|
||||
qnetd_log_err(LOG_ERR, "Can't acquire lock");
|
||||
}
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
qnetd_log(LOG_DEBUG, "Initializing nss");
|
||||
if (nss_sock_init_nss((tls_supported != TLV_TLS_UNSUPPORTED ?
|
||||
advanced_settings.nss_db_dir : NULL)) != 0) {
|
||||
qnetd_err_nss();
|
||||
}
|
||||
|
||||
if (SSL_ConfigServerSessionIDCache(0, 0, 0, NULL) != SECSuccess) {
|
||||
qnetd_err_nss();
|
||||
}
|
||||
|
||||
if (qnetd_instance_init(&instance, tls_supported, client_cert_required,
|
||||
max_clients, &advanced_settings) == -1) {
|
||||
qnetd_log(LOG_ERR, "Can't initialize qnetd");
|
||||
exit(1);
|
||||
}
|
||||
instance.host_addr = host_addr;
|
||||
instance.host_port = host_port;
|
||||
|
||||
if (tls_supported != TLV_TLS_UNSUPPORTED && qnetd_instance_init_certs(&instance) == -1) {
|
||||
qnetd_err_nss();
|
||||
}
|
||||
|
||||
qnetd_log(LOG_DEBUG, "Initializing local socket");
|
||||
if (qnetd_ipc_init(&instance) != 0) {
|
||||
return (1);
|
||||
}
|
||||
|
||||
qnetd_log(LOG_DEBUG, "Creating listening socket");
|
||||
instance.server.socket = nss_sock_create_listen_socket(instance.host_addr,
|
||||
instance.host_port, address_family);
|
||||
if (instance.server.socket == NULL) {
|
||||
qnetd_err_nss();
|
||||
}
|
||||
|
||||
if (nss_sock_set_non_blocking(instance.server.socket) != 0) {
|
||||
qnetd_err_nss();
|
||||
}
|
||||
|
||||
if (PR_Listen(instance.server.socket, instance.advanced_settings->listen_backlog) !=
|
||||
PR_SUCCESS) {
|
||||
qnetd_err_nss();
|
||||
}
|
||||
|
||||
global_instance = &instance;
|
||||
signal_handlers_register();
|
||||
|
||||
qnetd_log(LOG_DEBUG, "Registering algorithms");
|
||||
if (qnetd_algorithm_register_all() != 0) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
qnetd_log(LOG_DEBUG, "QNetd ready to provide service");
|
||||
|
||||
#ifdef HAVE_LIBSYSTEMD
|
||||
sd_notify(0, "READY=1");
|
||||
#endif
|
||||
|
||||
/*
|
||||
* MAIN LOOP
|
||||
*/
|
||||
while (qnetd_poll(&instance) == 0) {
|
||||
}
|
||||
|
||||
/*
|
||||
* Cleanup
|
||||
*/
|
||||
qnetd_ipc_destroy(&instance);
|
||||
|
||||
if (PR_Close(instance.server.socket) != PR_SUCCESS) {
|
||||
qnetd_warn_nss();
|
||||
}
|
||||
|
||||
CERT_DestroyCertificate(instance.server.cert);
|
||||
SECKEY_DestroyPrivateKey(instance.server.private_key);
|
||||
|
||||
SSL_ClearSessionCache();
|
||||
|
||||
SSL_ShutdownServerSessionIDCache();
|
||||
|
||||
qnetd_instance_destroy(&instance);
|
||||
|
||||
qnetd_advanced_settings_destroy(&advanced_settings);
|
||||
|
||||
if (NSS_Shutdown() != SECSuccess) {
|
||||
qnetd_warn_nss();
|
||||
}
|
||||
|
||||
if (PR_Cleanup() != PR_SUCCESS) {
|
||||
qnetd_warn_nss();
|
||||
}
|
||||
|
||||
qnetd_log_close();
|
||||
|
||||
return (0);
|
||||
}
|
129
qdevices/dynar-getopt-lex.c
Normal file
129
qdevices/dynar-getopt-lex.c
Normal file
@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "dynar-getopt-lex.h"
|
||||
|
||||
void
|
||||
dynar_getopt_lex_init(struct dynar_getopt_lex *lex, struct dynar *input)
|
||||
{
|
||||
|
||||
memset(lex, 0, sizeof(*lex));
|
||||
lex->input = input;
|
||||
dynar_init(&lex->option, dynar_max_size(input));
|
||||
dynar_init(&lex->value, dynar_max_size(input));
|
||||
}
|
||||
|
||||
void
|
||||
dynar_getopt_lex_destroy(struct dynar_getopt_lex *lex)
|
||||
{
|
||||
|
||||
dynar_destroy(&lex->option);
|
||||
dynar_destroy(&lex->value);
|
||||
memset(lex, 0, sizeof(*lex));
|
||||
}
|
||||
|
||||
/*
|
||||
* 0 - no error
|
||||
* -1 - Can't add character
|
||||
*/
|
||||
int
|
||||
dynar_getopt_lex_token_next(struct dynar_getopt_lex *lex)
|
||||
{
|
||||
size_t pos;
|
||||
size_t size;
|
||||
char *str;
|
||||
char ch;
|
||||
int state;
|
||||
|
||||
dynar_clean(&lex->option);
|
||||
dynar_clean(&lex->value);
|
||||
|
||||
size = dynar_size(lex->input);
|
||||
str = dynar_data(lex->input);
|
||||
|
||||
state = 1;
|
||||
pos = lex->pos;
|
||||
|
||||
while (state != 0 && pos < size) {
|
||||
ch = str[pos];
|
||||
|
||||
switch (state) {
|
||||
case 1:
|
||||
/*
|
||||
* Read option name, wait for = or ,
|
||||
*/
|
||||
if (ch == '=') {
|
||||
pos++;
|
||||
state = 2;
|
||||
} else if (ch == ',') {
|
||||
pos++;
|
||||
state = 0;
|
||||
} else {
|
||||
pos++;
|
||||
if (dynar_cat(&lex->option, &ch, sizeof(ch)) != 0) {
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
/*
|
||||
* Wait for end of str or ,
|
||||
*/
|
||||
if (ch == ',') {
|
||||
pos++;
|
||||
state = 0;
|
||||
} else {
|
||||
pos++;
|
||||
if (dynar_cat(&lex->value, &ch, sizeof(ch)) != 0) {
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ch = '\0';
|
||||
if (dynar_cat(&lex->option, &ch, sizeof(ch)) != 0) {
|
||||
return (-1);
|
||||
}
|
||||
if (dynar_cat(&lex->value, &ch, sizeof(ch)) != 0) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
lex->pos = pos;
|
||||
|
||||
return (0);
|
||||
}
|
61
qdevices/dynar-getopt-lex.h
Normal file
61
qdevices/dynar-getopt-lex.h
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _DYNAR_GETOPT_LEX_H_
|
||||
#define _DYNAR_GETOPT_LEX_H_
|
||||
|
||||
#include "dynar.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct dynar_getopt_lex {
|
||||
struct dynar option;
|
||||
struct dynar value;
|
||||
struct dynar *input;
|
||||
size_t pos;
|
||||
};
|
||||
|
||||
extern void dynar_getopt_lex_init(struct dynar_getopt_lex *lex, struct dynar *input);
|
||||
|
||||
extern void dynar_getopt_lex_destroy(struct dynar_getopt_lex *lex);
|
||||
|
||||
extern int dynar_getopt_lex_token_next(struct dynar_getopt_lex *lex);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _DYNAR_GETOPT_LEX_H_ */
|
203
qdevices/dynar-simple-lex.c
Normal file
203
qdevices/dynar-simple-lex.c
Normal file
@ -0,0 +1,203 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "dynar-simple-lex.h"
|
||||
|
||||
/*
|
||||
* Simple_lex is going to be used in protocol and it's not good idea to depend on locale
|
||||
*/
|
||||
static int
|
||||
dynar_simple_lex_is_space(char ch)
|
||||
{
|
||||
return (ch == ' ' || ch == '\f' || ch == '\n' || ch == '\r' || ch == '\t' || ch == '\v');
|
||||
}
|
||||
|
||||
void
|
||||
dynar_simple_lex_init(struct dynar_simple_lex *lex, struct dynar *input,
|
||||
enum dynar_simple_lex_type lex_type)
|
||||
{
|
||||
|
||||
memset(lex, 0, sizeof(*lex));
|
||||
lex->input = input;
|
||||
lex->lex_type = lex_type;
|
||||
dynar_init(&lex->token, dynar_max_size(input));
|
||||
}
|
||||
|
||||
void
|
||||
dynar_simple_lex_destroy(struct dynar_simple_lex *lex)
|
||||
{
|
||||
|
||||
dynar_destroy(&lex->token);
|
||||
memset(lex, 0, sizeof(*lex));
|
||||
}
|
||||
|
||||
struct dynar *
|
||||
dynar_simple_lex_token_next(struct dynar_simple_lex *lex)
|
||||
{
|
||||
size_t pos;
|
||||
size_t size;
|
||||
char *str;
|
||||
char ch, ch2;
|
||||
int add_char;
|
||||
int state;
|
||||
|
||||
dynar_clean(&lex->token);
|
||||
|
||||
size = dynar_size(lex->input);
|
||||
str = dynar_data(lex->input);
|
||||
|
||||
state = 1;
|
||||
pos = lex->pos;
|
||||
|
||||
while (state != 0) {
|
||||
if (pos < size) {
|
||||
ch = str[pos];
|
||||
} else {
|
||||
ch = '\0';
|
||||
}
|
||||
|
||||
add_char = 0;
|
||||
|
||||
switch (state) {
|
||||
case 1:
|
||||
/*
|
||||
* Skip spaces. Newline is special and means end of processing
|
||||
*/
|
||||
if (pos >= size || ch == '\n' || ch == '\r') {
|
||||
state = 0;
|
||||
} else if (dynar_simple_lex_is_space(ch)) {
|
||||
pos++;
|
||||
} else {
|
||||
state = 2;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
/*
|
||||
* Read word
|
||||
*/
|
||||
if (pos >= size) {
|
||||
state = 0;
|
||||
} else if ((lex->lex_type == DYNAR_SIMPLE_LEX_TYPE_BACKSLASH ||
|
||||
lex->lex_type == DYNAR_SIMPLE_LEX_TYPE_QUOTE) && ch == '\\') {
|
||||
pos++;
|
||||
state = 3;
|
||||
} else if (lex->lex_type == DYNAR_SIMPLE_LEX_TYPE_QUOTE &&
|
||||
ch == '"') {
|
||||
pos++;
|
||||
state = 4;
|
||||
} else if (dynar_simple_lex_is_space(ch)) {
|
||||
state = 0;
|
||||
} else {
|
||||
pos++;
|
||||
add_char = 1;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
/*
|
||||
* Process backslash
|
||||
*/
|
||||
if (pos >= size || ch == '\n' || ch == '\r') {
|
||||
/*
|
||||
* End of string. Do not include backslash (it's just ignored)
|
||||
*/
|
||||
state = 0;
|
||||
} else {
|
||||
add_char = 1;
|
||||
state = 2;
|
||||
pos++;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
/*
|
||||
* Quote word
|
||||
*/
|
||||
if (pos >= size) {
|
||||
state = 0;
|
||||
} else if (ch == '\\') {
|
||||
state = 5;
|
||||
pos++;
|
||||
} else if (ch == '"') {
|
||||
state = 2;
|
||||
pos++;
|
||||
} else if (ch == '\n' || ch == '\r') {
|
||||
state = 0;
|
||||
} else {
|
||||
pos++;
|
||||
add_char = 1;
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
/*
|
||||
* Quote word backslash
|
||||
*/
|
||||
if (pos >= size || ch == '\n' || ch == '\r') {
|
||||
/*
|
||||
* End of string. Do not include backslash (it's just ignored)
|
||||
*/
|
||||
state = 0;
|
||||
} else if (ch == '\\' || ch == '"') {
|
||||
add_char = 1;
|
||||
state = 4;
|
||||
pos++;
|
||||
} else {
|
||||
ch2 = '\\';
|
||||
if (dynar_cat(&lex->token, &ch2, sizeof(ch2)) != 0) {
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
add_char = 1;
|
||||
state = 4;
|
||||
pos++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (add_char) {
|
||||
if (dynar_cat(&lex->token, &ch, sizeof(ch)) != 0) {
|
||||
return (NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ch = '\0';
|
||||
if (dynar_cat(&lex->token, &ch, sizeof(ch)) != 0) {
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
lex->pos = pos;
|
||||
|
||||
return (&lex->token);
|
||||
}
|
68
qdevices/dynar-simple-lex.h
Normal file
68
qdevices/dynar-simple-lex.h
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _DYNAR_SIMPLE_LEX_H_
|
||||
#define _DYNAR_SIMPLE_LEX_H_
|
||||
|
||||
#include "dynar.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum dynar_simple_lex_type {
|
||||
DYNAR_SIMPLE_LEX_TYPE_PLAIN,
|
||||
DYNAR_SIMPLE_LEX_TYPE_BACKSLASH,
|
||||
DYNAR_SIMPLE_LEX_TYPE_QUOTE,
|
||||
};
|
||||
|
||||
struct dynar_simple_lex {
|
||||
struct dynar token;
|
||||
struct dynar *input;
|
||||
enum dynar_simple_lex_type lex_type;
|
||||
size_t pos;
|
||||
};
|
||||
|
||||
extern void dynar_simple_lex_init(struct dynar_simple_lex *lex, struct dynar *input,
|
||||
enum dynar_simple_lex_type lex_type);
|
||||
|
||||
extern void dynar_simple_lex_destroy(struct dynar_simple_lex *lex);
|
||||
|
||||
extern struct dynar *dynar_simple_lex_token_next(struct dynar_simple_lex *lex);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _DYNAR_SIMPLE_LEX_H_ */
|
169
qdevices/dynar-str.c
Normal file
169
qdevices/dynar-str.c
Normal file
@ -0,0 +1,169 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "dynar-str.h"
|
||||
|
||||
int
|
||||
dynar_str_cpy(struct dynar *dest, const char *str)
|
||||
{
|
||||
|
||||
if (strlen(str) > dynar_max_size(dest)) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
dynar_clean(dest);
|
||||
|
||||
return (dynar_str_cat(dest, str));
|
||||
}
|
||||
|
||||
int
|
||||
dynar_str_cat(struct dynar *dest, const char *str)
|
||||
{
|
||||
|
||||
return (dynar_cat(dest, str, strlen(str)));
|
||||
}
|
||||
|
||||
int
|
||||
dynar_str_prepend(struct dynar *dest, const char *str)
|
||||
{
|
||||
|
||||
return (dynar_prepend(dest, str, strlen(str)));
|
||||
}
|
||||
|
||||
int
|
||||
dynar_str_vcatf(struct dynar *dest, const char *format, va_list ap)
|
||||
{
|
||||
int to_write;
|
||||
int written;
|
||||
va_list ap_copy;
|
||||
size_t allocated;
|
||||
char buf;
|
||||
char *p;
|
||||
|
||||
/*
|
||||
* Find out how much bytes is needed
|
||||
*/
|
||||
va_copy(ap_copy, ap);
|
||||
to_write = vsnprintf(&buf, sizeof(buf), format, ap_copy);
|
||||
va_end(ap_copy);
|
||||
|
||||
if (to_write < 0) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if ((size_t)to_write < sizeof(buf)) {
|
||||
/*
|
||||
* Writing 1 byte string (snprintf writes also '\0') means string is empty
|
||||
*/
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
allocated = to_write + 1;
|
||||
if (dynar_prealloc(dest, allocated) != 0) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
p = dynar_data(dest) + dynar_size(dest);
|
||||
|
||||
va_copy(ap_copy, ap);
|
||||
written = vsnprintf(p, allocated, format, ap_copy);
|
||||
va_end(ap_copy);
|
||||
|
||||
if (written < 0) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if ((size_t)written >= allocated) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
dest->size += written;
|
||||
|
||||
return (written);
|
||||
}
|
||||
|
||||
int
|
||||
dynar_str_catf(struct dynar *dest, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int res;
|
||||
|
||||
va_start(ap, format);
|
||||
res = dynar_str_vcatf(dest, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
return (res);
|
||||
}
|
||||
|
||||
int
|
||||
dynar_str_quote_cat(struct dynar *dest, const char *str)
|
||||
{
|
||||
size_t zi;
|
||||
|
||||
if (dynar_str_cat(dest, "\"") != 0) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
for (zi = 0; zi < strlen(str); zi++) {
|
||||
if (str[zi] == '"' || str[zi] == '\\') {
|
||||
if (dynar_str_cat(dest, "\\") != 0) {
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
if (dynar_cat(dest, &str[zi], sizeof(str[zi])) != 0) {
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
if (dynar_str_cat(dest, "\"") != 0) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
dynar_str_quote_cpy(struct dynar *dest, const char *str)
|
||||
{
|
||||
|
||||
dynar_clean(dest);
|
||||
|
||||
return (dynar_str_quote_cat(dest, str));
|
||||
}
|
66
qdevices/dynar-str.h
Normal file
66
qdevices/dynar-str.h
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _DYNAR_STR_H_
|
||||
#define _DYNAR_STR_H_
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "dynar.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern int dynar_str_cpy(struct dynar *dest, const char *str);
|
||||
|
||||
extern int dynar_str_cat(struct dynar *dest, const char *str);
|
||||
|
||||
extern int dynar_str_catf(struct dynar *dest, const char *format, ...)
|
||||
__attribute__((__format__(__printf__, 2, 3)));
|
||||
|
||||
extern int dynar_str_vcatf(struct dynar *dest, const char *format, va_list ap)
|
||||
__attribute__((__format__(__printf__, 2, 0)));
|
||||
|
||||
extern int dynar_str_prepend(struct dynar *dest, const char *str);
|
||||
|
||||
extern int dynar_str_quote_cat(struct dynar *dest, const char *str);
|
||||
|
||||
extern int dynar_str_quote_cpy(struct dynar *dest, const char *str);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _DYNAR_STR_H_ */
|
183
qdevices/dynar.c
Normal file
183
qdevices/dynar.c
Normal file
@ -0,0 +1,183 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2017 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "dynar.h"
|
||||
|
||||
void
|
||||
dynar_init(struct dynar *array, size_t maximum_size)
|
||||
{
|
||||
|
||||
memset(array, 0, sizeof(*array));
|
||||
array->maximum_size = maximum_size;
|
||||
}
|
||||
|
||||
void
|
||||
dynar_set_max_size(struct dynar *array, size_t maximum_size)
|
||||
{
|
||||
|
||||
array->maximum_size = maximum_size;
|
||||
}
|
||||
|
||||
int
|
||||
dynar_set_size(struct dynar *array, size_t size)
|
||||
{
|
||||
|
||||
if (size > dynar_max_size(array)) {
|
||||
dynar_set_max_size(array, size);
|
||||
}
|
||||
|
||||
if (size > dynar_size(array)) {
|
||||
if (dynar_prealloc(array, size - dynar_size(array)) == -1) {
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
array->size = size;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
dynar_destroy(struct dynar *array)
|
||||
{
|
||||
|
||||
free(array->data);
|
||||
dynar_init(array, array->maximum_size);
|
||||
}
|
||||
|
||||
void
|
||||
dynar_clean(struct dynar *array)
|
||||
{
|
||||
|
||||
array->size = 0;
|
||||
}
|
||||
|
||||
size_t
|
||||
dynar_size(const struct dynar *array)
|
||||
{
|
||||
|
||||
return (array->size);
|
||||
}
|
||||
|
||||
size_t
|
||||
dynar_max_size(const struct dynar *array)
|
||||
{
|
||||
|
||||
return (array->maximum_size);
|
||||
}
|
||||
|
||||
char *
|
||||
dynar_data(const struct dynar *array)
|
||||
{
|
||||
|
||||
return (array->data);
|
||||
}
|
||||
|
||||
static int
|
||||
dynar_realloc(struct dynar *array, size_t new_array_size)
|
||||
{
|
||||
char *new_data;
|
||||
|
||||
if (new_array_size > array->maximum_size) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
new_data = realloc(array->data, new_array_size);
|
||||
|
||||
if (new_data == NULL) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
array->allocated = new_array_size;
|
||||
array->data = new_data;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
dynar_prealloc(struct dynar *array, size_t size)
|
||||
{
|
||||
size_t new_size;
|
||||
|
||||
if (array->size + size > array->maximum_size) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (array->size + size > array->allocated) {
|
||||
new_size = (array->allocated + size) * 2;
|
||||
if (new_size > array->maximum_size) {
|
||||
new_size = array->maximum_size;
|
||||
}
|
||||
|
||||
if (dynar_realloc(array, new_size) == -1) {
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
dynar_cat(struct dynar *array, const void *src, size_t size)
|
||||
{
|
||||
|
||||
if (dynar_prealloc(array, size) != 0) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
memmove(array->data + array->size, src, size);
|
||||
array->size += size;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
dynar_prepend(struct dynar *array, const void *src, size_t size)
|
||||
{
|
||||
|
||||
if (dynar_prealloc(array, size) != 0) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
memmove(array->data + size, array->data, array->size);
|
||||
memmove(array->data, src, size);
|
||||
array->size += size;
|
||||
|
||||
return (0);
|
||||
}
|
81
qdevices/dynar.h
Normal file
81
qdevices/dynar.h
Normal file
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2017 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _DYNAR_H_
|
||||
#define _DYNAR_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Dynamic array structure
|
||||
*/
|
||||
struct dynar {
|
||||
char *data;
|
||||
size_t size;
|
||||
size_t allocated;
|
||||
size_t maximum_size;
|
||||
};
|
||||
|
||||
extern void dynar_init(struct dynar *array, size_t maximum_size);
|
||||
|
||||
extern void dynar_destroy(struct dynar *array);
|
||||
|
||||
extern void dynar_clean(struct dynar *array);
|
||||
|
||||
extern size_t dynar_size(const struct dynar *array);
|
||||
|
||||
extern size_t dynar_max_size(const struct dynar *array);
|
||||
|
||||
extern void dynar_set_max_size(struct dynar *array, size_t maximum_size);
|
||||
|
||||
extern char *dynar_data(const struct dynar *array);
|
||||
|
||||
extern int dynar_cat(struct dynar *array, const void *src, size_t size);
|
||||
|
||||
extern int dynar_prealloc(struct dynar *array, size_t size);
|
||||
|
||||
extern int dynar_prepend(struct dynar *array, const void *src, size_t size);
|
||||
|
||||
extern int dynar_set_size(struct dynar *array, size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _DYNAR_H_ */
|
1095
qdevices/msg.c
Normal file
1095
qdevices/msg.c
Normal file
File diff suppressed because it is too large
Load Diff
212
qdevices/msg.h
Normal file
212
qdevices/msg.h
Normal file
@ -0,0 +1,212 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2017 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _MSG_H_
|
||||
#define _MSG_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "dynar.h"
|
||||
#include "tlv.h"
|
||||
#include "node-list.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum msg_type {
|
||||
MSG_TYPE_PREINIT = 0,
|
||||
MSG_TYPE_PREINIT_REPLY = 1,
|
||||
MSG_TYPE_STARTTLS = 2,
|
||||
MSG_TYPE_INIT = 3,
|
||||
MSG_TYPE_INIT_REPLY = 4,
|
||||
MSG_TYPE_SERVER_ERROR = 5,
|
||||
MSG_TYPE_SET_OPTION = 6,
|
||||
MSG_TYPE_SET_OPTION_REPLY = 7,
|
||||
MSG_TYPE_ECHO_REQUEST = 8,
|
||||
MSG_TYPE_ECHO_REPLY = 9,
|
||||
MSG_TYPE_NODE_LIST = 10,
|
||||
MSG_TYPE_NODE_LIST_REPLY = 11,
|
||||
MSG_TYPE_ASK_FOR_VOTE = 12,
|
||||
MSG_TYPE_ASK_FOR_VOTE_REPLY = 13,
|
||||
MSG_TYPE_VOTE_INFO = 14,
|
||||
MSG_TYPE_VOTE_INFO_REPLY = 15,
|
||||
MSG_TYPE_HEURISTICS_CHANGE = 16,
|
||||
MSG_TYPE_HEURISTICS_CHANGE_REPLY = 17,
|
||||
};
|
||||
|
||||
struct msg_decoded {
|
||||
enum msg_type type;
|
||||
uint8_t seq_number_set;
|
||||
uint32_t seq_number; /* Only valid if seq_number_set != 0 */
|
||||
size_t cluster_name_len;
|
||||
/* Valid only if != NULL. Trailing \0 is added but not counted in cluster_name_len */
|
||||
char *cluster_name;
|
||||
uint8_t tls_supported_set;
|
||||
enum tlv_tls_supported tls_supported; /* Valid only if tls_supported_set != 0. */
|
||||
uint8_t tls_client_cert_required_set;
|
||||
uint8_t tls_client_cert_required; /* Valid only if tls_client_cert_required_set != 0 */
|
||||
size_t no_supported_messages;
|
||||
enum msg_type *supported_messages; /* Valid only if != NULL */
|
||||
size_t no_supported_options;
|
||||
enum tlv_opt_type *supported_options; /* Valid only if != NULL */
|
||||
uint8_t reply_error_code_set;
|
||||
enum tlv_reply_error_code reply_error_code; /* Valid only if reply_error_code_set != 0 */
|
||||
uint8_t server_maximum_request_size_set;
|
||||
/* Valid only if server_maximum_request_size_set != 0 */
|
||||
size_t server_maximum_request_size;
|
||||
uint8_t server_maximum_reply_size_set;
|
||||
size_t server_maximum_reply_size; /* Valid only if server_maximum_reply_size_set != 0 */
|
||||
uint8_t node_id_set;
|
||||
uint32_t node_id;
|
||||
size_t no_supported_decision_algorithms;
|
||||
/* Valid only if != NULL */
|
||||
enum tlv_decision_algorithm_type *supported_decision_algorithms;
|
||||
uint8_t decision_algorithm_set;
|
||||
/* Valid only if decision_algorithm_set != 0 */
|
||||
enum tlv_decision_algorithm_type decision_algorithm;
|
||||
uint8_t heartbeat_interval_set;
|
||||
uint32_t heartbeat_interval; /* Valid only if heartbeat_interval_set != 0 */
|
||||
uint8_t ring_id_set;
|
||||
struct tlv_ring_id ring_id; /* Valid only if ring_id_set != 0 */
|
||||
uint8_t config_version_set;
|
||||
uint64_t config_version; /* Valid only if config_version_set != 0 */
|
||||
uint32_t data_center_id; /* Valid only if != 0 */
|
||||
enum tlv_node_state node_state; /* Valid only if != TLV_NODE_STATE_NOT_SET */
|
||||
struct node_list nodes; /* Valid only if node_list_is_empty(nodes) != 0 */
|
||||
int node_list_type_set;
|
||||
enum tlv_node_list_type node_list_type; /* Valid only if node_list_type_set != 0 */
|
||||
int vote_set;
|
||||
enum tlv_vote vote; /* Valid only if vote_set != 0 */
|
||||
int quorate_set;
|
||||
enum tlv_quorate quorate; /* Valid only if quorate_set != 0 */
|
||||
int tie_breaker_set;
|
||||
struct tlv_tie_breaker tie_breaker;
|
||||
enum tlv_heuristics heuristics; /* Always valid but can be TLV_HEURISTICS_UNDEFINED */
|
||||
};
|
||||
|
||||
extern size_t msg_create_preinit(struct dynar *msg, const char *cluster_name,
|
||||
int add_msg_seq_number, uint32_t msg_seq_number);
|
||||
|
||||
extern size_t msg_create_preinit_reply(struct dynar *msg, int add_msg_seq_number,
|
||||
uint32_t msg_seq_number, enum tlv_tls_supported tls_supported, int tls_client_cert_required);
|
||||
|
||||
extern size_t msg_create_starttls(struct dynar *msg, int add_msg_seq_number,
|
||||
uint32_t msg_seq_number);
|
||||
|
||||
extern size_t msg_create_init(struct dynar *msg, int add_msg_seq_number,
|
||||
uint32_t msg_seq_number, enum tlv_decision_algorithm_type decision_algorithm,
|
||||
const enum msg_type *supported_msgs, size_t no_supported_msgs,
|
||||
const enum tlv_opt_type *supported_opts, size_t no_supported_opts, uint32_t node_id,
|
||||
uint32_t heartbeat_interval, const struct tlv_tie_breaker *tie_breaker,
|
||||
const struct tlv_ring_id *ring_id);
|
||||
|
||||
extern size_t msg_create_server_error(struct dynar *msg, int add_msg_seq_number,
|
||||
uint32_t msg_seq_number, enum tlv_reply_error_code reply_error_code);
|
||||
|
||||
extern size_t msg_create_init_reply(struct dynar *msg, int add_msg_seq_number,
|
||||
uint32_t msg_seq_number, enum tlv_reply_error_code reply_error_code,
|
||||
const enum msg_type *supported_msgs, size_t no_supported_msgs,
|
||||
const enum tlv_opt_type *supported_opts, size_t no_supported_opts,
|
||||
size_t server_maximum_request_size, size_t server_maximum_reply_size,
|
||||
const enum tlv_decision_algorithm_type *supported_decision_algorithms,
|
||||
size_t no_supported_decision_algorithms);
|
||||
|
||||
extern size_t msg_create_set_option(struct dynar *msg,
|
||||
int add_msg_seq_number, uint32_t msg_seq_number,
|
||||
int add_heartbeat_interval, uint32_t heartbeat_interval);
|
||||
|
||||
extern size_t msg_create_set_option_reply(struct dynar *msg,
|
||||
int add_msg_seq_number, uint32_t msg_seq_number, uint32_t heartbeat_interval);
|
||||
|
||||
extern size_t msg_create_echo_request(struct dynar *msg, int add_msg_seq_number,
|
||||
uint32_t msg_seq_number);
|
||||
|
||||
extern size_t msg_create_echo_reply(struct dynar *msg,
|
||||
const struct dynar *echo_request_msg);
|
||||
|
||||
extern size_t msg_create_node_list(struct dynar *msg,
|
||||
uint32_t msg_seq_number, enum tlv_node_list_type node_list_type,
|
||||
int add_ring_id, const struct tlv_ring_id *ring_id,
|
||||
int add_config_version, uint64_t config_version,
|
||||
int add_quorate, enum tlv_quorate quorate,
|
||||
int add_heuristics, enum tlv_heuristics heuristics,
|
||||
const struct node_list *nodes);
|
||||
|
||||
extern size_t msg_create_node_list_reply(struct dynar *msg, uint32_t msg_seq_number,
|
||||
enum tlv_node_list_type node_list_type, const struct tlv_ring_id *ring_id,
|
||||
enum tlv_vote vote);
|
||||
|
||||
extern size_t msg_create_ask_for_vote(struct dynar *msg, uint32_t msg_seq_number);
|
||||
|
||||
extern size_t msg_create_ask_for_vote_reply(struct dynar *msg, uint32_t msg_seq_number,
|
||||
const struct tlv_ring_id *ring_id, enum tlv_vote vote);
|
||||
|
||||
extern size_t msg_create_vote_info(struct dynar *msg, uint32_t msg_seq_number,
|
||||
const struct tlv_ring_id *ring_id, enum tlv_vote vote);
|
||||
|
||||
extern size_t msg_create_vote_info_reply(struct dynar *msg, uint32_t msg_seq_number);
|
||||
|
||||
extern size_t msg_create_heuristics_change(struct dynar *msg, uint32_t msg_seq_number,
|
||||
enum tlv_heuristics heuristics);
|
||||
|
||||
extern size_t msg_create_heuristics_change_reply(struct dynar *msg,
|
||||
uint32_t msg_seq_number, const struct tlv_ring_id *ring_id, enum tlv_heuristics heuristics,
|
||||
enum tlv_vote vote);
|
||||
|
||||
extern size_t msg_get_header_length(void);
|
||||
|
||||
extern uint32_t msg_get_len(const struct dynar *msg);
|
||||
|
||||
extern enum msg_type msg_get_type(const struct dynar *msg);
|
||||
|
||||
extern int msg_is_valid_msg_type(const struct dynar *msg);
|
||||
|
||||
extern void msg_decoded_init(struct msg_decoded *decoded_msg);
|
||||
|
||||
extern void msg_decoded_destroy(struct msg_decoded *decoded_msg);
|
||||
|
||||
extern int msg_decode(const struct dynar *msg, struct msg_decoded *decoded_msg);
|
||||
|
||||
extern void msg_get_supported_messages(enum msg_type **supported_messages,
|
||||
size_t *no_supported_messages);
|
||||
|
||||
extern const char * msg_type_to_str(enum msg_type type);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _MSG_H_ */
|
218
qdevices/msgio.c
Normal file
218
qdevices/msgio.c
Normal file
@ -0,0 +1,218 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "msgio.h"
|
||||
#include "msg.h"
|
||||
|
||||
#define MSGIO_LOCAL_BUF_SIZE (1 << 10)
|
||||
|
||||
ssize_t
|
||||
msgio_send(PRFileDesc *sock, const char *msg, size_t msg_len, size_t *start_pos)
|
||||
{
|
||||
ssize_t sent_bytes;
|
||||
|
||||
if ((sent_bytes = PR_Send(sock, msg + *start_pos,
|
||||
msg_len - *start_pos, 0, PR_INTERVAL_NO_TIMEOUT)) != -1) {
|
||||
*start_pos += sent_bytes;
|
||||
}
|
||||
|
||||
return (sent_bytes);
|
||||
}
|
||||
|
||||
ssize_t
|
||||
msgio_send_blocking(PRFileDesc *sock, const char *msg, size_t msg_len)
|
||||
{
|
||||
PRPollDesc pfd;
|
||||
size_t already_sent_bytes;
|
||||
PRInt32 res;
|
||||
ssize_t ret;
|
||||
|
||||
already_sent_bytes = 0;
|
||||
ret = 0;
|
||||
|
||||
while (ret != -1 && already_sent_bytes < msg_len) {
|
||||
pfd.fd = sock;
|
||||
pfd.in_flags = PR_POLL_WRITE;
|
||||
pfd.out_flags = 0;
|
||||
|
||||
if ((res = PR_Poll(&pfd, 1, PR_INTERVAL_NO_TIMEOUT)) > 0) {
|
||||
if (pfd.out_flags & PR_POLL_WRITE) {
|
||||
if ((msgio_send(sock, msg, msg_len, &already_sent_bytes) == -1) &&
|
||||
PR_GetError() != PR_WOULD_BLOCK_ERROR) {
|
||||
ret = -1;
|
||||
} else {
|
||||
ret = already_sent_bytes;
|
||||
}
|
||||
} else if (pfd.out_flags & (PR_POLL_ERR | PR_POLL_NVAL | PR_POLL_HUP)) {
|
||||
PR_SetError(PR_IO_ERROR, 0);
|
||||
ret = -1;
|
||||
}
|
||||
} else {
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* -1 = send returned 0,
|
||||
* -2 = unhandled error.
|
||||
* 0 = success but whole buffer is still not sent
|
||||
* 1 = all data was sent
|
||||
*/
|
||||
int
|
||||
msgio_write(PRFileDesc *sock, const struct dynar *msg, size_t *already_sent_bytes)
|
||||
{
|
||||
PRInt32 sent;
|
||||
PRInt32 to_send;
|
||||
|
||||
to_send = dynar_size(msg) - *already_sent_bytes;
|
||||
if (to_send > MSGIO_LOCAL_BUF_SIZE) {
|
||||
to_send = MSGIO_LOCAL_BUF_SIZE;
|
||||
}
|
||||
|
||||
sent = PR_Send(sock, dynar_data(msg) + *already_sent_bytes, to_send, 0,
|
||||
PR_INTERVAL_NO_TIMEOUT);
|
||||
|
||||
if (sent > 0) {
|
||||
*already_sent_bytes += sent;
|
||||
|
||||
if (*already_sent_bytes == dynar_size(msg)) {
|
||||
/*
|
||||
* All data sent
|
||||
*/
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
|
||||
if (sent == 0) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (sent < 0 && PR_GetError() != PR_WOULD_BLOCK_ERROR) {
|
||||
return (-2);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* 1 Full message received
|
||||
* 0 Partial read (no error)
|
||||
* -1 End of connection
|
||||
* -2 Unhandled error
|
||||
* -3 Fatal error. Unable to store message header
|
||||
* -4 Unable to store message
|
||||
* -5 Invalid msg type
|
||||
* -6 Msg too long
|
||||
*/
|
||||
int
|
||||
msgio_read(PRFileDesc *sock, struct dynar *msg, size_t *already_received_bytes, int *skipping_msg)
|
||||
{
|
||||
char local_read_buffer[MSGIO_LOCAL_BUF_SIZE];
|
||||
PRInt32 readed;
|
||||
PRInt32 to_read;
|
||||
int ret;
|
||||
|
||||
ret = 0;
|
||||
|
||||
if (*already_received_bytes < msg_get_header_length()) {
|
||||
/*
|
||||
* Complete reading of header
|
||||
*/
|
||||
to_read = msg_get_header_length() - *already_received_bytes;
|
||||
} else {
|
||||
/*
|
||||
* Read rest of message (or at least as much as possible)
|
||||
*/
|
||||
to_read = (msg_get_header_length() + msg_get_len(msg)) - *already_received_bytes;
|
||||
}
|
||||
|
||||
if (to_read > MSGIO_LOCAL_BUF_SIZE) {
|
||||
to_read = MSGIO_LOCAL_BUF_SIZE;
|
||||
}
|
||||
|
||||
readed = PR_Recv(sock, local_read_buffer, to_read, 0, PR_INTERVAL_NO_TIMEOUT);
|
||||
if (readed > 0) {
|
||||
*already_received_bytes += readed;
|
||||
|
||||
if (!*skipping_msg) {
|
||||
if (dynar_cat(msg, local_read_buffer, readed) == -1) {
|
||||
*skipping_msg = 1;
|
||||
ret = -4;
|
||||
}
|
||||
}
|
||||
|
||||
if (*skipping_msg && *already_received_bytes < msg_get_header_length()) {
|
||||
/*
|
||||
* Fatal error. We were unable to store even message header
|
||||
*/
|
||||
return (-3);
|
||||
}
|
||||
|
||||
if (!*skipping_msg && *already_received_bytes == msg_get_header_length()) {
|
||||
/*
|
||||
* Full header received. Check type, maximum size, ...
|
||||
*/
|
||||
if (!msg_is_valid_msg_type(msg)) {
|
||||
*skipping_msg = 1;
|
||||
ret = -5;
|
||||
} else if ((msg_get_header_length() + msg_get_len(msg)) >
|
||||
dynar_max_size(msg)) {
|
||||
*skipping_msg = 1;
|
||||
ret = -6;
|
||||
}
|
||||
}
|
||||
|
||||
if (*already_received_bytes >= msg_get_header_length() &&
|
||||
*already_received_bytes == (msg_get_header_length() + msg_get_len(msg))) {
|
||||
/*
|
||||
* Full message skipped or received
|
||||
*/
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (readed == 0) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (readed < 0 && PR_GetError() != PR_WOULD_BLOCK_ERROR) {
|
||||
return (-2);
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
60
qdevices/msgio.h
Normal file
60
qdevices/msgio.h
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _MSGIO_H_
|
||||
#define _MSGIO_H_
|
||||
|
||||
#include <nspr.h>
|
||||
|
||||
#include "dynar.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern ssize_t msgio_send(PRFileDesc *sock, const char *msg, size_t msg_len,
|
||||
size_t *start_pos);
|
||||
|
||||
extern ssize_t msgio_send_blocking(PRFileDesc *sock, const char *msg, size_t msg_len);
|
||||
|
||||
extern int msgio_write(PRFileDesc *sock, const struct dynar *msg, size_t *already_sent_bytes);
|
||||
|
||||
extern int msgio_read(PRFileDesc *sock, struct dynar *msg, size_t *already_received_bytes,
|
||||
int *skipping_msg);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _MSGIO_H_ */
|
211
qdevices/node-list.c
Normal file
211
qdevices/node-list.c
Normal file
@ -0,0 +1,211 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "node-list.h"
|
||||
|
||||
void
|
||||
node_list_init(struct node_list *list)
|
||||
{
|
||||
|
||||
TAILQ_INIT(list);
|
||||
}
|
||||
|
||||
struct node_list_entry *
|
||||
node_list_add(struct node_list *list, uint32_t node_id, uint32_t data_center_id,
|
||||
enum tlv_node_state node_state)
|
||||
{
|
||||
struct node_list_entry *node;
|
||||
|
||||
node = (struct node_list_entry *)malloc(sizeof(*node));
|
||||
if (node == NULL) {
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
memset(node, 0, sizeof(*node));
|
||||
|
||||
node->node_id = node_id;
|
||||
node->data_center_id = data_center_id;
|
||||
node->node_state = node_state;
|
||||
|
||||
TAILQ_INSERT_TAIL(list, node, entries);
|
||||
|
||||
return (node);
|
||||
}
|
||||
|
||||
struct node_list_entry *
|
||||
node_list_add_from_node_info(struct node_list *list, const struct tlv_node_info *node_info)
|
||||
{
|
||||
|
||||
return (node_list_add(list, node_info->node_id, node_info->data_center_id,
|
||||
node_info->node_state));
|
||||
}
|
||||
|
||||
int
|
||||
node_list_clone(struct node_list *dst_list, const struct node_list *src_list)
|
||||
{
|
||||
struct node_list_entry *node_entry;
|
||||
|
||||
node_list_init(dst_list);
|
||||
|
||||
TAILQ_FOREACH(node_entry, src_list, entries) {
|
||||
if (node_list_add(dst_list, node_entry->node_id, node_entry->data_center_id,
|
||||
node_entry->node_state) == NULL) {
|
||||
node_list_free(dst_list);
|
||||
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
node_list_entry_to_tlv_node_info(const struct node_list_entry *node,
|
||||
struct tlv_node_info *node_info)
|
||||
{
|
||||
|
||||
node_info->node_id = node->node_id;
|
||||
node_info->data_center_id = node->data_center_id;
|
||||
node_info->node_state = node->node_state;
|
||||
}
|
||||
|
||||
void
|
||||
node_list_free(struct node_list *list)
|
||||
{
|
||||
struct node_list_entry *node;
|
||||
struct node_list_entry *node_next;
|
||||
|
||||
node = TAILQ_FIRST(list);
|
||||
|
||||
while (node != NULL) {
|
||||
node_next = TAILQ_NEXT(node, entries);
|
||||
|
||||
free(node);
|
||||
|
||||
node = node_next;
|
||||
}
|
||||
|
||||
TAILQ_INIT(list);
|
||||
}
|
||||
|
||||
void
|
||||
node_list_del(struct node_list *list, struct node_list_entry *node)
|
||||
{
|
||||
|
||||
TAILQ_REMOVE(list, node, entries);
|
||||
|
||||
free(node);
|
||||
}
|
||||
|
||||
int
|
||||
node_list_is_empty(const struct node_list *list)
|
||||
{
|
||||
|
||||
return (TAILQ_EMPTY(list));
|
||||
}
|
||||
|
||||
struct node_list_entry *
|
||||
node_list_find_node_id(const struct node_list *list, uint32_t node_id)
|
||||
{
|
||||
struct node_list_entry *node_entry;
|
||||
|
||||
TAILQ_FOREACH(node_entry, list, entries) {
|
||||
if (node_entry->node_id == node_id) {
|
||||
return (node_entry);
|
||||
}
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
int
|
||||
node_list_eq(const struct node_list *list1, const struct node_list *list2)
|
||||
{
|
||||
struct node_list_entry *node1_entry;
|
||||
struct node_list_entry *node2_entry;
|
||||
struct node_list tmp_list;
|
||||
int res;
|
||||
|
||||
res = 1;
|
||||
|
||||
if (node_list_clone(&tmp_list, list2) != 0) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
TAILQ_FOREACH(node1_entry, list1, entries) {
|
||||
node2_entry = node_list_find_node_id(&tmp_list, node1_entry->node_id);
|
||||
if (node2_entry == NULL) {
|
||||
res = 0;
|
||||
goto return_res;
|
||||
}
|
||||
|
||||
if (node1_entry->node_id != node2_entry->node_id ||
|
||||
node1_entry->data_center_id != node2_entry->data_center_id ||
|
||||
node1_entry->node_state != node2_entry->node_state) {
|
||||
res = 0;
|
||||
goto return_res;
|
||||
}
|
||||
|
||||
node_list_del(&tmp_list, node2_entry);
|
||||
}
|
||||
|
||||
if (!node_list_is_empty(&tmp_list)) {
|
||||
res = 0;
|
||||
goto return_res;
|
||||
}
|
||||
|
||||
return_res:
|
||||
node_list_free(&tmp_list);
|
||||
|
||||
return (res);
|
||||
}
|
||||
|
||||
size_t
|
||||
node_list_size(const struct node_list *nlist)
|
||||
{
|
||||
struct node_list_entry *node_entry;
|
||||
size_t res;
|
||||
|
||||
res = 0;
|
||||
|
||||
TAILQ_FOREACH(node_entry, nlist, entries) {
|
||||
res++;
|
||||
}
|
||||
|
||||
return (res);
|
||||
}
|
91
qdevices/node-list.h
Normal file
91
qdevices/node-list.h
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _NODE_LIST_H_
|
||||
#define _NODE_LIST_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <sys/queue.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "tlv.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct node_list_entry {
|
||||
uint32_t node_id;
|
||||
uint32_t data_center_id;
|
||||
enum tlv_node_state node_state;
|
||||
TAILQ_ENTRY(node_list_entry) entries;
|
||||
};
|
||||
|
||||
TAILQ_HEAD(node_list, node_list_entry);
|
||||
|
||||
extern void node_list_init(struct node_list *list);
|
||||
|
||||
extern struct node_list_entry *node_list_add(struct node_list *list,
|
||||
uint32_t node_id, uint32_t data_center_id, enum tlv_node_state node_state);
|
||||
|
||||
extern struct node_list_entry *node_list_add_from_node_info(
|
||||
struct node_list *list, const struct tlv_node_info *node_info);
|
||||
|
||||
extern int node_list_clone(struct node_list *dst_list,
|
||||
const struct node_list *src_list);
|
||||
|
||||
extern void node_list_free(struct node_list *list);
|
||||
|
||||
extern void node_list_del(struct node_list *list,
|
||||
struct node_list_entry *node);
|
||||
|
||||
extern int node_list_is_empty(const struct node_list *list);
|
||||
|
||||
extern void node_list_entry_to_tlv_node_info(
|
||||
const struct node_list_entry *node, struct tlv_node_info *node_info);
|
||||
|
||||
extern struct node_list_entry * node_list_find_node_id(const struct node_list *list,
|
||||
uint32_t node_id);
|
||||
|
||||
extern int node_list_eq(const struct node_list *list1,
|
||||
const struct node_list *list2);
|
||||
|
||||
extern size_t node_list_size(const struct node_list *nlist);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _NODE_LIST_H_ */
|
479
qdevices/nss-sock.c
Normal file
479
qdevices/nss-sock.c
Normal file
@ -0,0 +1,479 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#include "nss-sock.h"
|
||||
|
||||
int
|
||||
nss_sock_init_nss(char *config_dir)
|
||||
{
|
||||
if (config_dir == NULL) {
|
||||
if (NSS_NoDB_Init(NULL) != SECSuccess) {
|
||||
return (-1);
|
||||
}
|
||||
} else {
|
||||
if (NSS_Init(config_dir) != SECSuccess) {
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
if (NSS_SetDomesticPolicy() != SECSuccess) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set NSS socket non-blocking
|
||||
*/
|
||||
int
|
||||
nss_sock_set_non_blocking(PRFileDesc *sock)
|
||||
{
|
||||
PRSocketOptionData sock_opt;
|
||||
|
||||
memset(&sock_opt, 0, sizeof(sock_opt));
|
||||
sock_opt.option = PR_SockOpt_Nonblocking;
|
||||
sock_opt.value.non_blocking = PR_TRUE;
|
||||
if (PR_SetSocketOption(sock, &sock_opt) != PR_SUCCESS) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create TCP socket with af family. If reuse_addr is set, socket option
|
||||
* for reuse address is set.
|
||||
*/
|
||||
static PRFileDesc *
|
||||
nss_sock_create_socket(PRIntn af, int reuse_addr)
|
||||
{
|
||||
PRFileDesc *sock;
|
||||
PRSocketOptionData socket_option;
|
||||
|
||||
sock = PR_OpenTCPSocket(af);
|
||||
if (sock == NULL) {
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (reuse_addr) {
|
||||
socket_option.option = PR_SockOpt_Reuseaddr;
|
||||
socket_option.value.reuse_addr = PR_TRUE;
|
||||
if (PR_SetSocketOption(sock, &socket_option) != PR_SUCCESS) {
|
||||
return (NULL);
|
||||
}
|
||||
}
|
||||
|
||||
return (sock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create listen socket and bind it to address. hostname can be NULL and then
|
||||
* any address is used. Address family (af) can be ether PR_AF_INET6,
|
||||
* PR_AF_INET or PR_AF_UNSPEC.
|
||||
*/
|
||||
PRFileDesc *
|
||||
nss_sock_create_listen_socket(const char *hostname, uint16_t port, PRIntn af)
|
||||
{
|
||||
PRNetAddr addr;
|
||||
PRFileDesc *sock;
|
||||
PRAddrInfo *addr_info;
|
||||
void *addr_iter;
|
||||
|
||||
sock = NULL;
|
||||
|
||||
if (hostname == NULL) {
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
|
||||
if (PR_InitializeNetAddr(PR_IpAddrAny, port, &addr) != PR_SUCCESS) {
|
||||
return (NULL);
|
||||
}
|
||||
if (af == PR_AF_UNSPEC) {
|
||||
af = PR_AF_INET6;
|
||||
}
|
||||
addr.raw.family = af;
|
||||
|
||||
sock = nss_sock_create_socket(af, 1);
|
||||
if (sock == NULL) {
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (PR_Bind(sock, &addr) != PR_SUCCESS) {
|
||||
PR_Close(sock);
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
} else {
|
||||
addr_info = PR_GetAddrInfoByName(hostname, af, PR_AI_ADDRCONFIG);
|
||||
if (addr_info == NULL) {
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
addr_iter = NULL;
|
||||
|
||||
while ((addr_iter = PR_EnumerateAddrInfo(addr_iter, addr_info, port,
|
||||
&addr)) != NULL) {
|
||||
if (af == PR_AF_UNSPEC || addr.raw.family == af) {
|
||||
sock = nss_sock_create_socket(addr.raw.family, 1);
|
||||
if (sock == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (PR_Bind(sock, &addr) != PR_SUCCESS) {
|
||||
PR_Close(sock);
|
||||
sock = NULL;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Socket is sucesfully bound
|
||||
*/
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
PR_FreeAddrInfo(addr_info);
|
||||
|
||||
if (sock == NULL) {
|
||||
/*
|
||||
* No address succeeded
|
||||
*/
|
||||
PR_SetError(PR_ADDRESS_NOT_AVAILABLE_ERROR, 0);
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
}
|
||||
|
||||
return (sock);
|
||||
}
|
||||
|
||||
PRFileDesc *
|
||||
nss_sock_create_client_socket(const char *hostname, uint16_t port, PRIntn af,
|
||||
PRIntervalTime timeout)
|
||||
{
|
||||
PRNetAddr addr;
|
||||
PRFileDesc *sock;
|
||||
PRAddrInfo *addr_info;
|
||||
void *addr_iter;
|
||||
PRStatus res;
|
||||
int connect_failed;
|
||||
PRIntn tmp_af;
|
||||
|
||||
sock = NULL;
|
||||
connect_failed = 0;
|
||||
|
||||
tmp_af = af;
|
||||
if (af == PR_AF_INET6) {
|
||||
tmp_af = PR_AF_UNSPEC;
|
||||
}
|
||||
|
||||
addr_info = PR_GetAddrInfoByName(hostname, tmp_af, PR_AI_ADDRCONFIG);
|
||||
if (addr_info == NULL) {
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
addr_iter = NULL;
|
||||
|
||||
while ((addr_iter = PR_EnumerateAddrInfo(addr_iter, addr_info, port, &addr)) != NULL) {
|
||||
if (af != PR_AF_UNSPEC && addr.raw.family != af) {
|
||||
continue;
|
||||
}
|
||||
|
||||
sock = nss_sock_create_socket(addr.raw.family, 0);
|
||||
if (sock == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((res = PR_Connect(sock, &addr, timeout)) != PR_SUCCESS) {
|
||||
PR_Close(sock);
|
||||
sock = NULL;
|
||||
connect_failed = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Connection attempt finished
|
||||
*/
|
||||
break;
|
||||
}
|
||||
|
||||
PR_FreeAddrInfo(addr_info);
|
||||
|
||||
if (sock == NULL && !connect_failed) {
|
||||
PR_SetError(PR_ADDRESS_NOT_AVAILABLE_ERROR, 0);
|
||||
}
|
||||
|
||||
return (sock);
|
||||
}
|
||||
|
||||
int
|
||||
nss_sock_non_blocking_client_init(const char *host_name, uint16_t port, PRIntn af,
|
||||
struct nss_sock_non_blocking_client *client)
|
||||
{
|
||||
PRIntn tmp_af;
|
||||
|
||||
client->destroyed = 1;
|
||||
|
||||
if ((client->host_name = strdup(host_name)) == NULL) {
|
||||
PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
client->port = port;
|
||||
client->af = af;
|
||||
|
||||
tmp_af = af;
|
||||
if (af == PR_AF_INET6) {
|
||||
tmp_af = PR_AF_UNSPEC;
|
||||
}
|
||||
|
||||
client->addr_info = PR_GetAddrInfoByName(client->host_name, tmp_af, PR_AI_ADDRCONFIG);
|
||||
if (client->addr_info == NULL) {
|
||||
free(client->host_name);
|
||||
|
||||
return (-1);
|
||||
}
|
||||
client->addr_iter = NULL;
|
||||
client->connect_attempts = 0;
|
||||
client->socket = NULL;
|
||||
client->destroyed = 0;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
nss_sock_non_blocking_client_try_next(struct nss_sock_non_blocking_client *client)
|
||||
{
|
||||
PRNetAddr addr;
|
||||
PRStatus res;
|
||||
|
||||
if (client->destroyed) {
|
||||
PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (client->socket != NULL) {
|
||||
PR_Close(client->socket);
|
||||
client->socket = NULL;
|
||||
}
|
||||
|
||||
while ((client->addr_iter = PR_EnumerateAddrInfo(client->addr_iter, client->addr_info,
|
||||
client->port, &addr)) != NULL) {
|
||||
if (client->af != PR_AF_UNSPEC && addr.raw.family != client->af) {
|
||||
continue;
|
||||
}
|
||||
|
||||
client->socket = nss_sock_create_socket(addr.raw.family, 0);
|
||||
if (client->socket == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (nss_sock_set_non_blocking(client->socket) == -1) {
|
||||
PR_Close(client->socket);
|
||||
client->socket = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
res = PR_Connect(client->socket, &addr, PR_INTERVAL_NO_TIMEOUT);
|
||||
if (res == PR_SUCCESS || PR_GetError() == PR_IN_PROGRESS_ERROR) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
PR_Close(client->socket);
|
||||
client->socket = NULL;
|
||||
|
||||
if (client->connect_attempts < INT_MAX) {
|
||||
client->connect_attempts++;
|
||||
}
|
||||
}
|
||||
|
||||
if (client->connect_attempts == 0) {
|
||||
PR_SetError(PR_ADDRESS_NOT_AVAILABLE_ERROR, 0);
|
||||
}
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
void
|
||||
nss_sock_non_blocking_client_destroy(struct nss_sock_non_blocking_client *client)
|
||||
{
|
||||
|
||||
if (client->destroyed) {
|
||||
return ;
|
||||
}
|
||||
|
||||
if (client->addr_info != NULL) {
|
||||
PR_FreeAddrInfo(client->addr_info);
|
||||
client->addr_info = NULL;
|
||||
}
|
||||
|
||||
free(client->host_name);
|
||||
client->host_name = NULL;
|
||||
|
||||
client->destroyed = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* -1 = Client connect failed
|
||||
* 0 = Client connect still in progress
|
||||
* 1 = Client successfuly connected
|
||||
*/
|
||||
int
|
||||
nss_sock_non_blocking_client_succeeded(const PRPollDesc *pfd)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = -1;
|
||||
|
||||
if (PR_GetConnectStatus(pfd) == PR_SUCCESS) {
|
||||
res = 1;
|
||||
} else {
|
||||
if (PR_GetError() == PR_IN_PROGRESS_ERROR) {
|
||||
res = 0;
|
||||
} else {
|
||||
res = -1;
|
||||
}
|
||||
}
|
||||
|
||||
return (res);
|
||||
}
|
||||
|
||||
/*
|
||||
* Start client side SSL connection. This can block.
|
||||
*
|
||||
* ssl_url is expected server URL, bad_cert_hook is callback called when server certificate
|
||||
* verification fails.
|
||||
*/
|
||||
PRFileDesc *
|
||||
nss_sock_start_ssl_as_client(PRFileDesc *input_sock, const char *ssl_url,
|
||||
SSLBadCertHandler bad_cert_hook, SSLGetClientAuthData client_auth_hook,
|
||||
void *client_auth_hook_arg, int force_handshake, int *reset_would_block)
|
||||
{
|
||||
PRFileDesc *ssl_sock;
|
||||
|
||||
if (force_handshake) {
|
||||
*reset_would_block = 0;
|
||||
}
|
||||
|
||||
ssl_sock = SSL_ImportFD(NULL, input_sock);
|
||||
if (ssl_sock == NULL) {
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (SSL_SetURL(ssl_sock, ssl_url) != SECSuccess) {
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if ((SSL_OptionSet(ssl_sock, SSL_SECURITY, PR_TRUE) != SECSuccess) ||
|
||||
(SSL_OptionSet(ssl_sock, SSL_HANDSHAKE_AS_SERVER, PR_FALSE) != SECSuccess) ||
|
||||
(SSL_OptionSet(ssl_sock, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE) != SECSuccess)) {
|
||||
return (NULL);
|
||||
}
|
||||
if (bad_cert_hook != NULL && SSL_BadCertHook(ssl_sock, bad_cert_hook, NULL) != SECSuccess) {
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (client_auth_hook != NULL &&
|
||||
(SSL_GetClientAuthDataHook(ssl_sock, client_auth_hook,
|
||||
client_auth_hook_arg) != SECSuccess)) {
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (SSL_ResetHandshake(ssl_sock, PR_FALSE) != SECSuccess) {
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (force_handshake && SSL_ForceHandshake(ssl_sock) != SECSuccess) {
|
||||
if (PR_GetError() == PR_WOULD_BLOCK_ERROR) {
|
||||
/*
|
||||
* Mask would block error.
|
||||
*/
|
||||
*reset_would_block = 1;
|
||||
} else {
|
||||
return (NULL);
|
||||
}
|
||||
}
|
||||
|
||||
return (ssl_sock);
|
||||
}
|
||||
|
||||
PRFileDesc *
|
||||
nss_sock_start_ssl_as_server(PRFileDesc *input_sock, CERTCertificate *server_cert,
|
||||
SECKEYPrivateKey *server_key, int require_client_cert, int force_handshake,
|
||||
int *reset_would_block)
|
||||
{
|
||||
PRFileDesc *ssl_sock;
|
||||
|
||||
if (force_handshake) {
|
||||
*reset_would_block = 0;
|
||||
}
|
||||
|
||||
ssl_sock = SSL_ImportFD(NULL, input_sock);
|
||||
if (ssl_sock == NULL) {
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (SSL_ConfigSecureServer(ssl_sock, server_cert, server_key,
|
||||
NSS_FindCertKEAType(server_cert)) != SECSuccess) {
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if ((SSL_OptionSet(ssl_sock, SSL_SECURITY, PR_TRUE) != SECSuccess) ||
|
||||
(SSL_OptionSet(ssl_sock, SSL_HANDSHAKE_AS_SERVER, PR_TRUE) != SECSuccess) ||
|
||||
(SSL_OptionSet(ssl_sock, SSL_HANDSHAKE_AS_CLIENT, PR_FALSE) != SECSuccess) ||
|
||||
(SSL_OptionSet(ssl_sock, SSL_REQUEST_CERTIFICATE, require_client_cert) != SECSuccess) ||
|
||||
(SSL_OptionSet(ssl_sock, SSL_REQUIRE_CERTIFICATE, require_client_cert) != SECSuccess)) {
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (SSL_ResetHandshake(ssl_sock, PR_TRUE) != SECSuccess) {
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (force_handshake && SSL_ForceHandshake(ssl_sock) != SECSuccess) {
|
||||
if (PR_GetError() == PR_WOULD_BLOCK_ERROR) {
|
||||
/*
|
||||
* Mask would block error.
|
||||
*/
|
||||
*reset_would_block = 1;
|
||||
} else {
|
||||
return (NULL);
|
||||
}
|
||||
}
|
||||
|
||||
return (ssl_sock);
|
||||
}
|
90
qdevices/nss-sock.h
Normal file
90
qdevices/nss-sock.h
Normal file
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _NSS_SOCK_H_
|
||||
#define _NSS_SOCK_H_
|
||||
|
||||
#include <nss.h>
|
||||
#include <ssl.h>
|
||||
#include <prnetdb.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct nss_sock_non_blocking_client {
|
||||
char *host_name;
|
||||
uint16_t port;
|
||||
PRIntn af;
|
||||
PRFileDesc *socket;
|
||||
PRAddrInfo *addr_info;
|
||||
void *addr_iter;
|
||||
unsigned int connect_attempts;
|
||||
int destroyed;
|
||||
};
|
||||
|
||||
extern int nss_sock_init_nss(char *config_dir);
|
||||
|
||||
extern PRFileDesc *nss_sock_create_listen_socket(const char *hostname, uint16_t port,
|
||||
PRIntn af);
|
||||
|
||||
extern int nss_sock_set_non_blocking(PRFileDesc *sock);
|
||||
|
||||
extern PRFileDesc *nss_sock_create_client_socket(const char *hostname, uint16_t port,
|
||||
PRIntn af, PRIntervalTime timeout);
|
||||
|
||||
extern PRFileDesc *nss_sock_start_ssl_as_client(PRFileDesc *input_sock, const char *ssl_url,
|
||||
SSLBadCertHandler bad_cert_hook, SSLGetClientAuthData client_auth_hook,
|
||||
void *client_auth_hook_arg, int force_handshake, int *reset_would_block);
|
||||
|
||||
extern PRFileDesc *nss_sock_start_ssl_as_server(PRFileDesc *input_sock,
|
||||
CERTCertificate *server_cert, SECKEYPrivateKey *server_key, int require_client_cert,
|
||||
int force_handshake, int *reset_would_block);
|
||||
|
||||
extern int nss_sock_non_blocking_client_init(const char *host_name,
|
||||
uint16_t port, PRIntn af, struct nss_sock_non_blocking_client *client);
|
||||
|
||||
extern int nss_sock_non_blocking_client_try_next(
|
||||
struct nss_sock_non_blocking_client *client);
|
||||
|
||||
extern void nss_sock_non_blocking_client_destroy(
|
||||
struct nss_sock_non_blocking_client *client);
|
||||
|
||||
extern int nss_sock_non_blocking_client_succeeded(const PRPollDesc *pfd);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _NSS_SOCK_H_ */
|
156
qdevices/pr-poll-array.c
Normal file
156
qdevices/pr-poll-array.c
Normal file
@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "pr-poll-array.h"
|
||||
|
||||
void
|
||||
pr_poll_array_init(struct pr_poll_array *poll_array, size_t user_data_size)
|
||||
{
|
||||
|
||||
memset(poll_array, 0, sizeof(*poll_array));
|
||||
poll_array->user_data_size = user_data_size;
|
||||
}
|
||||
|
||||
void
|
||||
pr_poll_array_destroy(struct pr_poll_array *poll_array)
|
||||
{
|
||||
|
||||
free(poll_array->array);
|
||||
free(poll_array->user_data_array);
|
||||
pr_poll_array_init(poll_array, poll_array->user_data_size);
|
||||
}
|
||||
|
||||
void
|
||||
pr_poll_array_clean(struct pr_poll_array *poll_array)
|
||||
{
|
||||
|
||||
poll_array->items = 0;
|
||||
}
|
||||
|
||||
static int
|
||||
pr_poll_array_realloc(struct pr_poll_array *poll_array,
|
||||
ssize_t new_array_size)
|
||||
{
|
||||
PRPollDesc *new_array;
|
||||
char *new_user_data_array;
|
||||
|
||||
new_array = realloc(poll_array->array,
|
||||
sizeof(PRPollDesc) * new_array_size);
|
||||
|
||||
if (new_array == NULL) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
poll_array->allocated = new_array_size;
|
||||
poll_array->array = new_array;
|
||||
|
||||
if (poll_array->user_data_size > 0) {
|
||||
new_user_data_array = realloc(poll_array->user_data_array,
|
||||
poll_array->user_data_size * new_array_size);
|
||||
|
||||
if (new_user_data_array == NULL) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
poll_array->user_data_array = new_user_data_array;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
ssize_t
|
||||
pr_poll_array_size(struct pr_poll_array *poll_array)
|
||||
{
|
||||
|
||||
return (poll_array->items);
|
||||
}
|
||||
|
||||
ssize_t
|
||||
pr_poll_array_add(struct pr_poll_array *poll_array, PRPollDesc **pfds, void **user_data)
|
||||
{
|
||||
|
||||
if (pr_poll_array_size(poll_array) >= poll_array->allocated) {
|
||||
if (pr_poll_array_realloc(poll_array, (poll_array->allocated * 2) + 1)) {
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
*pfds = &poll_array->array[pr_poll_array_size(poll_array)];
|
||||
memset(*pfds, 0, sizeof(**pfds));
|
||||
|
||||
*user_data = poll_array->user_data_array + (poll_array->items * poll_array->user_data_size);
|
||||
memset(*user_data, 0, poll_array->user_data_size);
|
||||
|
||||
poll_array->items++;
|
||||
|
||||
return (poll_array->items - 1);
|
||||
}
|
||||
|
||||
void
|
||||
pr_poll_array_gc(struct pr_poll_array *poll_array)
|
||||
{
|
||||
|
||||
if (poll_array->allocated > (pr_poll_array_size(poll_array) * 3) + 1) {
|
||||
pr_poll_array_realloc(poll_array, (pr_poll_array_size(poll_array) * 2) + 1);
|
||||
}
|
||||
}
|
||||
|
||||
PRPollDesc *
|
||||
pr_poll_array_get(const struct pr_poll_array *poll_array, ssize_t pos)
|
||||
{
|
||||
|
||||
if (pos >= poll_array->items) {
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
return (&poll_array->array[pos]);
|
||||
}
|
||||
|
||||
void *
|
||||
pr_poll_array_get_user_data(const struct pr_poll_array *poll_array, ssize_t pos)
|
||||
{
|
||||
|
||||
if (pos >= poll_array->items) {
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
return (poll_array->user_data_array + (pos * poll_array->user_data_size));
|
||||
}
|
78
qdevices/pr-poll-array.h
Normal file
78
qdevices/pr-poll-array.h
Normal file
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _PR_POLL_ARRAY_H_
|
||||
#define _PR_POLL_ARRAY_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <nspr.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct pr_poll_array {
|
||||
PRPollDesc *array;
|
||||
char *user_data_array;
|
||||
size_t user_data_size;
|
||||
ssize_t allocated;
|
||||
ssize_t items;
|
||||
};
|
||||
|
||||
extern void pr_poll_array_init(struct pr_poll_array *poll_array, size_t user_data_size);
|
||||
|
||||
extern void pr_poll_array_destroy(struct pr_poll_array *poll_array);
|
||||
|
||||
extern void pr_poll_array_clean(struct pr_poll_array *poll_array);
|
||||
|
||||
extern ssize_t pr_poll_array_size(struct pr_poll_array *poll_array);
|
||||
|
||||
extern ssize_t pr_poll_array_add(struct pr_poll_array *poll_array, PRPollDesc **pfds,
|
||||
void **user_data);
|
||||
|
||||
extern PRPollDesc *pr_poll_array_get(const struct pr_poll_array *poll_array,
|
||||
ssize_t pos);
|
||||
|
||||
extern void *pr_poll_array_get_user_data(const struct pr_poll_array *poll_array,
|
||||
ssize_t pos);
|
||||
|
||||
extern void pr_poll_array_gc(struct pr_poll_array *poll_array);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _PR_POLL_ARRAY_H_ */
|
621
qdevices/process-list.c
Normal file
621
qdevices/process-list.c
Normal file
@ -0,0 +1,621 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <poll.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "dynar.h"
|
||||
#include "dynar-str.h"
|
||||
#include "dynar-simple-lex.h"
|
||||
#include "process-list.h"
|
||||
|
||||
static void process_list_free_argv(size_t no_params, char **argv);
|
||||
|
||||
static void process_list_entry_free(struct process_list_entry *entry);
|
||||
|
||||
static char **process_list_parse_command(const char *command, size_t *no_params);
|
||||
|
||||
static int process_list_entry_exec(const struct process_list *plist,
|
||||
struct process_list_entry *entry);
|
||||
|
||||
void
|
||||
process_list_init(struct process_list *plist, size_t max_list_entries, int use_execvp,
|
||||
process_list_notify_fn_t notify_fn, void *notify_fn_user_data)
|
||||
{
|
||||
|
||||
memset(plist, 0, sizeof(*plist));
|
||||
|
||||
plist->max_list_entries = max_list_entries;
|
||||
plist->allocated_list_entries = 0;
|
||||
plist->use_execvp = use_execvp;
|
||||
plist->notify_fn = notify_fn;
|
||||
plist->notify_fn_user_data = notify_fn_user_data;
|
||||
|
||||
TAILQ_INIT(&plist->active_list);
|
||||
TAILQ_INIT(&plist->to_kill_list);
|
||||
}
|
||||
|
||||
static void
|
||||
process_list_free_argv(size_t no_params, char **argv)
|
||||
{
|
||||
size_t zi;
|
||||
|
||||
for (zi = 0; zi < no_params; zi++) {
|
||||
free(argv[zi]);
|
||||
}
|
||||
free(argv);
|
||||
}
|
||||
|
||||
static void
|
||||
process_list_entry_free(struct process_list_entry *entry)
|
||||
{
|
||||
|
||||
process_list_free_argv(entry->exec_argc, entry->exec_argv);
|
||||
free(entry->name);
|
||||
free(entry);
|
||||
}
|
||||
|
||||
static char **
|
||||
process_list_parse_command(const char *command, size_t *no_params)
|
||||
{
|
||||
struct dynar command_dstr;
|
||||
struct dynar_simple_lex lex;
|
||||
struct dynar *token;
|
||||
int finished;
|
||||
char **res_argv;
|
||||
size_t zi;
|
||||
|
||||
res_argv = NULL;
|
||||
|
||||
dynar_init(&command_dstr, strlen(command) + 1);
|
||||
if (dynar_str_cpy(&command_dstr, command) != 0) {
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
dynar_simple_lex_init(&lex, &command_dstr, DYNAR_SIMPLE_LEX_TYPE_QUOTE);
|
||||
*no_params = 0;
|
||||
finished = 0;
|
||||
|
||||
while (!finished) {
|
||||
token = dynar_simple_lex_token_next(&lex);
|
||||
if (token == NULL) {
|
||||
goto exit_res;
|
||||
}
|
||||
|
||||
if (strcmp(dynar_data(token), "") == 0) {
|
||||
finished = 1;
|
||||
} else {
|
||||
(*no_params)++;
|
||||
}
|
||||
}
|
||||
|
||||
if (*no_params < 1) {
|
||||
goto exit_res;
|
||||
}
|
||||
|
||||
dynar_simple_lex_destroy(&lex);
|
||||
|
||||
res_argv = malloc(sizeof(char *) * (*no_params + 1));
|
||||
if (res_argv == NULL) {
|
||||
goto exit_res;
|
||||
}
|
||||
memset(res_argv, 0, sizeof(char *) * (*no_params + 1));
|
||||
|
||||
dynar_simple_lex_init(&lex, &command_dstr, DYNAR_SIMPLE_LEX_TYPE_QUOTE);
|
||||
|
||||
finished = 0;
|
||||
zi = 0;
|
||||
while (!finished) {
|
||||
token = dynar_simple_lex_token_next(&lex);
|
||||
if (token == NULL) {
|
||||
process_list_free_argv(*no_params, res_argv);
|
||||
res_argv = NULL;
|
||||
goto exit_res;
|
||||
}
|
||||
|
||||
if (strcmp(dynar_data(token), "") == 0) {
|
||||
finished = 1;
|
||||
} else {
|
||||
res_argv[zi] = strdup(dynar_data(token));
|
||||
if (res_argv[zi] == NULL) {
|
||||
process_list_free_argv(*no_params, res_argv);
|
||||
res_argv = NULL;
|
||||
}
|
||||
zi++;
|
||||
}
|
||||
}
|
||||
|
||||
if (zi != *no_params) {
|
||||
/*
|
||||
* If this happens it means something is seriously broken (memory corrupted)
|
||||
*/
|
||||
process_list_free_argv(*no_params, res_argv);
|
||||
res_argv = NULL;
|
||||
goto exit_res;
|
||||
}
|
||||
|
||||
exit_res:
|
||||
dynar_simple_lex_destroy(&lex);
|
||||
dynar_destroy(&command_dstr);
|
||||
return (res_argv);
|
||||
}
|
||||
|
||||
struct process_list_entry *
|
||||
process_list_add(struct process_list *plist, const char *name, const char *command)
|
||||
{
|
||||
struct process_list_entry *entry;
|
||||
|
||||
if (plist->allocated_list_entries + 1 > plist->max_list_entries) {
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Alloc new entry
|
||||
*/
|
||||
entry = malloc(sizeof(*entry));
|
||||
if (entry == NULL) {
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
memset(entry, 0, sizeof(*entry));
|
||||
entry->name = strdup(name);
|
||||
if (entry->name == NULL) {
|
||||
process_list_entry_free(entry);
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
entry->state = PROCESS_LIST_ENTRY_STATE_INITIALIZED;
|
||||
entry->exec_argv = process_list_parse_command(command, &entry->exec_argc);
|
||||
if (entry->exec_argv == NULL) {
|
||||
process_list_entry_free(entry);
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
plist->allocated_list_entries++;
|
||||
TAILQ_INSERT_TAIL(&plist->active_list, entry, entries);
|
||||
|
||||
return (entry);
|
||||
}
|
||||
|
||||
void
|
||||
process_list_free(struct process_list *plist)
|
||||
{
|
||||
struct process_list_entry *entry;
|
||||
struct process_list_entry *entry_next;
|
||||
|
||||
entry = TAILQ_FIRST(&plist->active_list);
|
||||
|
||||
while (entry != NULL) {
|
||||
entry_next = TAILQ_NEXT(entry, entries);
|
||||
|
||||
process_list_entry_free(entry);
|
||||
|
||||
entry = entry_next;
|
||||
}
|
||||
|
||||
entry = TAILQ_FIRST(&plist->to_kill_list);
|
||||
|
||||
while (entry != NULL) {
|
||||
entry_next = TAILQ_NEXT(entry, entries);
|
||||
|
||||
process_list_entry_free(entry);
|
||||
|
||||
entry = entry_next;
|
||||
}
|
||||
|
||||
plist->allocated_list_entries = 0;
|
||||
|
||||
TAILQ_INIT(&plist->active_list);
|
||||
TAILQ_INIT(&plist->to_kill_list);
|
||||
}
|
||||
|
||||
static void
|
||||
process_list_entry_exec_helper_set_stdfd(void)
|
||||
{
|
||||
int devnull;
|
||||
|
||||
devnull = open("/dev/null", O_RDWR);
|
||||
if (devnull == -1) {
|
||||
err(1, "Can't open /dev/null");
|
||||
}
|
||||
|
||||
if (dup2(devnull, 0) < 0 || dup2(devnull, 1) < 0 || dup2(devnull, 2) < 0) {
|
||||
close(devnull);
|
||||
err(1, "Can't dup2 stdin/out/err to /dev/null");
|
||||
}
|
||||
|
||||
close(devnull);
|
||||
}
|
||||
|
||||
static int
|
||||
process_list_entry_exec(const struct process_list *plist, struct process_list_entry *entry)
|
||||
{
|
||||
pid_t pid;
|
||||
|
||||
if (entry->state != PROCESS_LIST_ENTRY_STATE_INITIALIZED) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
pid = fork();
|
||||
if (pid == -1) {
|
||||
return (-1);
|
||||
} else if (pid == 0) {
|
||||
process_list_entry_exec_helper_set_stdfd();
|
||||
|
||||
if (!plist->use_execvp) {
|
||||
execv(entry->exec_argv[0], entry->exec_argv);
|
||||
} else {
|
||||
execvp(entry->exec_argv[0], entry->exec_argv);
|
||||
}
|
||||
|
||||
/*
|
||||
* Exec returned -> exec failed
|
||||
*/
|
||||
err(1, "Can't execute command %s (%s)", entry->name, entry->exec_argv[0]);
|
||||
} else {
|
||||
entry->pid = pid;
|
||||
entry->state = PROCESS_LIST_ENTRY_STATE_RUNNING;
|
||||
|
||||
if (plist->notify_fn != NULL) {
|
||||
plist->notify_fn(PROCESS_LIST_NOTIFY_REASON_EXECUTED, entry,
|
||||
plist->notify_fn_user_data);
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
process_list_exec_initialized(struct process_list *plist)
|
||||
{
|
||||
struct process_list_entry *entry;
|
||||
|
||||
TAILQ_FOREACH(entry, &plist->active_list, entries) {
|
||||
if (entry->state == PROCESS_LIST_ENTRY_STATE_INITIALIZED) {
|
||||
if (process_list_entry_exec(plist, entry) != 0) {
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
process_list_entry_waitpid(const struct process_list *plist, struct process_list_entry *entry)
|
||||
{
|
||||
pid_t wpid_res;
|
||||
int status;
|
||||
|
||||
if (entry->state == PROCESS_LIST_ENTRY_STATE_INITIALIZED ||
|
||||
entry->state == PROCESS_LIST_ENTRY_STATE_FINISHED) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
wpid_res = waitpid(entry->pid, &status, WNOHANG);
|
||||
if (wpid_res == -1) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (wpid_res == 0) {
|
||||
/*
|
||||
* No change
|
||||
*/
|
||||
return (0);
|
||||
}
|
||||
|
||||
entry->exit_status = status;
|
||||
|
||||
if (entry->state == PROCESS_LIST_ENTRY_STATE_RUNNING) {
|
||||
if (plist->notify_fn != NULL) {
|
||||
plist->notify_fn(PROCESS_LIST_NOTIFY_REASON_FINISHED, entry,
|
||||
plist->notify_fn_user_data);
|
||||
}
|
||||
}
|
||||
|
||||
entry->state = PROCESS_LIST_ENTRY_STATE_FINISHED;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
process_list_waitpid(struct process_list *plist)
|
||||
{
|
||||
struct process_list_entry *entry;
|
||||
struct process_list_entry *entry_next;
|
||||
|
||||
TAILQ_FOREACH(entry, &plist->active_list, entries) {
|
||||
if (process_list_entry_waitpid(plist, entry) != 0) {
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
entry = TAILQ_FIRST(&plist->to_kill_list);
|
||||
|
||||
while (entry != NULL) {
|
||||
entry_next = TAILQ_NEXT(entry, entries);
|
||||
|
||||
if (process_list_entry_waitpid(plist, entry) != 0) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (entry->state == PROCESS_LIST_ENTRY_STATE_FINISHED) {
|
||||
/*
|
||||
* Process finished -> remove it from list
|
||||
*/
|
||||
TAILQ_REMOVE(&plist->to_kill_list, entry, entries);
|
||||
process_list_entry_free(entry);
|
||||
plist->allocated_list_entries--;
|
||||
}
|
||||
|
||||
entry = entry_next;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
size_t
|
||||
process_list_get_no_running(struct process_list *plist)
|
||||
{
|
||||
struct process_list_entry *entry;
|
||||
size_t res;
|
||||
|
||||
res = 0;
|
||||
|
||||
TAILQ_FOREACH(entry, &plist->active_list, entries) {
|
||||
if (entry->state == PROCESS_LIST_ENTRY_STATE_RUNNING) {
|
||||
res++;
|
||||
}
|
||||
}
|
||||
|
||||
return (res);
|
||||
}
|
||||
|
||||
/*
|
||||
* -1 = Not all processes finished
|
||||
* 0 = All processes finished sucesfully
|
||||
* 1 - All processes finished but some of them not sucesfully
|
||||
*/
|
||||
int
|
||||
process_list_get_summary_result(struct process_list *plist)
|
||||
{
|
||||
struct process_list_entry *entry;
|
||||
int res;
|
||||
|
||||
res = 0;
|
||||
|
||||
TAILQ_FOREACH(entry, &plist->active_list, entries) {
|
||||
if (entry->state != PROCESS_LIST_ENTRY_STATE_FINISHED) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (!WIFEXITED(entry->exit_status) || WEXITSTATUS(entry->exit_status) != 0) {
|
||||
res = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return (res);
|
||||
}
|
||||
|
||||
/*
|
||||
* 0 = All processes finished sucesfully
|
||||
* 1 = Some process finished and failed
|
||||
* -1 = Not all processed finished and none of finished failed
|
||||
*/
|
||||
int
|
||||
process_list_get_summary_result_short(struct process_list *plist)
|
||||
{
|
||||
struct process_list_entry *entry;
|
||||
int res;
|
||||
|
||||
res = 0;
|
||||
|
||||
TAILQ_FOREACH(entry, &plist->active_list, entries) {
|
||||
if (entry->state == PROCESS_LIST_ENTRY_STATE_FINISHED) {
|
||||
if (!WIFEXITED(entry->exit_status) || WEXITSTATUS(entry->exit_status) != 0) {
|
||||
return (1);
|
||||
}
|
||||
} else {
|
||||
res = -1;
|
||||
}
|
||||
}
|
||||
|
||||
return (res);
|
||||
}
|
||||
|
||||
static void
|
||||
process_list_move_entry_to_kill_list(struct process_list *plist, struct process_list_entry *entry)
|
||||
{
|
||||
|
||||
TAILQ_REMOVE(&plist->active_list, entry, entries);
|
||||
TAILQ_INSERT_TAIL(&plist->to_kill_list, entry, entries);
|
||||
}
|
||||
|
||||
void
|
||||
process_list_move_active_entries_to_kill_list(struct process_list *plist)
|
||||
{
|
||||
struct process_list_entry *entry;
|
||||
struct process_list_entry *entry_next;
|
||||
|
||||
entry = TAILQ_FIRST(&plist->active_list);
|
||||
|
||||
while (entry != NULL) {
|
||||
entry_next = TAILQ_NEXT(entry, entries);
|
||||
|
||||
if (entry->state == PROCESS_LIST_ENTRY_STATE_INITIALIZED ||
|
||||
entry->state == PROCESS_LIST_ENTRY_STATE_FINISHED) {
|
||||
TAILQ_REMOVE(&plist->active_list, entry, entries);
|
||||
process_list_entry_free(entry);
|
||||
plist->allocated_list_entries--;
|
||||
} else {
|
||||
process_list_move_entry_to_kill_list(plist, entry);
|
||||
}
|
||||
|
||||
entry = entry_next;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
process_list_process_kill_list_entry(struct process_list *plist, struct process_list_entry *entry)
|
||||
{
|
||||
int sig_to_send;
|
||||
enum process_list_entry_state new_state;
|
||||
int res;
|
||||
|
||||
sig_to_send = 0;
|
||||
new_state = PROCESS_LIST_ENTRY_STATE_INITIALIZED;
|
||||
|
||||
switch (entry->state) {
|
||||
case PROCESS_LIST_ENTRY_STATE_INITIALIZED:
|
||||
/*
|
||||
* This shouldn't happen. If it does, process_list_move_active_entries_to_kill_list
|
||||
* doesn't work as expected or there is some kind of memory corruption.
|
||||
*/
|
||||
assert(entry->state != PROCESS_LIST_ENTRY_STATE_INITIALIZED);
|
||||
break;
|
||||
case PROCESS_LIST_ENTRY_STATE_FINISHED:
|
||||
/*
|
||||
* This shouldn't happen. If it does, process_list_waitpid
|
||||
* doesn't work as expected or there is some kind of memory corruption.
|
||||
*/
|
||||
assert(entry->state != PROCESS_LIST_ENTRY_STATE_FINISHED);
|
||||
break;
|
||||
case PROCESS_LIST_ENTRY_STATE_RUNNING:
|
||||
sig_to_send = SIGTERM;
|
||||
new_state = PROCESS_LIST_ENTRY_STATE_SIGTERM_SENT;
|
||||
break;
|
||||
case PROCESS_LIST_ENTRY_STATE_SIGTERM_SENT:
|
||||
sig_to_send = SIGKILL;
|
||||
new_state = PROCESS_LIST_ENTRY_STATE_SIGKILL_SENT;
|
||||
break;
|
||||
case PROCESS_LIST_ENTRY_STATE_SIGKILL_SENT:
|
||||
sig_to_send = SIGKILL;
|
||||
new_state = PROCESS_LIST_ENTRY_STATE_SIGKILL_SENT;
|
||||
break;
|
||||
}
|
||||
|
||||
res = 0;
|
||||
|
||||
if (kill(entry->pid, sig_to_send) == -1) {
|
||||
if (errno == EPERM || errno == EINVAL) {
|
||||
res = -1;
|
||||
}
|
||||
}
|
||||
|
||||
entry->state = new_state;
|
||||
|
||||
return (res);
|
||||
}
|
||||
|
||||
int
|
||||
process_list_process_kill_list(struct process_list *plist)
|
||||
{
|
||||
struct process_list_entry *entry;
|
||||
|
||||
if (process_list_waitpid(plist) != 0) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
TAILQ_FOREACH(entry, &plist->to_kill_list, entries) {
|
||||
if (process_list_process_kill_list_entry(plist, entry) != 0) {
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
size_t
|
||||
process_list_get_kill_list_items(struct process_list *plist)
|
||||
{
|
||||
struct process_list_entry *entry;
|
||||
size_t res;
|
||||
|
||||
res = 0;
|
||||
|
||||
TAILQ_FOREACH(entry, &plist->to_kill_list, entries) {
|
||||
res++;
|
||||
}
|
||||
|
||||
return (res);
|
||||
}
|
||||
|
||||
int
|
||||
process_list_killall(struct process_list *plist, uint32_t timeout)
|
||||
{
|
||||
uint32_t action_timeout;
|
||||
int i;
|
||||
|
||||
process_list_move_active_entries_to_kill_list(plist);
|
||||
|
||||
action_timeout = timeout / 10;
|
||||
if (action_timeout < 1) {
|
||||
action_timeout = 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < 10; i++) {
|
||||
/*
|
||||
* Make sure all process got signal (quick phase)
|
||||
*/
|
||||
if (process_list_process_kill_list(plist) != 0) {
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < 10 && process_list_get_kill_list_items(plist) > 0; i++) {
|
||||
if (process_list_process_kill_list(plist) != 0) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
poll(NULL, 0, action_timeout);
|
||||
}
|
||||
|
||||
if (process_list_get_kill_list_items(plist) > 0) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
120
qdevices/process-list.h
Normal file
120
qdevices/process-list.h
Normal file
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2017 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _PROCESS_LIST_H_
|
||||
#define _PROCESS_LIST_H_
|
||||
|
||||
#include <signal.h>
|
||||
#include <sys/queue.h>
|
||||
|
||||
#include "dynar.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum process_list_entry_state {
|
||||
PROCESS_LIST_ENTRY_STATE_INITIALIZED,
|
||||
PROCESS_LIST_ENTRY_STATE_RUNNING,
|
||||
PROCESS_LIST_ENTRY_STATE_FINISHED,
|
||||
PROCESS_LIST_ENTRY_STATE_SIGTERM_SENT,
|
||||
PROCESS_LIST_ENTRY_STATE_SIGKILL_SENT,
|
||||
};
|
||||
|
||||
enum process_list_notify_reason {
|
||||
PROCESS_LIST_NOTIFY_REASON_EXECUTED,
|
||||
PROCESS_LIST_NOTIFY_REASON_FINISHED,
|
||||
};
|
||||
|
||||
struct process_list_entry {
|
||||
char *name;
|
||||
enum process_list_entry_state state;
|
||||
char **exec_argv;
|
||||
size_t exec_argc;
|
||||
pid_t pid;
|
||||
int exit_status;
|
||||
|
||||
TAILQ_ENTRY(process_list_entry) entries;
|
||||
};
|
||||
|
||||
typedef void (*process_list_notify_fn_t) (enum process_list_notify_reason reason,
|
||||
const struct process_list_entry *entry, void *user_data);
|
||||
|
||||
struct process_list {
|
||||
int use_execvp;
|
||||
size_t max_list_entries;
|
||||
size_t allocated_list_entries;
|
||||
process_list_notify_fn_t notify_fn;
|
||||
void *notify_fn_user_data;
|
||||
|
||||
TAILQ_HEAD(, process_list_entry) active_list;
|
||||
TAILQ_HEAD(, process_list_entry) to_kill_list;
|
||||
};
|
||||
|
||||
|
||||
extern void process_list_init(struct process_list *plist,
|
||||
size_t max_list_entries, int use_execvp, process_list_notify_fn_t notify_fn,
|
||||
void *notify_fn_user_data);
|
||||
|
||||
extern struct process_list_entry *process_list_add(struct process_list *plist,
|
||||
const char *name, const char *command);
|
||||
|
||||
extern void process_list_free(struct process_list *plist);
|
||||
|
||||
extern int process_list_exec_initialized(struct process_list *plist);
|
||||
|
||||
extern int process_list_waitpid(struct process_list *plist);
|
||||
|
||||
extern size_t process_list_get_no_running(struct process_list *plist);
|
||||
|
||||
extern int process_list_get_summary_result(struct process_list *plist);
|
||||
|
||||
extern int process_list_get_summary_result_short(
|
||||
struct process_list *plist);
|
||||
|
||||
extern void process_list_move_active_entries_to_kill_list(
|
||||
struct process_list *plist);
|
||||
|
||||
extern int process_list_process_kill_list(struct process_list *plist);
|
||||
|
||||
extern size_t process_list_get_kill_list_items(struct process_list *plist);
|
||||
|
||||
extern int process_list_killall(struct process_list *plist,
|
||||
uint32_t timeout);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _PROCESS_LIST_H_ */
|
357
qdevices/qdevice-advanced-settings.c
Normal file
357
qdevices/qdevice-advanced-settings.c
Normal file
@ -0,0 +1,357 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2017 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "dynar.h"
|
||||
#include "dynar-getopt-lex.h"
|
||||
#include "dynar-str.h"
|
||||
#include "qdevice-config.h"
|
||||
#include "qnet-config.h"
|
||||
#include "qdevice-advanced-settings.h"
|
||||
#include "utils.h"
|
||||
|
||||
int
|
||||
qdevice_advanced_settings_init(struct qdevice_advanced_settings *settings)
|
||||
{
|
||||
|
||||
memset(settings, 0, sizeof(*settings));
|
||||
if ((settings->lock_file = strdup(QDEVICE_DEFAULT_LOCK_FILE)) == NULL) {
|
||||
return (-1);
|
||||
}
|
||||
if ((settings->local_socket_file = strdup(QDEVICE_DEFAULT_LOCAL_SOCKET_FILE)) == NULL) {
|
||||
return (-1);
|
||||
}
|
||||
settings->local_socket_backlog = QDEVICE_DEFAULT_LOCAL_SOCKET_BACKLOG;
|
||||
settings->max_cs_try_again = QDEVICE_DEFAULT_MAX_CS_TRY_AGAIN;
|
||||
if ((settings->votequorum_device_name = strdup(QDEVICE_DEFAULT_VOTEQUORUM_DEVICE_NAME)) == NULL) {
|
||||
return (-1);
|
||||
}
|
||||
settings->ipc_max_clients = QDEVICE_DEFAULT_IPC_MAX_CLIENTS;
|
||||
settings->ipc_max_receive_size = QDEVICE_DEFAULT_IPC_MAX_RECEIVE_SIZE;
|
||||
settings->ipc_max_send_size = QDEVICE_DEFAULT_IPC_MAX_SEND_SIZE;
|
||||
|
||||
settings->heuristics_ipc_max_send_buffers = QDEVICE_DEFAULT_HEURISTICS_IPC_MAX_SEND_BUFFERS;
|
||||
settings->heuristics_ipc_max_send_receive_size = QDEVICE_DEFAULT_HEURISTICS_IPC_MAX_SEND_RECEIVE_SIZE;
|
||||
|
||||
settings->heuristics_min_timeout = QDEVICE_DEFAULT_HEURISTICS_MIN_TIMEOUT;
|
||||
settings->heuristics_max_timeout = QDEVICE_DEFAULT_HEURISTICS_MAX_TIMEOUT;
|
||||
settings->heuristics_min_interval = QDEVICE_DEFAULT_HEURISTICS_MIN_INTERVAL;
|
||||
settings->heuristics_max_interval = QDEVICE_DEFAULT_HEURISTICS_MAX_INTERVAL;
|
||||
|
||||
settings->heuristics_max_execs = QDEVICE_DEFAULT_HEURISTICS_MAX_EXECS;
|
||||
|
||||
settings->heuristics_use_execvp = QDEVICE_DEFAULT_HEURISTICS_USE_EXECVP;
|
||||
settings->heuristics_max_processes = QDEVICE_DEFAULT_HEURISTICS_MAX_PROCESSES;
|
||||
settings->heuristics_kill_list_interval = QDEVICE_DEFAULT_HEURISTICS_KILL_LIST_INTERVAL;
|
||||
|
||||
if ((settings->net_nss_db_dir = strdup(QDEVICE_NET_DEFAULT_NSS_DB_DIR)) == NULL) {
|
||||
return (-1);
|
||||
}
|
||||
settings->net_initial_msg_receive_size = QDEVICE_NET_DEFAULT_INITIAL_MSG_RECEIVE_SIZE;
|
||||
settings->net_initial_msg_send_size = QDEVICE_NET_DEFAULT_INITIAL_MSG_SEND_SIZE;
|
||||
settings->net_min_msg_send_size = QDEVICE_NET_DEFAULT_MIN_MSG_SEND_SIZE;
|
||||
settings->net_max_msg_receive_size = QDEVICE_NET_DEFAULT_MAX_MSG_RECEIVE_SIZE;
|
||||
settings->net_max_send_buffers = QDEVICE_NET_DEFAULT_MAX_SEND_BUFFERS;
|
||||
if ((settings->net_nss_qnetd_cn = strdup(QDEVICE_NET_DEFAULT_NSS_QNETD_CN)) == NULL) {
|
||||
return (-1);
|
||||
}
|
||||
if ((settings->net_nss_client_cert_nickname =
|
||||
strdup(QDEVICE_NET_DEFAULT_NSS_CLIENT_CERT_NICKNAME)) == NULL) {
|
||||
return (-1);
|
||||
}
|
||||
settings->net_heartbeat_interval_min = QDEVICE_NET_DEFAULT_HEARTBEAT_INTERVAL_MIN;
|
||||
settings->net_heartbeat_interval_max = QDEVICE_NET_DEFAULT_HEARTBEAT_INTERVAL_MAX;
|
||||
settings->net_min_connect_timeout = QDEVICE_NET_DEFAULT_MIN_CONNECT_TIMEOUT;
|
||||
settings->net_max_connect_timeout = QDEVICE_NET_DEFAULT_MAX_CONNECT_TIMEOUT;
|
||||
settings->net_test_algorithm_enabled = QDEVICE_NET_DEFAULT_TEST_ALGORITHM_ENABLED;
|
||||
|
||||
settings->master_wins = QDEVICE_ADVANCED_SETTINGS_MASTER_WINS_MODEL;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
qdevice_advanced_settings_destroy(struct qdevice_advanced_settings *settings)
|
||||
{
|
||||
|
||||
free(settings->local_socket_file);
|
||||
free(settings->lock_file);
|
||||
free(settings->votequorum_device_name);
|
||||
free(settings->net_nss_db_dir);
|
||||
free(settings->net_nss_qnetd_cn);
|
||||
free(settings->net_nss_client_cert_nickname);
|
||||
}
|
||||
|
||||
/*
|
||||
* 0 - No error
|
||||
* -1 - Unknown option
|
||||
* -2 - Incorrect value
|
||||
*/
|
||||
int
|
||||
qdevice_advanced_settings_set(struct qdevice_advanced_settings *settings,
|
||||
const char *option, const char *value)
|
||||
{
|
||||
long long int tmpll;
|
||||
char *ep;
|
||||
|
||||
if (strcasecmp(option, "lock_file") == 0) {
|
||||
free(settings->lock_file);
|
||||
|
||||
if ((settings->lock_file = strdup(value)) == NULL) {
|
||||
return (-1);
|
||||
}
|
||||
} else if (strcasecmp(option, "local_socket_file") == 0) {
|
||||
free(settings->local_socket_file);
|
||||
|
||||
if ((settings->local_socket_file = strdup(value)) == NULL) {
|
||||
return (-1);
|
||||
}
|
||||
} else if (strcasecmp(option, "local_socket_backlog") == 0) {
|
||||
tmpll = strtoll(value, &ep, 10);
|
||||
if (tmpll < QDEVICE_MIN_LOCAL_SOCKET_BACKLOG || errno != 0 || *ep != '\0') {
|
||||
return (-2);
|
||||
}
|
||||
|
||||
settings->local_socket_backlog = (int)tmpll;
|
||||
} else if (strcasecmp(option, "max_cs_try_again") == 0) {
|
||||
tmpll = strtoll(value, &ep, 10);
|
||||
if (tmpll < QDEVICE_MIN_MAX_CS_TRY_AGAIN || errno != 0 || *ep != '\0') {
|
||||
return (-2);
|
||||
}
|
||||
|
||||
settings->max_cs_try_again = (int)tmpll;
|
||||
} else if (strcasecmp(option, "votequorum_device_name") == 0) {
|
||||
free(settings->votequorum_device_name);
|
||||
|
||||
if ((settings->votequorum_device_name = strdup(value)) == NULL) {
|
||||
return (-1);
|
||||
}
|
||||
} else if (strcasecmp(option, "ipc_max_clients") == 0) {
|
||||
tmpll = strtoll(value, &ep, 10);
|
||||
if (tmpll < QDEVICE_MIN_IPC_MAX_CLIENTS || errno != 0 || *ep != '\0') {
|
||||
return (-2);
|
||||
}
|
||||
|
||||
settings->ipc_max_clients = (size_t)tmpll;
|
||||
} else if (strcasecmp(option, "ipc_max_receive_size") == 0) {
|
||||
tmpll = strtoll(value, &ep, 10);
|
||||
if (tmpll < QDEVICE_MIN_IPC_RECEIVE_SEND_SIZE || errno != 0 || *ep != '\0') {
|
||||
return (-2);
|
||||
}
|
||||
|
||||
settings->ipc_max_receive_size = (size_t)tmpll;
|
||||
} else if (strcasecmp(option, "ipc_max_send_size") == 0) {
|
||||
tmpll = strtoll(value, &ep, 10);
|
||||
if (tmpll < QDEVICE_MIN_IPC_RECEIVE_SEND_SIZE || errno != 0 || *ep != '\0') {
|
||||
return (-2);
|
||||
}
|
||||
|
||||
settings->ipc_max_send_size = (size_t)tmpll;
|
||||
} else if (strcasecmp(option, "heuristics_ipc_max_send_buffers") == 0) {
|
||||
tmpll = strtoll(value, &ep, 10);
|
||||
if (tmpll < QDEVICE_MIN_HEURISTICS_IPC_MAX_SEND_BUFFERS || errno != 0 || *ep != '\0') {
|
||||
return (-2);
|
||||
}
|
||||
|
||||
settings->heuristics_ipc_max_send_buffers = (size_t)tmpll;
|
||||
} else if (strcasecmp(option, "heuristics_ipc_max_send_receive_size") == 0) {
|
||||
tmpll = strtoll(value, &ep, 10);
|
||||
if (tmpll < QDEVICE_MIN_HEURISTICS_IPC_MAX_SEND_RECEIVE_SIZE || errno != 0 || *ep != '\0') {
|
||||
return (-2);
|
||||
}
|
||||
|
||||
settings->heuristics_ipc_max_send_receive_size = (size_t)tmpll;
|
||||
} else if (strcasecmp(option, "heuristics_min_timeout") == 0) {
|
||||
tmpll = strtoll(value, &ep, 10);
|
||||
if (tmpll < QDEVICE_MIN_HEURISTICS_TIMEOUT || errno != 0 || *ep != '\0') {
|
||||
return (-2);
|
||||
}
|
||||
|
||||
settings->heuristics_min_timeout = (uint32_t)tmpll;
|
||||
} else if (strcasecmp(option, "heuristics_max_timeout") == 0) {
|
||||
tmpll = strtoll(value, &ep, 10);
|
||||
if (tmpll < QDEVICE_MIN_HEURISTICS_TIMEOUT || errno != 0 || *ep != '\0') {
|
||||
return (-2);
|
||||
}
|
||||
|
||||
settings->heuristics_max_timeout = (uint32_t)tmpll;
|
||||
} else if (strcasecmp(option, "heuristics_min_interval") == 0) {
|
||||
tmpll = strtoll(value, &ep, 10);
|
||||
if (tmpll < QDEVICE_MIN_HEURISTICS_INTERVAL || errno != 0 || *ep != '\0') {
|
||||
return (-2);
|
||||
}
|
||||
|
||||
settings->heuristics_min_interval = (uint32_t)tmpll;
|
||||
} else if (strcasecmp(option, "heuristics_max_interval") == 0) {
|
||||
tmpll = strtoll(value, &ep, 10);
|
||||
if (tmpll < QDEVICE_MIN_HEURISTICS_INTERVAL || errno != 0 || *ep != '\0') {
|
||||
return (-2);
|
||||
}
|
||||
|
||||
settings->heuristics_max_interval = (uint32_t)tmpll;
|
||||
} else if (strcasecmp(option, "heuristics_max_execs") == 0) {
|
||||
tmpll = strtoll(value, &ep, 10);
|
||||
if (tmpll < QDEVICE_MIN_HEURISTICS_MAX_EXECS || errno != 0 || *ep != '\0') {
|
||||
return (-2);
|
||||
}
|
||||
|
||||
settings->heuristics_max_execs = (size_t)tmpll;
|
||||
} else if (strcasecmp(option, "heuristics_use_execvp") == 0) {
|
||||
if ((tmpll = utils_parse_bool_str(value)) == -1) {
|
||||
return (-2);
|
||||
}
|
||||
|
||||
settings->heuristics_use_execvp = (uint8_t)tmpll;
|
||||
} else if (strcasecmp(option, "heuristics_max_processes") == 0) {
|
||||
tmpll = strtoll(value, &ep, 10);
|
||||
if (tmpll < QDEVICE_MIN_HEURISTICS_MAX_PROCESSES || errno != 0 || *ep != '\0') {
|
||||
return (-2);
|
||||
}
|
||||
|
||||
settings->heuristics_max_processes = (size_t)tmpll;
|
||||
} else if (strcasecmp(option, "heuristics_kill_list_interval") == 0) {
|
||||
tmpll = strtoll(value, &ep, 10);
|
||||
if (tmpll < QDEVICE_MIN_HEURISTICS_KILL_LIST_INTERVAL || errno != 0 || *ep != '\0') {
|
||||
return (-2);
|
||||
}
|
||||
|
||||
settings->heuristics_kill_list_interval = (uint32_t)tmpll;
|
||||
} else if (strcasecmp(option, "net_nss_db_dir") == 0) {
|
||||
free(settings->net_nss_db_dir);
|
||||
|
||||
if ((settings->net_nss_db_dir = strdup(value)) == NULL) {
|
||||
return (-1);
|
||||
}
|
||||
} else if (strcasecmp(option, "net_initial_msg_receive_size") == 0) {
|
||||
tmpll = strtoll(value, &ep, 10);
|
||||
if (tmpll < QDEVICE_NET_MIN_MSG_RECEIVE_SEND_SIZE || errno != 0 || *ep != '\0') {
|
||||
return (-2);
|
||||
}
|
||||
|
||||
settings->net_initial_msg_receive_size = (size_t)tmpll;
|
||||
} else if (strcasecmp(option, "net_initial_msg_send_size") == 0) {
|
||||
tmpll = strtoll(value, &ep, 10);
|
||||
if (tmpll < QDEVICE_NET_MIN_MSG_RECEIVE_SEND_SIZE || errno != 0 || *ep != '\0') {
|
||||
return (-2);
|
||||
}
|
||||
|
||||
settings->net_initial_msg_send_size = (size_t)tmpll;
|
||||
} else if (strcasecmp(option, "net_min_msg_send_size") == 0) {
|
||||
tmpll = strtoll(value, &ep, 10);
|
||||
if (tmpll < QDEVICE_NET_MIN_MSG_RECEIVE_SEND_SIZE || errno != 0 || *ep != '\0') {
|
||||
return (-2);
|
||||
}
|
||||
|
||||
settings->net_min_msg_send_size = (size_t)tmpll;
|
||||
} else if (strcasecmp(option, "net_max_msg_receive_size") == 0) {
|
||||
tmpll = strtoll(value, &ep, 10);
|
||||
if (tmpll < QDEVICE_NET_MIN_MSG_RECEIVE_SEND_SIZE || errno != 0 || *ep != '\0') {
|
||||
return (-2);
|
||||
}
|
||||
|
||||
settings->net_max_msg_receive_size = (size_t)tmpll;
|
||||
} else if (strcasecmp(option, "net_max_send_buffers") == 0) {
|
||||
tmpll = strtoll(value, &ep, 10);
|
||||
if (tmpll < QDEVICE_NET_MIN_MAX_SEND_BUFFERS || errno != 0 || *ep != '\0') {
|
||||
return (-2);
|
||||
}
|
||||
|
||||
settings->net_max_send_buffers = (size_t)tmpll;
|
||||
} else if (strcasecmp(option, "net_nss_qnetd_cn") == 0) {
|
||||
free(settings->net_nss_qnetd_cn);
|
||||
|
||||
if ((settings->net_nss_qnetd_cn = strdup(value)) == NULL) {
|
||||
return (-1);
|
||||
}
|
||||
} else if (strcasecmp(option, "net_nss_client_cert_nickname") == 0) {
|
||||
free(settings->net_nss_client_cert_nickname);
|
||||
|
||||
if ((settings->net_nss_client_cert_nickname = strdup(value)) == NULL) {
|
||||
return (-1);
|
||||
}
|
||||
} else if (strcasecmp(option, "net_heartbeat_interval_min") == 0) {
|
||||
tmpll = strtoll(value, &ep, 10);
|
||||
if (tmpll < QDEVICE_NET_MIN_HEARTBEAT_INTERVAL || errno != 0 || *ep != '\0') {
|
||||
return (-2);
|
||||
}
|
||||
|
||||
settings->net_heartbeat_interval_min = (uint32_t)tmpll;
|
||||
} else if (strcasecmp(option, "net_heartbeat_interval_max") == 0) {
|
||||
tmpll = strtoll(value, &ep, 10);
|
||||
if (tmpll < QDEVICE_NET_MIN_HEARTBEAT_INTERVAL || errno != 0 || *ep != '\0') {
|
||||
return (-2);
|
||||
}
|
||||
|
||||
settings->net_heartbeat_interval_max = (uint32_t)tmpll;
|
||||
} else if (strcasecmp(option, "net_min_connect_timeout") == 0) {
|
||||
tmpll = strtoll(value, &ep, 10);
|
||||
if (tmpll < QDEVICE_NET_MIN_CONNECT_TIMEOUT || errno != 0 || *ep != '\0') {
|
||||
return (-2);
|
||||
}
|
||||
|
||||
settings->net_min_connect_timeout = (uint32_t)tmpll;
|
||||
} else if (strcasecmp(option, "net_max_connect_timeout") == 0) {
|
||||
tmpll = strtoll(value, &ep, 10);
|
||||
if (tmpll < QDEVICE_NET_MIN_CONNECT_TIMEOUT || errno != 0 || *ep != '\0') {
|
||||
return (-2);
|
||||
}
|
||||
|
||||
settings->net_max_connect_timeout = (uint32_t)tmpll;
|
||||
} else if (strcasecmp(option, "net_test_algorithm_enabled") == 0) {
|
||||
if ((tmpll = utils_parse_bool_str(value)) == -1) {
|
||||
return (-2);
|
||||
}
|
||||
|
||||
settings->net_test_algorithm_enabled = (uint8_t)tmpll;
|
||||
} else if (strcasecmp(option, "master_wins") == 0) {
|
||||
tmpll = utils_parse_bool_str(value);
|
||||
|
||||
if (tmpll == 0) {
|
||||
settings->master_wins = QDEVICE_ADVANCED_SETTINGS_MASTER_WINS_FORCE_OFF;
|
||||
} else if (tmpll == 1) {
|
||||
settings->master_wins = QDEVICE_ADVANCED_SETTINGS_MASTER_WINS_FORCE_ON;
|
||||
} else if (strcasecmp(value, "model") == 0) {
|
||||
settings->master_wins = QDEVICE_ADVANCED_SETTINGS_MASTER_WINS_MODEL;
|
||||
} else {
|
||||
return (-2);
|
||||
}
|
||||
} else {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
98
qdevices/qdevice-advanced-settings.h
Normal file
98
qdevices/qdevice-advanced-settings.h
Normal file
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2017 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _QDEVICE_ADVANCED_SETTINGS_H_
|
||||
#define _QDEVICE_ADVANCED_SETTINGS_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum qdevice_advanced_settings_master_wins {
|
||||
QDEVICE_ADVANCED_SETTINGS_MASTER_WINS_MODEL,
|
||||
QDEVICE_ADVANCED_SETTINGS_MASTER_WINS_FORCE_ON,
|
||||
QDEVICE_ADVANCED_SETTINGS_MASTER_WINS_FORCE_OFF,
|
||||
};
|
||||
|
||||
struct qdevice_advanced_settings {
|
||||
char *lock_file;
|
||||
char *local_socket_file;
|
||||
int local_socket_backlog;
|
||||
int max_cs_try_again;
|
||||
char *votequorum_device_name;
|
||||
size_t ipc_max_clients;
|
||||
size_t ipc_max_send_size;
|
||||
size_t ipc_max_receive_size;
|
||||
enum qdevice_advanced_settings_master_wins master_wins;
|
||||
size_t heuristics_ipc_max_send_buffers;
|
||||
size_t heuristics_ipc_max_send_receive_size;
|
||||
uint32_t heuristics_min_timeout;
|
||||
uint32_t heuristics_max_timeout;
|
||||
uint32_t heuristics_min_interval;
|
||||
uint32_t heuristics_max_interval;
|
||||
size_t heuristics_max_execs;
|
||||
int heuristics_use_execvp;
|
||||
size_t heuristics_max_processes;
|
||||
uint32_t heuristics_kill_list_interval;
|
||||
|
||||
/*
|
||||
* Related to model NET
|
||||
*/
|
||||
char *net_nss_db_dir;
|
||||
size_t net_initial_msg_receive_size;
|
||||
size_t net_initial_msg_send_size;
|
||||
size_t net_min_msg_send_size;
|
||||
size_t net_max_msg_receive_size;
|
||||
size_t net_max_send_buffers;
|
||||
char *net_nss_qnetd_cn;
|
||||
char *net_nss_client_cert_nickname;
|
||||
uint32_t net_heartbeat_interval_min;
|
||||
uint32_t net_heartbeat_interval_max;
|
||||
uint32_t net_min_connect_timeout;
|
||||
uint32_t net_max_connect_timeout;
|
||||
uint8_t net_test_algorithm_enabled;
|
||||
};
|
||||
|
||||
extern int qdevice_advanced_settings_init(struct qdevice_advanced_settings *settings);
|
||||
|
||||
extern int qdevice_advanced_settings_set(struct qdevice_advanced_settings *settings,
|
||||
const char *option, const char *value);
|
||||
|
||||
extern void qdevice_advanced_settings_destroy(struct qdevice_advanced_settings *settings);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _QDEVICE_ADVANCED_SETTINGS_H_ */
|
508
qdevices/qdevice-cmap.c
Normal file
508
qdevices/qdevice-cmap.c
Normal file
@ -0,0 +1,508 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <poll.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <netdb.h>
|
||||
|
||||
#include "qdevice-config.h"
|
||||
#include "qdevice-cmap.h"
|
||||
#include "qdevice-log.h"
|
||||
#include "qdevice-log-debug.h"
|
||||
#include "qdevice-model.h"
|
||||
#include "utils.h"
|
||||
|
||||
static uint32_t
|
||||
qdevice_cmap_autogenerate_node_id(const char *addr, int clear_node_high_byte)
|
||||
{
|
||||
struct addrinfo *ainfo;
|
||||
struct addrinfo ahints;
|
||||
int ret, i;
|
||||
|
||||
memset(&ahints, 0, sizeof(ahints));
|
||||
ahints.ai_socktype = SOCK_DGRAM;
|
||||
ahints.ai_protocol = IPPROTO_UDP;
|
||||
/*
|
||||
* Hardcoded AF_INET because autogenerated nodeid is valid only for ipv4
|
||||
*/
|
||||
ahints.ai_family = AF_INET;
|
||||
|
||||
ret = getaddrinfo(addr, NULL, &ahints, &ainfo);
|
||||
if (ret != 0)
|
||||
return (0);
|
||||
|
||||
if (ainfo->ai_family != AF_INET) {
|
||||
|
||||
freeaddrinfo(ainfo);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
memcpy(&i, &((struct sockaddr_in *)ainfo->ai_addr)->sin_addr, sizeof(struct in_addr));
|
||||
freeaddrinfo(ainfo);
|
||||
|
||||
ret = htonl(i);
|
||||
|
||||
if (clear_node_high_byte) {
|
||||
ret &= 0x7FFFFFFF;
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
int
|
||||
qdevice_cmap_get_nodelist(cmap_handle_t cmap_handle, struct node_list *list)
|
||||
{
|
||||
cs_error_t cs_err;
|
||||
cmap_iter_handle_t iter_handle;
|
||||
char key_name[CMAP_KEYNAME_MAXLEN + 1];
|
||||
char tmp_key[CMAP_KEYNAME_MAXLEN + 1];
|
||||
int res;
|
||||
int ret_value;
|
||||
unsigned int node_pos;
|
||||
uint32_t node_id;
|
||||
uint32_t data_center_id;
|
||||
char *tmp_str;
|
||||
char *addr0_str;
|
||||
int clear_node_high_byte;
|
||||
|
||||
ret_value = 0;
|
||||
|
||||
node_list_init(list);
|
||||
|
||||
cs_err = cmap_iter_init(cmap_handle, "nodelist.node.", &iter_handle);
|
||||
if (cs_err != CS_OK) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
while ((cs_err = cmap_iter_next(cmap_handle, iter_handle, key_name, NULL, NULL)) == CS_OK) {
|
||||
res = sscanf(key_name, "nodelist.node.%u.%s", &node_pos, tmp_key);
|
||||
if (res != 2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp(tmp_key, "ring0_addr") != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
snprintf(tmp_key, CMAP_KEYNAME_MAXLEN, "nodelist.node.%u.nodeid", node_pos);
|
||||
cs_err = cmap_get_uint32(cmap_handle, tmp_key, &node_id);
|
||||
|
||||
if (cs_err == CS_ERR_NOT_EXIST) {
|
||||
/*
|
||||
* Nodeid doesn't exists -> autogenerate node id
|
||||
*/
|
||||
clear_node_high_byte = 0;
|
||||
|
||||
if (cmap_get_string(cmap_handle, "totem.clear_node_high_bit",
|
||||
&tmp_str) == CS_OK) {
|
||||
if (strcmp (tmp_str, "yes") == 0) {
|
||||
clear_node_high_byte = 1;
|
||||
}
|
||||
|
||||
free(tmp_str);
|
||||
}
|
||||
|
||||
if (cmap_get_string(cmap_handle, key_name, &addr0_str) != CS_OK) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
node_id = qdevice_cmap_autogenerate_node_id(addr0_str,
|
||||
clear_node_high_byte);
|
||||
|
||||
free(addr0_str);
|
||||
} else if (cs_err != CS_OK) {
|
||||
ret_value = -1;
|
||||
|
||||
goto iter_finalize;
|
||||
}
|
||||
|
||||
snprintf(tmp_key, CMAP_KEYNAME_MAXLEN, "nodelist.node.%u.datacenterid", node_pos);
|
||||
if (cmap_get_uint32(cmap_handle, tmp_key, &data_center_id) != CS_OK) {
|
||||
data_center_id = 0;
|
||||
}
|
||||
|
||||
if (node_list_add(list, node_id, data_center_id, TLV_NODE_STATE_NOT_SET) == NULL) {
|
||||
ret_value = -1;
|
||||
|
||||
goto iter_finalize;
|
||||
}
|
||||
}
|
||||
|
||||
iter_finalize:
|
||||
cmap_iter_finalize(cmap_handle, iter_handle);
|
||||
|
||||
if (ret_value != 0) {
|
||||
node_list_free(list);
|
||||
}
|
||||
|
||||
return (ret_value);
|
||||
}
|
||||
|
||||
int
|
||||
qdevice_cmap_get_config_version(cmap_handle_t cmap_handle, uint64_t *config_version)
|
||||
{
|
||||
int res;
|
||||
|
||||
if (cmap_get_uint64(cmap_handle, "totem.config_version", config_version) == CS_OK) {
|
||||
res = 0;
|
||||
} else {
|
||||
*config_version = 0;
|
||||
res = -1;
|
||||
}
|
||||
|
||||
return (res);
|
||||
}
|
||||
|
||||
int
|
||||
qdevice_cmap_store_config_node_list(struct qdevice_instance *instance)
|
||||
{
|
||||
int res;
|
||||
|
||||
node_list_free(&instance->config_node_list);
|
||||
|
||||
if (qdevice_cmap_get_nodelist(instance->cmap_handle, &instance->config_node_list) != 0) {
|
||||
qdevice_log(LOG_ERR, "Can't get configuration node list.");
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
res = qdevice_cmap_get_config_version(instance->cmap_handle, &instance->config_node_list_version);
|
||||
instance->config_node_list_version_set = (res == 0);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
qdevice_cmap_init(struct qdevice_instance *instance)
|
||||
{
|
||||
cs_error_t res;
|
||||
int no_retries;
|
||||
|
||||
no_retries = 0;
|
||||
|
||||
while ((res = cmap_initialize(&instance->cmap_handle)) == CS_ERR_TRY_AGAIN &&
|
||||
no_retries++ < instance->advanced_settings->max_cs_try_again) {
|
||||
(void)poll(NULL, 0, 1000);
|
||||
}
|
||||
|
||||
if (res != CS_OK) {
|
||||
errx(1, "Failed to initialize the cmap API. Error %s", cs_strerror(res));
|
||||
}
|
||||
|
||||
if ((res = cmap_context_set(instance->cmap_handle, (void *)instance)) != CS_OK) {
|
||||
errx(1, "Can't set cmap context. Error %s", cs_strerror(res));
|
||||
}
|
||||
|
||||
cmap_fd_get(instance->cmap_handle, &instance->cmap_poll_fd);
|
||||
}
|
||||
|
||||
static void
|
||||
qdevice_cmap_node_list_event(struct qdevice_instance *instance)
|
||||
{
|
||||
struct node_list nlist;
|
||||
int config_version_set;
|
||||
uint64_t config_version;
|
||||
|
||||
qdevice_log(LOG_DEBUG, "Node list configuration possibly changed");
|
||||
if (qdevice_cmap_get_nodelist(instance->cmap_handle, &nlist) != 0) {
|
||||
qdevice_log(LOG_ERR, "Can't get configuration node list.");
|
||||
|
||||
if (qdevice_model_get_config_node_list_failed(instance) != 0) {
|
||||
qdevice_log(LOG_DEBUG, "qdevice_model_get_config_node_list_failed returned error -> exit");
|
||||
exit(2);
|
||||
}
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
config_version_set = (qdevice_cmap_get_config_version(instance->cmap_handle,
|
||||
&config_version) == 0);
|
||||
|
||||
if (node_list_eq(&instance->config_node_list, &nlist)) {
|
||||
return ;
|
||||
}
|
||||
|
||||
qdevice_log(LOG_DEBUG, "Node list changed");
|
||||
if (config_version_set) {
|
||||
qdevice_log(LOG_DEBUG, " config_version = "UTILS_PRI_CONFIG_VERSION, config_version);
|
||||
}
|
||||
qdevice_log_debug_dump_node_list(&nlist);
|
||||
|
||||
if (qdevice_model_config_node_list_changed(instance, &nlist,
|
||||
config_version_set, config_version) != 0) {
|
||||
qdevice_log(LOG_DEBUG, "qdevice_model_config_node_list_changed returned error -> exit");
|
||||
exit(2);
|
||||
}
|
||||
|
||||
node_list_free(&instance->config_node_list);
|
||||
if (node_list_clone(&instance->config_node_list, &nlist) != 0) {
|
||||
qdevice_log(LOG_ERR, "Can't allocate instance->config_node_list clone");
|
||||
|
||||
node_list_free(&nlist);
|
||||
|
||||
if (qdevice_model_get_config_node_list_failed(instance) != 0) {
|
||||
qdevice_log(LOG_DEBUG, "qdevice_model_get_config_node_list_failed returned error -> exit");
|
||||
exit(2);
|
||||
}
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
instance->config_node_list_version_set = config_version_set;
|
||||
|
||||
if (config_version_set) {
|
||||
instance->config_node_list_version = config_version;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
qdevice_cmap_logging_event(struct qdevice_instance *instance)
|
||||
{
|
||||
|
||||
qdevice_log(LOG_DEBUG, "Logging configuration possibly changed");
|
||||
qdevice_log_configure(instance);
|
||||
}
|
||||
|
||||
static void
|
||||
qdevice_cmap_heuristics_event(struct qdevice_instance *instance)
|
||||
{
|
||||
|
||||
qdevice_log(LOG_DEBUG, "Heuristics configuration possibly changed");
|
||||
if (qdevice_instance_configure_from_cmap_heuristics(instance) != 0) {
|
||||
qdevice_log(LOG_DEBUG, "qdevice_instance_configure_from_cmap_heuristics returned error -> exit");
|
||||
exit(2);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
qdevice_cmap_reload_cb(cmap_handle_t cmap_handle, cmap_track_handle_t cmap_track_handle,
|
||||
int32_t event, const char *key_name,
|
||||
struct cmap_notify_value new_value, struct cmap_notify_value old_value,
|
||||
void *user_data)
|
||||
{
|
||||
cs_error_t cs_res;
|
||||
uint8_t reload;
|
||||
struct qdevice_instance *instance;
|
||||
const char *node_list_prefix_str;
|
||||
const char *logging_prefix_str;
|
||||
const char *heuristics_prefix_str;
|
||||
struct qdevice_cmap_change_events events;
|
||||
|
||||
memset(&events, 0, sizeof(events));
|
||||
node_list_prefix_str = "nodelist.";
|
||||
logging_prefix_str = "logging.";
|
||||
heuristics_prefix_str = "quorum.device.heuristics.";
|
||||
|
||||
if (cmap_context_get(cmap_handle, (const void **)&instance) != CS_OK) {
|
||||
qdevice_log(LOG_ERR, "Fatal error. Can't get cmap context");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait for full reload
|
||||
*/
|
||||
if (strcmp(key_name, "config.totemconfig_reload_in_progress") == 0 &&
|
||||
new_value.type == CMAP_VALUETYPE_UINT8 && new_value.len == sizeof(reload)) {
|
||||
reload = 1;
|
||||
if (memcmp(new_value.data, &reload, sizeof(reload)) == 0) {
|
||||
/*
|
||||
* Ignore nodelist changes
|
||||
*/
|
||||
instance->cmap_reload_in_progress = 1;
|
||||
return ;
|
||||
} else {
|
||||
instance->cmap_reload_in_progress = 0;
|
||||
events.node_list = 1;
|
||||
events.logging = 1;
|
||||
events.heuristics = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (instance->cmap_reload_in_progress) {
|
||||
return ;
|
||||
}
|
||||
|
||||
if (((cs_res = cmap_get_uint8(cmap_handle, "config.totemconfig_reload_in_progress",
|
||||
&reload)) == CS_OK) && reload == 1) {
|
||||
return ;
|
||||
}
|
||||
|
||||
if (strncmp(key_name, node_list_prefix_str, strlen(node_list_prefix_str)) == 0) {
|
||||
events.node_list = 1;
|
||||
}
|
||||
|
||||
if (strncmp(key_name, logging_prefix_str, strlen(logging_prefix_str)) == 0) {
|
||||
events.logging = 1;
|
||||
}
|
||||
|
||||
if (strncmp(key_name, heuristics_prefix_str, strlen(heuristics_prefix_str)) == 0) {
|
||||
events.heuristics = 1;
|
||||
}
|
||||
|
||||
if (events.logging) {
|
||||
qdevice_cmap_logging_event(instance);
|
||||
}
|
||||
|
||||
if (events.node_list) {
|
||||
qdevice_cmap_node_list_event(instance);
|
||||
}
|
||||
|
||||
if (events.heuristics) {
|
||||
qdevice_cmap_heuristics_event(instance);
|
||||
}
|
||||
|
||||
/*
|
||||
* Inform model about change
|
||||
*/
|
||||
if (qdevice_model_cmap_changed(instance, &events) != 0) {
|
||||
qdevice_log(LOG_DEBUG, "qdevice_model_cmap_changed returned error -> exit");
|
||||
exit(2);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
qdevice_cmap_add_track(struct qdevice_instance *instance)
|
||||
{
|
||||
cs_error_t res;
|
||||
|
||||
res = cmap_track_add(instance->cmap_handle, "config.totemconfig_reload_in_progress",
|
||||
CMAP_TRACK_ADD | CMAP_TRACK_MODIFY, qdevice_cmap_reload_cb,
|
||||
NULL, &instance->cmap_reload_track_handle);
|
||||
|
||||
if (res != CS_OK) {
|
||||
qdevice_log(LOG_ERR, "Can't initialize cmap totemconfig_reload_in_progress tracking");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
res = cmap_track_add(instance->cmap_handle, "nodelist.",
|
||||
CMAP_TRACK_ADD | CMAP_TRACK_DELETE | CMAP_TRACK_MODIFY | CMAP_TRACK_PREFIX,
|
||||
qdevice_cmap_reload_cb,
|
||||
NULL, &instance->cmap_nodelist_track_handle);
|
||||
|
||||
if (res != CS_OK) {
|
||||
qdevice_log(LOG_ERR, "Can't initialize cmap nodelist tracking");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
res = cmap_track_add(instance->cmap_handle, "logging.",
|
||||
CMAP_TRACK_ADD | CMAP_TRACK_DELETE | CMAP_TRACK_MODIFY | CMAP_TRACK_PREFIX,
|
||||
qdevice_cmap_reload_cb,
|
||||
NULL, &instance->cmap_logging_track_handle);
|
||||
|
||||
if (res != CS_OK) {
|
||||
qdevice_log(LOG_ERR, "Can't initialize logging tracking");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
res = cmap_track_add(instance->cmap_handle, "quorum.device.heuristics.",
|
||||
CMAP_TRACK_ADD | CMAP_TRACK_DELETE | CMAP_TRACK_MODIFY | CMAP_TRACK_PREFIX,
|
||||
qdevice_cmap_reload_cb,
|
||||
NULL, &instance->cmap_heuristics_track_handle);
|
||||
|
||||
if (res != CS_OK) {
|
||||
qdevice_log(LOG_ERR, "Can't initialize logging tracking");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
qdevice_cmap_del_track(struct qdevice_instance *instance)
|
||||
{
|
||||
cs_error_t res;
|
||||
|
||||
res = cmap_track_delete(instance->cmap_handle, instance->cmap_reload_track_handle);
|
||||
if (res != CS_OK) {
|
||||
qdevice_log(LOG_WARNING, "Can't delete cmap totemconfig_reload_in_progress tracking");
|
||||
}
|
||||
|
||||
res = cmap_track_delete(instance->cmap_handle, instance->cmap_nodelist_track_handle);
|
||||
if (res != CS_OK) {
|
||||
qdevice_log(LOG_WARNING, "Can't delete cmap nodelist tracking");
|
||||
}
|
||||
|
||||
res = cmap_track_delete(instance->cmap_handle, instance->cmap_logging_track_handle);
|
||||
if (res != CS_OK) {
|
||||
qdevice_log(LOG_WARNING, "Can't delete cmap logging tracking");
|
||||
}
|
||||
|
||||
res = cmap_track_delete(instance->cmap_handle, instance->cmap_heuristics_track_handle);
|
||||
if (res != CS_OK) {
|
||||
qdevice_log(LOG_WARNING, "Can't delete cmap heuristics tracking");
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
qdevice_cmap_destroy(struct qdevice_instance *instance)
|
||||
{
|
||||
cs_error_t res;
|
||||
|
||||
res = cmap_finalize(instance->cmap_handle);
|
||||
|
||||
if (res != CS_OK) {
|
||||
qdevice_log(LOG_WARNING, "Can't finalize cmap. Error %s", cs_strerror(res));
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
qdevice_cmap_dispatch(struct qdevice_instance *instance)
|
||||
{
|
||||
cs_error_t res;
|
||||
|
||||
/*
|
||||
* dispatch can block if corosync is during sync phase
|
||||
*/
|
||||
if (instance->sync_in_progress) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
res = cmap_dispatch(instance->cmap_handle, CS_DISPATCH_ALL);
|
||||
|
||||
if (res != CS_OK && res != CS_ERR_TRY_AGAIN) {
|
||||
qdevice_log(LOG_ERR, "Can't dispatch cmap messages");
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
77
qdevices/qdevice-cmap.h
Normal file
77
qdevices/qdevice-cmap.h
Normal file
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _QDEVICE_CMAP_H_
|
||||
#define _QDEVICE_CMAP_H_
|
||||
|
||||
#include <corosync/cmap.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include "node-list.h"
|
||||
#include "qdevice-instance.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct qdevice_cmap_change_events {
|
||||
unsigned int logging : 1;
|
||||
unsigned int node_list : 1;
|
||||
unsigned int heuristics : 1;
|
||||
};
|
||||
|
||||
extern int qdevice_cmap_get_nodelist(cmap_handle_t cmap_handle,
|
||||
struct node_list *list);
|
||||
|
||||
extern int qdevice_cmap_get_config_version(cmap_handle_t cmap_handle,
|
||||
uint64_t *config_version);
|
||||
|
||||
extern void qdevice_cmap_init(struct qdevice_instance *instance);
|
||||
|
||||
extern int qdevice_cmap_add_track(struct qdevice_instance *instance);
|
||||
|
||||
extern int qdevice_cmap_del_track(struct qdevice_instance *instance);
|
||||
|
||||
extern void qdevice_cmap_destroy(struct qdevice_instance *instance);
|
||||
|
||||
extern int qdevice_cmap_dispatch(struct qdevice_instance *instance);
|
||||
|
||||
extern int qdevice_cmap_store_config_node_list(struct qdevice_instance *instance);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _QDEVICE_CMAP_H_ */
|
116
qdevices/qdevice-config.h
Normal file
116
qdevices/qdevice-config.h
Normal file
@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2017 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _QDEVICE_CONFIG_H_
|
||||
#define _QDEVICE_CONFIG_H_
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <qb/qbdefs.h>
|
||||
#include <qb/qblog.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <string.h>
|
||||
#include "qdevice-heuristics-mode.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* There are "hardcoded" defines for qdevice. It's not so good
|
||||
* idea to change them as long as you are not 100% sure what you are doing. Also
|
||||
* most of them can be changed in CLI via advanced_settings (-S).
|
||||
*/
|
||||
#define QDEVICE_DEFAULT_LOCK_FILE LOCALSTATEDIR"/run/corosync-qdevice/corosync-qdevice.pid"
|
||||
#define QDEVICE_DEFAULT_LOCAL_SOCKET_FILE LOCALSTATEDIR"/run/corosync-qdevice/corosync-qdevice.sock"
|
||||
#define QDEVICE_DEFAULT_LOCAL_SOCKET_BACKLOG 10
|
||||
#define QDEVICE_MIN_LOCAL_SOCKET_BACKLOG 1
|
||||
|
||||
#define QDEVICE_DEFAULT_MAX_CS_TRY_AGAIN 10
|
||||
#define QDEVICE_MIN_MAX_CS_TRY_AGAIN 1
|
||||
|
||||
#define QDEVICE_PROGRAM_NAME "corosync-qdevice"
|
||||
#define QDEVICE_LOG_SUBSYS "QDEVICE"
|
||||
#define QDEVICE_LOG_DEFAULT_TO_STDERR 1
|
||||
#define QDEVICE_LOG_DEFAULT_TO_SYSLOG 1
|
||||
#define QDEVICE_LOG_DEFAULT_TO_LOGFILE 0
|
||||
#define QDEVICE_LOG_DEFAULT_SYSLOG_FACILITY LOG_DAEMON
|
||||
#define QDEVICE_LOG_DEFAULT_SYSLOG_PRIORITY LOG_INFO
|
||||
#define QDEVICE_LOG_DEFAULT_DEBUG 0
|
||||
#define QDEVICE_LOG_DEFAULT_FILELINE 0
|
||||
#define QDEVICE_LOG_DEFAULT_TIMESTAMP 0
|
||||
#define QDEVICE_LOG_DEFAULT_FUNCTION_NAME 0
|
||||
|
||||
#define QDEVICE_DEFAULT_VOTEQUORUM_DEVICE_NAME "Qdevice"
|
||||
|
||||
#define QDEVICE_DEFAULT_IPC_MAX_CLIENTS 10
|
||||
#define QDEVICE_MIN_IPC_MAX_CLIENTS 0
|
||||
#define QDEVICE_DEFAULT_IPC_MAX_RECEIVE_SIZE (4*1024)
|
||||
#define QDEVICE_DEFAULT_IPC_MAX_SEND_SIZE (64*1024)
|
||||
#define QDEVICE_MIN_IPC_RECEIVE_SEND_SIZE 1024
|
||||
|
||||
#define QDEVICE_DEFAULT_HEURISTICS_IPC_MAX_SEND_BUFFERS 128
|
||||
#define QDEVICE_MIN_HEURISTICS_IPC_MAX_SEND_BUFFERS 10
|
||||
#define QDEVICE_DEFAULT_HEURISTICS_IPC_MAX_SEND_RECEIVE_SIZE (4 * 1024)
|
||||
#define QDEVICE_MIN_HEURISTICS_IPC_MAX_SEND_RECEIVE_SIZE 1024
|
||||
|
||||
#define QDEVICE_DEFAULT_HEURISTICS_MIN_TIMEOUT (1 * 1000)
|
||||
#define QDEVICE_DEFAULT_HEURISTICS_MAX_TIMEOUT (2 * 60 * 1000)
|
||||
#define QDEVICE_MIN_HEURISTICS_TIMEOUT 250
|
||||
#define QDEVICE_DEFAULT_HEURISTICS_MIN_INTERVAL QDEVICE_DEFAULT_HEURISTICS_MIN_TIMEOUT
|
||||
#define QDEVICE_DEFAULT_HEURISTICS_MAX_INTERVAL (60 * 60 * 1000)
|
||||
#define QDEVICE_MIN_HEURISTICS_INTERVAL QDEVICE_MIN_HEURISTICS_TIMEOUT
|
||||
|
||||
#define QDEVICE_DEFAULT_HEURISTICS_MODE QDEVICE_HEURISTICS_MODE_DISABLED
|
||||
|
||||
#define QDEVICE_DEFAULT_HEURISTICS_MAX_EXECS 32
|
||||
#define QDEVICE_MIN_HEURISTICS_MAX_EXECS 1
|
||||
|
||||
#define QDEVICE_DEFAULT_HEURISTICS_USE_EXECVP 0
|
||||
|
||||
#define QDEVICE_DEFAULT_HEURISTICS_MAX_PROCESSES (QDEVICE_DEFAULT_HEURISTICS_MAX_EXECS * 5)
|
||||
#define QDEVICE_MIN_HEURISTICS_MAX_PROCESSES 1
|
||||
|
||||
#define QDEVICE_DEFAULT_HEURISTICS_KILL_LIST_INTERVAL (5 * 1000)
|
||||
#define QDEVICE_MIN_HEURISTICS_KILL_LIST_INTERVAL QDEVICE_MIN_HEURISTICS_TIMEOUT
|
||||
|
||||
#define QDEVICE_TOOL_PROGRAM_NAME "corosync-qdevice-tool"
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _QDEVICE_CONFIG_H_ */
|
56
qdevices/qdevice-heuristics-cmd-str.h
Normal file
56
qdevices/qdevice-heuristics-cmd-str.h
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2017 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _QDEVICE_HEURISTICS_CMD_STR_H_
|
||||
#define _QDEVICE_HEURISTICS_CMD_STR_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define QDEVICE_HEURISTICS_CMD_STR_EXEC_LIST_CLEAR "exec-list-clear"
|
||||
#define QDEVICE_HEURISTICS_CMD_STR_EXEC_LIST_ADD "exec-list-add"
|
||||
#define QDEVICE_HEURISTICS_CMD_STR_EXEC_LIST_ADD_SPACE \
|
||||
QDEVICE_HEURISTICS_CMD_STR_EXEC_LIST_ADD " "
|
||||
#define QDEVICE_HEURISTICS_CMD_STR_EXEC "exec"
|
||||
#define QDEVICE_HEURISTICS_CMD_STR_EXEC_ADD_SPACE QDEVICE_HEURISTICS_CMD_STR_EXEC " "
|
||||
#define QDEVICE_HEURISTICS_CMD_STR_EXEC_RESULT "exec-result"
|
||||
#define QDEVICE_HEURISTICS_CMD_STR_EXEC_RESULT_ADD_SPACE \
|
||||
QDEVICE_HEURISTICS_CMD_STR_EXEC_RESULT " "
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _QDEVICE_HEURISTICS_CMD_STR_H_ */
|
353
qdevices/qdevice-heuristics-cmd.c
Normal file
353
qdevices/qdevice-heuristics-cmd.c
Normal file
@ -0,0 +1,353 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2017 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "dynar.h"
|
||||
#include "dynar-str.h"
|
||||
#include "qdevice-heuristics-exec-result.h"
|
||||
#include "qdevice-heuristics-cmd.h"
|
||||
#include "qdevice-heuristics-cmd-str.h"
|
||||
#include "qdevice-heuristics-io.h"
|
||||
#include "qdevice-log.h"
|
||||
|
||||
static int
|
||||
qdevice_heuristics_cmd_process_exec_result(struct qdevice_heuristics_instance *instance,
|
||||
struct dynar *data)
|
||||
{
|
||||
uint32_t seq_number;
|
||||
char *str;
|
||||
enum qdevice_heuristics_exec_result exec_result;
|
||||
|
||||
str = dynar_data(data);
|
||||
|
||||
if (sscanf(str, QDEVICE_HEURISTICS_CMD_STR_EXEC_RESULT_ADD_SPACE "%"PRIu32" %u", &seq_number,
|
||||
&exec_result) != 2) {
|
||||
qdevice_log(LOG_CRIT, "Can't parse exec result command (sscanf)");
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
qdevice_log(LOG_DEBUG,
|
||||
"Received heuristics exec result command with seq_no \"%"PRIu32"\" and result \"%s\"", seq_number,
|
||||
qdevice_heuristics_exec_result_to_str(exec_result));
|
||||
|
||||
if (!instance->waiting_for_result) {
|
||||
qdevice_log(LOG_DEBUG, "Received exec result is not expected. Ignoring.");
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (seq_number != instance->expected_reply_seq_number) {
|
||||
qdevice_log(LOG_DEBUG, "Received heuristics exec result seq number %"PRIu32
|
||||
" is not expected one (expected %"PRIu32"). Ignoring.", seq_number,
|
||||
instance->expected_reply_seq_number);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
instance->waiting_for_result = 0;
|
||||
|
||||
if (qdevice_heuristics_result_notifier_notify(&instance->exec_result_notifier_list,
|
||||
(void *)instance, seq_number, exec_result) != 0) {
|
||||
qdevice_log(LOG_DEBUG, "qdevice_heuristics_result_notifier_notify returned non-zero result");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* 1 - Line processed
|
||||
* 0 - No line to process - everything processed
|
||||
* -1 - Error
|
||||
*/
|
||||
static int
|
||||
qdevice_heuristics_cmd_process_one_line(struct qdevice_heuristics_instance *instance,
|
||||
struct dynar *data)
|
||||
{
|
||||
char *str;
|
||||
size_t str_len;
|
||||
size_t nl_pos;
|
||||
size_t zi;
|
||||
|
||||
str = dynar_data(data);
|
||||
str_len = dynar_size(data);
|
||||
|
||||
/*
|
||||
* Find valid line
|
||||
*/
|
||||
for (zi = 0; zi < str_len && str[zi] != '\r' && str[zi] != '\n'; zi++) ;
|
||||
|
||||
if (zi >= str_len) {
|
||||
/*
|
||||
* Command is not yet fully readed
|
||||
*/
|
||||
return (0);
|
||||
}
|
||||
|
||||
nl_pos = zi;
|
||||
|
||||
str[nl_pos] = '\0';
|
||||
|
||||
if (strncmp(str, QDEVICE_HEURISTICS_CMD_STR_EXEC_RESULT_ADD_SPACE,
|
||||
strlen(QDEVICE_HEURISTICS_CMD_STR_EXEC_RESULT_ADD_SPACE)) == 0) {
|
||||
if (qdevice_heuristics_cmd_process_exec_result(instance, data) != 0) {
|
||||
return (-1);
|
||||
}
|
||||
} else {
|
||||
qdevice_log(LOG_CRIT,
|
||||
"Heuristics worker sent unknown command \"%s\"", str);
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find place where is begining of new "valid" line
|
||||
*/
|
||||
for (zi = nl_pos + 1; zi < str_len && (str[zi] == '\0' || str[zi] == '\n' || str[zi] == '\r'); zi++) ;
|
||||
|
||||
memmove(str, str + zi, str_len - zi);
|
||||
if (dynar_set_size(data, str_len - zi) == -1) {
|
||||
qdevice_log(LOG_CRIT,
|
||||
"qdevice_heuristics_cmd_process_one_line: Can't set dynar size");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* 0 - No error
|
||||
* -1 - Error
|
||||
*/
|
||||
static int
|
||||
qdevice_heuristics_cmd_process(struct qdevice_heuristics_instance *instance)
|
||||
{
|
||||
int res;
|
||||
|
||||
while ((res =
|
||||
qdevice_heuristics_cmd_process_one_line(instance, &instance->cmd_in_buffer)) == 1) ;
|
||||
|
||||
return (res);
|
||||
}
|
||||
|
||||
/*
|
||||
* 0 - No error
|
||||
* 1 - Error
|
||||
*/
|
||||
int
|
||||
qdevice_heuristics_cmd_read_from_pipe(struct qdevice_heuristics_instance *instance)
|
||||
{
|
||||
int res;
|
||||
int ret;
|
||||
|
||||
res = qdevice_heuristics_io_read(instance->pipe_cmd_recv, &instance->cmd_in_buffer);
|
||||
|
||||
ret = 0;
|
||||
|
||||
switch (res) {
|
||||
case 0:
|
||||
/*
|
||||
* Partial read
|
||||
*/
|
||||
break;
|
||||
case -1:
|
||||
qdevice_log(LOG_ERR, "Lost connection with heuristics worker");
|
||||
ret = -1;
|
||||
break;
|
||||
case -2:
|
||||
qdevice_log(LOG_ERR, "Heuristics worker sent too long cmd.");
|
||||
ret = -1;
|
||||
break;
|
||||
case -3:
|
||||
qdevice_log(LOG_ERR, "Unhandled error when reading from heuristics worker cmd fd");
|
||||
ret = -1;
|
||||
break;
|
||||
case 1:
|
||||
/*
|
||||
* At least one cmd line received
|
||||
*/
|
||||
ret = qdevice_heuristics_cmd_process(instance);
|
||||
break;
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* 0 - No error
|
||||
* 1 - Error
|
||||
*/
|
||||
int
|
||||
qdevice_heuristics_cmd_write(struct qdevice_heuristics_instance *instance)
|
||||
{
|
||||
struct send_buffer_list_entry *send_buffer;
|
||||
int res;
|
||||
|
||||
send_buffer = send_buffer_list_get_active(&instance->cmd_out_buffer_list);
|
||||
if (send_buffer == NULL) {
|
||||
qdevice_log(LOG_CRIT, "send_buffer_list_get_active in qdevice_heuristics_cmd_write returned NULL");
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
res = qdevice_heuristics_io_write(instance->pipe_cmd_send, &send_buffer->buffer,
|
||||
&send_buffer->msg_already_sent_bytes);
|
||||
|
||||
if (res == 1) {
|
||||
send_buffer_list_delete(&instance->cmd_out_buffer_list, send_buffer);
|
||||
}
|
||||
|
||||
if (res == -1) {
|
||||
qdevice_log(LOG_CRIT, "qdevice_heuristics_io_write returned -1 (write returned 0)");
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (res == -2) {
|
||||
qdevice_log(LOG_CRIT, "Unhandled error in during sending message to heuristics "
|
||||
"worker (qdevice_heuristics_io_write returned -2)");
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
qdevice_heuristics_cmd_remove_newlines(struct dynar *str)
|
||||
{
|
||||
size_t len;
|
||||
size_t zi;
|
||||
char *buf;
|
||||
|
||||
len = dynar_size(str);
|
||||
buf = dynar_data(str);
|
||||
|
||||
for (zi = 0; zi < len ; zi++) {
|
||||
if (buf[zi] == '\n' || buf[zi] == '\r') {
|
||||
buf[zi] = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
qdevice_heuristics_cmd_write_exec_list(struct qdevice_heuristics_instance *instance,
|
||||
const struct qdevice_heuristics_exec_list *new_exec_list)
|
||||
{
|
||||
struct send_buffer_list_entry *send_buffer;
|
||||
struct qdevice_heuristics_exec_list_entry *entry;
|
||||
|
||||
send_buffer = send_buffer_list_get_new(&instance->cmd_out_buffer_list);
|
||||
if (send_buffer == NULL) {
|
||||
qdevice_log(LOG_ERR, "Can't alloc send list for cmd change exec list");
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (dynar_str_cpy(&send_buffer->buffer, QDEVICE_HEURISTICS_CMD_STR_EXEC_LIST_CLEAR) == -1 ||
|
||||
dynar_str_cat(&send_buffer->buffer, "\n") == -1) {
|
||||
qdevice_log(LOG_ERR, "Can't alloc list clear message");
|
||||
|
||||
send_buffer_list_discard_new(&instance->cmd_out_buffer_list, send_buffer);
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
send_buffer_list_put(&instance->cmd_out_buffer_list, send_buffer);
|
||||
|
||||
if (new_exec_list == NULL) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* new_exec_list is not NULL, send it
|
||||
*/
|
||||
TAILQ_FOREACH(entry, new_exec_list, entries) {
|
||||
send_buffer = send_buffer_list_get_new(&instance->cmd_out_buffer_list);
|
||||
if (send_buffer == NULL) {
|
||||
qdevice_log(LOG_ERR, "Can't alloc send list for cmd change exec list");
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (dynar_str_cpy(&send_buffer->buffer,
|
||||
QDEVICE_HEURISTICS_CMD_STR_EXEC_LIST_ADD_SPACE) == -1 ||
|
||||
dynar_str_cat(&send_buffer->buffer, entry->name) == -1 ||
|
||||
dynar_str_cat(&send_buffer->buffer, " ") == -1 ||
|
||||
dynar_str_cat(&send_buffer->buffer, entry->command) == -1 ||
|
||||
qdevice_heuristics_cmd_remove_newlines(&send_buffer->buffer) == -1 ||
|
||||
dynar_str_cat(&send_buffer->buffer, "\n") == -1) {
|
||||
qdevice_log(LOG_ERR, "Can't alloc list add message");
|
||||
|
||||
send_buffer_list_discard_new(&instance->cmd_out_buffer_list, send_buffer);
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
send_buffer_list_put(&instance->cmd_out_buffer_list, send_buffer);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
qdevice_heuristics_cmd_write_exec(struct qdevice_heuristics_instance *instance,
|
||||
uint32_t timeout, uint32_t seq_number)
|
||||
{
|
||||
struct send_buffer_list_entry *send_buffer;
|
||||
|
||||
send_buffer = send_buffer_list_get_new(&instance->cmd_out_buffer_list);
|
||||
if (send_buffer == NULL) {
|
||||
qdevice_log(LOG_ERR, "Can't alloc send list for cmd change exec list");
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (dynar_str_cpy(&send_buffer->buffer, QDEVICE_HEURISTICS_CMD_STR_EXEC_ADD_SPACE) == -1 ||
|
||||
dynar_str_catf(&send_buffer->buffer, "%"PRIu32" %"PRIu32"\n", timeout, seq_number) == -1) {
|
||||
qdevice_log(LOG_ERR, "Can't alloc exec message");
|
||||
|
||||
send_buffer_list_discard_new(&instance->cmd_out_buffer_list, send_buffer);
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
send_buffer_list_put(&instance->cmd_out_buffer_list, send_buffer);
|
||||
|
||||
return (0);
|
||||
}
|
60
qdevices/qdevice-heuristics-cmd.h
Normal file
60
qdevices/qdevice-heuristics-cmd.h
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2017 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _QDEVICE_HEURISTICS_CMD_H_
|
||||
#define _QDEVICE_HEURISTICS_CMD_H_
|
||||
|
||||
#include "qdevice-heuristics-instance.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern int qdevice_heuristics_cmd_write(
|
||||
struct qdevice_heuristics_instance *instance);
|
||||
|
||||
extern int qdevice_heuristics_cmd_write_exec_list(
|
||||
struct qdevice_heuristics_instance *instance, const struct qdevice_heuristics_exec_list *new_exec_list);
|
||||
|
||||
extern int qdevice_heuristics_cmd_write_exec(struct qdevice_heuristics_instance *instance,
|
||||
uint32_t timeout, uint32_t seq_number);
|
||||
|
||||
extern int qdevice_heuristics_cmd_read_from_pipe(
|
||||
struct qdevice_heuristics_instance *instance);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _QDEVICE_HEURISTICS_CMD_H_ */
|
209
qdevices/qdevice-heuristics-exec-list.c
Normal file
209
qdevices/qdevice-heuristics-exec-list.c
Normal file
@ -0,0 +1,209 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2017 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "qdevice-heuristics-exec-list.h"
|
||||
|
||||
void
|
||||
qdevice_heuristics_exec_list_init(struct qdevice_heuristics_exec_list *list)
|
||||
{
|
||||
|
||||
TAILQ_INIT(list);
|
||||
}
|
||||
|
||||
struct qdevice_heuristics_exec_list_entry *
|
||||
qdevice_heuristics_exec_list_add(struct qdevice_heuristics_exec_list *list,
|
||||
char *name, char *command)
|
||||
{
|
||||
struct qdevice_heuristics_exec_list_entry *entry;
|
||||
|
||||
entry = (struct qdevice_heuristics_exec_list_entry *)malloc(sizeof(*entry));
|
||||
if (entry == NULL) {
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
memset(entry, 0, sizeof(*entry));
|
||||
|
||||
entry->name = strdup(name);
|
||||
if (entry->name == NULL) {
|
||||
free(entry);
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
entry->command = strdup(command);
|
||||
if (entry->command == NULL) {
|
||||
free(entry->name);
|
||||
free(entry);
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
TAILQ_INSERT_TAIL(list, entry, entries);
|
||||
|
||||
return (entry);
|
||||
}
|
||||
|
||||
void
|
||||
qdevice_heuristics_exec_list_free(struct qdevice_heuristics_exec_list *list)
|
||||
{
|
||||
struct qdevice_heuristics_exec_list_entry *entry;
|
||||
struct qdevice_heuristics_exec_list_entry *entry_next;
|
||||
|
||||
entry = TAILQ_FIRST(list);
|
||||
|
||||
while (entry != NULL) {
|
||||
entry_next = TAILQ_NEXT(entry, entries);
|
||||
|
||||
free(entry->name);
|
||||
free(entry->command);
|
||||
free(entry);
|
||||
|
||||
entry = entry_next;
|
||||
}
|
||||
|
||||
TAILQ_INIT(list);
|
||||
}
|
||||
|
||||
size_t
|
||||
qdevice_heuristics_exec_list_size(const struct qdevice_heuristics_exec_list *list)
|
||||
{
|
||||
struct qdevice_heuristics_exec_list_entry *entry;
|
||||
size_t res;
|
||||
|
||||
res = 0;
|
||||
|
||||
TAILQ_FOREACH(entry, list, entries) {
|
||||
res++;
|
||||
}
|
||||
|
||||
return (res);
|
||||
}
|
||||
|
||||
int
|
||||
qdevice_heuristics_exec_list_clone(struct qdevice_heuristics_exec_list *dst_list,
|
||||
const struct qdevice_heuristics_exec_list *src_list)
|
||||
{
|
||||
struct qdevice_heuristics_exec_list_entry *entry;
|
||||
|
||||
qdevice_heuristics_exec_list_init(dst_list);
|
||||
|
||||
TAILQ_FOREACH(entry, src_list, entries) {
|
||||
if (qdevice_heuristics_exec_list_add(dst_list, entry->name, entry->command) == NULL) {
|
||||
qdevice_heuristics_exec_list_free(dst_list);
|
||||
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
qdevice_heuristics_exec_list_del(struct qdevice_heuristics_exec_list *list,
|
||||
struct qdevice_heuristics_exec_list_entry *entry)
|
||||
{
|
||||
|
||||
TAILQ_REMOVE(list, entry, entries);
|
||||
|
||||
free(entry->name);
|
||||
free(entry->command);
|
||||
free(entry);
|
||||
}
|
||||
|
||||
int
|
||||
qdevice_heuristics_exec_list_is_empty(const struct qdevice_heuristics_exec_list *list)
|
||||
{
|
||||
|
||||
return (TAILQ_EMPTY(list));
|
||||
}
|
||||
|
||||
struct qdevice_heuristics_exec_list_entry *
|
||||
qdevice_heuristics_exec_list_find_name(const struct qdevice_heuristics_exec_list *list,
|
||||
const char *name)
|
||||
{
|
||||
struct qdevice_heuristics_exec_list_entry *entry;
|
||||
|
||||
TAILQ_FOREACH(entry, list, entries) {
|
||||
if (strcmp(entry->name, name) == 0) {
|
||||
return (entry);
|
||||
}
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
int
|
||||
qdevice_heuristics_exec_list_eq(const struct qdevice_heuristics_exec_list *list1,
|
||||
const struct qdevice_heuristics_exec_list *list2)
|
||||
{
|
||||
struct qdevice_heuristics_exec_list_entry *entry1;
|
||||
struct qdevice_heuristics_exec_list_entry *entry2;
|
||||
struct qdevice_heuristics_exec_list tmp_list;
|
||||
int res;
|
||||
|
||||
res = 1;
|
||||
|
||||
if (qdevice_heuristics_exec_list_clone(&tmp_list, list2) != 0) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
TAILQ_FOREACH(entry1, list1, entries) {
|
||||
entry2 = qdevice_heuristics_exec_list_find_name(&tmp_list, entry1->name);
|
||||
if (entry2 == NULL) {
|
||||
res = 0;
|
||||
goto return_res;
|
||||
}
|
||||
|
||||
if (strcmp(entry1->command, entry2->command) != 0) {
|
||||
res = 0;
|
||||
goto return_res;
|
||||
}
|
||||
|
||||
qdevice_heuristics_exec_list_del(&tmp_list, entry2);
|
||||
}
|
||||
|
||||
if (!qdevice_heuristics_exec_list_is_empty(&tmp_list)) {
|
||||
res = 0;
|
||||
goto return_res;
|
||||
}
|
||||
|
||||
return_res:
|
||||
qdevice_heuristics_exec_list_free(&tmp_list);
|
||||
|
||||
return (res);
|
||||
}
|
88
qdevices/qdevice-heuristics-exec-list.h
Normal file
88
qdevices/qdevice-heuristics-exec-list.h
Normal file
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2017 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _QDEVICE_HEURISTICS_EXEC_LIST_H_
|
||||
#define _QDEVICE_HEURISTICS_EXEC_LIST_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <sys/queue.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct qdevice_heuristics_exec_list_entry {
|
||||
char *name;
|
||||
char *command;
|
||||
TAILQ_ENTRY(qdevice_heuristics_exec_list_entry) entries;
|
||||
};
|
||||
|
||||
TAILQ_HEAD(qdevice_heuristics_exec_list, qdevice_heuristics_exec_list_entry);
|
||||
|
||||
extern void qdevice_heuristics_exec_list_init(
|
||||
struct qdevice_heuristics_exec_list *list);
|
||||
|
||||
extern struct qdevice_heuristics_exec_list_entry *qdevice_heuristics_exec_list_add(
|
||||
struct qdevice_heuristics_exec_list *list, char *name, char *command);
|
||||
|
||||
extern void qdevice_heuristics_exec_list_free(
|
||||
struct qdevice_heuristics_exec_list *list);
|
||||
|
||||
extern size_t qdevice_heuristics_exec_list_size(
|
||||
const struct qdevice_heuristics_exec_list *list);
|
||||
|
||||
extern int qdevice_heuristics_exec_list_clone(
|
||||
struct qdevice_heuristics_exec_list *dst_list,
|
||||
const struct qdevice_heuristics_exec_list *src_list);
|
||||
|
||||
extern void qdevice_heuristics_exec_list_del(
|
||||
struct qdevice_heuristics_exec_list *list, struct qdevice_heuristics_exec_list_entry *entry);
|
||||
|
||||
extern int qdevice_heuristics_exec_list_is_empty(
|
||||
const struct qdevice_heuristics_exec_list *list);
|
||||
|
||||
extern struct qdevice_heuristics_exec_list_entry *qdevice_heuristics_exec_list_find_name(
|
||||
const struct qdevice_heuristics_exec_list *list, const char *name);
|
||||
|
||||
extern int qdevice_heuristics_exec_list_eq(
|
||||
const struct qdevice_heuristics_exec_list *list1,
|
||||
const struct qdevice_heuristics_exec_list *list2);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _QDEVICE_HEURISTICS_EXEC_LIST_H_ */
|
48
qdevices/qdevice-heuristics-exec-result.c
Normal file
48
qdevices/qdevice-heuristics-exec-result.c
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2017 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "qdevice-heuristics-exec-result.h"
|
||||
|
||||
const char *
|
||||
qdevice_heuristics_exec_result_to_str(enum qdevice_heuristics_exec_result exec_result)
|
||||
{
|
||||
|
||||
switch (exec_result) {
|
||||
case QDEVICE_HEURISTICS_EXEC_RESULT_FAIL: return("Fail"); break;
|
||||
case QDEVICE_HEURISTICS_EXEC_RESULT_PASS: return("Pass"); break;
|
||||
case QDEVICE_HEURISTICS_EXEC_RESULT_DISABLED: return("Disabled"); break;
|
||||
}
|
||||
|
||||
return ("Unknown heuristics exec result value");
|
||||
}
|
65
qdevices/qdevice-heuristics-exec-result.h
Normal file
65
qdevices/qdevice-heuristics-exec-result.h
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2017 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _QDEVICE_HEURISTICS_EXEC_RESULT_H_
|
||||
#define _QDEVICE_HEURISTICS_EXEC_RESULT_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum qdevice_heuristics_exec_result {
|
||||
/*
|
||||
* Heuristics worker received command to exec heuristics but list is empty. This
|
||||
* is happening when heuristics is disabled.
|
||||
*/
|
||||
QDEVICE_HEURISTICS_EXEC_RESULT_DISABLED = 0,
|
||||
/*
|
||||
* All executed commands passed
|
||||
*/
|
||||
QDEVICE_HEURISTICS_EXEC_RESULT_PASS = 1,
|
||||
/*
|
||||
* One (or more) commands failed or timed-out
|
||||
*/
|
||||
QDEVICE_HEURISTICS_EXEC_RESULT_FAIL = 2,
|
||||
};
|
||||
|
||||
extern const char * qdevice_heuristics_exec_result_to_str(
|
||||
enum qdevice_heuristics_exec_result exec_result);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _QDEVICE_HEURISTICS_EXEC_RESULT_H_ */
|
60
qdevices/qdevice-heuristics-instance.c
Normal file
60
qdevices/qdevice-heuristics-instance.c
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2017 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "qdevice-heuristics-instance.h"
|
||||
#include "qdevice-heuristics-exec-list.h"
|
||||
|
||||
int
|
||||
qdevice_heuristics_instance_init(struct qdevice_heuristics_instance *instance)
|
||||
{
|
||||
|
||||
memset(instance, 0, sizeof(*instance));
|
||||
|
||||
qdevice_heuristics_exec_list_init(&instance->exec_list);
|
||||
qdevice_heuristics_result_notifier_list_init(&instance->exec_result_notifier_list);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
qdevice_heuristics_instance_destroy(struct qdevice_heuristics_instance *instance)
|
||||
{
|
||||
|
||||
qdevice_heuristics_result_notifier_list_free(&instance->exec_result_notifier_list);
|
||||
qdevice_heuristics_exec_list_free(&instance->exec_list);
|
||||
|
||||
return (0);
|
||||
}
|
82
qdevices/qdevice-heuristics-instance.h
Normal file
82
qdevices/qdevice-heuristics-instance.h
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2017 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _QDEVICE_HEURISTICS_INSTANCE_H_
|
||||
#define _QDEVICE_HEURISTICS_INSTANCE_H_
|
||||
|
||||
#include "dynar.h"
|
||||
#include "send-buffer-list.h"
|
||||
#include "qdevice-heuristics-mode.h"
|
||||
#include "qdevice-heuristics-exec-list.h"
|
||||
#include "qdevice-heuristics-exec-result.h"
|
||||
#include "qdevice-heuristics-result-notifier.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct qdevice_heuristics_instance {
|
||||
int pipe_cmd_send;
|
||||
int pipe_cmd_recv;
|
||||
int pipe_log_recv;
|
||||
pid_t worker_pid;
|
||||
struct send_buffer_list cmd_out_buffer_list;
|
||||
struct dynar log_in_buffer;
|
||||
struct dynar cmd_in_buffer;
|
||||
|
||||
uint32_t timeout;
|
||||
uint32_t sync_timeout;
|
||||
uint32_t interval;
|
||||
|
||||
enum qdevice_heuristics_mode mode;
|
||||
|
||||
int waiting_for_result;
|
||||
uint32_t expected_reply_seq_number;
|
||||
|
||||
struct qdevice_heuristics_exec_list exec_list;
|
||||
|
||||
struct qdevice_instance *qdevice_instance_ptr;
|
||||
|
||||
struct qdevice_heuristics_result_notifier_list exec_result_notifier_list;
|
||||
};
|
||||
|
||||
extern int qdevice_heuristics_instance_init(struct qdevice_heuristics_instance *instance);
|
||||
|
||||
extern int qdevice_heuristics_instance_destroy(struct qdevice_heuristics_instance *instance);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _QDEVICE_HEURISTICS_INSTANCE_H_ */
|
151
qdevices/qdevice-heuristics-io.c
Normal file
151
qdevices/qdevice-heuristics-io.c
Normal file
@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2017 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "qdevice-heuristics-io.h"
|
||||
|
||||
#define QDEVICE_HEURISTICS_IO_BUFFER_SIZE 256
|
||||
|
||||
ssize_t
|
||||
qdevice_heuristics_io_blocking_write(int fd, const void *buf, size_t count)
|
||||
{
|
||||
ssize_t bytes_written;
|
||||
ssize_t tmp_bytes_written;
|
||||
|
||||
bytes_written = 0;
|
||||
|
||||
do {
|
||||
tmp_bytes_written = write(fd, (const char *)buf + bytes_written,
|
||||
(count - bytes_written > SSIZE_MAX) ? SSIZE_MAX : count - bytes_written);
|
||||
if (tmp_bytes_written == -1) {
|
||||
if (errno != EAGAIN && errno != EINTR && errno != EWOULDBLOCK) {
|
||||
return (-1);
|
||||
}
|
||||
} else {
|
||||
bytes_written += tmp_bytes_written;
|
||||
}
|
||||
} while ((size_t)bytes_written != count);
|
||||
|
||||
return (bytes_written);
|
||||
}
|
||||
|
||||
/*
|
||||
* 1 Full line readed (at least one \n found)
|
||||
* 0 Partial read (no error)
|
||||
* -1 End of connection
|
||||
* -2 Buffer too long
|
||||
* -3 Unhandled error
|
||||
*/
|
||||
int
|
||||
qdevice_heuristics_io_read(int fd, struct dynar *dest)
|
||||
{
|
||||
char buf[QDEVICE_HEURISTICS_IO_BUFFER_SIZE];
|
||||
ssize_t readed;
|
||||
int res;
|
||||
size_t zi;
|
||||
|
||||
res = 0;
|
||||
readed = read(fd, buf, sizeof(buf));
|
||||
if (readed > 0) {
|
||||
if (dynar_cat(dest, buf, readed) == -1) {
|
||||
res = -2;
|
||||
goto exit_err;
|
||||
}
|
||||
|
||||
for (zi = 0; zi < (size_t)readed; zi++) {
|
||||
if (buf[zi] == '\n') {
|
||||
res = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (readed == 0) {
|
||||
res = -1;
|
||||
}
|
||||
|
||||
if (readed < 0 && errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) {
|
||||
res = -3;
|
||||
}
|
||||
|
||||
exit_err:
|
||||
return (res);
|
||||
}
|
||||
|
||||
/*
|
||||
* 1 All data succesfully sent
|
||||
* 0 Partial send (no error)
|
||||
* -1 send returned 0,
|
||||
* -2 Unhandled error
|
||||
*/
|
||||
int
|
||||
qdevice_heuristics_io_write(int fd, const struct dynar *msg, size_t *already_sent_bytes)
|
||||
{
|
||||
ssize_t sent;
|
||||
size_t to_send;
|
||||
int res;
|
||||
|
||||
res = 0;
|
||||
|
||||
to_send = dynar_size(msg) - *already_sent_bytes;
|
||||
if (to_send > QDEVICE_HEURISTICS_IO_BUFFER_SIZE) {
|
||||
to_send = QDEVICE_HEURISTICS_IO_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
sent = write(fd, dynar_data(msg) + *already_sent_bytes,
|
||||
to_send);
|
||||
|
||||
if (sent > 0) {
|
||||
*already_sent_bytes += sent;
|
||||
|
||||
if (*already_sent_bytes == dynar_size(msg)) {
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
|
||||
if (sent == 0) {
|
||||
res = -1;
|
||||
}
|
||||
|
||||
if (sent < 0 && errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) {
|
||||
res = -2;
|
||||
}
|
||||
|
||||
return (res);
|
||||
}
|
56
qdevices/qdevice-heuristics-io.h
Normal file
56
qdevices/qdevice-heuristics-io.h
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2017 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _QDEVICE_HEURISTICS_IO_H_
|
||||
#define _QDEVICE_HEURISTICS_IO_H_
|
||||
|
||||
#include "dynar.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern ssize_t qdevice_heuristics_io_blocking_write(int fd, const void *buf,
|
||||
size_t count);
|
||||
|
||||
extern int qdevice_heuristics_io_read(int fd, struct dynar *dest);
|
||||
|
||||
extern int qdevice_heuristics_io_write(int fd, const struct dynar *msg,
|
||||
size_t *already_sent_bytes);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _QDEVICE_HEURISTICS_IO_H_ */
|
173
qdevices/qdevice-heuristics-log.c
Normal file
173
qdevices/qdevice-heuristics-log.c
Normal file
@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2017 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "qdevice-heuristics-io.h"
|
||||
#include "qdevice-heuristics-log.h"
|
||||
#include "qdevice-log.h"
|
||||
|
||||
/*
|
||||
* 1 - Line logged
|
||||
* 0 - No line to log - everything processed
|
||||
* -1 - Error
|
||||
*/
|
||||
static int
|
||||
qdevice_heuristics_log_process_one_line(struct dynar *data)
|
||||
{
|
||||
char *str;
|
||||
char *log_str_start;
|
||||
size_t str_len;
|
||||
size_t nl_pos;
|
||||
size_t zi;
|
||||
int status;
|
||||
unsigned int log_priority;
|
||||
|
||||
str = dynar_data(data);
|
||||
str_len = dynar_size(data);
|
||||
log_str_start = str;
|
||||
|
||||
status = 0;
|
||||
log_priority = 0;
|
||||
/*
|
||||
* Find start of log message and end of line
|
||||
*/
|
||||
for (zi = 0; zi < str_len && status != -1; zi++) {
|
||||
switch (status) {
|
||||
case 0:
|
||||
if (str[zi] >= '0' && str[zi] <= '9') {
|
||||
log_priority = log_priority * 10 + (str[zi] - '0');
|
||||
} else if (str[zi] == ' ') {
|
||||
status = 1;
|
||||
} else {
|
||||
qdevice_log(LOG_ERR, "Parsing of heuristics log line failed. "
|
||||
"Unexpected char '%c'", str[zi]);
|
||||
return (-1);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (str[zi] != ' ') {
|
||||
status = 2;
|
||||
log_str_start = str + zi;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (str[zi] == '\n' || str[zi] == '\r') {
|
||||
str[zi] = '\0';
|
||||
nl_pos = zi;
|
||||
status = -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (status != -1) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Do actual logging
|
||||
*/
|
||||
qb_log_from_external_source(__func__, __FILE__, "worker: %s", log_priority, __LINE__, 0, log_str_start);
|
||||
|
||||
/*
|
||||
* Find place where is begining of new "valid" line
|
||||
*/
|
||||
for (zi = nl_pos + 1; zi < str_len && (str[zi] == '\0' || str[zi] == '\n' || str[zi] == '\r'); zi++) ;
|
||||
|
||||
memmove(str, str + zi, str_len - zi);
|
||||
if (dynar_set_size(data, str_len - zi) == -1) {
|
||||
qdevice_log(LOG_ERR, "qdevice_heuristics_log_process_one_line: Can't set dynar size");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (1);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 0 - No error
|
||||
* -1 - Error
|
||||
*/
|
||||
static int
|
||||
qdevice_heuristics_log_process(struct qdevice_heuristics_instance *instance)
|
||||
{
|
||||
int res;
|
||||
|
||||
while ((res = qdevice_heuristics_log_process_one_line(&instance->log_in_buffer)) == 1) ;
|
||||
|
||||
return (res);
|
||||
}
|
||||
|
||||
/*
|
||||
* 0 - No error
|
||||
* 1 - Error
|
||||
*/
|
||||
int
|
||||
qdevice_heuristics_log_read_from_pipe(struct qdevice_heuristics_instance *instance)
|
||||
{
|
||||
int res;
|
||||
int ret;
|
||||
|
||||
res = qdevice_heuristics_io_read(instance->pipe_log_recv, &instance->log_in_buffer);
|
||||
|
||||
ret = 0;
|
||||
|
||||
switch (res) {
|
||||
case 0:
|
||||
/*
|
||||
* Partial read
|
||||
*/
|
||||
break;
|
||||
case -1:
|
||||
qdevice_log(LOG_ERR, "Lost connection with heuristics worker");
|
||||
ret = -1;
|
||||
break;
|
||||
case -2:
|
||||
qdevice_log(LOG_ERR, "Heuristics worker sent too long log. Ignoring line");
|
||||
dynar_clean(&instance->log_in_buffer);
|
||||
break;
|
||||
case -3:
|
||||
qdevice_log(LOG_ERR, "Unhandled error when reading from heuristics worker log fd");
|
||||
ret = -1;
|
||||
break;
|
||||
case 1:
|
||||
/*
|
||||
* At least one log line received
|
||||
*/
|
||||
ret = qdevice_heuristics_log_process(instance);
|
||||
break;
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
51
qdevices/qdevice-heuristics-log.h
Normal file
51
qdevices/qdevice-heuristics-log.h
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2017 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _QDEVICE_HEURISTICS_LOG_H_
|
||||
#define _QDEVICE_HEURISTICS_LOG_H_
|
||||
|
||||
#include "qdevice-heuristics-instance.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern int qdevice_heuristics_log_read_from_pipe(
|
||||
struct qdevice_heuristics_instance *instance);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _QDEVICE_HEURISTICS_LOG_H_ */
|
51
qdevices/qdevice-heuristics-mode.c
Normal file
51
qdevices/qdevice-heuristics-mode.c
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "qdevice-heuristics-mode.h"
|
||||
|
||||
const char*
|
||||
qdevice_heuristics_mode_to_str(enum qdevice_heuristics_mode mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case QDEVICE_HEURISTICS_MODE_DISABLED: return ("Disabled"); break;
|
||||
case QDEVICE_HEURISTICS_MODE_ENABLED: return ("Enabled"); break;
|
||||
case QDEVICE_HEURISTICS_MODE_SYNC: return ("Enabled only on sync"); break;
|
||||
}
|
||||
|
||||
return ("Undefined");
|
||||
}
|
55
qdevices/qdevice-heuristics-mode.h
Normal file
55
qdevices/qdevice-heuristics-mode.h
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2017 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _QDEVICE_HEURISTICS_MODE_H_
|
||||
#define _QDEVICE_HEURISTICS_MODE_H_
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum qdevice_heuristics_mode {
|
||||
QDEVICE_HEURISTICS_MODE_DISABLED = 0,
|
||||
QDEVICE_HEURISTICS_MODE_ENABLED = 1,
|
||||
QDEVICE_HEURISTICS_MODE_SYNC = 2,
|
||||
};
|
||||
|
||||
extern const char *qdevice_heuristics_mode_to_str(enum qdevice_heuristics_mode mode);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _QDEVICE_HEURISTICS_MODE_H_ */
|
134
qdevices/qdevice-heuristics-result-notifier.c
Normal file
134
qdevices/qdevice-heuristics-result-notifier.c
Normal file
@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2017 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "qdevice-heuristics-result-notifier.h"
|
||||
|
||||
void
|
||||
qdevice_heuristics_result_notifier_list_init(struct qdevice_heuristics_result_notifier_list *notifier_list)
|
||||
{
|
||||
|
||||
TAILQ_INIT(notifier_list);
|
||||
}
|
||||
|
||||
struct qdevice_heuristics_result_notifier_item *
|
||||
qdevice_heuristics_result_notifier_list_get(struct qdevice_heuristics_result_notifier_list *notifier_list,
|
||||
qdevice_heuristics_result_notifier_callback callback)
|
||||
{
|
||||
struct qdevice_heuristics_result_notifier_item *item;
|
||||
|
||||
TAILQ_FOREACH(item, notifier_list, entries) {
|
||||
if (item->callback == callback) {
|
||||
return (item);
|
||||
}
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
struct qdevice_heuristics_result_notifier_item *
|
||||
qdevice_heuristics_result_notifier_list_add(struct qdevice_heuristics_result_notifier_list *notifier_list,
|
||||
qdevice_heuristics_result_notifier_callback callback)
|
||||
{
|
||||
struct qdevice_heuristics_result_notifier_item *item;
|
||||
|
||||
item = qdevice_heuristics_result_notifier_list_get(notifier_list, callback);
|
||||
if (item != NULL) {
|
||||
return (item);
|
||||
}
|
||||
|
||||
item = (struct qdevice_heuristics_result_notifier_item *)malloc(sizeof(*item));
|
||||
if (item == NULL) {
|
||||
return (NULL);
|
||||
}
|
||||
memset(item, 0, sizeof(*item));
|
||||
item->callback = callback;
|
||||
item->active = 0;
|
||||
|
||||
TAILQ_INSERT_TAIL(notifier_list, item, entries);
|
||||
|
||||
return (item);
|
||||
}
|
||||
|
||||
int
|
||||
qdevice_heuristics_result_notifier_list_set_active(struct qdevice_heuristics_result_notifier_list *notifier_list,
|
||||
qdevice_heuristics_result_notifier_callback callback, int active)
|
||||
{
|
||||
struct qdevice_heuristics_result_notifier_item *item;
|
||||
|
||||
item = qdevice_heuristics_result_notifier_list_get(notifier_list, callback);
|
||||
if (item == NULL) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
item->active = active;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
qdevice_heuristics_result_notifier_list_free(struct qdevice_heuristics_result_notifier_list *notifier_list)
|
||||
{
|
||||
struct qdevice_heuristics_result_notifier_item *item;
|
||||
struct qdevice_heuristics_result_notifier_item *item_next;
|
||||
|
||||
item = TAILQ_FIRST(notifier_list);
|
||||
while (item != NULL) {
|
||||
item_next = TAILQ_NEXT(item, entries);
|
||||
|
||||
free(item);
|
||||
item = item_next;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
qdevice_heuristics_result_notifier_notify(struct qdevice_heuristics_result_notifier_list *notifier_list,
|
||||
void *heuristics_instance, uint32_t seq_number, enum qdevice_heuristics_exec_result exec_result)
|
||||
{
|
||||
struct qdevice_heuristics_result_notifier_item *item;
|
||||
|
||||
TAILQ_FOREACH(item, notifier_list, entries) {
|
||||
if (!item->active) {
|
||||
continue ;
|
||||
}
|
||||
|
||||
if (item->callback(heuristics_instance, seq_number, exec_result) != 0) {
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
87
qdevices/qdevice-heuristics-result-notifier.h
Normal file
87
qdevices/qdevice-heuristics-result-notifier.h
Normal file
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2017 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _QDEVICE_HEURISTICS_RESULT_NOTIFIER_H_
|
||||
#define _QDEVICE_HEURISTICS_RESULT_NOTIFIER_H_
|
||||
|
||||
#include <sys/queue.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "qdevice-heuristics-exec-result.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef int (*qdevice_heuristics_result_notifier_callback)(void *heuristics_instance, uint32_t seq_number,
|
||||
enum qdevice_heuristics_exec_result exec_result);
|
||||
|
||||
struct qdevice_heuristics_result_notifier_item {
|
||||
qdevice_heuristics_result_notifier_callback callback;
|
||||
int active;
|
||||
TAILQ_ENTRY(qdevice_heuristics_result_notifier_item) entries;
|
||||
};
|
||||
|
||||
TAILQ_HEAD(qdevice_heuristics_result_notifier_list, qdevice_heuristics_result_notifier_item);
|
||||
|
||||
extern void qdevice_heuristics_result_notifier_list_init(
|
||||
struct qdevice_heuristics_result_notifier_list *notifier_list);
|
||||
|
||||
extern struct qdevice_heuristics_result_notifier_item *qdevice_heuristics_result_notifier_list_add(
|
||||
struct qdevice_heuristics_result_notifier_list *notifier_list,
|
||||
qdevice_heuristics_result_notifier_callback callback);
|
||||
|
||||
extern struct qdevice_heuristics_result_notifier_item *qdevice_heuristics_result_notifier_list_get(
|
||||
struct qdevice_heuristics_result_notifier_list *notifier_list,
|
||||
qdevice_heuristics_result_notifier_callback callback);
|
||||
|
||||
extern int qdevice_heuristics_result_notifier_list_set_active(
|
||||
struct qdevice_heuristics_result_notifier_list *notifier_list,
|
||||
qdevice_heuristics_result_notifier_callback callback, int active);
|
||||
|
||||
extern void qdevice_heuristics_result_notifier_list_free(
|
||||
struct qdevice_heuristics_result_notifier_list *notifier_list);
|
||||
|
||||
extern int qdevice_heuristics_result_notifier_notify(
|
||||
struct qdevice_heuristics_result_notifier_list *notifier_list,
|
||||
void *heuristics_instance, uint32_t seq_number,
|
||||
enum qdevice_heuristics_exec_result exec_result);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _QDEVICE_HEURISTICS_RESULT_NOTIFIER_H_ */
|
384
qdevices/qdevice-heuristics-worker-cmd.c
Normal file
384
qdevices/qdevice-heuristics-worker-cmd.c
Normal file
@ -0,0 +1,384 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2017 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "dynar.h"
|
||||
#include "dynar-str.h"
|
||||
#include "qdevice-heuristics-io.h"
|
||||
#include "qdevice-heuristics-worker.h"
|
||||
#include "qdevice-heuristics-worker-cmd.h"
|
||||
#include "qdevice-heuristics-cmd-str.h"
|
||||
#include "qdevice-heuristics-worker-log.h"
|
||||
|
||||
static int
|
||||
qdevice_heuristics_worker_cmd_process_exec_list_add(struct qdevice_heuristics_worker_instance *instance,
|
||||
struct dynar *data)
|
||||
{
|
||||
size_t zi;
|
||||
char *exec_name;
|
||||
char *exec_command;
|
||||
char *str;
|
||||
|
||||
str = dynar_data(data);
|
||||
|
||||
/*
|
||||
* Skip to first space
|
||||
*/
|
||||
for (zi = 0; str[zi] != ' ' && str[zi] != '\0'; zi++) ;
|
||||
|
||||
if (str[zi] == '\0') {
|
||||
qdevice_heuristics_worker_log_printf(instance, LOG_CRIT,
|
||||
"qdevice_heuristics_worker_cmd_process_exec_list_add: Can't find first space");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Skip to the end of spaces
|
||||
*/
|
||||
for (; str[zi] == ' '; zi++) ;
|
||||
|
||||
if (str[zi] == '\0') {
|
||||
qdevice_heuristics_worker_log_printf(instance, LOG_CRIT,
|
||||
"qdevice_heuristics_worker_cmd_process_exec_list_add: Can't find start of exec name");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Found exec name
|
||||
*/
|
||||
exec_name = str + zi;
|
||||
|
||||
/*
|
||||
* Skip to the next spaces
|
||||
*/
|
||||
for (; str[zi] != ' ' && str[zi] != '\0'; zi++) ;
|
||||
|
||||
if (str[zi] == '\0') {
|
||||
qdevice_heuristics_worker_log_printf(instance, LOG_CRIT,
|
||||
"qdevice_heuristics_worker_cmd_process_exec_list_add: Can't find second space");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Put trailing \0 into exec_name
|
||||
*/
|
||||
str[zi] = '\0';
|
||||
zi++;
|
||||
|
||||
/*
|
||||
* Skip to the end of next spaces
|
||||
*/
|
||||
for (; str[zi] == ' '; zi++) ;
|
||||
|
||||
if (str[zi] == '\0') {
|
||||
qdevice_heuristics_worker_log_printf(instance, LOG_CRIT,
|
||||
"qdevice_heuristics_worker_cmd_process_exec_list_add: Can't find start of exec command");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Found exec_command
|
||||
*/
|
||||
exec_command = str + zi;
|
||||
|
||||
qdevice_heuristics_worker_log_printf(instance, LOG_DEBUG,
|
||||
"qdevice_heuristics_worker_cmd_process_one_line: Received exec-list-add command "
|
||||
"with name \"%s\" and command \"%s\"", exec_name, exec_command);
|
||||
|
||||
if (qdevice_heuristics_exec_list_add(&instance->exec_list, exec_name, exec_command) == NULL) {
|
||||
qdevice_heuristics_worker_log_printf(instance, LOG_CRIT,
|
||||
"qdevice_heuristics_worker_cmd_process_exec_list_add: Can't alloc exec list entry");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
qdevice_heuristics_worker_cmd_process_exec(struct qdevice_heuristics_worker_instance *instance,
|
||||
struct dynar *data)
|
||||
{
|
||||
uint32_t timeout;
|
||||
uint32_t seq_number;
|
||||
char *str;
|
||||
struct qdevice_heuristics_exec_list_entry *exec_list_entry;
|
||||
struct process_list_entry *plist_entry;
|
||||
|
||||
str = dynar_data(data);
|
||||
|
||||
if (sscanf(str, QDEVICE_HEURISTICS_CMD_STR_EXEC_ADD_SPACE "%"PRIu32" %"PRIu32, &timeout,
|
||||
&seq_number) != 2) {
|
||||
qdevice_heuristics_worker_log_printf(instance, LOG_CRIT,
|
||||
"qdevice_heuristics_worker_cmd_process_exec: Can't parse command (sscanf)");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
qdevice_heuristics_worker_log_printf(instance, LOG_DEBUG,
|
||||
"qdevice_heuristics_worker_cmd_process_exec: Received exec command "
|
||||
"with seq_no \"%"PRIu32"\" and timeout \"%"PRIu32"\"", seq_number, timeout);
|
||||
|
||||
if (instance->exec_timeout_timer != NULL) {
|
||||
process_list_move_active_entries_to_kill_list(&instance->main_process_list);
|
||||
|
||||
timer_list_delete(&instance->main_timer_list, instance->exec_timeout_timer);
|
||||
instance->exec_timeout_timer = NULL;
|
||||
}
|
||||
|
||||
instance->last_exec_seq_number = seq_number;
|
||||
|
||||
if (qdevice_heuristics_exec_list_is_empty(&instance->exec_list)) {
|
||||
if (qdevice_heuristics_worker_cmd_write_exec_result(instance,
|
||||
instance->last_exec_seq_number,
|
||||
QDEVICE_HEURISTICS_EXEC_RESULT_DISABLED) != 0) {
|
||||
return (-1);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Initialize process list (from exec list)
|
||||
*/
|
||||
TAILQ_FOREACH(exec_list_entry, &instance->exec_list, entries) {
|
||||
plist_entry = process_list_add(&instance->main_process_list,
|
||||
exec_list_entry->name, exec_list_entry->command);
|
||||
|
||||
if (plist_entry == NULL) {
|
||||
qdevice_heuristics_worker_log_printf(instance, LOG_ERR,
|
||||
"qdevice_heuristics_worker_cmd_process_exec: Can't allocate "
|
||||
"process list entry");
|
||||
|
||||
process_list_move_active_entries_to_kill_list(
|
||||
&instance->main_process_list);
|
||||
|
||||
if (qdevice_heuristics_worker_cmd_write_exec_result(instance,
|
||||
instance->last_exec_seq_number,
|
||||
QDEVICE_HEURISTICS_EXEC_RESULT_FAIL) != 0) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
if (process_list_exec_initialized(&instance->main_process_list) != 0) {
|
||||
qdevice_heuristics_worker_log_printf(instance, LOG_ERR,
|
||||
"qdevice_heuristics_worker_cmd_process_exec: Can't execute "
|
||||
"process list");
|
||||
|
||||
process_list_move_active_entries_to_kill_list(&instance->main_process_list);
|
||||
|
||||
if (qdevice_heuristics_worker_cmd_write_exec_result(instance,
|
||||
instance->last_exec_seq_number,
|
||||
QDEVICE_HEURISTICS_EXEC_RESULT_FAIL) != 0) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
instance->exec_timeout_timer = timer_list_add(&instance->main_timer_list,
|
||||
timeout, qdevice_heuristics_worker_exec_timeout_timer_callback,
|
||||
(void *)instance, NULL);
|
||||
if (instance->exec_timeout_timer == NULL) {
|
||||
qdevice_heuristics_worker_log_printf(instance, LOG_ERR,
|
||||
"qdevice_heuristics_worker_cmd_process_exec: Can't add exec timeout "
|
||||
"timer to timer list");
|
||||
|
||||
process_list_move_active_entries_to_kill_list(&instance->main_process_list);
|
||||
|
||||
if (qdevice_heuristics_worker_cmd_write_exec_result(instance,
|
||||
instance->last_exec_seq_number,
|
||||
QDEVICE_HEURISTICS_EXEC_RESULT_FAIL) != 0) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* 1 - Line processed
|
||||
* 0 - No line to process - everything processed
|
||||
* -1 - Error
|
||||
*/
|
||||
static int
|
||||
qdevice_heuristics_worker_cmd_process_one_line(struct qdevice_heuristics_worker_instance *instance,
|
||||
struct dynar *data)
|
||||
{
|
||||
char *str;
|
||||
size_t str_len;
|
||||
size_t nl_pos;
|
||||
size_t zi;
|
||||
|
||||
str = dynar_data(data);
|
||||
str_len = dynar_size(data);
|
||||
|
||||
/*
|
||||
* Find valid line
|
||||
*/
|
||||
for (zi = 0; zi < str_len && str[zi] != '\r' && str[zi] != '\n'; zi++) ;
|
||||
|
||||
if (zi >= str_len) {
|
||||
/*
|
||||
* Command is not yet fully readed
|
||||
*/
|
||||
return (0);
|
||||
}
|
||||
|
||||
nl_pos = zi;
|
||||
|
||||
str[nl_pos] = '\0';
|
||||
|
||||
if (strcmp(str, QDEVICE_HEURISTICS_CMD_STR_EXEC_LIST_CLEAR) == 0) {
|
||||
qdevice_heuristics_worker_log_printf(instance, LOG_DEBUG,
|
||||
"qdevice_heuristics_worker_cmd_process_one_line: Received exec-list-clear command");
|
||||
|
||||
qdevice_heuristics_exec_list_free(&instance->exec_list);
|
||||
} else if (strncmp(str, QDEVICE_HEURISTICS_CMD_STR_EXEC_LIST_ADD_SPACE,
|
||||
strlen(QDEVICE_HEURISTICS_CMD_STR_EXEC_LIST_ADD)) == 0) {
|
||||
if (qdevice_heuristics_worker_cmd_process_exec_list_add(instance, data) != 0) {
|
||||
return (-1);
|
||||
}
|
||||
} else if (strncmp(str, QDEVICE_HEURISTICS_CMD_STR_EXEC_ADD_SPACE,
|
||||
strlen(QDEVICE_HEURISTICS_CMD_STR_EXEC_ADD_SPACE)) == 0) {
|
||||
if (qdevice_heuristics_worker_cmd_process_exec(instance, data) != 0) {
|
||||
return (-1);
|
||||
}
|
||||
} else {
|
||||
qdevice_heuristics_worker_log_printf(instance, LOG_CRIT,
|
||||
"qdevice_heuristics_worker_cmd_process_one_line: Unknown command \"%s\" "
|
||||
"received from main qdevice process", str);
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find place where is begining of new "valid" line
|
||||
*/
|
||||
for (zi = nl_pos + 1; zi < str_len && (str[zi] == '\0' || str[zi] == '\n' || str[zi] == '\r'); zi++) ;
|
||||
|
||||
memmove(str, str + zi, str_len - zi);
|
||||
if (dynar_set_size(data, str_len - zi) == -1) {
|
||||
qdevice_heuristics_worker_log_printf(instance, LOG_CRIT,
|
||||
"qdevice_heuristics_worker_cmd_process_one_line: Can't set dynar size");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* 0 - No error
|
||||
* -1 - Error
|
||||
*/
|
||||
static int
|
||||
qdevice_heuristics_worker_cmd_process(struct qdevice_heuristics_worker_instance *instance)
|
||||
{
|
||||
int res;
|
||||
|
||||
while ((res =
|
||||
qdevice_heuristics_worker_cmd_process_one_line(instance, &instance->cmd_in_buffer)) == 1) ;
|
||||
|
||||
return (res);
|
||||
}
|
||||
|
||||
/*
|
||||
* 0 - No error
|
||||
* 1 - Error
|
||||
*/
|
||||
int
|
||||
qdevice_heuristics_worker_cmd_read_from_pipe(struct qdevice_heuristics_worker_instance *instance)
|
||||
{
|
||||
int res;
|
||||
int ret;
|
||||
|
||||
res = qdevice_heuristics_io_read(QDEVICE_HEURISTICS_WORKER_CMD_IN_FD, &instance->cmd_in_buffer);
|
||||
|
||||
ret = 0;
|
||||
|
||||
switch (res) {
|
||||
case 0:
|
||||
/*
|
||||
* Partial read
|
||||
*/
|
||||
break;
|
||||
case -1:
|
||||
qdevice_heuristics_worker_log_printf(instance, LOG_ERR,
|
||||
"Lost connection with main qdevice process");
|
||||
ret = -1;
|
||||
break;
|
||||
case -2:
|
||||
qdevice_heuristics_worker_log_printf(instance, LOG_ERR,
|
||||
"Heuristics sent too long command line");
|
||||
ret = -1;
|
||||
break;
|
||||
case -3:
|
||||
qdevice_heuristics_worker_log_printf(instance, LOG_ERR,
|
||||
"Unhandled error when reading from heuristics command in fd");
|
||||
ret = -1;
|
||||
break;
|
||||
case 1:
|
||||
/*
|
||||
* At least one log line received
|
||||
*/
|
||||
ret = qdevice_heuristics_worker_cmd_process(instance);
|
||||
break;
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
int
|
||||
qdevice_heuristics_worker_cmd_write_exec_result(struct qdevice_heuristics_worker_instance *instance,
|
||||
uint32_t seq_number, enum qdevice_heuristics_exec_result exec_result)
|
||||
{
|
||||
if (dynar_str_cpy(&instance->cmd_out_buffer,
|
||||
QDEVICE_HEURISTICS_CMD_STR_EXEC_RESULT_ADD_SPACE) != -1 &&
|
||||
dynar_str_catf(&instance->cmd_out_buffer, "%"PRIu32" %u\n", seq_number,
|
||||
(int)exec_result) != -1) {
|
||||
(void)qdevice_heuristics_io_blocking_write(QDEVICE_HEURISTICS_WORKER_CMD_OUT_FD,
|
||||
dynar_data(&instance->cmd_out_buffer), dynar_size(&instance->cmd_out_buffer));
|
||||
} else {
|
||||
qdevice_heuristics_worker_log_printf(instance, LOG_CRIT,
|
||||
"Can't alloc memory for exec result");
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
56
qdevices/qdevice-heuristics-worker-cmd.h
Normal file
56
qdevices/qdevice-heuristics-worker-cmd.h
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2017 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _QDEVICE_HEURISTICS_WORKER_CMD_H_
|
||||
#define _QDEVICE_HEURISTICS_WORKER_CMD_H_
|
||||
|
||||
#include "qdevice-heuristics-worker-instance.h"
|
||||
#include "qdevice-heuristics-exec-result.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern int qdevice_heuristics_worker_cmd_read_from_pipe(
|
||||
struct qdevice_heuristics_worker_instance *instance);
|
||||
|
||||
extern int qdevice_heuristics_worker_cmd_write_exec_result(
|
||||
struct qdevice_heuristics_worker_instance *instance, uint32_t seq_number,
|
||||
enum qdevice_heuristics_exec_result exec_result);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _QDEVICE_HEURISTICS_WORKER_CMD_H_ */
|
69
qdevices/qdevice-heuristics-worker-instance.h
Normal file
69
qdevices/qdevice-heuristics-worker-instance.h
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2017 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _QDEVICE_HEURISTICS_WORKER_INSTANCE_H_
|
||||
#define _QDEVICE_HEURISTICS_WORKER_INSTANCE_H_
|
||||
|
||||
#include "dynar.h"
|
||||
|
||||
#include "qdevice-heuristics-exec-list.h"
|
||||
#include "process-list.h"
|
||||
#include "timer-list.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct qdevice_heuristics_worker_instance {
|
||||
struct dynar cmd_in_buffer;
|
||||
struct dynar cmd_out_buffer;
|
||||
struct dynar log_out_buffer;
|
||||
|
||||
struct qdevice_heuristics_exec_list exec_list;
|
||||
struct process_list main_process_list;
|
||||
struct timer_list main_timer_list;
|
||||
|
||||
struct timer_list_entry *kill_list_timer;
|
||||
struct timer_list_entry *exec_timeout_timer;
|
||||
|
||||
uint32_t last_exec_seq_number;
|
||||
|
||||
int schedule_exit;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _QDEVICE_HEURISTICS_WORKER_INSTANCE_H_ */
|
96
qdevices/qdevice-heuristics-worker-log.c
Normal file
96
qdevices/qdevice-heuristics-worker-log.c
Normal file
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2017 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <syslog.h>
|
||||
|
||||
#include "dynar.h"
|
||||
#include "dynar-str.h"
|
||||
#include "qdevice-heuristics-io.h"
|
||||
#include "qdevice-heuristics-worker.h"
|
||||
#include "qdevice-heuristics-worker-log.h"
|
||||
|
||||
static int
|
||||
qdevice_heuristics_worker_log_remove_newlines(struct dynar *str)
|
||||
{
|
||||
size_t len;
|
||||
size_t zi;
|
||||
char *buf;
|
||||
|
||||
len = dynar_size(str);
|
||||
buf = dynar_data(str);
|
||||
|
||||
for (zi = 0; zi < len ; zi++) {
|
||||
if (buf[zi] == '\n' || buf[zi] == '\r') {
|
||||
buf[zi] = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
qdevice_heuristics_worker_log_printf(struct qdevice_heuristics_worker_instance *instance,
|
||||
int priority, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_list ap_copy;
|
||||
|
||||
va_start(ap, format);
|
||||
|
||||
if (dynar_str_cpy(&instance->log_out_buffer, "") != -1 &&
|
||||
dynar_str_catf(&instance->log_out_buffer, "%u ", priority) != -1 &&
|
||||
dynar_str_vcatf(&instance->log_out_buffer, format, ap) != -1 &&
|
||||
qdevice_heuristics_worker_log_remove_newlines(&instance->log_out_buffer) != -1 &&
|
||||
dynar_str_cat(&instance->log_out_buffer, "\n") != -1) {
|
||||
/*
|
||||
* It was possible to log everything
|
||||
*/
|
||||
(void)qdevice_heuristics_io_blocking_write(QDEVICE_HEURISTICS_WORKER_LOG_OUT_FD,
|
||||
dynar_data(&instance->log_out_buffer), dynar_size(&instance->log_out_buffer));
|
||||
} else {
|
||||
/*
|
||||
* As a fallback try to log to syslog
|
||||
*/
|
||||
va_copy(ap_copy, ap);
|
||||
openlog("qdevice_heuristics_worker", LOG_PID, LOG_DAEMON);
|
||||
syslog(LOG_ERR, "Log entry sent to syslog instead of parent process");
|
||||
vsyslog(priority, format, ap_copy);
|
||||
closelog();
|
||||
va_end(ap_copy);
|
||||
}
|
||||
|
||||
va_end(ap);
|
||||
}
|
54
qdevices/qdevice-heuristics-worker-log.h
Normal file
54
qdevices/qdevice-heuristics-worker-log.h
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2017 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _QDEVICE_HEURISTICS_WORKER_LOG_H_
|
||||
#define _QDEVICE_HEURISTICS_WORKER_LOG_H_
|
||||
|
||||
#include <syslog.h>
|
||||
|
||||
#include "qdevice-heuristics-worker-instance.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern void qdevice_heuristics_worker_log_printf(
|
||||
struct qdevice_heuristics_worker_instance *instance,
|
||||
int priority, const char *format, ...) __attribute__((__format__(__printf__, 3, 0)));
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _QDEVICE_HEURISTICS_WORKER_LOG_H_ */
|
353
qdevices/qdevice-heuristics-worker.c
Normal file
353
qdevices/qdevice-heuristics-worker.c
Normal file
@ -0,0 +1,353 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2017 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
#include <poll.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "dynar-str.h"
|
||||
#include "qdevice-config.h"
|
||||
#include "qdevice-heuristics-io.h"
|
||||
#include "qdevice-heuristics-worker.h"
|
||||
#include "qdevice-heuristics-worker-instance.h"
|
||||
#include "qdevice-heuristics-worker-log.h"
|
||||
#include "qdevice-heuristics-worker-cmd.h"
|
||||
|
||||
/*
|
||||
* Declarations
|
||||
*/
|
||||
static int qdevice_heuristics_worker_kill_list_timer_callback(void *data1,
|
||||
void *data2);
|
||||
|
||||
static void qdevice_heuristics_worker_process_list_notify(
|
||||
enum process_list_notify_reason reason, const struct process_list_entry *entry,
|
||||
void *user_data);
|
||||
|
||||
static void qdevice_heuristics_worker_signal_handlers_register(void);
|
||||
|
||||
|
||||
/*
|
||||
* Definitions
|
||||
*/
|
||||
static void
|
||||
qdevice_heuristics_worker_process_list_notify(enum process_list_notify_reason reason,
|
||||
const struct process_list_entry *entry, void *user_data)
|
||||
{
|
||||
struct qdevice_heuristics_worker_instance *instance;
|
||||
|
||||
instance = (struct qdevice_heuristics_worker_instance *)user_data;
|
||||
|
||||
switch (reason) {
|
||||
case PROCESS_LIST_NOTIFY_REASON_EXECUTED:
|
||||
qdevice_heuristics_worker_log_printf(instance, LOG_DEBUG,
|
||||
"process %s executed", entry->name);
|
||||
break;
|
||||
case PROCESS_LIST_NOTIFY_REASON_FINISHED:
|
||||
if (!WIFEXITED(entry->exit_status) || WEXITSTATUS(entry->exit_status) != 0) {
|
||||
if (WIFEXITED(entry->exit_status)) {
|
||||
qdevice_heuristics_worker_log_printf(instance, LOG_WARNING,
|
||||
"process %s finished with status %d", entry->name,
|
||||
WEXITSTATUS(entry->exit_status));
|
||||
} else if (WIFSIGNALED(entry->exit_status)) {
|
||||
qdevice_heuristics_worker_log_printf(instance, LOG_WARNING,
|
||||
"process %s killed by signal %d", entry->name,
|
||||
WTERMSIG(entry->exit_status));
|
||||
} else {
|
||||
qdevice_heuristics_worker_log_printf(instance, LOG_WARNING,
|
||||
"process %s finished with non zero status", entry->name);
|
||||
}
|
||||
} else {
|
||||
qdevice_heuristics_worker_log_printf(instance, LOG_DEBUG,
|
||||
"process %s sucesfully finished", entry->name);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
qdevice_heuristics_worker_signal_handlers_register(void)
|
||||
{
|
||||
struct sigaction act;
|
||||
|
||||
act.sa_handler = SIG_DFL;
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_flags = SA_RESTART;
|
||||
|
||||
sigaction(SIGCHLD, &act, NULL);
|
||||
|
||||
act.sa_handler = SIG_IGN;
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_flags = SA_RESTART;
|
||||
|
||||
sigaction(SIGPIPE, &act, NULL);
|
||||
|
||||
act.sa_handler = SIG_IGN;
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_flags = SA_RESTART;
|
||||
|
||||
sigaction(SIGINT, &act, NULL);
|
||||
}
|
||||
|
||||
static int
|
||||
qdevice_heuristics_worker_kill_list_timer_callback(void *data1, void *data2)
|
||||
{
|
||||
struct qdevice_heuristics_worker_instance *instance;
|
||||
size_t kill_list_size;
|
||||
|
||||
instance = (struct qdevice_heuristics_worker_instance *)data1;
|
||||
|
||||
if (process_list_process_kill_list(&instance->main_process_list) != 0) {
|
||||
qdevice_heuristics_worker_log_printf(instance, LOG_CRIT,
|
||||
"qdevice_heuristics_worker_kill_list_timer_callback: process kill list failed. "
|
||||
"Shutting down worker");
|
||||
|
||||
instance->schedule_exit = 1;
|
||||
return (0);
|
||||
}
|
||||
|
||||
kill_list_size = process_list_get_kill_list_items(&instance->main_process_list);
|
||||
|
||||
if (kill_list_size > 0) {
|
||||
qdevice_heuristics_worker_log_printf(instance, LOG_DEBUG,
|
||||
"Still waiting for %zu processes exit", kill_list_size);
|
||||
}
|
||||
|
||||
/*
|
||||
* Schedule this timer again
|
||||
*/
|
||||
return (-1);
|
||||
}
|
||||
|
||||
int
|
||||
qdevice_heuristics_worker_exec_timeout_timer_callback(void *data1, void *data2)
|
||||
{
|
||||
struct qdevice_heuristics_worker_instance *instance;
|
||||
|
||||
instance = (struct qdevice_heuristics_worker_instance *)data1;
|
||||
|
||||
qdevice_heuristics_worker_log_printf(instance, LOG_WARNING,
|
||||
"Not all heuristics execs finished on time");
|
||||
|
||||
process_list_move_active_entries_to_kill_list(&instance->main_process_list);
|
||||
|
||||
instance->exec_timeout_timer = NULL;
|
||||
|
||||
if (qdevice_heuristics_worker_cmd_write_exec_result(instance, instance->last_exec_seq_number,
|
||||
QDEVICE_HEURISTICS_EXEC_RESULT_FAIL) != 0) {
|
||||
instance->schedule_exit = 1;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
qdevice_heuristics_worker_poll(struct qdevice_heuristics_worker_instance *instance)
|
||||
{
|
||||
int poll_res;
|
||||
struct pollfd poll_input_fd;
|
||||
uint32_t timeout;
|
||||
int plist_summary;
|
||||
|
||||
/*
|
||||
* Poll command input
|
||||
*/
|
||||
poll_input_fd.fd = QDEVICE_HEURISTICS_WORKER_CMD_IN_FD;
|
||||
poll_input_fd.events = POLLIN;
|
||||
poll_input_fd.revents = 0;
|
||||
|
||||
timeout = timer_list_time_to_expire_ms(&instance->main_timer_list);
|
||||
if (timeout > QDEVICE_MIN_HEURISTICS_TIMEOUT) {
|
||||
timeout = QDEVICE_MIN_HEURISTICS_TIMEOUT;
|
||||
}
|
||||
|
||||
if ((poll_res = poll(&poll_input_fd, 1, timeout)) >= 0) {
|
||||
if (poll_input_fd.revents & POLLIN) {
|
||||
/*
|
||||
* POLLIN
|
||||
*/
|
||||
if (qdevice_heuristics_worker_cmd_read_from_pipe(instance) != 0) {
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
if (poll_input_fd.revents & POLLOUT) {
|
||||
/*
|
||||
* Pollout shouldn't happen (critical error)
|
||||
*/
|
||||
qdevice_heuristics_worker_log_printf(instance, LOG_CRIT,
|
||||
"qdevice_heuristics_worker_poll: POLLOUT set. Shutting down worker");
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (poll_input_fd.revents & (POLLERR|POLLHUP|POLLNVAL) &&
|
||||
!(poll_input_fd.revents & (POLLIN|POLLOUT))) {
|
||||
/*
|
||||
* Qdevice closed pipe
|
||||
*/
|
||||
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
if (process_list_waitpid(&instance->main_process_list) != 0) {
|
||||
qdevice_heuristics_worker_log_printf(instance, LOG_CRIT,
|
||||
"qdevice_heuristics_worker_poll: Waitpid failed. Shutting down worker");
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (instance->exec_timeout_timer != NULL) {
|
||||
plist_summary = process_list_get_summary_result_short(&instance->main_process_list);
|
||||
|
||||
switch (plist_summary) {
|
||||
case -1:
|
||||
/*
|
||||
* Processes not finished -> continue
|
||||
*/
|
||||
break;
|
||||
case 0:
|
||||
/*
|
||||
* All processes finished sucesfully
|
||||
*/
|
||||
if (qdevice_heuristics_worker_cmd_write_exec_result(instance,
|
||||
instance->last_exec_seq_number, QDEVICE_HEURISTICS_EXEC_RESULT_PASS) != 0) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
process_list_move_active_entries_to_kill_list(&instance->main_process_list);
|
||||
|
||||
timer_list_delete(&instance->main_timer_list, instance->exec_timeout_timer);
|
||||
instance->exec_timeout_timer = NULL;
|
||||
|
||||
break;
|
||||
case 1:
|
||||
/*
|
||||
* Some processes failed
|
||||
*/
|
||||
if (qdevice_heuristics_worker_cmd_write_exec_result(instance,
|
||||
instance->last_exec_seq_number, QDEVICE_HEURISTICS_EXEC_RESULT_FAIL) != 0) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
process_list_move_active_entries_to_kill_list(&instance->main_process_list);
|
||||
|
||||
timer_list_delete(&instance->main_timer_list, instance->exec_timeout_timer);
|
||||
instance->exec_timeout_timer = NULL;
|
||||
break;
|
||||
default:
|
||||
qdevice_heuristics_worker_log_printf(instance, LOG_CRIT,
|
||||
"qdevice_heuristics_worker_poll: Unhandled "
|
||||
"process_list_get_summary_result. Shutting down worker");
|
||||
|
||||
return (-1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
timer_list_expire(&instance->main_timer_list);
|
||||
|
||||
if (instance->schedule_exit) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
qdevice_heuristics_worker_start(size_t ipc_max_send_receive_size, int use_execvp,
|
||||
size_t max_processes, uint32_t kill_list_interval)
|
||||
{
|
||||
struct qdevice_heuristics_worker_instance instance;
|
||||
|
||||
memset(&instance, 0, sizeof(instance));
|
||||
|
||||
instance.schedule_exit = 0;
|
||||
|
||||
dynar_init(&instance.cmd_in_buffer, ipc_max_send_receive_size);
|
||||
dynar_init(&instance.cmd_out_buffer, ipc_max_send_receive_size);
|
||||
dynar_init(&instance.log_out_buffer, ipc_max_send_receive_size);
|
||||
|
||||
process_list_init(&instance.main_process_list, max_processes, use_execvp,
|
||||
qdevice_heuristics_worker_process_list_notify, (void *)&instance);
|
||||
|
||||
timer_list_init(&instance.main_timer_list);
|
||||
instance.kill_list_timer = timer_list_add(&instance.main_timer_list,
|
||||
kill_list_interval, qdevice_heuristics_worker_kill_list_timer_callback,
|
||||
(void *)&instance, NULL);
|
||||
|
||||
if (instance.kill_list_timer == NULL) {
|
||||
qdevice_heuristics_worker_log_printf(&instance, LOG_CRIT,
|
||||
"Can't create kill list timer");
|
||||
return ;
|
||||
}
|
||||
|
||||
instance.exec_timeout_timer = NULL;
|
||||
|
||||
qdevice_heuristics_exec_list_init(&instance.exec_list);
|
||||
|
||||
qdevice_heuristics_worker_signal_handlers_register();
|
||||
|
||||
qdevice_heuristics_worker_log_printf(&instance, LOG_DEBUG, "Heuristic worker initialized");
|
||||
|
||||
while (qdevice_heuristics_worker_poll(&instance) == 0) {
|
||||
}
|
||||
|
||||
qdevice_heuristics_worker_log_printf(&instance, LOG_DEBUG, "Heuristic worker shutdown "
|
||||
"requested");
|
||||
|
||||
qdevice_heuristics_exec_list_free(&instance.exec_list);
|
||||
|
||||
timer_list_free(&instance.main_timer_list);
|
||||
|
||||
qdevice_heuristics_worker_log_printf(&instance, LOG_DEBUG,
|
||||
"Waiting for all processes to exit");
|
||||
|
||||
if (process_list_killall(&instance.main_process_list, kill_list_interval) != 0) {
|
||||
qdevice_heuristics_worker_log_printf(&instance, LOG_WARNING,
|
||||
"Not all process exited");
|
||||
}
|
||||
|
||||
process_list_free(&instance.main_process_list);
|
||||
|
||||
dynar_destroy(&instance.cmd_in_buffer);
|
||||
dynar_destroy(&instance.cmd_out_buffer);
|
||||
dynar_destroy(&instance.log_out_buffer);
|
||||
}
|
55
qdevices/qdevice-heuristics-worker.h
Normal file
55
qdevices/qdevice-heuristics-worker.h
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2017 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _QDEVICE_HEURISTICS_WORKER_H_
|
||||
#define _QDEVICE_HEURISTICS_WORKER_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define QDEVICE_HEURISTICS_WORKER_CMD_IN_FD 0
|
||||
#define QDEVICE_HEURISTICS_WORKER_CMD_OUT_FD 1
|
||||
#define QDEVICE_HEURISTICS_WORKER_LOG_OUT_FD 2
|
||||
|
||||
void qdevice_heuristics_worker_start(size_t ipc_max_send_receive_size,
|
||||
int use_execvp, size_t max_processes, uint32_t kill_list_interval);
|
||||
|
||||
int qdevice_heuristics_worker_exec_timeout_timer_callback(void *data1, void *data2);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _QDEVICE_HEURISTICS_WORKER_H_ */
|
372
qdevices/qdevice-heuristics.c
Normal file
372
qdevices/qdevice-heuristics.c
Normal file
@ -0,0 +1,372 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2017 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <poll.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "qdevice-log.h"
|
||||
#include "qdevice-heuristics.h"
|
||||
#include "qdevice-heuristics-cmd.h"
|
||||
#include "qdevice-heuristics-worker.h"
|
||||
#include "qdevice-heuristics-io.h"
|
||||
#include "qdevice-votequorum.h"
|
||||
#include "utils.h"
|
||||
|
||||
#define QDEVICE_HEURISTICS_WAIT_FOR_INITIAL_EXEC_RESULT_MAX_PFDS 5
|
||||
|
||||
void
|
||||
qdevice_heuristics_init(struct qdevice_heuristics_instance *instance,
|
||||
struct qdevice_advanced_settings *advanced_settings)
|
||||
{
|
||||
int pipe_cmd_in[2], pipe_cmd_out[2], pipe_log_out[2];
|
||||
pid_t pid;
|
||||
|
||||
if (pipe(pipe_cmd_in) != 0) {
|
||||
err(1, "Can't create command input pipe");
|
||||
}
|
||||
|
||||
if (pipe(pipe_cmd_out) != 0) {
|
||||
err(1, "Can't create command output pipe");
|
||||
}
|
||||
|
||||
if (pipe(pipe_log_out) != 0) {
|
||||
err(1, "Can't create logging output pipe");
|
||||
}
|
||||
|
||||
pid = fork();
|
||||
if (pid == -1) {
|
||||
err(1, "Can't create child process");
|
||||
} else if (pid == 0) {
|
||||
/*
|
||||
* Child
|
||||
*/
|
||||
(void)setsid();
|
||||
if (dup2(pipe_cmd_in[0], 0) == -1) {
|
||||
err(1, "Can't dup2 command input pipe");
|
||||
}
|
||||
close(pipe_cmd_in[1]);
|
||||
close(pipe_cmd_in[0]);
|
||||
if (utils_fd_set_non_blocking(0) == -1) {
|
||||
err(1, "Can't set non blocking flag on command input pipe");
|
||||
}
|
||||
|
||||
if (dup2(pipe_cmd_out[1], 1) == -1) {
|
||||
err(1, "Can't dup2 command output pipe");
|
||||
}
|
||||
close(pipe_cmd_out[0]);
|
||||
close(pipe_cmd_out[1]);
|
||||
|
||||
if (dup2(pipe_log_out[1], 2) == -1) {
|
||||
err(1, "Can't dup2 logging output pipe");
|
||||
}
|
||||
close(pipe_log_out[0]);
|
||||
close(pipe_log_out[1]);
|
||||
|
||||
qdevice_heuristics_worker_start(advanced_settings->heuristics_ipc_max_send_receive_size,
|
||||
advanced_settings->heuristics_use_execvp, advanced_settings->heuristics_max_processes,
|
||||
advanced_settings->heuristics_kill_list_interval);
|
||||
|
||||
qdevice_advanced_settings_destroy(advanced_settings);
|
||||
|
||||
exit(0);
|
||||
} else {
|
||||
close(pipe_cmd_in[0]);
|
||||
close(pipe_cmd_out[1]);
|
||||
close(pipe_log_out[1]);
|
||||
|
||||
qdevice_heuristics_instance_init(instance);
|
||||
|
||||
instance->pipe_cmd_send = pipe_cmd_in[1];
|
||||
if (utils_fd_set_non_blocking(instance->pipe_cmd_send) == -1) {
|
||||
err(1, "Can't set non blocking flag on command input pipe");
|
||||
}
|
||||
instance->pipe_cmd_recv = pipe_cmd_out[0];
|
||||
if (utils_fd_set_non_blocking(instance->pipe_cmd_recv) == -1) {
|
||||
err(1, "Can't set non blocking flag on command output pipe");
|
||||
}
|
||||
instance->pipe_log_recv = pipe_log_out[0];
|
||||
if (utils_fd_set_non_blocking(instance->pipe_cmd_recv) == -1) {
|
||||
err(1, "Can't set non blocking flag on logging output pipe");
|
||||
}
|
||||
instance->worker_pid = pid;
|
||||
|
||||
send_buffer_list_init(&instance->cmd_out_buffer_list,
|
||||
advanced_settings->heuristics_ipc_max_send_buffers,
|
||||
advanced_settings->heuristics_ipc_max_send_receive_size);
|
||||
dynar_init(&instance->log_in_buffer,
|
||||
advanced_settings->heuristics_ipc_max_send_receive_size);
|
||||
dynar_init(&instance->cmd_in_buffer,
|
||||
advanced_settings->heuristics_ipc_max_send_receive_size);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
qdevice_heuristics_destroy(struct qdevice_heuristics_instance *instance)
|
||||
{
|
||||
int status;
|
||||
|
||||
/*
|
||||
* Close of pipe_cmd_send result is correct and almost instant exit of worker
|
||||
*/
|
||||
close(instance->pipe_cmd_send);
|
||||
|
||||
qdevice_log(LOG_DEBUG, "Waiting for heuristics worker to finish");
|
||||
if (waitpid(instance->worker_pid, &status, 0) == -1) {
|
||||
qdevice_log_err(LOG_ERR, "Heuristics worker waitpid failed");
|
||||
} else {
|
||||
/*
|
||||
* Log what left in worker log buffer. Errors can be ignored
|
||||
*/
|
||||
(void)qdevice_heuristics_log_read_from_pipe(instance);
|
||||
}
|
||||
|
||||
close(instance->pipe_cmd_recv);
|
||||
close(instance->pipe_log_recv);
|
||||
|
||||
dynar_destroy(&instance->log_in_buffer);
|
||||
dynar_destroy(&instance->cmd_in_buffer);
|
||||
send_buffer_list_free(&instance->cmd_out_buffer_list);
|
||||
|
||||
qdevice_heuristics_instance_destroy(instance);
|
||||
}
|
||||
|
||||
int
|
||||
qdevice_heuristics_exec(struct qdevice_heuristics_instance *instance, int sync_in_progress)
|
||||
{
|
||||
uint32_t timeout;
|
||||
|
||||
instance->expected_reply_seq_number++;
|
||||
instance->waiting_for_result = 1;
|
||||
|
||||
if (sync_in_progress) {
|
||||
timeout = instance->sync_timeout;
|
||||
} else {
|
||||
timeout = instance->timeout;
|
||||
}
|
||||
|
||||
return (qdevice_heuristics_cmd_write_exec(instance, timeout,
|
||||
instance->expected_reply_seq_number));
|
||||
}
|
||||
|
||||
int
|
||||
qdevice_heuristics_waiting_for_result(const struct qdevice_heuristics_instance *instance)
|
||||
{
|
||||
|
||||
return (instance->waiting_for_result);
|
||||
}
|
||||
|
||||
int
|
||||
qdevice_heuristics_change_exec_list(struct qdevice_heuristics_instance *instance,
|
||||
const struct qdevice_heuristics_exec_list *new_exec_list, int sync_in_progress)
|
||||
{
|
||||
|
||||
if (qdevice_heuristics_cmd_write_exec_list(instance, new_exec_list) != 0) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
qdevice_heuristics_exec_list_free(&instance->exec_list);
|
||||
|
||||
if (new_exec_list != NULL) {
|
||||
if (qdevice_heuristics_exec_list_clone(&instance->exec_list, new_exec_list) != 0) {
|
||||
qdevice_log(LOG_ERR, "Can't clone exec list");
|
||||
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
if (qdevice_heuristics_waiting_for_result(instance)) {
|
||||
if (qdevice_heuristics_exec(instance, sync_in_progress) != 0) {
|
||||
qdevice_log(LOG_ERR, "Can't execute heuristics");
|
||||
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
qdevice_heuristics_wait_for_initial_exec_result(struct qdevice_heuristics_instance *instance)
|
||||
{
|
||||
struct pollfd pfds[QDEVICE_HEURISTICS_WAIT_FOR_INITIAL_EXEC_RESULT_MAX_PFDS];
|
||||
int no_pfds;
|
||||
int poll_res;
|
||||
int timeout;
|
||||
int i;
|
||||
int case_processed;
|
||||
int res;
|
||||
|
||||
while (!instance->qdevice_instance_ptr->vq_node_list_initial_heuristics_finished) {
|
||||
no_pfds = 0;
|
||||
|
||||
assert(no_pfds < QDEVICE_HEURISTICS_WAIT_FOR_INITIAL_EXEC_RESULT_MAX_PFDS);
|
||||
pfds[no_pfds].fd = instance->pipe_log_recv;
|
||||
pfds[no_pfds].events = POLLIN;
|
||||
pfds[no_pfds].revents = 0;
|
||||
no_pfds++;
|
||||
|
||||
assert(no_pfds < QDEVICE_HEURISTICS_WAIT_FOR_INITIAL_EXEC_RESULT_MAX_PFDS);
|
||||
pfds[no_pfds].fd = instance->pipe_cmd_recv;
|
||||
pfds[no_pfds].events = POLLIN;
|
||||
pfds[no_pfds].revents = 0;
|
||||
no_pfds++;
|
||||
|
||||
assert(no_pfds < QDEVICE_HEURISTICS_WAIT_FOR_INITIAL_EXEC_RESULT_MAX_PFDS);
|
||||
pfds[no_pfds].fd = instance->qdevice_instance_ptr->votequorum_poll_fd;
|
||||
pfds[no_pfds].events = POLLIN;
|
||||
pfds[no_pfds].revents = 0;
|
||||
no_pfds++;
|
||||
|
||||
if (!send_buffer_list_empty(&instance->cmd_out_buffer_list)) {
|
||||
assert(no_pfds < QDEVICE_HEURISTICS_WAIT_FOR_INITIAL_EXEC_RESULT_MAX_PFDS);
|
||||
pfds[no_pfds].fd = instance->pipe_cmd_send;
|
||||
pfds[no_pfds].events = POLLOUT;
|
||||
pfds[no_pfds].revents = 0;
|
||||
no_pfds++;
|
||||
}
|
||||
|
||||
/*
|
||||
* We know this is never larger than QDEVICE_DEFAULT_HEURISTICS_MAX_TIMEOUT * 2
|
||||
*/
|
||||
timeout = (int)instance->sync_timeout * 2;
|
||||
|
||||
poll_res = poll(pfds, no_pfds, timeout);
|
||||
if (poll_res > 0) {
|
||||
for (i = 0; i < no_pfds; i++) {
|
||||
if (pfds[i].revents & POLLIN) {
|
||||
case_processed = 0;
|
||||
switch (i) {
|
||||
case 0:
|
||||
case_processed = 1;
|
||||
|
||||
res = qdevice_heuristics_log_read_from_pipe(instance);
|
||||
if (res == -1) {
|
||||
return (-1);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
case_processed = 1;
|
||||
res = qdevice_heuristics_cmd_read_from_pipe(instance);
|
||||
if (res == -1) {
|
||||
return (-1);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
case_processed = 1;
|
||||
res = qdevice_votequorum_dispatch(instance->qdevice_instance_ptr);
|
||||
if (res == -1) {
|
||||
return (-1);
|
||||
}
|
||||
case 3:
|
||||
/*
|
||||
* Read on heuristics cmd send fs shouldn't happen
|
||||
*/
|
||||
break;
|
||||
}
|
||||
|
||||
if (!case_processed) {
|
||||
qdevice_log(LOG_CRIT, "Unhandled read on poll descriptor %u", i);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (pfds[i].revents & POLLOUT) {
|
||||
case_processed = 0;
|
||||
switch (i) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
/*
|
||||
* Write on heuristics log, cmd recv or vq shouldn't happen
|
||||
*/
|
||||
break;
|
||||
case 3:
|
||||
case_processed = 1;
|
||||
res = qdevice_heuristics_cmd_write(instance);
|
||||
if (res == -1) {
|
||||
return (-1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (!case_processed) {
|
||||
qdevice_log(LOG_CRIT, "Unhandled write on poll descriptor %u", i);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if ((pfds[i].revents & (POLLERR|POLLHUP|POLLNVAL)) &&
|
||||
!(pfds[i].revents & (POLLIN|POLLOUT))) {
|
||||
switch (i) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 3:
|
||||
/*
|
||||
* Closed pipe doesn't mean return of POLLIN. To display
|
||||
* better log message, we call read log as if POLLIN would
|
||||
* be set.
|
||||
*/
|
||||
res = qdevice_heuristics_log_read_from_pipe(instance);
|
||||
if (res == -1) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
qdevice_log(LOG_ERR, "POLLERR (%u) on heuristics pipe. Exiting");
|
||||
return (-1);
|
||||
break;
|
||||
case 2:
|
||||
qdevice_log(LOG_ERR, "POLLERR (%u) on corosync socket. Exiting");
|
||||
return (-1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (poll_res == 0) {
|
||||
qdevice_log(LOG_ERR, "Timeout waiting for initial heuristics exec result");
|
||||
return (-1);
|
||||
} else {
|
||||
qdevice_log_err(LOG_ERR, "Initial heuristics exec result poll failed");
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
70
qdevices/qdevice-heuristics.h
Normal file
70
qdevices/qdevice-heuristics.h
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2017 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _QDEVICE_HEURISTICS_H_
|
||||
#define _QDEVICE_HEURISTICS_H_
|
||||
|
||||
#include "dynar.h"
|
||||
#include "qdevice-advanced-settings.h"
|
||||
#include "send-buffer-list.h"
|
||||
#include "qdevice-heuristics-instance.h"
|
||||
#include "qdevice-heuristics-log.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern void qdevice_heuristics_init(struct qdevice_heuristics_instance *instance,
|
||||
struct qdevice_advanced_settings *advanced_settings);
|
||||
|
||||
extern void qdevice_heuristics_destroy(struct qdevice_heuristics_instance *instance);
|
||||
|
||||
extern int qdevice_heuristics_exec(struct qdevice_heuristics_instance *instance,
|
||||
int sync_in_progress);
|
||||
|
||||
extern int qdevice_heuristics_waiting_for_result(
|
||||
const struct qdevice_heuristics_instance *instance);
|
||||
|
||||
extern int qdevice_heuristics_change_exec_list(
|
||||
struct qdevice_heuristics_instance *instance,
|
||||
const struct qdevice_heuristics_exec_list *new_exec_list, int sync_in_progress);
|
||||
|
||||
extern int qdevice_heuristics_wait_for_initial_exec_result(
|
||||
struct qdevice_heuristics_instance *instance);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _QDEVICE_HEURISTICS_H_ */
|
297
qdevices/qdevice-instance.c
Normal file
297
qdevices/qdevice-instance.c
Normal file
@ -0,0 +1,297 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2017 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "qdevice-config.h"
|
||||
#include "qdevice-instance.h"
|
||||
#include "qdevice-heuristics-exec-list.h"
|
||||
#include "qdevice-log.h"
|
||||
#include "qdevice-model.h"
|
||||
#include "utils.h"
|
||||
|
||||
int
|
||||
qdevice_instance_init(struct qdevice_instance *instance,
|
||||
const struct qdevice_advanced_settings *advanced_settings)
|
||||
{
|
||||
|
||||
memset(instance, 0, sizeof(*instance));
|
||||
|
||||
node_list_init(&instance->config_node_list);
|
||||
|
||||
instance->vq_last_poll = ((time_t) -1);
|
||||
instance->advanced_settings = advanced_settings;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
qdevice_instance_destroy(struct qdevice_instance *instance)
|
||||
{
|
||||
|
||||
node_list_free(&instance->config_node_list);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
qdevice_instance_configure_from_cmap_heuristics(struct qdevice_instance *instance)
|
||||
{
|
||||
char *str;
|
||||
long int li;
|
||||
char *ep;
|
||||
int i;
|
||||
int res;
|
||||
cs_error_t cs_err;
|
||||
cmap_iter_handle_t iter_handle;
|
||||
char key_name[CMAP_KEYNAME_MAXLEN + 1];
|
||||
size_t value_len;
|
||||
cmap_value_types_t type;
|
||||
struct qdevice_heuristics_exec_list tmp_exec_list;
|
||||
struct qdevice_heuristics_exec_list *exec_list;
|
||||
char *command;
|
||||
char exec_name[CMAP_KEYNAME_MAXLEN + 1];
|
||||
char tmp_key[CMAP_KEYNAME_MAXLEN + 1];
|
||||
size_t no_execs;
|
||||
int send_exec_list;
|
||||
|
||||
instance->heuristics_instance.timeout = instance->heartbeat_interval / 2;
|
||||
if (cmap_get_string(instance->cmap_handle,
|
||||
"quorum.device.heuristics.timeout", &str) == CS_OK) {
|
||||
li = strtol(str, &ep, 10);
|
||||
if (li < instance->advanced_settings->heuristics_min_timeout ||
|
||||
li > instance->advanced_settings->heuristics_max_timeout || *ep != '\0') {
|
||||
qdevice_log(LOG_ERR, "heuristics.timeout must be valid number in "
|
||||
"range <%"PRIu32",%"PRIu32">",
|
||||
instance->advanced_settings->heuristics_min_timeout,
|
||||
instance->advanced_settings->heuristics_max_timeout);
|
||||
|
||||
free(str);
|
||||
return (-1);
|
||||
} else {
|
||||
instance->heuristics_instance.timeout = li;
|
||||
}
|
||||
|
||||
free(str);
|
||||
}
|
||||
|
||||
instance->heuristics_instance.sync_timeout = instance->sync_heartbeat_interval / 2;
|
||||
if (cmap_get_string(instance->cmap_handle,
|
||||
"quorum.device.heuristics.sync_timeout", &str) == CS_OK) {
|
||||
li = strtol(str, &ep, 10);
|
||||
if (li < instance->advanced_settings->heuristics_min_timeout ||
|
||||
li > instance->advanced_settings->heuristics_max_timeout || *ep != '\0') {
|
||||
qdevice_log(LOG_ERR, "heuristics.sync_timeout must be valid number in "
|
||||
"range <%"PRIu32",%"PRIu32">",
|
||||
instance->advanced_settings->heuristics_min_timeout,
|
||||
instance->advanced_settings->heuristics_max_timeout);
|
||||
|
||||
free(str);
|
||||
return (-1);
|
||||
} else {
|
||||
instance->heuristics_instance.sync_timeout = li;
|
||||
}
|
||||
|
||||
free(str);
|
||||
}
|
||||
|
||||
instance->heuristics_instance.interval = instance->heartbeat_interval * 3;
|
||||
if (cmap_get_string(instance->cmap_handle,
|
||||
"quorum.device.heuristics.interval", &str) == CS_OK) {
|
||||
li = strtol(str, &ep, 10);
|
||||
if (li < instance->advanced_settings->heuristics_min_interval ||
|
||||
li > instance->advanced_settings->heuristics_max_interval || *ep != '\0') {
|
||||
qdevice_log(LOG_ERR, "heuristics.interval must be valid number in "
|
||||
"range <%"PRIu32",%"PRIu32">",
|
||||
instance->advanced_settings->heuristics_min_interval,
|
||||
instance->advanced_settings->heuristics_max_interval);
|
||||
|
||||
free(str);
|
||||
return (-1);
|
||||
} else {
|
||||
instance->heuristics_instance.interval = li;
|
||||
}
|
||||
|
||||
free(str);
|
||||
}
|
||||
|
||||
instance->heuristics_instance.mode = QDEVICE_DEFAULT_HEURISTICS_MODE;
|
||||
|
||||
if (cmap_get_string(instance->cmap_handle, "quorum.device.heuristics.mode", &str) == CS_OK) {
|
||||
if ((i = utils_parse_bool_str(str)) == -1) {
|
||||
if (strcasecmp(str, "sync") != 0) {
|
||||
qdevice_log(LOG_ERR, "quorum.device.heuristics.mode value is not valid.");
|
||||
|
||||
free(str);
|
||||
return (-1);
|
||||
} else {
|
||||
instance->heuristics_instance.mode = QDEVICE_HEURISTICS_MODE_SYNC;
|
||||
}
|
||||
} else {
|
||||
if (i == 1) {
|
||||
instance->heuristics_instance.mode = QDEVICE_HEURISTICS_MODE_ENABLED;
|
||||
} else {
|
||||
instance->heuristics_instance.mode = QDEVICE_HEURISTICS_MODE_DISABLED;
|
||||
}
|
||||
}
|
||||
|
||||
free(str);
|
||||
}
|
||||
|
||||
send_exec_list = 0;
|
||||
exec_list = NULL;
|
||||
qdevice_heuristics_exec_list_init(&tmp_exec_list);
|
||||
|
||||
if (instance->heuristics_instance.mode == QDEVICE_HEURISTICS_MODE_DISABLED) {
|
||||
exec_list = NULL;
|
||||
send_exec_list = 1;
|
||||
} else if (instance->heuristics_instance.mode == QDEVICE_HEURISTICS_MODE_ENABLED ||
|
||||
instance->heuristics_instance.mode == QDEVICE_HEURISTICS_MODE_SYNC) {
|
||||
/*
|
||||
* Walk thru list of commands to exec
|
||||
*/
|
||||
cs_err = cmap_iter_init(instance->cmap_handle, "quorum.device.heuristics.exec_", &iter_handle);
|
||||
if (cs_err != CS_OK) {
|
||||
qdevice_log(LOG_ERR, "Can't iterate quorum.device.heuristics.exec_ keys. "
|
||||
"Error %s", cs_strerror(cs_err));
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
while ((cs_err = cmap_iter_next(instance->cmap_handle, iter_handle, key_name,
|
||||
&value_len, &type)) == CS_OK) {
|
||||
if (type != CMAP_VALUETYPE_STRING) {
|
||||
qdevice_log(LOG_WARNING, "%s key is not of string type. Ignoring");
|
||||
continue ;
|
||||
}
|
||||
|
||||
res = sscanf(key_name, "quorum.device.heuristics.exec_%[^.]%s", exec_name, tmp_key);
|
||||
if (res != 1) {
|
||||
qdevice_log(LOG_WARNING, "%s key is not correct heuristics exec name. Ignoring");
|
||||
continue ;
|
||||
}
|
||||
|
||||
cs_err = cmap_get_string(instance->cmap_handle, key_name, &command);
|
||||
if (cs_err != CS_OK) {
|
||||
qdevice_log(LOG_WARNING, "Can't get value of %s key. Ignoring");
|
||||
continue ;
|
||||
}
|
||||
|
||||
if (qdevice_heuristics_exec_list_add(&tmp_exec_list, exec_name, command) == NULL) {
|
||||
qdevice_log(LOG_WARNING, "Can't store value of %s key into list. Ignoring");
|
||||
}
|
||||
|
||||
free(command);
|
||||
}
|
||||
|
||||
no_execs = qdevice_heuristics_exec_list_size(&tmp_exec_list);
|
||||
|
||||
if (no_execs == 0) {
|
||||
qdevice_log(LOG_INFO, "No valid heuristics execs defined. Disabling heuristics.");
|
||||
instance->heuristics_instance.mode = QDEVICE_HEURISTICS_MODE_DISABLED;
|
||||
exec_list = NULL;
|
||||
send_exec_list = 1;
|
||||
} else if (no_execs > instance->advanced_settings->heuristics_max_execs) {
|
||||
qdevice_log(LOG_ERR, "Too much (%zu) heuristics execs defined (max is %zu)."
|
||||
" Disabling heuristics.", no_execs,
|
||||
instance->advanced_settings->heuristics_max_execs);
|
||||
instance->heuristics_instance.mode = QDEVICE_HEURISTICS_MODE_DISABLED;
|
||||
exec_list = NULL;
|
||||
send_exec_list = 1;
|
||||
} else if (qdevice_heuristics_exec_list_eq(&tmp_exec_list,
|
||||
&instance->heuristics_instance.exec_list) == 1) {
|
||||
qdevice_log(LOG_DEBUG, "Heuristics list is unchanged");
|
||||
send_exec_list = 0;
|
||||
} else {
|
||||
qdevice_log(LOG_DEBUG, "Heuristics list changed");
|
||||
exec_list = &tmp_exec_list;
|
||||
send_exec_list = 1;
|
||||
}
|
||||
|
||||
} else {
|
||||
qdevice_log(LOG_CRIT, "Undefined heuristics mode");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (send_exec_list) {
|
||||
if (qdevice_heuristics_change_exec_list(&instance->heuristics_instance,
|
||||
exec_list, instance->sync_in_progress) != 0) {
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
qdevice_heuristics_exec_list_free(&tmp_exec_list);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
qdevice_instance_configure_from_cmap(struct qdevice_instance *instance)
|
||||
{
|
||||
char *str;
|
||||
|
||||
if (cmap_get_string(instance->cmap_handle, "quorum.device.model", &str) != CS_OK) {
|
||||
qdevice_log(LOG_ERR, "Can't read quorum.device.model cmap key.");
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (qdevice_model_str_to_type(str, &instance->model_type) != 0) {
|
||||
qdevice_log(LOG_ERR, "Configured device model %s is not supported.", str);
|
||||
free(str);
|
||||
|
||||
return (-1);
|
||||
}
|
||||
free(str);
|
||||
|
||||
if (cmap_get_uint32(instance->cmap_handle, "runtime.votequorum.this_node_id",
|
||||
&instance->node_id) != CS_OK) {
|
||||
qdevice_log(LOG_ERR, "Unable to retrieve this node nodeid.");
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (cmap_get_uint32(instance->cmap_handle, "quorum.device.timeout", &instance->heartbeat_interval) != CS_OK) {
|
||||
instance->heartbeat_interval = VOTEQUORUM_QDEVICE_DEFAULT_TIMEOUT;
|
||||
}
|
||||
|
||||
if (cmap_get_uint32(instance->cmap_handle, "quorum.device.sync_timeout",
|
||||
&instance->sync_heartbeat_interval) != CS_OK) {
|
||||
instance->sync_heartbeat_interval = VOTEQUORUM_QDEVICE_DEFAULT_SYNC_TIMEOUT;
|
||||
}
|
||||
|
||||
if (qdevice_instance_configure_from_cmap_heuristics(instance) != 0) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
136
qdevices/qdevice-instance.h
Normal file
136
qdevices/qdevice-instance.h
Normal file
@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2017 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _QDEVICE_INSTANCE_H_
|
||||
#define _QDEVICE_INSTANCE_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <corosync/cmap.h>
|
||||
#include <corosync/votequorum.h>
|
||||
|
||||
#include "qdevice-advanced-settings.h"
|
||||
#include "qdevice-heuristics.h"
|
||||
#include "qdevice-model-type.h"
|
||||
#include "node-list.h"
|
||||
#include "unix-socket-ipc.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct qdevice_instance {
|
||||
cmap_handle_t cmap_handle;
|
||||
int cmap_poll_fd;
|
||||
int cmap_reload_in_progress;
|
||||
cmap_track_handle_t cmap_reload_track_handle;
|
||||
cmap_track_handle_t cmap_nodelist_track_handle;
|
||||
cmap_track_handle_t cmap_logging_track_handle;
|
||||
cmap_track_handle_t cmap_heuristics_track_handle;
|
||||
|
||||
votequorum_handle_t votequorum_handle;
|
||||
int votequorum_poll_fd;
|
||||
|
||||
struct unix_socket_ipc local_ipc;
|
||||
|
||||
enum qdevice_model_type model_type;
|
||||
|
||||
uint32_t node_id;
|
||||
uint32_t heartbeat_interval; /* Heartbeat interval during normal operation */
|
||||
uint32_t sync_heartbeat_interval; /* Heartbeat interval during corosync sync */
|
||||
|
||||
struct node_list config_node_list;
|
||||
int config_node_list_version_set;
|
||||
uint64_t config_node_list_version;
|
||||
|
||||
/*
|
||||
* Copy of votequorum_quorum_notify_fn callback paramters.
|
||||
* Set after model callback is called.
|
||||
*/
|
||||
uint32_t vq_quorum_quorate;
|
||||
uint32_t vq_quorum_node_list_entries;
|
||||
votequorum_node_t *vq_quorum_node_list;
|
||||
|
||||
/*
|
||||
* Copy of current votequorum_nodelist_notify_fn callback parameters.
|
||||
* Set after model callback qdevice_votequorum_node_list_notify_callback is called.
|
||||
*/
|
||||
uint8_t vq_node_list_initial_ring_id_set;
|
||||
votequorum_ring_id_t vq_node_list_ring_id;
|
||||
uint32_t vq_node_list_entries;
|
||||
uint32_t *vq_node_list;
|
||||
uint8_t vq_node_list_initial_heuristics_finished;
|
||||
enum qdevice_heuristics_exec_result vq_node_list_heuristics_result;
|
||||
|
||||
/*
|
||||
* Copy of current votequorum_nodelist_notify_fn callback ring id
|
||||
* It's set before any callback is called and used for qdevice_votequorum_poll
|
||||
*/
|
||||
votequorum_ring_id_t vq_poll_ring_id;
|
||||
|
||||
/*
|
||||
* Copy of votequorum_expectedvotes_notify_fn callback parameters.
|
||||
* Set after model callback is called.
|
||||
*/
|
||||
uint32_t vq_expected_votes;
|
||||
|
||||
time_t vq_last_poll;
|
||||
int vq_last_poll_cast_vote;
|
||||
|
||||
void *model_data;
|
||||
|
||||
const struct qdevice_advanced_settings *advanced_settings;
|
||||
|
||||
int sync_in_progress;
|
||||
|
||||
struct qdevice_heuristics_instance heuristics_instance;
|
||||
};
|
||||
|
||||
extern int qdevice_instance_init(struct qdevice_instance *instance,
|
||||
const struct qdevice_advanced_settings *advanced_settings);
|
||||
|
||||
extern int qdevice_instance_destroy(struct qdevice_instance *instance);
|
||||
|
||||
extern int qdevice_instance_configure_from_cmap(struct qdevice_instance *instance);
|
||||
|
||||
extern int qdevice_instance_configure_from_cmap_heuristics(struct qdevice_instance *instance);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _QDEVICE_INSTANCE_H_ */
|
279
qdevices/qdevice-ipc-cmd.c
Normal file
279
qdevices/qdevice-ipc-cmd.c
Normal file
@ -0,0 +1,279 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "qdevice-ipc-cmd.h"
|
||||
#include "qdevice-log.h"
|
||||
#include "qdevice-model.h"
|
||||
#include "dynar-str.h"
|
||||
#include "utils.h"
|
||||
|
||||
static int
|
||||
qdevice_ipc_cmd_status_add_header(struct qdevice_instance *instance, struct dynar *outbuf,
|
||||
int verbose)
|
||||
{
|
||||
|
||||
return ((dynar_str_catf(outbuf, "Qdevice information\n") != -1) &&
|
||||
(dynar_str_catf(outbuf, "-------------------\n") != -1));
|
||||
}
|
||||
|
||||
static int
|
||||
qdevice_ipc_cmd_status_add_model(struct qdevice_instance *instance, struct dynar *outbuf,
|
||||
int verbose)
|
||||
{
|
||||
|
||||
return (dynar_str_catf(outbuf, "Model:\t\t\t%s\n",
|
||||
qdevice_model_type_to_str(instance->model_type)) != -1);
|
||||
}
|
||||
|
||||
static int
|
||||
qdevice_ipc_cmd_status_add_nodeid(struct qdevice_instance *instance, struct dynar *outbuf,
|
||||
int verbose)
|
||||
{
|
||||
|
||||
return (dynar_str_catf(outbuf, "Node ID:\t\t"UTILS_PRI_NODE_ID"\n",
|
||||
instance->node_id) != -1);
|
||||
}
|
||||
|
||||
static int
|
||||
qdevice_ipc_cmd_status_add_intervals(struct qdevice_instance *instance, struct dynar *outbuf,
|
||||
int verbose)
|
||||
{
|
||||
|
||||
if (!verbose) {
|
||||
return (1);
|
||||
}
|
||||
|
||||
return ((dynar_str_catf(outbuf, "HB interval:\t\t%"PRIu32"ms\n",
|
||||
instance->heartbeat_interval) != -1) &&
|
||||
(dynar_str_catf(outbuf, "Sync HB interval:\t%"PRIu32"ms\n",
|
||||
instance->sync_heartbeat_interval) != -1));
|
||||
}
|
||||
|
||||
static int
|
||||
qdevice_ipc_cmd_status_add_config_node_list(struct qdevice_instance *instance, struct dynar *outbuf,
|
||||
int verbose)
|
||||
{
|
||||
struct node_list_entry *node_info;
|
||||
size_t zi;
|
||||
|
||||
if (instance->config_node_list_version_set) {
|
||||
if (dynar_str_catf(outbuf, "Configuration version:\t"UTILS_PRI_CONFIG_VERSION"\n",
|
||||
instance->config_node_list_version) == -1) {
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
if (dynar_str_catf(outbuf, "Configured node list:\n") == -1) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
zi = 0;
|
||||
|
||||
TAILQ_FOREACH(node_info, &instance->config_node_list, entries) {
|
||||
if ((dynar_str_catf(outbuf, " %zu\tNode ID = "UTILS_PRI_NODE_ID, zi,
|
||||
node_info->node_id) == -1) ||
|
||||
(node_info->data_center_id != 0 && dynar_str_catf(outbuf, ", Data center ID = "
|
||||
UTILS_PRI_DATACENTER_ID, node_info->data_center_id) == -1) ||
|
||||
(dynar_str_catf(outbuf, "\n") == -1)) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
zi++;
|
||||
}
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
static int
|
||||
qdevice_ipc_cmd_status_add_membership_node_list(struct qdevice_instance *instance, struct dynar *outbuf,
|
||||
int verbose)
|
||||
{
|
||||
uint32_t u32;
|
||||
|
||||
if (verbose && dynar_str_catf(outbuf, "Ring ID:\t\t"UTILS_PRI_RING_ID"\n",
|
||||
instance->vq_node_list_ring_id.nodeid, instance->vq_node_list_ring_id.seq) == -1) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (dynar_str_catf(outbuf, "Membership node list:\t") == -1) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
for (u32 = 0; u32 < instance->vq_node_list_entries; u32++) {
|
||||
if (u32 != 0) {
|
||||
if (dynar_str_catf(outbuf, ", ") == -1) {
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
if (dynar_str_catf(outbuf, UTILS_PRI_NODE_ID, instance->vq_node_list[u32]) == -1) {
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
if (dynar_str_catf(outbuf, "\n") == -1) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
static const char *
|
||||
qdevice_ipc_cmd_vq_nodestate_to_str(uint32_t state)
|
||||
{
|
||||
|
||||
switch (state) {
|
||||
case VOTEQUORUM_NODESTATE_MEMBER: return ("member"); break;
|
||||
case VOTEQUORUM_NODESTATE_DEAD: return ("dead"); break;
|
||||
case VOTEQUORUM_NODESTATE_LEAVING: return ("leaving"); break;
|
||||
default:
|
||||
qdevice_log(LOG_ERR, "qdevice_ipc_cmd_vq_nodestate_to_str: Unhandled votequorum "
|
||||
"node state %"PRIu32, state);
|
||||
exit(1);
|
||||
break;
|
||||
}
|
||||
|
||||
return ("Unhandled votequorum node state");
|
||||
}
|
||||
|
||||
static int
|
||||
qdevice_ipc_cmd_status_add_quorum_node_list(struct qdevice_instance *instance, struct dynar *outbuf,
|
||||
int verbose)
|
||||
{
|
||||
uint32_t u32;
|
||||
votequorum_node_t *node;
|
||||
|
||||
if (!verbose) {
|
||||
return (1);
|
||||
}
|
||||
|
||||
if (dynar_str_catf(outbuf, "Quorate:\t\t%s\n",
|
||||
(instance->vq_quorum_quorate ? "Yes" : "No")) == -1) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (dynar_str_catf(outbuf, "Quorum node list:\n") == -1) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
for (u32 = 0; u32 < instance->vq_quorum_node_list_entries; u32++) {
|
||||
node = &instance->vq_quorum_node_list[u32];
|
||||
|
||||
if (node->nodeid == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dynar_str_catf(outbuf, " %"PRIu32"\tNode ID = "UTILS_PRI_NODE_ID
|
||||
", State = %s\n", u32, node->nodeid,
|
||||
qdevice_ipc_cmd_vq_nodestate_to_str(node->state)) == -1) {
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
static int
|
||||
qdevice_ipc_cmd_status_add_expected_votes(struct qdevice_instance *instance, struct dynar *outbuf,
|
||||
int verbose)
|
||||
{
|
||||
|
||||
if (!verbose) {
|
||||
return (1);
|
||||
}
|
||||
|
||||
return (dynar_str_catf(outbuf, "Expected votes:\t\t"UTILS_PRI_EXPECTED_VOTES"\n",
|
||||
instance->vq_expected_votes) != -1);
|
||||
}
|
||||
|
||||
static int
|
||||
qdevice_ipc_cmd_status_add_last_poll(struct qdevice_instance *instance, struct dynar *outbuf,
|
||||
int verbose)
|
||||
{
|
||||
struct tm tm_res;
|
||||
|
||||
if (!verbose) {
|
||||
return (1);
|
||||
}
|
||||
|
||||
if (instance->vq_last_poll == ((time_t) -1)) {
|
||||
return (dynar_str_catf(outbuf, "Last poll call:\t\tNever\n") != -1);
|
||||
}
|
||||
|
||||
localtime_r(&instance->vq_last_poll, &tm_res);
|
||||
|
||||
if (dynar_str_catf(outbuf, "Last poll call:\t\t%04d-%02d-%02dT%02d:%02d:%02d%s\n",
|
||||
tm_res.tm_year + 1900, tm_res.tm_mon + 1, tm_res.tm_mday,
|
||||
tm_res.tm_hour, tm_res.tm_min, tm_res.tm_sec,
|
||||
(instance->vq_last_poll_cast_vote ? " (cast vote)" : "")) == -1) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
static int
|
||||
qdevice_ipc_cmd_status_add_heuristics(struct qdevice_instance *instance, struct dynar *outbuf,
|
||||
int verbose)
|
||||
{
|
||||
|
||||
if (!verbose) {
|
||||
return (1);
|
||||
}
|
||||
|
||||
return (dynar_str_catf(outbuf, "Heuristics:\t\t%s\n",
|
||||
qdevice_heuristics_mode_to_str(instance->heuristics_instance.mode)) != 0);
|
||||
}
|
||||
|
||||
int
|
||||
qdevice_ipc_cmd_status(struct qdevice_instance *instance, struct dynar *outbuf, int verbose)
|
||||
{
|
||||
|
||||
if (qdevice_ipc_cmd_status_add_header(instance, outbuf, verbose) &&
|
||||
qdevice_ipc_cmd_status_add_model(instance, outbuf, verbose) &&
|
||||
qdevice_ipc_cmd_status_add_nodeid(instance, outbuf, verbose) &&
|
||||
qdevice_ipc_cmd_status_add_intervals(instance, outbuf, verbose) &&
|
||||
qdevice_ipc_cmd_status_add_config_node_list(instance, outbuf, verbose) &&
|
||||
qdevice_ipc_cmd_status_add_heuristics(instance, outbuf, verbose) &&
|
||||
qdevice_ipc_cmd_status_add_membership_node_list(instance, outbuf, verbose) &&
|
||||
qdevice_ipc_cmd_status_add_quorum_node_list(instance, outbuf, verbose) &&
|
||||
qdevice_ipc_cmd_status_add_expected_votes(instance, outbuf, verbose) &&
|
||||
qdevice_ipc_cmd_status_add_last_poll(instance, outbuf, verbose) &&
|
||||
dynar_str_catf(outbuf, "\n") != -1 &&
|
||||
qdevice_model_ipc_cmd_status(instance, outbuf, verbose) != -1) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
return (-1);
|
||||
}
|
52
qdevices/qdevice-ipc-cmd.h
Normal file
52
qdevices/qdevice-ipc-cmd.h
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _QDEVICE_IPC_CMD_H_
|
||||
#define _QDEVICE_IPC_CMD_H_
|
||||
|
||||
#include "dynar.h"
|
||||
#include "qdevice-instance.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern int qdevice_ipc_cmd_status(struct qdevice_instance *instance, struct dynar *outbuf,
|
||||
int verbose);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _QDEVICE_IPC_CMD_H_ */
|
335
qdevices/qdevice-ipc.c
Normal file
335
qdevices/qdevice-ipc.c
Normal file
@ -0,0 +1,335 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "qdevice-config.h"
|
||||
#include "qdevice-ipc.h"
|
||||
#include "qdevice-log.h"
|
||||
#include "unix-socket-ipc.h"
|
||||
#include "dynar-simple-lex.h"
|
||||
#include "dynar-str.h"
|
||||
#include "qdevice-ipc-cmd.h"
|
||||
|
||||
int
|
||||
qdevice_ipc_init(struct qdevice_instance *instance)
|
||||
{
|
||||
if (unix_socket_ipc_init(&instance->local_ipc,
|
||||
instance->advanced_settings->local_socket_file,
|
||||
instance->advanced_settings->local_socket_backlog,
|
||||
instance->advanced_settings->ipc_max_clients,
|
||||
instance->advanced_settings->ipc_max_receive_size,
|
||||
instance->advanced_settings->ipc_max_send_size) != 0) {
|
||||
qdevice_log_err(LOG_ERR, "Can't create unix socket");
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
qdevice_ipc_close(struct qdevice_instance *instance)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = unix_socket_ipc_close(&instance->local_ipc);
|
||||
if (res != 0) {
|
||||
qdevice_log_err(LOG_WARNING, "Can't close local IPC");
|
||||
}
|
||||
|
||||
return (res);
|
||||
}
|
||||
|
||||
int
|
||||
qdevice_ipc_is_closed(struct qdevice_instance *instance)
|
||||
{
|
||||
|
||||
return (unix_socket_ipc_is_closed(&instance->local_ipc));
|
||||
}
|
||||
|
||||
int
|
||||
qdevice_ipc_destroy(struct qdevice_instance *instance)
|
||||
{
|
||||
int res;
|
||||
struct unix_socket_client *client;
|
||||
const struct unix_socket_client_list *ipc_client_list;
|
||||
|
||||
ipc_client_list = &instance->local_ipc.clients;
|
||||
|
||||
TAILQ_FOREACH(client, ipc_client_list, entries) {
|
||||
free(client->user_data);
|
||||
}
|
||||
|
||||
res = unix_socket_ipc_destroy(&instance->local_ipc);
|
||||
if (res != 0) {
|
||||
qdevice_log_err(LOG_WARNING, "Can't destroy local IPC");
|
||||
}
|
||||
|
||||
return (res);
|
||||
}
|
||||
|
||||
int
|
||||
qdevice_ipc_accept(struct qdevice_instance *instance, struct unix_socket_client **res_client)
|
||||
{
|
||||
int res;
|
||||
int accept_res;
|
||||
|
||||
accept_res = unix_socket_ipc_accept(&instance->local_ipc, res_client);
|
||||
|
||||
switch (accept_res) {
|
||||
case -1:
|
||||
qdevice_log_err(LOG_ERR, "Can't accept local IPC connection");
|
||||
res = -1;
|
||||
goto return_res;
|
||||
break;
|
||||
case -2:
|
||||
qdevice_log(LOG_ERR, "Maximum IPC clients reached. Not accepting connection");
|
||||
res = -1;
|
||||
goto return_res;
|
||||
break;
|
||||
case -3:
|
||||
qdevice_log(LOG_ERR, "Can't add client to list");
|
||||
res = -1;
|
||||
goto return_res;
|
||||
break;
|
||||
default:
|
||||
unix_socket_client_read_line(*res_client, 1);
|
||||
res = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
(*res_client)->user_data = malloc(sizeof(struct qdevice_ipc_user_data));
|
||||
if ((*res_client)->user_data == NULL) {
|
||||
qdevice_log(LOG_ERR, "Can't alloc IPC client user data");
|
||||
res = -1;
|
||||
qdevice_ipc_client_disconnect(instance, *res_client);
|
||||
} else {
|
||||
memset((*res_client)->user_data, 0, sizeof(struct qdevice_ipc_user_data));
|
||||
}
|
||||
|
||||
return_res:
|
||||
return (res);
|
||||
}
|
||||
|
||||
void
|
||||
qdevice_ipc_client_disconnect(struct qdevice_instance *instance, struct unix_socket_client *client)
|
||||
{
|
||||
|
||||
free(client->user_data);
|
||||
unix_socket_ipc_client_disconnect(&instance->local_ipc, client);
|
||||
}
|
||||
|
||||
int
|
||||
qdevice_ipc_send_error(struct qdevice_instance *instance, struct unix_socket_client *client,
|
||||
const char *error_fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int res;
|
||||
|
||||
va_start(ap, error_fmt);
|
||||
res = ((dynar_str_cpy(&client->send_buffer, "Error\n") == 0) &&
|
||||
(dynar_str_vcatf(&client->send_buffer, error_fmt, ap) > 0) &&
|
||||
(dynar_str_cat(&client->send_buffer, "\n") == 0));
|
||||
|
||||
va_end(ap);
|
||||
|
||||
if (res) {
|
||||
unix_socket_client_write_buffer(client, 1);
|
||||
} else {
|
||||
qdevice_log(LOG_ERR, "Can't send ipc error to client (buffer too small)");
|
||||
}
|
||||
|
||||
return (res ? 0 : -1);
|
||||
}
|
||||
|
||||
int
|
||||
qdevice_ipc_send_buffer(struct qdevice_instance *instance, struct unix_socket_client *client)
|
||||
{
|
||||
|
||||
if (dynar_str_prepend(&client->send_buffer, "OK\n") != 0) {
|
||||
qdevice_log(LOG_ERR, "Can't send ipc message to client (buffer too small)");
|
||||
|
||||
if (qdevice_ipc_send_error(instance, client, "Internal IPC buffer too small") != 0) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
unix_socket_client_write_buffer(client, 1);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
qdevice_ipc_parse_line(struct qdevice_instance *instance, struct unix_socket_client *client)
|
||||
{
|
||||
struct dynar_simple_lex lex;
|
||||
struct dynar *token;
|
||||
char *str;
|
||||
struct qdevice_ipc_user_data *ipc_user_data;
|
||||
int verbose;
|
||||
|
||||
ipc_user_data = (struct qdevice_ipc_user_data *)client->user_data;
|
||||
|
||||
dynar_simple_lex_init(&lex, &client->receive_buffer, DYNAR_SIMPLE_LEX_TYPE_PLAIN);
|
||||
token = dynar_simple_lex_token_next(&lex);
|
||||
|
||||
verbose = 0;
|
||||
|
||||
if (token == NULL) {
|
||||
qdevice_log(LOG_ERR, "Can't alloc memory for simple lex");
|
||||
|
||||
if (qdevice_ipc_send_error(instance, client, "Command too long") != 0) {
|
||||
client->schedule_disconnect = 1;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
str = dynar_data(token);
|
||||
if (strcasecmp(str, "") == 0) {
|
||||
qdevice_log(LOG_DEBUG, "IPC client doesn't send command");
|
||||
if (qdevice_ipc_send_error(instance, client, "No command specified") != 0) {
|
||||
client->schedule_disconnect = 1;
|
||||
}
|
||||
} else if (strcasecmp(str, "shutdown") == 0) {
|
||||
qdevice_log(LOG_DEBUG, "IPC client requested shutdown");
|
||||
|
||||
ipc_user_data->shutdown_requested = 1;
|
||||
|
||||
if (qdevice_ipc_send_buffer(instance, client) != 0) {
|
||||
client->schedule_disconnect = 1;
|
||||
}
|
||||
} else if (strcasecmp(str, "status") == 0) {
|
||||
token = dynar_simple_lex_token_next(&lex);
|
||||
|
||||
if (token != NULL && (str = dynar_data(token), strcmp(str, "")) != 0) {
|
||||
if (strcasecmp(str, "verbose") == 0) {
|
||||
verbose = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (qdevice_ipc_cmd_status(instance, &client->send_buffer, verbose) != 0) {
|
||||
if (qdevice_ipc_send_error(instance, client, "Can't get QDevice status") != 0) {
|
||||
client->schedule_disconnect = 1;
|
||||
}
|
||||
} else {
|
||||
if (qdevice_ipc_send_buffer(instance, client) != 0) {
|
||||
client->schedule_disconnect = 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
qdevice_log(LOG_DEBUG, "IPC client sent unknown command");
|
||||
if (qdevice_ipc_send_error(instance, client, "Unknown command '%s'", str) != 0) {
|
||||
client->schedule_disconnect = 1;
|
||||
}
|
||||
}
|
||||
|
||||
dynar_simple_lex_destroy(&lex);
|
||||
}
|
||||
|
||||
void
|
||||
qdevice_ipc_io_read(struct qdevice_instance *instance, struct unix_socket_client *client)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = unix_socket_client_io_read(client);
|
||||
|
||||
switch (res) {
|
||||
case 0:
|
||||
/*
|
||||
* Partial read
|
||||
*/
|
||||
break;
|
||||
case -1:
|
||||
qdevice_log(LOG_DEBUG, "IPC client closed connection");
|
||||
client->schedule_disconnect = 1;
|
||||
break;
|
||||
case -2:
|
||||
qdevice_log(LOG_ERR, "Can't store message from IPC client. Disconnecting client.");
|
||||
client->schedule_disconnect = 1;
|
||||
break;
|
||||
case -3:
|
||||
qdevice_log_err(LOG_ERR, "Can't receive message from IPC client. Disconnecting client.");
|
||||
client->schedule_disconnect = 1;
|
||||
break;
|
||||
case 1:
|
||||
/*
|
||||
* Full message received
|
||||
*/
|
||||
unix_socket_client_read_line(client, 0);
|
||||
|
||||
qdevice_ipc_parse_line(instance, client);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
qdevice_ipc_io_write(struct qdevice_instance *instance, struct unix_socket_client *client)
|
||||
{
|
||||
int res;
|
||||
struct qdevice_ipc_user_data *ipc_user_data;
|
||||
|
||||
ipc_user_data = (struct qdevice_ipc_user_data *)client->user_data;
|
||||
|
||||
res = unix_socket_client_io_write(client);
|
||||
|
||||
switch (res) {
|
||||
case 0:
|
||||
/*
|
||||
* Partial send
|
||||
*/
|
||||
break;
|
||||
case -1:
|
||||
qdevice_log(LOG_DEBUG, "IPC client closed connection");
|
||||
client->schedule_disconnect = 1;
|
||||
break;
|
||||
case -2:
|
||||
qdevice_log_err(LOG_ERR, "Can't send message to IPC client. Disconnecting client");
|
||||
client->schedule_disconnect = 1;
|
||||
break;
|
||||
case 1:
|
||||
/*
|
||||
* Full message sent
|
||||
*/
|
||||
unix_socket_client_write_buffer(client, 0);
|
||||
client->schedule_disconnect = 1;
|
||||
|
||||
if (ipc_user_data->shutdown_requested) {
|
||||
qdevice_ipc_close(instance);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
80
qdevices/qdevice-ipc.h
Normal file
80
qdevices/qdevice-ipc.h
Normal file
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _QDEVICE_IPC_H_
|
||||
#define _QDEVICE_IPC_H_
|
||||
|
||||
#include "qdevice-instance.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct qdevice_ipc_user_data {
|
||||
void *model_data;
|
||||
int shutdown_requested;
|
||||
};
|
||||
|
||||
extern int qdevice_ipc_init(struct qdevice_instance *instance);
|
||||
|
||||
extern int qdevice_ipc_close(struct qdevice_instance *instance);
|
||||
|
||||
extern int qdevice_ipc_destroy(struct qdevice_instance *instance);
|
||||
|
||||
extern int qdevice_ipc_accept(struct qdevice_instance *instance,
|
||||
struct unix_socket_client **res_client);
|
||||
|
||||
extern void qdevice_ipc_client_disconnect(struct qdevice_instance *instance,
|
||||
struct unix_socket_client *client);
|
||||
|
||||
extern void qdevice_ipc_io_read(struct qdevice_instance *instance,
|
||||
struct unix_socket_client *client);
|
||||
|
||||
extern void qdevice_ipc_io_write(struct qdevice_instance *instance,
|
||||
struct unix_socket_client *client);
|
||||
|
||||
extern int qdevice_ipc_send_error(struct qdevice_instance *instance,
|
||||
struct unix_socket_client *client, const char *error_fmt, ...)
|
||||
__attribute__((__format__(__printf__, 3, 4)));
|
||||
|
||||
extern int qdevice_ipc_send_buffer(struct qdevice_instance *instance,
|
||||
struct unix_socket_client *client);
|
||||
|
||||
extern int qdevice_ipc_is_closed(struct qdevice_instance *instance);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _QDEVICE_IPC_H_ */
|
56
qdevices/qdevice-log-debug.c
Normal file
56
qdevices/qdevice-log-debug.c
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "qdevice-log-debug.h"
|
||||
#include "qdevice-log.h"
|
||||
#include "utils.h"
|
||||
|
||||
void
|
||||
qdevice_log_debug_dump_node_list(const struct node_list *nlist)
|
||||
{
|
||||
struct node_list_entry *node_info;
|
||||
size_t zi;
|
||||
|
||||
qdevice_log(LOG_DEBUG, " Node list:");
|
||||
|
||||
zi = 0;
|
||||
|
||||
TAILQ_FOREACH(node_info, nlist, entries) {
|
||||
qdevice_log(LOG_DEBUG, " %zu node_id = "UTILS_PRI_NODE_ID", "
|
||||
"data_center_id = "UTILS_PRI_DATACENTER_ID", node_state = %s",
|
||||
zi, node_info->node_id, node_info->data_center_id,
|
||||
tlv_node_state_to_str(node_info->node_state));
|
||||
zi++;
|
||||
}
|
||||
}
|
50
qdevices/qdevice-log-debug.h
Normal file
50
qdevices/qdevice-log-debug.h
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _QDEVICE_LOG_DEBUG_H_
|
||||
#define _QDEVICE_LOG_DEBUG_H_
|
||||
|
||||
#include "node-list.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern void qdevice_log_debug_dump_node_list(const struct node_list *nlist);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _QDEVICE_LOG_DEBUG_H_ */
|
323
qdevices/qdevice-log.c
Normal file
323
qdevices/qdevice-log.c
Normal file
@ -0,0 +1,323 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "qdevice-log.h"
|
||||
#include "qdevice-config.h"
|
||||
#include "utils.h"
|
||||
|
||||
static int qdevice_log_global_force_debug;
|
||||
|
||||
struct qdevice_log_syslog_names {
|
||||
const char *prio_name;
|
||||
int priority;
|
||||
};
|
||||
|
||||
static struct qdevice_log_syslog_names qdevice_log_priority_names[] = {
|
||||
{ "alert", LOG_ALERT },
|
||||
{ "crit", LOG_CRIT },
|
||||
{ "debug", LOG_DEBUG },
|
||||
{ "emerg", LOG_EMERG },
|
||||
{ "err", LOG_ERR },
|
||||
{ "error", LOG_ERR },
|
||||
{ "info", LOG_INFO },
|
||||
{ "notice", LOG_NOTICE },
|
||||
{ "warning", LOG_WARNING },
|
||||
{ NULL, -1 }};
|
||||
|
||||
static int
|
||||
qdevice_log_priority_str_to_int(const char *priority_str)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; qdevice_log_priority_names[i].prio_name != NULL; i++) {
|
||||
if (strcasecmp(priority_str, qdevice_log_priority_names[i].prio_name) == 0) {
|
||||
return (qdevice_log_priority_names[i].priority);
|
||||
}
|
||||
}
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
void
|
||||
qdevice_log_configure(struct qdevice_instance *instance)
|
||||
{
|
||||
int to_stderr;
|
||||
int to_syslog;
|
||||
int syslog_facility;
|
||||
int syslog_priority;
|
||||
int logfile_priority;
|
||||
int debug;
|
||||
char *str;
|
||||
int i;
|
||||
int fileline;
|
||||
int timestamp;
|
||||
int function_name;
|
||||
char log_format_syslog[64];
|
||||
char log_format_stderr[64];
|
||||
|
||||
to_stderr = QDEVICE_LOG_DEFAULT_TO_STDERR;
|
||||
if (cmap_get_string(instance->cmap_handle, "logging.to_stderr", &str) == CS_OK) {
|
||||
if ((i = utils_parse_bool_str(str)) == -1) {
|
||||
qdevice_log(LOG_WARNING, "logging.to_stderr value is not valid");
|
||||
} else {
|
||||
to_stderr = i;
|
||||
}
|
||||
free(str);
|
||||
}
|
||||
|
||||
if (cmap_get_string(instance->cmap_handle,
|
||||
"logging.logger_subsys." QDEVICE_LOG_SUBSYS ".to_stderr", &str) == CS_OK) {
|
||||
if ((i = utils_parse_bool_str(str)) == -1) {
|
||||
qdevice_log(LOG_WARNING,
|
||||
"logging.logger_subsys." QDEVICE_LOG_SUBSYS ".to_stderr value is not valid.");
|
||||
} else {
|
||||
to_stderr = i;
|
||||
}
|
||||
free(str);
|
||||
}
|
||||
|
||||
to_syslog = QDEVICE_LOG_DEFAULT_TO_SYSLOG;
|
||||
if (cmap_get_string(instance->cmap_handle, "logging.to_syslog", &str) == CS_OK) {
|
||||
if ((i = utils_parse_bool_str(str)) == -1) {
|
||||
qdevice_log(LOG_WARNING, "logging.to_syslog value is not valid");
|
||||
} else {
|
||||
to_syslog = i;
|
||||
}
|
||||
free(str);
|
||||
}
|
||||
|
||||
if (cmap_get_string(instance->cmap_handle,
|
||||
"logging.logger_subsys." QDEVICE_LOG_SUBSYS ".to_syslog", &str) == CS_OK) {
|
||||
if ((i = utils_parse_bool_str(str)) == -1) {
|
||||
qdevice_log(LOG_WARNING,
|
||||
"logging.logger_subsys." QDEVICE_LOG_SUBSYS ".to_syslog value is not valid.");
|
||||
} else {
|
||||
to_syslog = i;
|
||||
}
|
||||
free(str);
|
||||
}
|
||||
|
||||
syslog_facility = QDEVICE_LOG_DEFAULT_SYSLOG_FACILITY;
|
||||
if (cmap_get_string(instance->cmap_handle, "logging.syslog_facility", &str) == CS_OK) {
|
||||
if ((i = qb_log_facility2int(str)) < 0) {
|
||||
qdevice_log(LOG_WARNING, "logging.syslog_facility value is not valid");
|
||||
} else {
|
||||
syslog_facility = i;
|
||||
}
|
||||
|
||||
free(str);
|
||||
}
|
||||
|
||||
if (cmap_get_string(instance->cmap_handle,
|
||||
"logging.logger_subsys." QDEVICE_LOG_SUBSYS ".syslog_facility", &str) == CS_OK) {
|
||||
if ((i = qb_log_facility2int(str)) < 0) {
|
||||
qdevice_log(LOG_WARNING,
|
||||
"logging.logger_subsys." QDEVICE_LOG_SUBSYS ".syslog_facility value is not valid.");
|
||||
} else {
|
||||
syslog_facility = i;
|
||||
}
|
||||
free(str);
|
||||
}
|
||||
|
||||
syslog_priority = QDEVICE_LOG_DEFAULT_SYSLOG_PRIORITY;
|
||||
if (cmap_get_string(instance->cmap_handle, "logging.syslog_priority", &str) == CS_OK) {
|
||||
if ((i = qdevice_log_priority_str_to_int(str)) < 0) {
|
||||
qdevice_log(LOG_WARNING, "logging.syslog_priority value is not valid");
|
||||
} else {
|
||||
syslog_priority = i;
|
||||
}
|
||||
|
||||
free(str);
|
||||
}
|
||||
|
||||
if (cmap_get_string(instance->cmap_handle,
|
||||
"logging.logger_subsys." QDEVICE_LOG_SUBSYS ".syslog_priority", &str) == CS_OK) {
|
||||
if ((i = qdevice_log_priority_str_to_int(str)) < 0) {
|
||||
qdevice_log(LOG_WARNING,
|
||||
"logging.logger_subsys." QDEVICE_LOG_SUBSYS ".syslog_priority value is not valid.");
|
||||
} else {
|
||||
syslog_priority = i;
|
||||
}
|
||||
free(str);
|
||||
}
|
||||
|
||||
logfile_priority = QDEVICE_LOG_DEFAULT_SYSLOG_PRIORITY;
|
||||
if (cmap_get_string(instance->cmap_handle, "logging.logfile_priority", &str) == CS_OK) {
|
||||
if ((i = qdevice_log_priority_str_to_int(str)) < 0) {
|
||||
qdevice_log(LOG_WARNING, "logging.logfile_priority value is not valid");
|
||||
} else {
|
||||
logfile_priority = i;
|
||||
}
|
||||
|
||||
free(str);
|
||||
}
|
||||
|
||||
if (cmap_get_string(instance->cmap_handle,
|
||||
"logging.logger_subsys." QDEVICE_LOG_SUBSYS ".logfile_priority", &str) == CS_OK) {
|
||||
if ((i = qdevice_log_priority_str_to_int(str)) < 0) {
|
||||
qdevice_log(LOG_WARNING,
|
||||
"logging.logger_subsys." QDEVICE_LOG_SUBSYS ".logfile_priority value is not valid.");
|
||||
} else {
|
||||
logfile_priority = i;
|
||||
}
|
||||
free(str);
|
||||
}
|
||||
|
||||
debug = QDEVICE_LOG_DEFAULT_DEBUG;
|
||||
if (cmap_get_string(instance->cmap_handle, "logging.debug", &str) == CS_OK) {
|
||||
if ((i = utils_parse_bool_str(str)) == -1) {
|
||||
if (strcasecmp(str, "trace") == 0) {
|
||||
debug = 1;
|
||||
} else {
|
||||
qdevice_log(LOG_WARNING, "logging.debug value is not valid");
|
||||
}
|
||||
} else {
|
||||
debug = i;
|
||||
}
|
||||
free(str);
|
||||
}
|
||||
|
||||
if (cmap_get_string(instance->cmap_handle,
|
||||
"logging.logger_subsys." QDEVICE_LOG_SUBSYS ".debug", &str) == CS_OK) {
|
||||
if ((i = utils_parse_bool_str(str)) == -1) {
|
||||
if (strcasecmp(str, "trace") == 0) {
|
||||
debug = 1;
|
||||
} else {
|
||||
qdevice_log(LOG_WARNING,
|
||||
"logging.logger_subsys." QDEVICE_LOG_SUBSYS ".debug value is not valid.");
|
||||
}
|
||||
} else {
|
||||
debug = i;
|
||||
}
|
||||
free(str);
|
||||
}
|
||||
|
||||
fileline = QDEVICE_LOG_DEFAULT_FILELINE;
|
||||
if (cmap_get_string(instance->cmap_handle, "logging.fileline", &str) == CS_OK) {
|
||||
if ((i = utils_parse_bool_str(str)) == -1) {
|
||||
qdevice_log(LOG_WARNING, "logging.fileline value is not valid");
|
||||
} else {
|
||||
fileline = i;
|
||||
}
|
||||
free(str);
|
||||
}
|
||||
|
||||
timestamp = QDEVICE_LOG_DEFAULT_TIMESTAMP;
|
||||
if (cmap_get_string(instance->cmap_handle, "logging.timestamp", &str) == CS_OK) {
|
||||
if ((i = utils_parse_bool_str(str)) == -1) {
|
||||
qdevice_log(LOG_WARNING, "logging.timestamp value is not valid");
|
||||
} else {
|
||||
timestamp = i;
|
||||
}
|
||||
free(str);
|
||||
}
|
||||
|
||||
function_name = QDEVICE_LOG_DEFAULT_FUNCTION_NAME;
|
||||
if (cmap_get_string(instance->cmap_handle, "logging.function_name", &str) == CS_OK) {
|
||||
if ((i = utils_parse_bool_str(str)) == -1) {
|
||||
qdevice_log(LOG_WARNING, "logging.function_name value is not valid");
|
||||
} else {
|
||||
function_name = i;
|
||||
}
|
||||
free(str);
|
||||
}
|
||||
|
||||
strcpy(log_format_syslog, "");
|
||||
|
||||
if (fileline) {
|
||||
strcat(log_format_syslog, "%f:");
|
||||
|
||||
if (function_name) {
|
||||
strcat(log_format_syslog, "%n:");
|
||||
}
|
||||
|
||||
strcat(log_format_syslog, "%l ");
|
||||
}
|
||||
|
||||
strcat(log_format_syslog, "%b");
|
||||
|
||||
strcpy(log_format_stderr, "");
|
||||
if (timestamp) {
|
||||
strcpy(log_format_stderr, "%t %7p ");
|
||||
}
|
||||
strcat(log_format_stderr, log_format_syslog);
|
||||
|
||||
if (qdevice_log_global_force_debug) {
|
||||
debug = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Finally reconfigure log system
|
||||
*/
|
||||
qb_log_ctl(QB_LOG_STDERR, QB_LOG_CONF_ENABLED, to_stderr);
|
||||
qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, to_syslog);
|
||||
qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_FACILITY, syslog_facility);
|
||||
qb_log_filter_ctl(QB_LOG_SYSLOG, QB_LOG_FILTER_CLEAR_ALL, QB_LOG_FILTER_FILE, "*", LOG_TRACE);
|
||||
qb_log_filter_ctl(QB_LOG_SYSLOG, QB_LOG_FILTER_ADD, QB_LOG_FILTER_FILE, "*",
|
||||
(debug ? LOG_DEBUG : syslog_priority));
|
||||
qb_log_filter_ctl(QB_LOG_STDERR, QB_LOG_FILTER_CLEAR_ALL, QB_LOG_FILTER_FILE, "*", LOG_TRACE);
|
||||
qb_log_filter_ctl(QB_LOG_STDERR, QB_LOG_FILTER_ADD, QB_LOG_FILTER_FILE, "*",
|
||||
(debug ? LOG_DEBUG : logfile_priority));
|
||||
|
||||
qb_log_format_set(QB_LOG_STDERR, log_format_stderr);
|
||||
qb_log_format_set(QB_LOG_SYSLOG, log_format_syslog);
|
||||
}
|
||||
|
||||
void
|
||||
qdevice_log_init(struct qdevice_instance *instance, int force_debug)
|
||||
{
|
||||
qdevice_log_global_force_debug = force_debug;
|
||||
|
||||
qb_log_init(QDEVICE_PROGRAM_NAME, QDEVICE_LOG_DEFAULT_SYSLOG_FACILITY,
|
||||
QDEVICE_LOG_DEFAULT_SYSLOG_PRIORITY);
|
||||
|
||||
qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_FALSE);
|
||||
qb_log_ctl(QB_LOG_STDOUT, QB_LOG_CONF_ENABLED, QB_FALSE);
|
||||
qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_ENABLED, QB_FALSE);
|
||||
qb_log_ctl(QB_LOG_STDERR, QB_LOG_CONF_ENABLED, QB_TRUE);
|
||||
|
||||
qb_log_filter_ctl(QB_LOG_STDERR, QB_LOG_FILTER_ADD, QB_LOG_FILTER_FILE, "*", LOG_INFO);
|
||||
qb_log_filter_ctl(QB_LOG_SYSLOG, QB_LOG_FILTER_ADD, QB_LOG_FILTER_FILE, "*", LOG_INFO);
|
||||
qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_PRIORITY_BUMP, LOG_INFO - LOG_DEBUG);
|
||||
qb_log_format_set(QB_LOG_STDERR, "%t %7p %b");
|
||||
|
||||
qdevice_log_configure(instance);
|
||||
}
|
||||
|
||||
void
|
||||
qdevice_log_close(struct qdevice_instance *instance)
|
||||
{
|
||||
|
||||
qb_log_fini();
|
||||
}
|
65
qdevices/qdevice-log.h
Normal file
65
qdevices/qdevice-log.h
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _QDEVICE_LOG_H_
|
||||
#define _QDEVICE_LOG_H_
|
||||
|
||||
#include <qb/qbdefs.h>
|
||||
#include <qb/qblog.h>
|
||||
#include <prerror.h>
|
||||
|
||||
#include "qdevice-instance.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define qdevice_log qb_log
|
||||
#define qdevice_log_nss(priority, str) qdevice_log(priority, "%s (%d): %s", \
|
||||
str, PR_GetError(), PR_ErrorToString(PR_GetError(), PR_LANGUAGE_I_DEFAULT));
|
||||
|
||||
#define qdevice_log_err(priority, str) qdevice_log(priority, "%s (%d): %s", \
|
||||
str, errno, strerror(errno));
|
||||
|
||||
extern void qdevice_log_init(struct qdevice_instance *instance, int force_debug);
|
||||
|
||||
extern void qdevice_log_configure(struct qdevice_instance *instance);
|
||||
|
||||
extern void qdevice_log_close(struct qdevice_instance *instance);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _QDEVICE_LOG_H_ */
|
686
qdevices/qdevice-model-net.c
Normal file
686
qdevices/qdevice-model-net.c
Normal file
@ -0,0 +1,686 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2017 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <poll.h>
|
||||
|
||||
#include "qdevice-model.h"
|
||||
#include "qdevice-model-net.h"
|
||||
#include "qdevice-log.h"
|
||||
#include "qdevice-net-cast-vote-timer.h"
|
||||
#include "qdevice-net-instance.h"
|
||||
#include "qdevice-net-ipc-cmd.h"
|
||||
#include "qdevice-net-algorithm.h"
|
||||
#include "qdevice-net-heuristics.h"
|
||||
#include "qdevice-net-poll.h"
|
||||
#include "qdevice-net-send.h"
|
||||
#include "qdevice-net-votequorum.h"
|
||||
#include "qnet-config.h"
|
||||
#include "nss-sock.h"
|
||||
|
||||
int
|
||||
qdevice_model_net_init(struct qdevice_instance *instance)
|
||||
{
|
||||
|
||||
struct qdevice_net_instance *net_instance;
|
||||
|
||||
qdevice_log(LOG_DEBUG, "Initializing qdevice_net_instance");
|
||||
if (qdevice_net_instance_init_from_cmap(instance) != 0) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
net_instance = instance->model_data;
|
||||
|
||||
qdevice_log(LOG_DEBUG, "Registering algorithms");
|
||||
if (qdevice_net_algorithm_register_all() != 0) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
qdevice_log(LOG_DEBUG, "Initializing NSS");
|
||||
if (nss_sock_init_nss((net_instance->tls_supported != TLV_TLS_UNSUPPORTED ?
|
||||
instance->advanced_settings->net_nss_db_dir : NULL)) != 0) {
|
||||
qdevice_log_nss(LOG_ERR, "Can't init nss");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (qdevice_net_cast_vote_timer_update(net_instance, TLV_VOTE_ASK_LATER) != 0) {
|
||||
qdevice_log(LOG_ERR, "Can't update cast vote timer");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (qdevice_net_algorithm_init(net_instance) != 0) {
|
||||
qdevice_log(LOG_ERR, "Algorithm init failed");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (qdevice_net_heuristics_init(net_instance) != 0) {
|
||||
qdevice_log(LOG_ERR, "Can't initialize net heuristics");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
qdevice_model_net_destroy(struct qdevice_instance *instance)
|
||||
{
|
||||
struct qdevice_net_instance *net_instance;
|
||||
|
||||
net_instance = instance->model_data;
|
||||
|
||||
qdevice_log(LOG_DEBUG, "Destroying algorithm");
|
||||
qdevice_net_algorithm_destroy(net_instance);
|
||||
|
||||
qdevice_log(LOG_DEBUG, "Destroying qdevice_net_instance");
|
||||
qdevice_net_instance_destroy(net_instance);
|
||||
|
||||
qdevice_log(LOG_DEBUG, "Shutting down NSS");
|
||||
SSL_ClearSessionCache();
|
||||
|
||||
if (NSS_Shutdown() != SECSuccess) {
|
||||
qdevice_log_nss(LOG_WARNING, "Can't shutdown NSS");
|
||||
}
|
||||
|
||||
if (PR_Cleanup() != PR_SUCCESS) {
|
||||
qdevice_log_nss(LOG_WARNING, "Can't shutdown NSPR");
|
||||
}
|
||||
|
||||
free(net_instance);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
qdevice_model_net_timer_connect_timeout(void *data1, void *data2)
|
||||
{
|
||||
struct qdevice_net_instance *instance;
|
||||
|
||||
instance = (struct qdevice_net_instance *)data1;
|
||||
|
||||
qdevice_log(LOG_ERR, "Connect timeout");
|
||||
|
||||
instance->schedule_disconnect = 1;
|
||||
|
||||
instance->connect_timer = NULL;
|
||||
instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_CONNECT_TO_THE_SERVER;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static PRIntn
|
||||
qdevice_model_net_get_af(const struct qdevice_net_instance *instance)
|
||||
{
|
||||
PRIntn af;
|
||||
|
||||
af = PR_AF_UNSPEC;
|
||||
if (instance->force_ip_version == 4) {
|
||||
af = PR_AF_INET;
|
||||
}
|
||||
|
||||
if (instance->force_ip_version == 6) {
|
||||
af = PR_AF_INET6;
|
||||
}
|
||||
|
||||
return (af);
|
||||
}
|
||||
|
||||
int
|
||||
qdevice_model_net_run(struct qdevice_instance *instance)
|
||||
{
|
||||
struct qdevice_net_instance *net_instance;
|
||||
int try_connect;
|
||||
int res;
|
||||
enum tlv_vote vote;
|
||||
int delay_before_reconnect;
|
||||
|
||||
net_instance = instance->model_data;
|
||||
|
||||
qdevice_log(LOG_DEBUG, "Executing qdevice-net");
|
||||
|
||||
try_connect = 1;
|
||||
while (try_connect) {
|
||||
net_instance->state = QDEVICE_NET_INSTANCE_STATE_WAITING_CONNECT;
|
||||
net_instance->socket = NULL;
|
||||
|
||||
net_instance->connect_timer = timer_list_add(&net_instance->main_timer_list,
|
||||
net_instance->connect_timeout, qdevice_model_net_timer_connect_timeout,
|
||||
(void *)net_instance, NULL);
|
||||
|
||||
if (net_instance->connect_timer == NULL) {
|
||||
qdevice_log(LOG_CRIT, "Can't schedule connect timer");
|
||||
|
||||
try_connect = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
qdevice_log(LOG_DEBUG, "Trying connect to qnetd server %s:%u (timeout = %ums)",
|
||||
net_instance->host_addr, net_instance->host_port, net_instance->connect_timeout);
|
||||
|
||||
res = nss_sock_non_blocking_client_init(net_instance->host_addr,
|
||||
net_instance->host_port, qdevice_model_net_get_af(net_instance),
|
||||
&net_instance->non_blocking_client);
|
||||
if (res == -1) {
|
||||
qdevice_log_nss(LOG_ERR, "Can't initialize non blocking client connection");
|
||||
}
|
||||
|
||||
res = nss_sock_non_blocking_client_try_next(&net_instance->non_blocking_client);
|
||||
if (res == -1) {
|
||||
qdevice_log_nss(LOG_ERR, "Can't connect to qnetd host");
|
||||
nss_sock_non_blocking_client_destroy(&net_instance->non_blocking_client);
|
||||
}
|
||||
|
||||
while (qdevice_net_poll(net_instance) == 0) {
|
||||
};
|
||||
|
||||
if (net_instance->connect_timer != NULL) {
|
||||
timer_list_delete(&net_instance->main_timer_list, net_instance->connect_timer);
|
||||
net_instance->connect_timer = NULL;
|
||||
}
|
||||
|
||||
if (net_instance->echo_request_timer != NULL) {
|
||||
timer_list_delete(&net_instance->main_timer_list, net_instance->echo_request_timer);
|
||||
net_instance->echo_request_timer = NULL;
|
||||
}
|
||||
|
||||
try_connect = qdevice_net_disconnect_reason_try_reconnect(net_instance->disconnect_reason);
|
||||
|
||||
/*
|
||||
* Unpause cast vote timer, because if it is paused we cannot remove tracking
|
||||
*/
|
||||
qdevice_net_cast_vote_timer_set_paused(net_instance, 0);
|
||||
|
||||
vote = TLV_VOTE_NO_CHANGE;
|
||||
|
||||
if (qdevice_net_algorithm_disconnected(net_instance,
|
||||
net_instance->disconnect_reason, &try_connect, &vote) != 0) {
|
||||
qdevice_log(LOG_ERR, "Algorithm returned error, force exit");
|
||||
return (-1);
|
||||
} else {
|
||||
qdevice_log(LOG_DEBUG, "Algorithm result vote is %s",
|
||||
tlv_vote_to_str(vote));
|
||||
}
|
||||
|
||||
if (qdevice_net_cast_vote_timer_update(net_instance, vote) != 0) {
|
||||
qdevice_log(LOG_ERR, "qdevice_model_net_run fatal error. "
|
||||
" Can't update cast vote timer vote");
|
||||
}
|
||||
|
||||
if (qdevice_net_disconnect_reason_force_disconnect(net_instance->disconnect_reason)) {
|
||||
try_connect = 0;
|
||||
}
|
||||
|
||||
if (net_instance->socket != NULL) {
|
||||
if (PR_Close(net_instance->socket) != PR_SUCCESS) {
|
||||
qdevice_log_nss(LOG_WARNING, "Unable to close connection");
|
||||
}
|
||||
net_instance->socket = NULL;
|
||||
}
|
||||
|
||||
if (!net_instance->non_blocking_client.destroyed) {
|
||||
nss_sock_non_blocking_client_destroy(&net_instance->non_blocking_client);
|
||||
}
|
||||
|
||||
if (net_instance->non_blocking_client.socket != NULL) {
|
||||
if (PR_Close(net_instance->non_blocking_client.socket) != PR_SUCCESS) {
|
||||
qdevice_log_nss(LOG_WARNING, "Unable to close non-blocking client connection");
|
||||
}
|
||||
net_instance->non_blocking_client.socket = NULL;
|
||||
}
|
||||
|
||||
if (try_connect &&
|
||||
net_instance->state != QDEVICE_NET_INSTANCE_STATE_WAITING_CONNECT) {
|
||||
/*
|
||||
* Give qnetd server a little time before reconnect
|
||||
*/
|
||||
delay_before_reconnect = random() %
|
||||
(int)(net_instance->cast_vote_timer_interval * 0.9);
|
||||
|
||||
qdevice_log(LOG_DEBUG, "Sleeping for %u ms before reconnect",
|
||||
delay_before_reconnect);
|
||||
(void)poll(NULL, 0, delay_before_reconnect);
|
||||
}
|
||||
|
||||
qdevice_net_instance_clean(net_instance);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Called when cmap reload (or nodelist) was requested.
|
||||
*
|
||||
* nlist is node list
|
||||
* config_version is valid only if config_version_set != 0
|
||||
*
|
||||
* Should return 0 if processing should continue or -1 to call exit
|
||||
*/
|
||||
int
|
||||
qdevice_model_net_config_node_list_changed(struct qdevice_instance *instance,
|
||||
const struct node_list *nlist, int config_version_set, uint64_t config_version)
|
||||
{
|
||||
struct qdevice_net_instance *net_instance;
|
||||
int send_node_list;
|
||||
enum tlv_vote vote;
|
||||
|
||||
net_instance = instance->model_data;
|
||||
|
||||
if (net_instance->state != QDEVICE_NET_INSTANCE_STATE_WAITING_VOTEQUORUM_CMAP_EVENTS) {
|
||||
/*
|
||||
* Nodelist changed, but connection to qnetd not initiated yet.
|
||||
*/
|
||||
send_node_list = 0;
|
||||
|
||||
if (net_instance->cast_vote_timer_vote == TLV_VOTE_ACK) {
|
||||
vote = TLV_VOTE_NACK;
|
||||
} else {
|
||||
vote = TLV_VOTE_NO_CHANGE;
|
||||
}
|
||||
} else {
|
||||
send_node_list = 1;
|
||||
vote = TLV_VOTE_NO_CHANGE;
|
||||
}
|
||||
|
||||
if (qdevice_net_algorithm_config_node_list_changed(net_instance, nlist, config_version_set,
|
||||
config_version, &send_node_list, &vote) != 0) {
|
||||
qdevice_log(LOG_ERR, "Algorithm returned error, Disconnecting");
|
||||
|
||||
net_instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_ALGO_CONFIG_NODE_LIST_CHANGED_ERR;
|
||||
net_instance->schedule_disconnect = 1;
|
||||
|
||||
return (0);
|
||||
} else {
|
||||
qdevice_log(LOG_DEBUG, "Algorithm decided to %s node list and result vote is %s",
|
||||
(send_node_list ? "send" : "not send"), tlv_vote_to_str(vote));
|
||||
}
|
||||
|
||||
if (qdevice_net_cast_vote_timer_update(net_instance, vote) != 0) {
|
||||
qdevice_log(LOG_CRIT, "qdevice_model_net_config_node_list_changed fatal error. "
|
||||
" Can't update cast vote timer vote");
|
||||
net_instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_SCHEDULE_VOTING_TIMER;
|
||||
net_instance->schedule_disconnect = 1;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (send_node_list) {
|
||||
if (qdevice_net_send_config_node_list(net_instance, nlist, config_version_set,
|
||||
config_version, 0) != 0) {
|
||||
net_instance->schedule_disconnect = 1;
|
||||
net_instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_ALLOCATE_MSG_BUFFER;
|
||||
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Called when cmap reload (or nodelist) was requested, but it was not possible to
|
||||
* get node list.
|
||||
*
|
||||
* Should return 0 if processing should continue or -1 to call exit
|
||||
*/
|
||||
int
|
||||
qdevice_model_net_get_config_node_list_failed(struct qdevice_instance *instance)
|
||||
{
|
||||
struct qdevice_net_instance *net_instance;
|
||||
|
||||
net_instance = instance->model_data;
|
||||
|
||||
net_instance->schedule_disconnect = 1;
|
||||
net_instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_ALLOCATE_MSG_BUFFER;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
qdevice_model_net_votequorum_quorum_notify(struct qdevice_instance *instance,
|
||||
uint32_t quorate, uint32_t node_list_entries, votequorum_node_t node_list[])
|
||||
{
|
||||
struct qdevice_net_instance *net_instance;
|
||||
int send_node_list;
|
||||
enum tlv_vote vote;
|
||||
|
||||
net_instance = instance->model_data;
|
||||
|
||||
if (net_instance->state != QDEVICE_NET_INSTANCE_STATE_WAITING_VOTEQUORUM_CMAP_EVENTS) {
|
||||
/*
|
||||
* Nodelist changed, but connection to qnetd not initiated yet.
|
||||
*/
|
||||
send_node_list = 0;
|
||||
|
||||
if (net_instance->cast_vote_timer_vote == TLV_VOTE_ACK) {
|
||||
vote = TLV_VOTE_NACK;
|
||||
} else {
|
||||
vote = TLV_VOTE_NO_CHANGE;
|
||||
}
|
||||
} else {
|
||||
send_node_list = 1;
|
||||
vote = TLV_VOTE_NO_CHANGE;
|
||||
}
|
||||
|
||||
if (qdevice_net_algorithm_votequorum_quorum_notify(net_instance, quorate,
|
||||
node_list_entries, node_list, &send_node_list, &vote) != 0) {
|
||||
qdevice_log(LOG_ERR, "Algorithm returned error. Disconnecting.");
|
||||
|
||||
net_instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_ALGO_VOTEQUORUM_QUORUM_NOTIFY_ERR;
|
||||
net_instance->schedule_disconnect = 1;
|
||||
|
||||
return (0);
|
||||
} else {
|
||||
qdevice_log(LOG_DEBUG, "Algorithm decided to %s list and result vote is %s",
|
||||
(send_node_list ? "send" : "not send"), tlv_vote_to_str(vote));
|
||||
}
|
||||
|
||||
if (qdevice_net_cast_vote_timer_update(net_instance, vote) != 0) {
|
||||
qdevice_log(LOG_CRIT, "qdevice_model_net_votequorum_quorum_notify fatal error. "
|
||||
" Can't update cast vote timer vote");
|
||||
net_instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_SCHEDULE_VOTING_TIMER;
|
||||
net_instance->schedule_disconnect = 1;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (send_node_list) {
|
||||
if (qdevice_net_send_quorum_node_list(net_instance,
|
||||
(quorate ? TLV_QUORATE_QUORATE : TLV_QUORATE_INQUORATE),
|
||||
node_list_entries, node_list) != 0) {
|
||||
/*
|
||||
* Fatal error -> schedule disconnect
|
||||
*/
|
||||
net_instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_ALLOCATE_MSG_BUFFER;
|
||||
net_instance->schedule_disconnect = 1;
|
||||
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
qdevice_model_net_votequorum_node_list_heuristics_notify(struct qdevice_instance *instance,
|
||||
votequorum_ring_id_t votequorum_ring_id, uint32_t node_list_entries, uint32_t node_list[],
|
||||
enum qdevice_heuristics_exec_result heuristics_exec_result)
|
||||
{
|
||||
struct qdevice_net_instance *net_instance;
|
||||
struct tlv_ring_id tlv_rid;
|
||||
enum tlv_vote vote;
|
||||
enum tlv_heuristics heuristics;
|
||||
int send_node_list;
|
||||
|
||||
net_instance = instance->model_data;
|
||||
|
||||
qdevice_net_votequorum_ring_id_to_tlv(&tlv_rid, &votequorum_ring_id);
|
||||
heuristics = qdevice_net_heuristics_exec_result_to_tlv(heuristics_exec_result);
|
||||
|
||||
if (net_instance->state != QDEVICE_NET_INSTANCE_STATE_WAITING_VOTEQUORUM_CMAP_EVENTS) {
|
||||
/*
|
||||
* Nodelist changed, but connection to qnetd not initiated yet.
|
||||
*/
|
||||
send_node_list = 0;
|
||||
|
||||
if (net_instance->cast_vote_timer_vote == TLV_VOTE_ACK) {
|
||||
vote = TLV_VOTE_NACK;
|
||||
} else {
|
||||
vote = TLV_VOTE_NO_CHANGE;
|
||||
}
|
||||
} else {
|
||||
send_node_list = 1;
|
||||
vote = TLV_VOTE_WAIT_FOR_REPLY;
|
||||
}
|
||||
|
||||
if (qdevice_net_algorithm_votequorum_node_list_heuristics_notify(net_instance, &tlv_rid,
|
||||
node_list_entries, node_list, &send_node_list, &vote, &heuristics) != 0) {
|
||||
qdevice_log(LOG_ERR, "Algorithm returned error. Disconnecting.");
|
||||
|
||||
net_instance->disconnect_reason =
|
||||
QDEVICE_NET_DISCONNECT_REASON_ALGO_VOTEQUORUM_NODE_LIST_HEURISTICS_NOTIFY_ERR;
|
||||
net_instance->schedule_disconnect = 1;
|
||||
|
||||
return (0);
|
||||
} else {
|
||||
qdevice_log(LOG_DEBUG, "Algorithm decided to %s list, result vote is %s and heuristics is %s",
|
||||
(send_node_list ? "send" : "not send"), tlv_vote_to_str(vote),
|
||||
tlv_heuristics_to_str(heuristics));
|
||||
}
|
||||
|
||||
if (send_node_list) {
|
||||
if (qdevice_net_send_membership_node_list(net_instance, &tlv_rid,
|
||||
node_list_entries, node_list, heuristics) != 0) {
|
||||
/*
|
||||
* Fatal error -> schedule disconnect
|
||||
*/
|
||||
net_instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_ALLOCATE_MSG_BUFFER;
|
||||
net_instance->schedule_disconnect = 1;
|
||||
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Unpause cast vote timer
|
||||
*/
|
||||
qdevice_net_cast_vote_timer_set_paused(net_instance, 0);
|
||||
|
||||
if (qdevice_net_cast_vote_timer_update(net_instance, vote) != 0) {
|
||||
qdevice_log(LOG_CRIT, "qdevice_model_net_votequorum_node_list_notify fatal error "
|
||||
"Can't update cast vote timer");
|
||||
net_instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_SCHEDULE_VOTING_TIMER;
|
||||
net_instance->schedule_disconnect = 1;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
net_instance->latest_vq_heuristics_result = heuristics;
|
||||
net_instance->latest_heuristics_result = heuristics;
|
||||
|
||||
if (qdevice_net_heuristics_schedule_timer(net_instance) != 0) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
qdevice_model_net_votequorum_node_list_notify(struct qdevice_instance *instance,
|
||||
votequorum_ring_id_t votequorum_ring_id, uint32_t node_list_entries, uint32_t node_list[])
|
||||
{
|
||||
struct qdevice_net_instance *net_instance;
|
||||
struct tlv_ring_id tlv_rid;
|
||||
enum tlv_vote vote;
|
||||
int pause_cast_vote_timer;
|
||||
|
||||
net_instance = instance->model_data;
|
||||
|
||||
/*
|
||||
* Stop regular heuristics till qdevice_model_net_votequorum_node_list_heuristics_notify
|
||||
* is called
|
||||
*/
|
||||
if (qdevice_net_heuristics_stop_timer(net_instance) != 0) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
pause_cast_vote_timer = 1;
|
||||
vote = TLV_VOTE_NO_CHANGE;
|
||||
|
||||
if (net_instance->state != QDEVICE_NET_INSTANCE_STATE_WAITING_VOTEQUORUM_CMAP_EVENTS &&
|
||||
net_instance->cast_vote_timer_vote == TLV_VOTE_ACK) {
|
||||
/*
|
||||
* Nodelist changed and vote timer still votes ACK. It's needed to start voting
|
||||
* NACK.
|
||||
*/
|
||||
if (net_instance->cast_vote_timer_vote == TLV_VOTE_ACK) {
|
||||
vote = TLV_VOTE_NACK;
|
||||
}
|
||||
}
|
||||
|
||||
qdevice_net_votequorum_ring_id_to_tlv(&tlv_rid, &votequorum_ring_id);
|
||||
|
||||
if (qdevice_net_algorithm_votequorum_node_list_notify(net_instance, &tlv_rid,
|
||||
node_list_entries, node_list, &pause_cast_vote_timer, &vote) != 0) {
|
||||
qdevice_log(LOG_ERR, "Algorithm returned error. Disconnecting.");
|
||||
|
||||
net_instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_ALGO_VOTEQUORUM_NODE_LIST_NOTIFY_ERR;
|
||||
net_instance->schedule_disconnect = 1;
|
||||
|
||||
return (0);
|
||||
} else {
|
||||
qdevice_log(LOG_DEBUG, "Algorithm decided to %s cast vote timer and result vote is %s ",
|
||||
(pause_cast_vote_timer ? "pause" : "not pause"), tlv_vote_to_str(vote));
|
||||
}
|
||||
|
||||
if (qdevice_net_cast_vote_timer_update(net_instance, vote) != 0) {
|
||||
qdevice_log(LOG_CRIT, "qdevice_model_net_votequorum_node_list_notify fatal error "
|
||||
"Can't update cast vote timer");
|
||||
net_instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_SCHEDULE_VOTING_TIMER;
|
||||
net_instance->schedule_disconnect = 1;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
qdevice_net_cast_vote_timer_set_paused(net_instance, pause_cast_vote_timer);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
qdevice_model_net_votequorum_expected_votes_notify(struct qdevice_instance *instance,
|
||||
uint32_t expected_votes)
|
||||
{
|
||||
struct qdevice_net_instance *net_instance;
|
||||
enum tlv_vote vote;
|
||||
|
||||
net_instance = instance->model_data;
|
||||
|
||||
qdevice_log(LOG_DEBUG, "qdevice_model_net_votequorum_expected_votes_notify"
|
||||
" (expected votes old=%"PRIu32" / new=%"PRIu32")",
|
||||
net_instance->qdevice_instance_ptr->vq_expected_votes, expected_votes);
|
||||
|
||||
vote = TLV_VOTE_NO_CHANGE;
|
||||
|
||||
if (qdevice_net_algorithm_votequorum_expected_votes_notify(net_instance, expected_votes,
|
||||
&vote) != 0) {
|
||||
qdevice_log(LOG_DEBUG, "Algorithm returned error. Disconnecting.");
|
||||
|
||||
net_instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_ALGO_VOTEQUORUM_EXPECTED_VOTES_NOTIFY_ERR;
|
||||
net_instance->schedule_disconnect = 1;
|
||||
|
||||
return (0);
|
||||
} else {
|
||||
qdevice_log(LOG_DEBUG, "Algorithm result vote is %s", tlv_vote_to_str(vote));
|
||||
}
|
||||
|
||||
if (qdevice_net_cast_vote_timer_update(net_instance, vote) != 0) {
|
||||
qdevice_log(LOG_CRIT, "qdevice_model_net_votequorum_expected_votes_notify fatal error. "
|
||||
" Can't update cast vote timer vote");
|
||||
net_instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_SCHEDULE_VOTING_TIMER;
|
||||
net_instance->schedule_disconnect = 1;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
qdevice_model_net_cmap_changed(struct qdevice_instance *instance,
|
||||
const struct qdevice_cmap_change_events *events)
|
||||
{
|
||||
struct qdevice_net_instance *net_instance;
|
||||
enum qdevice_heuristics_mode active_heuristics_mode;
|
||||
int heuristics_enabled;
|
||||
|
||||
net_instance = instance->model_data;
|
||||
|
||||
if (events->heuristics) {
|
||||
active_heuristics_mode = instance->heuristics_instance.mode;
|
||||
heuristics_enabled = (active_heuristics_mode == QDEVICE_HEURISTICS_MODE_ENABLED ||
|
||||
active_heuristics_mode == QDEVICE_HEURISTICS_MODE_SYNC);
|
||||
|
||||
if (net_instance->state == QDEVICE_NET_INSTANCE_STATE_WAITING_VOTEQUORUM_CMAP_EVENTS &&
|
||||
!net_instance->server_supports_heuristics && heuristics_enabled) {
|
||||
qdevice_log(LOG_ERR, "Heuristics are enabled but not supported by the server");
|
||||
|
||||
net_instance->disconnect_reason =
|
||||
QDEVICE_NET_DISCONNECT_REASON_SERVER_DOESNT_SUPPORT_REQUIRED_OPT;
|
||||
|
||||
net_instance->schedule_disconnect = 1;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (qdevice_net_heuristics_schedule_timer(net_instance) != 0) {
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
qdevice_model_net_ipc_cmd_status(struct qdevice_instance *instance,
|
||||
struct dynar *outbuf, int verbose)
|
||||
{
|
||||
struct qdevice_net_instance *net_instance;
|
||||
|
||||
net_instance = instance->model_data;
|
||||
|
||||
if (!qdevice_net_ipc_cmd_status(net_instance, outbuf, verbose)) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static struct qdevice_model qdevice_model_net = {
|
||||
.name = "net",
|
||||
.init = qdevice_model_net_init,
|
||||
.destroy = qdevice_model_net_destroy,
|
||||
.run = qdevice_model_net_run,
|
||||
.get_config_node_list_failed = qdevice_model_net_get_config_node_list_failed,
|
||||
.config_node_list_changed = qdevice_model_net_config_node_list_changed,
|
||||
.votequorum_quorum_notify = qdevice_model_net_votequorum_quorum_notify,
|
||||
.votequorum_node_list_notify = qdevice_model_net_votequorum_node_list_notify,
|
||||
.votequorum_node_list_heuristics_notify = qdevice_model_net_votequorum_node_list_heuristics_notify,
|
||||
.votequorum_expected_votes_notify = qdevice_model_net_votequorum_expected_votes_notify,
|
||||
.cmap_changed = qdevice_model_net_cmap_changed,
|
||||
.ipc_cmd_status = qdevice_model_net_ipc_cmd_status,
|
||||
};
|
||||
|
||||
int
|
||||
qdevice_model_net_register(void)
|
||||
{
|
||||
return (qdevice_model_register(QDEVICE_MODEL_TYPE_NET, &qdevice_model_net));
|
||||
}
|
82
qdevices/qdevice-model-net.h
Normal file
82
qdevices/qdevice-model-net.h
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2017 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _QDEVICE_MODEL_NET_H_
|
||||
#define _QDEVICE_MODEL_NET_H_
|
||||
|
||||
#include "qdevice-instance.h"
|
||||
#include "qdevice-model.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern int qdevice_model_net_init(struct qdevice_instance *instance);
|
||||
|
||||
extern int qdevice_model_net_destroy(struct qdevice_instance *instance);
|
||||
|
||||
extern int qdevice_model_net_run(struct qdevice_instance *instance);
|
||||
|
||||
extern int qdevice_model_net_get_config_node_list_failed(struct qdevice_instance *instance);
|
||||
|
||||
extern int qdevice_model_net_config_node_list_changed(struct qdevice_instance *instance,
|
||||
const struct node_list *nlist, int config_version_set, uint64_t config_version);
|
||||
|
||||
extern int qdevice_model_net_votequorum_quorum_notify(struct qdevice_instance *instance,
|
||||
uint32_t quorate, uint32_t node_list_entries, votequorum_node_t node_list[]);
|
||||
|
||||
extern int qdevice_model_net_votequorum_node_list_notify(struct qdevice_instance *instance,
|
||||
votequorum_ring_id_t votequorum_ring_id, uint32_t node_list_entries, uint32_t node_list[]);
|
||||
|
||||
extern int qdevice_model_net_votequorum_node_list_heuristics_notify(
|
||||
struct qdevice_instance *instance,
|
||||
votequorum_ring_id_t votequorum_ring_id, uint32_t node_list_entries, uint32_t node_list[],
|
||||
enum qdevice_heuristics_exec_result heuristics_exec_result);
|
||||
|
||||
extern int qdevice_model_net_votequorum_expected_votes_notify(struct qdevice_instance *instance,
|
||||
uint32_t expected_votes);
|
||||
|
||||
extern int qdevice_model_net_cmap_changed(struct qdevice_instance *instance,
|
||||
const struct qdevice_cmap_change_events *events);
|
||||
|
||||
extern int qdevice_model_net_ipc_cmd_status(struct qdevice_instance *instance,
|
||||
struct dynar *outbuf, int verbose);
|
||||
|
||||
extern int qdevice_model_net_register(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _QDEVICE_MODEL_NET_H_ */
|
51
qdevices/qdevice-model-type.h
Normal file
51
qdevices/qdevice-model-type.h
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _QDEVICE_MODEL_TYPE_H_
|
||||
#define _QDEVICE_MODEL_TYPE_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum qdevice_model_type {
|
||||
QDEVICE_MODEL_TYPE_NET = 0,
|
||||
QDEVICE_MODEL_TYPE_ARRAY_SIZE,
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _QDEVICE_MODEL_TYPE_H_ */
|
257
qdevices/qdevice-model.c
Normal file
257
qdevices/qdevice-model.c
Normal file
@ -0,0 +1,257 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "qdevice-log.h"
|
||||
#include "qdevice-model.h"
|
||||
#include "qdevice-model-net.h"
|
||||
|
||||
static struct qdevice_model *qdevice_model_array[QDEVICE_MODEL_TYPE_ARRAY_SIZE];
|
||||
|
||||
int
|
||||
qdevice_model_init(struct qdevice_instance *instance)
|
||||
{
|
||||
|
||||
if (instance->model_type >= QDEVICE_MODEL_TYPE_ARRAY_SIZE ||
|
||||
qdevice_model_array[instance->model_type] == NULL) {
|
||||
qdevice_log(LOG_CRIT, "qdevice_model_init unhandled model");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return (qdevice_model_array[instance->model_type]->init(instance));
|
||||
}
|
||||
|
||||
int
|
||||
qdevice_model_destroy(struct qdevice_instance *instance)
|
||||
{
|
||||
|
||||
if (instance->model_type >= QDEVICE_MODEL_TYPE_ARRAY_SIZE ||
|
||||
qdevice_model_array[instance->model_type] == NULL) {
|
||||
qdevice_log(LOG_CRIT, "qdevice_model_destroy unhandled model");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return (qdevice_model_array[instance->model_type]->destroy(instance));
|
||||
}
|
||||
|
||||
int
|
||||
qdevice_model_run(struct qdevice_instance *instance)
|
||||
{
|
||||
|
||||
if (instance->model_type >= QDEVICE_MODEL_TYPE_ARRAY_SIZE ||
|
||||
qdevice_model_array[instance->model_type] == NULL) {
|
||||
qdevice_log(LOG_CRIT, "qdevice_model_run unhandled model");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return (qdevice_model_array[instance->model_type]->run(instance));
|
||||
}
|
||||
|
||||
int
|
||||
qdevice_model_get_config_node_list_failed(struct qdevice_instance *instance)
|
||||
{
|
||||
|
||||
if (instance->model_type >= QDEVICE_MODEL_TYPE_ARRAY_SIZE ||
|
||||
qdevice_model_array[instance->model_type] == NULL) {
|
||||
qdevice_log(LOG_CRIT, "qdevice_model_run unhandled model");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return (qdevice_model_array[instance->model_type]->get_config_node_list_failed(instance));
|
||||
}
|
||||
|
||||
int
|
||||
qdevice_model_config_node_list_changed(struct qdevice_instance *instance,
|
||||
const struct node_list *nlist, int config_version_set, uint64_t config_version)
|
||||
{
|
||||
|
||||
if (instance->model_type >= QDEVICE_MODEL_TYPE_ARRAY_SIZE ||
|
||||
qdevice_model_array[instance->model_type] == NULL) {
|
||||
qdevice_log(LOG_CRIT, "qdevice_model_run unhandled model");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return (qdevice_model_array[instance->model_type]->
|
||||
config_node_list_changed(instance, nlist, config_version_set, config_version));
|
||||
}
|
||||
|
||||
int
|
||||
qdevice_model_votequorum_quorum_notify(struct qdevice_instance *instance,
|
||||
uint32_t quorate, uint32_t node_list_entries, votequorum_node_t node_list[])
|
||||
{
|
||||
|
||||
if (instance->model_type >= QDEVICE_MODEL_TYPE_ARRAY_SIZE ||
|
||||
qdevice_model_array[instance->model_type] == NULL) {
|
||||
qdevice_log(LOG_CRIT, "qdevice_model_votequorum_quorum_notify unhandled model");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return (qdevice_model_array[instance->model_type]->
|
||||
votequorum_quorum_notify(instance, quorate, node_list_entries, node_list));
|
||||
}
|
||||
|
||||
int
|
||||
qdevice_model_votequorum_node_list_notify(struct qdevice_instance *instance,
|
||||
votequorum_ring_id_t votequorum_ring_id, uint32_t node_list_entries, uint32_t node_list[])
|
||||
{
|
||||
|
||||
if (instance->model_type >= QDEVICE_MODEL_TYPE_ARRAY_SIZE ||
|
||||
qdevice_model_array[instance->model_type] == NULL) {
|
||||
qdevice_log(LOG_CRIT, "qdevice_model_votequorum_node_list_notify unhandled model");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return (qdevice_model_array[instance->model_type]->
|
||||
votequorum_node_list_notify(instance, votequorum_ring_id, node_list_entries, node_list));
|
||||
}
|
||||
|
||||
int
|
||||
qdevice_model_votequorum_node_list_heuristics_notify(struct qdevice_instance *instance,
|
||||
votequorum_ring_id_t votequorum_ring_id, uint32_t node_list_entries, uint32_t node_list[],
|
||||
enum qdevice_heuristics_exec_result heuristics_exec_result)
|
||||
{
|
||||
|
||||
if (instance->model_type >= QDEVICE_MODEL_TYPE_ARRAY_SIZE ||
|
||||
qdevice_model_array[instance->model_type] == NULL) {
|
||||
qdevice_log(LOG_CRIT, "qdevice_model_votequorum_node_list_heuristics_notify unhandled model");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return (qdevice_model_array[instance->model_type]->
|
||||
votequorum_node_list_heuristics_notify(instance, votequorum_ring_id, node_list_entries,
|
||||
node_list, heuristics_exec_result));
|
||||
}
|
||||
|
||||
int
|
||||
qdevice_model_votequorum_expected_votes_notify(struct qdevice_instance *instance,
|
||||
uint32_t expected_votes)
|
||||
{
|
||||
|
||||
if (instance->model_type >= QDEVICE_MODEL_TYPE_ARRAY_SIZE ||
|
||||
qdevice_model_array[instance->model_type] == NULL) {
|
||||
qdevice_log(LOG_CRIT, "qdevice_model_votequorum_expected_votes_notify unhandled model");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return (qdevice_model_array[instance->model_type]->
|
||||
votequorum_expected_votes_notify(instance, expected_votes));
|
||||
}
|
||||
|
||||
int
|
||||
qdevice_model_ipc_cmd_status(struct qdevice_instance *instance, struct dynar *outbuf, int verbose)
|
||||
{
|
||||
|
||||
if (instance->model_type >= QDEVICE_MODEL_TYPE_ARRAY_SIZE ||
|
||||
qdevice_model_array[instance->model_type] == NULL) {
|
||||
qdevice_log(LOG_CRIT, "qdevice_model_ipc_cmd_status unhandled model");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return (qdevice_model_array[instance->model_type]->
|
||||
ipc_cmd_status(instance, outbuf, verbose));
|
||||
}
|
||||
|
||||
int
|
||||
qdevice_model_cmap_changed(struct qdevice_instance *instance,
|
||||
const struct qdevice_cmap_change_events *events)
|
||||
{
|
||||
|
||||
if (instance->model_type >= QDEVICE_MODEL_TYPE_ARRAY_SIZE ||
|
||||
qdevice_model_array[instance->model_type] == NULL) {
|
||||
qdevice_log(LOG_CRIT, "qdevice_model_cmap_chaged unhandled model");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return (qdevice_model_array[instance->model_type]->
|
||||
cmap_changed(instance, events));
|
||||
}
|
||||
|
||||
int
|
||||
qdevice_model_register(enum qdevice_model_type model_type,
|
||||
struct qdevice_model *model)
|
||||
{
|
||||
|
||||
if (model_type >= QDEVICE_MODEL_TYPE_ARRAY_SIZE) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (qdevice_model_array[model_type] != NULL) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
qdevice_model_array[model_type] = model;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
qdevice_model_register_all(void)
|
||||
{
|
||||
|
||||
if (qdevice_model_net_register() != 0) {
|
||||
qdevice_log(LOG_CRIT, "Failed to register model 'net' ");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
qdevice_model_str_to_type(const char *str, enum qdevice_model_type *model_type)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < QDEVICE_MODEL_TYPE_ARRAY_SIZE; i++) {
|
||||
if (qdevice_model_array[i] != NULL &&
|
||||
strcmp(qdevice_model_array[i]->name, str) == 0) {
|
||||
*model_type = i;
|
||||
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
const char *
|
||||
qdevice_model_type_to_str(enum qdevice_model_type model_type)
|
||||
{
|
||||
|
||||
switch (model_type) {
|
||||
case QDEVICE_MODEL_TYPE_NET: return ("Net"); break;
|
||||
case QDEVICE_MODEL_TYPE_ARRAY_SIZE: return ("Unknown model"); break;
|
||||
/*
|
||||
* Default is not defined intentionally. Compiler shows warning when new model is added
|
||||
*/
|
||||
}
|
||||
|
||||
return ("Unknown model");
|
||||
}
|
114
qdevices/qdevice-model.h
Normal file
114
qdevices/qdevice-model.h
Normal file
@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2017 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Jan Friesse (jfriesse@redhat.com)
|
||||
*
|
||||
* This software licensed under BSD license, the text of which follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Red Hat, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _QDEVICE_MODEL_H_
|
||||
#define _QDEVICE_MODEL_H_
|
||||
|
||||
#include "qdevice-cmap.h"
|
||||
#include "qdevice-instance.h"
|
||||
#include "qdevice-model-type.h"
|
||||
#include "qdevice-heuristics-exec-result.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern int qdevice_model_init(struct qdevice_instance *instance);
|
||||
|
||||
extern int qdevice_model_destroy(struct qdevice_instance *instance);
|
||||
|
||||
extern int qdevice_model_run(struct qdevice_instance *instance);
|
||||
|
||||
extern int qdevice_model_get_config_node_list_failed(struct qdevice_instance *instance);
|
||||
|
||||
extern int qdevice_model_config_node_list_changed(struct qdevice_instance *instance,
|
||||
const struct node_list *nlist, int config_version_set, uint64_t config_version);
|
||||
|
||||
extern int qdevice_model_votequorum_quorum_notify(struct qdevice_instance *instance,
|
||||
uint32_t quorate, uint32_t node_list_entries, votequorum_node_t node_list[]);
|
||||
|
||||
extern int qdevice_model_votequorum_node_list_notify(struct qdevice_instance *instance,
|
||||
votequorum_ring_id_t votequorum_ring_id, uint32_t node_list_entries, uint32_t node_list[]);
|
||||
|
||||
extern int qdevice_model_votequorum_node_list_heuristics_notify(struct qdevice_instance *instance,
|
||||
votequorum_ring_id_t votequorum_ring_id, uint32_t node_list_entries, uint32_t node_list[],
|
||||
enum qdevice_heuristics_exec_result heuristics_exec_result);
|
||||
|
||||
extern int qdevice_model_votequorum_expected_votes_notify(struct qdevice_instance *instance,
|
||||
uint32_t expected_votes);
|
||||
|
||||
extern int qdevice_model_ipc_cmd_status(struct qdevice_instance *instance,
|
||||
struct dynar *outbuf, int verbose);
|
||||
|
||||
extern int qdevice_model_cmap_changed(struct qdevice_instance *instance,
|
||||
const struct qdevice_cmap_change_events *events);
|
||||
|
||||
struct qdevice_model {
|
||||
const char *name;
|
||||
int (*init)(struct qdevice_instance *instance);
|
||||
int (*destroy)(struct qdevice_instance *instance);
|
||||
int (*run)(struct qdevice_instance *instance);
|
||||
int (*get_config_node_list_failed)(struct qdevice_instance *instance);
|
||||
int (*config_node_list_changed)(struct qdevice_instance *instance,
|
||||
const struct node_list *nlist, int config_version_set, uint64_t config_version);
|
||||
int (*votequorum_quorum_notify)(struct qdevice_instance *instance,
|
||||
uint32_t quorate, uint32_t node_list_entries, votequorum_node_t node_list[]);
|
||||
int (*votequorum_node_list_notify)(struct qdevice_instance *instance,
|
||||
votequorum_ring_id_t votequorum_ring_id,uint32_t node_list_entries,
|
||||
uint32_t node_list[]);
|
||||
int (*votequorum_node_list_heuristics_notify)(struct qdevice_instance *instance,
|
||||
votequorum_ring_id_t votequorum_ring_id,uint32_t node_list_entries,
|
||||
uint32_t node_list[], enum qdevice_heuristics_exec_result heuristics_exec_result);
|
||||
int (*votequorum_expected_votes_notify)(struct qdevice_instance *instance,
|
||||
uint32_t expected_votes);
|
||||
int (*ipc_cmd_status)(struct qdevice_instance *instance, struct dynar *outbuf, int verbose);
|
||||
int (*cmap_changed)(struct qdevice_instance *instance,
|
||||
const struct qdevice_cmap_change_events *events);
|
||||
};
|
||||
|
||||
extern int qdevice_model_register(
|
||||
enum qdevice_model_type model_type, struct qdevice_model *model);
|
||||
|
||||
extern void qdevice_model_register_all(void);
|
||||
|
||||
extern int qdevice_model_str_to_type(const char *str,
|
||||
enum qdevice_model_type *model_type);
|
||||
|
||||
extern const char *qdevice_model_type_to_str(enum qdevice_model_type model_type);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _QDEVICE_MODEL_H_ */
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user