author | Sebastian Harl <sh@tokkee.org> | |
Fri, 11 Apr 2014 06:44:10 +0000 (08:44 +0200) | ||
committer | Sebastian Harl <sh@tokkee.org> | |
Fri, 11 Apr 2014 06:44:10 +0000 (08:44 +0200) |
26 files changed:
diff --git a/.gitignore b/.gitignore
index f097f95edab772a39db674201301578f8e708b9a..9f1fd8ff4e3ca14646e8733b29d48b78738fa7d2 100644 (file)
--- a/.gitignore
+++ b/.gitignore
ltmain.sh
# build output
+doc/*.1
+doc/*.5
src/frontend/grammar.c
src/frontend/grammar.h
src/frontend/scanner.c
*.la
*.lo
*.o
-sysdbd.1
-sysdbd.conf.5
sysdb.h
# unit testing output
diff --git a/.travis.yml b/.travis.yml
index f3d8c0e693768fb170ea2aba8fb62a6d2165f739..87badb67b5e6da759f1a72b8eb031f8740e321f5 100644 (file)
--- a/.travis.yml
+++ b/.travis.yml
install:
- sudo apt-get install -qq check flex bison libtool libltdl-dev
- sudo apt-get install -qq libdbi-dev libedit-dev libreadline-dev
- - sudo pip install cpp-coveralls --use-mirrors
+ - sudo pip install cpp-coveralls
+ - pip show cpp-coveralls
script: ./t/cibuild.sh
after_success:
- - coveralls --exclude t --verbose
+ - test "${CC}x" != "gccx" || coveralls --build-root src --exclude t
branches:
only:
- master
index 1db223979cb6daa1db6f3d450f90954b412d9481..e9578012ce00157679918eaa77b718f6a500b6c7 100644 (file)
--- a/README
+++ b/README
library. It used used to mock I/O related functions. In case this function
is not available, the respective tests will be disabled automatically.
+ For the latest build status, see:
+ <https://travis-ci.org/tokkee/sysdb>
+
Code coverage testing using Gcov may be enabled when using the
‘--enable-gcov’ configure option.
+ For the latest coverage report, see:
+ <https://coveralls.io/r/tokkee/sysdb>
+
Configuring / Compiling / Installing
------------------------------------
diff --git a/doc/Makefile.am b/doc/Makefile.am
index a89ea25268609bb04aeca53c8e8e7f20603b5519..76d488fb455960035131a9539c70063c40d12a17 100644 (file)
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
SUFFIXES = .1 .5 .1.txt .5.txt
EXTRA_DIST = \
+ sysdb.1.txt \
sysdbd.1.txt \
sysdbd.conf.5.txt
CLEANFILES = \
+ sysdb.1 \
sysdbd.1 \
sysdbd.conf.5
man_MANS = \
+ sysdb.1 \
sysdbd.1 \
sysdbd.conf.5
+ADOC_ATTRS = -apackage_version=$(PACKAGE_VERSION) \
+ -abuild_date="$$( date --utc '+%F' )" \
+ -alocalstatedir=$(localstatedir)
+
+sysdb.1: sysdb.1.txt ../version
+
sysdbd.1: sysdbd.1.txt ../version
sysdbd.conf.5: sysdbd.conf.5.txt ../version
.1.txt.1:
- @A2X@ -d manpage -f manpage \
- -apackage_version=$(PACKAGE_VERSION) \
- -abuild_date="$$( date --utc '+%F' )" \
- $<
+ @A2X@ -d manpage -f manpage $(ADOC_ATTRS) $<
.5.txt.5:
- @A2X@ -d manpage -f manpage \
- -apackage_version=$(PACKAGE_VERSION) \
- -abuild_date="$$( date --utc '+%F' )" \
- $<
+ @A2X@ -d manpage -f manpage $(ADOC_ATTRS) $<
diff --git a/doc/sysdb.1.txt b/doc/sysdb.1.txt
--- /dev/null
+++ b/doc/sysdb.1.txt
@@ -0,0 +1,76 @@
+sysdb(1)
+========
+Sebastian "tokkee" Harl <sh@tokkee.org>
+version {package_version}, {build_date}
+:doctype: manpage
+
+NAME
+----
+sysdb - interactive client for the system management and inventory collection
+service
+
+SYNOPSIS
+--------
+*sysdb* ['options']
+
+DESCRIPTION
+-----------
+*sysdb* is a terminal-based, interactive client program for SysDB, a
+multi-backend system management and inventory collection daemon. It connects
+to a running daemon and then accepts commands from the user, send them to the
+server, and display the result.
+
+OPTIONS
+-------
+*sysdb* accepts the following command-line options.
+
+*-H* '<host>'::
+ The SysDB host to connect to. May be specified as the path to a UNIX
+ socket opened by the daemon. Defaults to {localstatedir}/run/sysdbd.sock.
+
+*-U* '<username>'::
+ The username used to authenticate against the server. Defaults to the
+ current user.
+
+*-c* '<command>'::
+ Send the specified command to the server after authenticating. This option
+ may be used multiple times. Each command will be send to the server
+ separately. Exit the process after handling the reply from the last
+ command.
+
+*-h*::
+ Display a usage and help summary and exit.
+
+*-V*::
+ Display the version number and copyright information.
+
+EXIT CODES
+----------
+*0*::
+ Success.
+
+*1*::
+ Failure (syntax or usage error).
+
+BUGS
+----
+None known.
+
+SEE ALSO
+--------
+*sysdbd*(1)
+
+AUTHOR
+------
+sysdbd was written by Sebastian "tokkee" Harl <sh@tokkee.org>.
+
+COPYRIGHT
+---------
+Copyright (C) 2012-2014 Sebastian "tokkee" Harl <sh@tokkee.org>
+
+This is free software under the terms of the BSD license, see the source for
+copying conditions. There is NO WARRANTY; not even for MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.
+
+// vim: set tw=78 sw=4 ts=4 noexpandtab spell spelllang=en_us :
+
diff --git a/doc/sysdbd.1.txt b/doc/sysdbd.1.txt
index 76d0944ecdac127435d5141998c00a2ef0a435e4..d3a7046f640266dfdf236c1a96d552a1907fc854 100644 (file)
--- a/doc/sysdbd.1.txt
+++ b/doc/sysdbd.1.txt
SEE ALSO
--------
-*sysdb.conf*(5)
+*sysdbd.conf*(5)
AUTHOR
------
diff --git a/src/Makefile.am b/src/Makefile.am
index 8bd82149163643967aa3a5e3d833b769d41d609d..f6df34a25e7cdd16ac80ea4a06564ddf689cd785 100644 (file)
--- a/src/Makefile.am
+++ b/src/Makefile.am
libsysdb_scanner_la_CFLAGS = -DBUILD_DATE="\"$$( date --utc '+%F %T' ) (UTC)\""
sysdb_SOURCES = tools/sysdb/main.c include/client/sysdb.h \
tools/sysdb/command.c tools/sysdb/command.h \
- tools/sysdb/input.c tools/sysdb/input.h
+ tools/sysdb/input.c tools/sysdb/input.h \
+ core/object.c include/core/object.h \
+ utils/llist.c include/utils/llist.h
sysdb_CFLAGS = -DBUILD_DATE="\"$$( date --utc '+%F %T' ) (UTC)\"" \
$(AM_CFLAGS) @READLINE_CFLAGS@
sysdb_LDADD = libsysdb_scanner.la libsysdbclient.la @READLINE_LIBS@
diff --git a/src/core/object.c b/src/core/object.c
index 177ac4c3ada9a76009805187d0a0cd4eda322b9e..9101918654379a1ff41491df64187d399468d186 100644 (file)
--- a/src/core/object.c
+++ b/src/core/object.c
{
sdb_object_t *obj;
- if (type.size <= sizeof(sdb_object_t))
+ if (type.size < sizeof(sdb_object_t))
return NULL;
obj = malloc(type.size);
index 7416800a2281dd398ee90af83b5942c3eaf3eb07..bb32157402d8c047a20326aab81e069a4073e5f1 100644 (file)
--- a/src/core/store_lookup.c
+++ b/src/core/store_lookup.c
return 1;
} /* match_name */
+static char *
+name_tostring(name_matcher_t *m, char *buf, size_t buflen)
+{
+ snprintf(buf, buflen, "{ %s%s%s, %p }",
+ m->name ? "'" : "", m->name ? m->name : "NULL", m->name ? "'" : "",
+ m->name_re);
+ return buf;
+} /* name_tostring */
+
+static char *
+logical_tostring(sdb_store_matcher_t *m, char *buf, size_t buflen)
+{
+ char left[buflen + 1], right[buflen + 1];
+
+ if (! m) {
+ /* this should not happen */
+ snprintf(buf, buflen, "()");
+ return buf;
+ }
+
+ assert((m->type == MATCHER_OR) || (m->type == MATCHER_AND));
+ snprintf(buf, buflen, "(%s, %s, %s)",
+ m->type == MATCHER_OR ? "OR" : "AND",
+ sdb_store_matcher_tostring(OP_M(m)->left, left, sizeof(left)),
+ sdb_store_matcher_tostring(OP_M(m)->right, right, sizeof(right)));
+ return buf;
+} /* logical_tostring */
+
+static char *
+unary_tostring(sdb_store_matcher_t *m, char *buf, size_t buflen)
+{
+ char op[buflen + 1];
+
+ if (! m) {
+ /* this should not happen */
+ snprintf(buf, buflen, "()");
+ return buf;
+ }
+
+ assert(m->type == MATCHER_NOT);
+ snprintf(buf, buflen, "(NOT, %s)",
+ sdb_store_matcher_tostring(UOP_M(m)->op, op, sizeof(op)));
+ return buf;
+} /* unary_tostring */
+
+static char *
+attr_tostring(sdb_store_matcher_t *m, char *buf, size_t buflen)
+{
+ char name[buflen + 1], value[buflen + 1];
+
+ if (! m) {
+ snprintf(buf, buflen, "ATTR{}");
+ return buf;
+ }
+
+ assert(m->type == MATCHER_ATTR);
+ snprintf(buf, buflen, "ATTR{ NAME%s, VALUE%s }",
+ name_tostring(&OBJ_M(m)->name, name, sizeof(name)),
+ name_tostring(&ATTR_M(m)->value, value, sizeof(value)));
+ return buf;
+} /* attr_tostring */
+
+static char *
+service_tostring(sdb_store_matcher_t *m, char *buf, size_t buflen)
+{
+ char name[buflen + 1], attr[buflen + 1];
+
+ if (! m) {
+ snprintf(buf, buflen, "SERVICE{}");
+ return buf;
+ }
+
+ assert(m->type == MATCHER_SERVICE);
+ snprintf(buf, buflen, "SERVICE{ NAME%s, %s }",
+ name_tostring(&OBJ_M(m)->name, name, sizeof(name)),
+ attr_tostring(SDB_STORE_MATCHER(SERVICE_M(m)->attr),
+ attr, sizeof(attr)));
+ return buf;
+} /* service_tostring */
+
+static char *
+host_tostring(sdb_store_matcher_t *m, char *buf, size_t buflen)
+{
+ char name[buflen + 1], service[buflen + 1], attr[buflen + 1];
+
+ if (! m) {
+ snprintf(buf, buflen, "HOST{}");
+ return buf;
+ }
+
+ assert(m->type == MATCHER_HOST);
+ snprintf(buf, buflen, "HOST{ NAME%s, %s, %s }",
+ name_tostring(&OBJ_M(m)->name, name, sizeof(name)),
+ service_tostring(SDB_STORE_MATCHER(HOST_M(m)->service),
+ service, sizeof(service)),
+ attr_tostring(SDB_STORE_MATCHER(HOST_M(m)->attr),
+ attr, sizeof(attr)));
+ return buf;
+} /* host_tostring */
+
/* match attribute specific values;
* always call this function through match_obj() */
static int
match_obj,
};
+typedef char *(*matcher_tostring_cb)(sdb_store_matcher_t *, char *, size_t);
+
+static matcher_tostring_cb matchers_tostring[] = {
+ logical_tostring,
+ logical_tostring,
+ unary_tostring,
+ attr_tostring,
+ service_tostring,
+ host_tostring,
+};
+
static int
match_logical(sdb_store_matcher_t *m, sdb_store_base_t *obj)
{
/* accept */
}
else if (typ == SDB_ATTRIBUTE)
- m = sdb_store_attr_matcher(attr, NULL, matcher, matcher_re);
+ m = sdb_store_host_matcher(/* name = */ NULL, NULL,
+ /* service = */ NULL,
+ sdb_store_attr_matcher(attr, NULL, matcher, matcher_re));
else
return NULL;
else if (typ == SDB_HOST)
m = sdb_store_host_matcher(matcher, matcher_re, NULL, NULL);
else if (typ == SDB_SERVICE)
- m = sdb_store_service_matcher(matcher, matcher_re, NULL);
+ m = sdb_store_host_matcher(/* name = */ NULL, NULL,
+ sdb_store_service_matcher(matcher, matcher_re, NULL),
+ /* attr = */ NULL);
else if (typ == SDB_ATTRIBUTE)
- m = sdb_store_attr_matcher(matcher, matcher_re, NULL, NULL);
+ m = sdb_store_host_matcher(/* name = */ NULL, NULL,
+ /* service = */ NULL,
+ sdb_store_attr_matcher(matcher, matcher_re, NULL, NULL));
if (m && inv) {
sdb_store_matcher_t *tmp;
return matchers[m->type](m, obj);
} /* sdb_store_matcher_matches */
+char *
+sdb_store_matcher_tostring(sdb_store_matcher_t *m, char *buf, size_t buflen)
+{
+ if (! m)
+ return NULL;
+
+ if ((m->type < 0)
+ || (((size_t)m->type >= SDB_STATIC_ARRAY_LEN(matchers_tostring))))
+ return NULL;
+ return matchers_tostring[m->type](m, buf, buflen);
+} /* sdb_store_matcher_tostring */
+
int
sdb_store_lookup(sdb_store_matcher_t *m, sdb_store_lookup_cb cb,
void *user_data)
index 12812c7132b20e35da6954757ddbcb5f6f2e7a7d..69c71edbd3e6f7ac9e5876841d9237f738267ab5 100644 (file)
sdb_log(SDB_LOG_DEBUG, "frontend: Closing connection on fd=%i",
conn->fd);
- close(conn->fd);
+ if (conn->fd >= 0)
+ close(conn->fd);
conn->fd = -1;
sdb_strbuf_destroy(conn->buf);
{
ssize_t n = 0;
+ if ((! conn) || (conn->fd < 0))
+ return -1;
+
while (42) {
ssize_t status;
if (status < 0) {
if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
break;
+
+ close(conn->fd);
+ conn->fd = -1;
return (int)status;
}
else if (! status) /* EOF */
if (status < 0) {
char errbuf[1024];
+ /* tell other code that there was a problem and, more importantly,
+ * make sure we don't try to send further logs to the connection */
+ close(conn->fd);
+ conn->fd = -1;
+
sdb_log(SDB_LOG_ERR, "frontend: Failed to send msg "
"(code: %u, len: %u) to client: %s", code, msg_len,
sdb_strerror(errno, errbuf, sizeof(errbuf)));
diff --git a/src/frontend/grammar.y b/src/frontend/grammar.y
index 1cf068538bc13f7686fc12df2d0ba22247f9d553..a261c4c81d3253320b9d8cf960378918f84d0249 100644 (file)
--- a/src/frontend/grammar.y
+++ b/src/frontend/grammar.y
expression:
matcher
{
- sdb_store_matcher_t *m = $1;
- if (! m) {
+ if (! $1) {
/* TODO: improve error reporting */
sdb_fe_yyerror(&yylloc, scanner,
YY_("syntax error, invalid expression"));
$$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL,
conn_node_matcher_t, conn_matcher_destroy));
$$->cmd = CONNECTION_EXPR;
-
- if ((M(m)->type == MATCHER_HOST)
- || (M(m)->type == MATCHER_AND)
- || (M(m)->type == MATCHER_OR)
- || (M(m)->type == MATCHER_NOT))
- CONN_MATCHER($$)->matcher = m;
- else if (M(m)->type == MATCHER_SERVICE)
- CONN_MATCHER($$)->matcher = sdb_store_host_matcher(NULL,
- /* name_re = */ NULL, /* service = */ m,
- /* attr = */ NULL);
- else if (M(m)->type == MATCHER_ATTR)
- CONN_MATCHER($$)->matcher = sdb_store_host_matcher(NULL,
- /* name_re = */ NULL, /* service = */ NULL,
- /* attr = */ m);
- else {
- char errbuf[1024];
- snprintf(errbuf, sizeof(errbuf),
- YY_("syntax error, unexpected matcher type %d"),
- M(m)->type);
- sdb_object_deref(SDB_OBJ($$));
- sdb_fe_yyerror(&yylloc, scanner, errbuf);
- YYABORT;
- }
+ CONN_MATCHER($$)->matcher = $1;
}
;
diff --git a/src/frontend/sock.c b/src/frontend/sock.c
index 3b9799496df8bf1e70d501393e36b91de0ebd86e..7cfdb7cac4b84d21c2f476e38b08855ea80c970b 100644 (file)
--- a/src/frontend/sock.c
+++ b/src/frontend/sock.c
while (sdb_llist_iter_has_next(iter)) {
sdb_object_t *obj = sdb_llist_iter_get_next(iter);
- if (FD_ISSET(CONN(obj)->fd, exceptions))
+ if (FD_ISSET(CONN(obj)->fd, exceptions)) {
sdb_log(SDB_LOG_INFO, "Exception on fd %d",
CONN(obj)->fd);
+ /* close the connection */
+ sdb_llist_iter_remove_current(iter);
+ sdb_object_deref(obj);
+ continue;
+ }
if (FD_ISSET(CONN(obj)->fd, ready)) {
sdb_llist_iter_remove_current(iter);
while (sdb_llist_iter_has_next(iter)) {
sdb_object_t *obj = sdb_llist_iter_get_next(iter);
+
+ if (CONN(obj)->fd < 0) {
+ sdb_llist_iter_remove_current(iter);
+ sdb_object_deref(obj);
+ continue;
+ }
+
FD_SET(CONN(obj)->fd, &ready);
FD_SET(CONN(obj)->fd, &exceptions);
index 4fd54baa1c5fa7ac99c3c0f46bbf2e2d8f8f2cd6..bce3da91898a670a00eb532e630e2b0663462321 100644 (file)
* connection.
*
* Returns:
- * - 0 on success
+ * - the number of bytes send
* - a negative value else.
*/
ssize_t
index cde6ad0b8c2763dd15b4759b27f005b87441db5a..6106b3fdbe2490629a6b1e42d02ee85184d134dc 100644 (file)
--- a/src/include/core/store.h
+++ b/src/include/core/store.h
int
sdb_store_matcher_matches(sdb_store_matcher_t *m, sdb_store_base_t *obj);
+/*
+ * sdb_store_matcher_tostring:
+ * Format a matcher object as string. This is meant for logging or debugging
+ * purposes.
+ */
+char *
+sdb_store_matcher_tostring(sdb_store_matcher_t *m, char *buf, size_t buflen);
+
/*
* sdb_store_lookup_cb:
* Lookup callback. It is called for each matching object when looking up data
index 1128c388e8bbd827f63e63cb2cd2628137e146fd..c79259e401c0786bb80336601208b058180e23e9 100644 (file)
*/
int
-sdb_command_print_reply(sdb_input_t *input)
+sdb_command_print_reply(sdb_client_t *client)
{
sdb_strbuf_t *recv_buf;
const char *result;
if (! recv_buf)
return -1;
- if (sdb_client_recv(input->client, &rcode, recv_buf) < 0)
+ if (sdb_client_recv(client, &rcode, recv_buf) < 0)
rcode = UINT32_MAX;
- if (sdb_client_eof(input->client))
+ if (sdb_client_eof(client))
return -1;
if (rcode == UINT32_MAX)
/* ignore errors; we'll only hide the command from the caller */
sdb_client_send(input->client, CONNECTION_QUERY, query_len, query);
- if (sdb_command_print_reply(input))
+ if (sdb_command_print_reply(input->client))
return NULL;
}
index 726e27a59f05f1229ecf79ac8874df625203b6a5..febf64f144a3c6f54ecee86d077531d14b414f76 100644 (file)
* - a negative value else
*/
int
-sdb_command_print_reply(sdb_input_t *input);
+sdb_command_print_reply(sdb_client_t *client);
/*
* sdb_command_exec:
index 3814f0c2def7a239d8397d9cad4558cbd52112ae..b515c4e10931db0c8e599d9820b991d974a6fb6b 100644 (file)
--- a/src/tools/sysdb/input.c
+++ b/src/tools/sysdb/input.c
/* some response / error message from the server pending */
/* XXX: clear current line */
printf("\n");
- sdb_command_print_reply(sysdb_input);
+ sdb_command_print_reply(sysdb_input->client);
rl_forced_update_display();
}
diff --git a/src/tools/sysdb/main.c b/src/tools/sysdb/main.c
index 33f96c4461c24cbea9dd17b5b8c0c611fc428fa9..991e1ffb6d8e744252309646f4741e67abfe901d 100644 (file)
--- a/src/tools/sysdb/main.c
+++ b/src/tools/sysdb/main.c
# include "config.h"
#endif /* HAVE_CONFIG_H */
+#include "tools/sysdb/command.h"
#include "tools/sysdb/input.h"
#include "client/sysdb.h"
#include "client/sock.h"
#include "utils/error.h"
+#include "utils/llist.h"
#include "utils/strbuf.h"
#include <errno.h>
# define DEFAULT_SOCKET "unix:"LOCALSTATEDIR"/run/sysdbd.sock"
#endif
-static void
-exit_usage(char *name, int status)
-{
- printf(
-"Usage: %s <options>\n"
-
-"\nOptions:\n"
-" -h display this help and exit\n"
-" -V display the version number and copyright\n"
-
-"\nSysDB client "SDB_CLIENT_VERSION_STRING SDB_CLIENT_VERSION_EXTRA", "
-PACKAGE_URL"\n", basename(name));
- exit(status);
-} /* exit_usage */
-
-static void
-exit_version(void)
-{
- printf("SysDB version "SDB_CLIENT_VERSION_STRING
- SDB_CLIENT_VERSION_EXTRA", built "BUILD_DATE"\n"
- "using libsysdbclient version %s%s\n"
- "Copyright (C) 2012-2014 "PACKAGE_MAINTAINER"\n"
-
- "\nThis is free software under the terms of the BSD license, see "
- "the source for\ncopying conditions. There is NO WARRANTY; not "
- "even for MERCHANTABILITY or\nFITNESS FOR A PARTICULAR "
- "PURPOSE.\n", sdb_client_version_string(),
- sdb_client_version_extra());
- exit(0);
-} /* exit_version */
-
static const char *
get_current_user(void)
{
return result->pw_dir;
} /* get_homedir */
+static void
+exit_usage(char *name, int status)
+{
+ printf(
+"Usage: %s <options>\n"
+
+"\nOptions:\n"
+" -H HOST the host to connect to\n"
+" default: "DEFAULT_SOCKET"\n"
+" -U USER the username to connect as\n"
+" default: %s\n"
+" -c CMD execute the specified command and then exit\n"
+"\n"
+" -h display this help and exit\n"
+" -V display the version number and copyright\n"
+
+"\nSysDB client "SDB_CLIENT_VERSION_STRING SDB_CLIENT_VERSION_EXTRA", "
+PACKAGE_URL"\n", basename(name), get_current_user());
+ exit(status);
+} /* exit_usage */
+
+static void
+exit_version(void)
+{
+ printf("SysDB version "SDB_CLIENT_VERSION_STRING
+ SDB_CLIENT_VERSION_EXTRA", built "BUILD_DATE"\n"
+ "using libsysdbclient version %s%s\n"
+ "Copyright (C) 2012-2014 "PACKAGE_MAINTAINER"\n"
+
+ "\nThis is free software under the terms of the BSD license, see "
+ "the source for\ncopying conditions. There is NO WARRANTY; not "
+ "even for MERCHANTABILITY or\nFITNESS FOR A PARTICULAR "
+ "PURPOSE.\n", sdb_client_version_string(),
+ sdb_client_version_extra());
+ exit(0);
+} /* exit_version */
+
+static int
+execute_commands(sdb_client_t *client, sdb_llist_t *commands)
+{
+ sdb_llist_iter_t *iter;
+ int status = 0;
+
+ iter = sdb_llist_get_iter(commands);
+ if (! iter) {
+ sdb_log(SDB_LOG_ERR, "Failed to iterate commands");
+ return 1;
+ }
+
+ while (sdb_llist_iter_has_next(iter)) {
+ sdb_object_t *obj = sdb_llist_iter_get_next(iter);
+ if (sdb_client_send(client, CONNECTION_QUERY,
+ (uint32_t)strlen(obj->name), obj->name) <= 0) {
+ sdb_log(SDB_LOG_ERR, "Failed to send command '%s' to server",
+ obj->name);
+ status = 1;
+ break;
+ }
+ if (sdb_command_print_reply(client)) {
+ sdb_log(SDB_LOG_ERR, "Failed to read reply from server");
+ status = 1;
+ break;
+ }
+ }
+
+ sdb_llist_iter_destroy(iter);
+ return status;
+} /* execute_commands */
+
int
main(int argc, char **argv)
{
char hist_file[1024] = "";
sdb_input_t input = SDB_INPUT_INIT;
+ sdb_llist_t *commands = NULL;
while (42) {
- int opt = getopt(argc, argv, "H:U:hV");
+ int opt = getopt(argc, argv, "H:U:c:hV");
if (-1 == opt)
break;
user = optarg;
break;
+ case 'c':
+ {
+ sdb_object_t *obj;
+
+ if (! commands)
+ commands = sdb_llist_create();
+ if (! commands) {
+ sdb_log(SDB_LOG_ERR, "Failed to create list object");
+ exit(1);
+ }
+
+ if (! (obj = sdb_object_create_T(optarg, sdb_object_t))) {
+ sdb_log(SDB_LOG_ERR, "Failed to create object");
+ exit(1);
+ }
+ if (sdb_llist_append(commands, obj)) {
+ sdb_log(SDB_LOG_ERR, "Failed to append command to list");
+ sdb_object_deref(obj);
+ exit(1);
+ }
+ sdb_object_deref(obj);
+ }
+ break;
+
case 'h':
exit_usage(argv[0], 0);
break;
exit(1);
}
+ if (commands) {
+ int status = execute_commands(input.client, commands);
+ sdb_llist_destroy(commands);
+ sdb_client_destroy(input.client);
+ exit(status);
+ }
+
sdb_log(SDB_LOG_INFO, "SysDB client "SDB_CLIENT_VERSION_STRING
SDB_CLIENT_VERSION_EXTRA"\n");
index ca1c50de3866318efefe06f399539d65a762f35d..9828bf0881bd1c6510b8c3bef22ef567ad776fa1 100644 (file)
--- a/src/tools/sysdbd/main.c
+++ b/src/tools/sysdbd/main.c
sdb_plugin_init_all();
plugin_main_loop.default_interval = SECS_TO_SDB_TIME(60);
+ /* ignore, we see this, for example, if a client disconnects without
+ * closing the connection cleanly */
+ signal(SIGPIPE, SIG_IGN);
+
memset(&backend_thread, 0, sizeof(backend_thread));
if (pthread_create(&backend_thread, /* attr = */ NULL,
backend_handler, /* arg = */ NULL)) {
diff --git a/t/Makefile.am b/t/Makefile.am
index c63a2bb21d0c8f9a8e1ee25836723266f70fbebe..cc2607f75e2b09d9129cc9ff77cfe08630649932 100644 (file)
--- a/t/Makefile.am
+++ b/t/Makefile.am
libsysdb_test_SOURCES = \
libsysdb_test.c libsysdb_test.h \
+ libsysdb_testutils.c libsysdb_testutils.h \
core/data_test.c \
core/object_test.c \
core/store_test.c \
libsysdb_test_LDADD = $(top_builddir)/src/libsysdb.la @CHECK_LIBS@
libsysdb_net_test_SOURCES = \
- libsysdb_net_test.c libsysdb_test.h
+ libsysdb_net_test.c libsysdb_test.h \
+ libsysdb_testutils.c libsysdb_testutils.h
if BUILD_WITH_FOPENCOOKIE
libsysdb_net_test_SOURCES += utils/unixsock_test.c
endif
index a16d343d37d0a9991e244d419c6226ecc64c23d5..2b52a66de1d32e05d7a79a371c6d095d3eed6fc8 100644 (file)
#include "core/store.h"
#include "core/store-private.h"
+#include "frontend/parser.h"
#include "libsysdb_test.h"
#include <check.h>
{ "host", "attr", "=", "hostname", -1 },
{ "host", "attr", "!=", "hostname", -1 },
{ "host", "name", "&^", "hostname", -1 },
- { "service", "name", "=", "srvname", MATCHER_SERVICE },
+ { "service", "name", "=", "srvname", MATCHER_HOST },
{ "service", "name", "!=", "srvname", MATCHER_NOT },
- { "service", "name", "=~", "srvname", MATCHER_SERVICE },
+ { "service", "name", "=~", "srvname", MATCHER_HOST },
{ "service", "name", "!~", "srvname", MATCHER_NOT },
{ "service", "attr", "=", "srvname", -1 },
{ "service", "attr", "!=", "srvname", -1 },
{ "service", "name", "&^", "srvname", -1 },
- { "attribute", "name", "=", "attrname", MATCHER_ATTR },
+ { "attribute", "name", "=", "attrname", MATCHER_HOST },
{ "attribute", "name", "!=", "attrname", MATCHER_NOT },
- { "attribute", "name", "=~", "attrname", MATCHER_ATTR },
+ { "attribute", "name", "=~", "attrname", MATCHER_HOST },
{ "attribute", "name", "!~", "attrname", MATCHER_NOT },
- { "attribute", "attr", "=", "attrname", MATCHER_ATTR },
+ { "attribute", "attr", "=", "attrname", MATCHER_HOST },
{ "attribute", "attr", "!=", "attrname", MATCHER_NOT },
- { "attribute", "attr", "=~", "attrname", MATCHER_ATTR },
+ { "attribute", "attr", "=~", "attrname", MATCHER_HOST },
{ "attribute", "attr", "!~", "attrname", MATCHER_NOT },
{ "attribute", "attr", "&^", "attrname", -1 },
};
static int
lookup_cb(sdb_store_base_t *obj, void *user_data)
{
- intptr_t *i = user_data;
+ int *i = user_data;
fail_unless(obj != NULL,
"sdb_store_lookup callback received NULL obj; expected: "
START_TEST(test_lookup)
{
- intptr_t i = 0;
- int check;
+#define PTR_RE "0x[0-9a-f]+"
+ struct {
+ const char *query;
+ int expected;
+ const char *tostring_re;
+ } golden_data[] = {
+ { "host.name = 'a'", 1,
+ "HOST\\{ NAME\\{ 'a', \\(nil\\) \\}, SERVICE\\{\\}, ATTR\\{\\} \\}" },
+ { "host.name =~ 'a|b'", 2,
+ "HOST\\{ NAME\\{ NULL, "PTR_RE" \\}, SERVICE\\{\\}, ATTR\\{\\} \\}" },
+ { "host.name =~ 'host'", 0,
+ "HOST\\{ NAME\\{ NULL, "PTR_RE" \\}, SERVICE\\{\\}, ATTR\\{\\} \\}" },
+ { "host.name =~ '.'", 3,
+ "HOST\\{ NAME\\{ NULL, "PTR_RE" \\}, SERVICE\\{\\}, ATTR\\{\\} \\}" },
+ { "service.name = 's1'", 2,
+ "HOST\\{ NAME\\{ NULL, \\(nil\\) \\}, SERVICE\\{ "
+ "NAME\\{ 's1', \\(nil\\) }, ATTR\\{\\} "
+ "\\}, ATTR\\{\\} \\}" },
+ { "service.name =~ 's'", 2,
+ "HOST\\{ NAME\\{ NULL, \\(nil\\) \\}, SERVICE\\{ "
+ "NAME\\{ NULL, "PTR_RE" }, ATTR\\{\\} "
+ "\\}, ATTR\\{\\} \\}" },
+ { "service.name !~ 's'", 1,
+ "(NOT, HOST\\{ NAME\\{ NULL, \\(nil\\) \\}, SERVICE\\{ "
+ "NAME\\{ NULL, "PTR_RE" }, ATTR\\{\\} "
+ "\\}, ATTR\\{\\} \\})" },
+ { "attribute.name = 'k1'", 1,
+ "HOST\\{ NAME\\{ NULL, \\(nil\\) \\}, SERVICE\\{\\}, ATTR\\{ "
+ "NAME\\{ 'k1', \\(nil\\) }, VALUE\\{ NULL, \\(nil\\) \\} "
+ "\\} \\}" },
+ { "attribute.name = 'x'", 0,
+ "HOST\\{ NAME\\{ NULL, \\(nil\\) \\}, SERVICE\\{\\}, ATTR\\{ "
+ "NAME\\{ 'x', \\(nil\\) }, VALUE\\{ NULL, \\(nil\\) \\} "
+ "\\} \\}" },
+ { "attribute.k1 = 'v1'", 1,
+ "HOST\\{ NAME\\{ NULL, \\(nil\\) \\}, SERVICE\\{\\}, ATTR\\{ "
+ "NAME\\{ 'k1', \\(nil\\) }, VALUE\\{ 'v1', \\(nil\\) \\} "
+ "\\} \\}" },
+ { "attribute.k1 != 'v1'", 2,
+ "(NOT, HOST\\{ NAME\\{ NULL, \\(nil\\) \\}, SERVICE\\{\\}, ATTR\\{ "
+ "NAME\\{ 'k1', \\(nil\\) }, VALUE\\{ 'v1', \\(nil\\) \\} "
+ "\\} \\})" },
+ { "attribute.k1 != 'v2'", 3,
+ "(NOT, HOST\\{ NAME\\{ NULL, \\(nil\\) \\}, SERVICE\\{\\}, ATTR\\{ "
+ "NAME\\{ 'k1', \\(nil\\) }, VALUE\\{ 'v2', \\(nil\\) \\} "
+ "\\} \\})" },
+ { "attribute.name != 'x' "
+ "AND attribute.y !~ 'x'", 3,
+ "\\(AND, \\(NOT, HOST\\{ NAME\\{ NULL, \\(nil\\) \\}, SERVICE\\{\\}, ATTR\\{ "
+ "NAME\\{ 'x', \\(nil\\) }, VALUE\\{ NULL, \\(nil\\) \\} "
+ "\\} \\}\\), \\(NOT, HOST\\{ NAME\\{ NULL, \\(nil\\) \\}, SERVICE\\{\\}, ATTR\\{ "
+ "NAME\\{ 'y', \\(nil\\) }, VALUE\\{ NULL, "PTR_RE" \\} "
+ "\\} \\}\\)\\)" },
+ };
+
+ int check, n;
+ size_t i;
- check = sdb_store_lookup(NULL, lookup_cb, &i);
+ n = 0;
+ check = sdb_store_lookup(NULL, lookup_cb, &n);
fail_unless(check == 0,
"sdb_store_lookup() = %d; expected: 0", check);
- fail_unless(i == 3,
- "sdb_store_lookup called callback %d times; expected: 3", (int)i);
+ fail_unless(n == 3,
+ "sdb_store_lookup called callback %d times; expected: 3", (int)n);
+
+ for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
+ sdb_store_matcher_t *m;
+ char buf[4096];
+
+ m = sdb_fe_parse_matcher(golden_data[i].query, -1);
+ fail_unless(m != NULL,
+ "sdb_fe_parse_matcher(%s, -1) = NULL; expected: <matcher>",
+ golden_data[i].query);
+ fail_unless(sdb_regmatches(golden_data[i].tostring_re,
+ sdb_store_matcher_tostring(m, buf, sizeof(buf))) == 0,
+ "sdb_fe_parse_matcher(%s, -1) = %s; expected: %s",
+ golden_data[i].query,
+ sdb_store_matcher_tostring(m, buf, sizeof(buf)),
+ golden_data[i].tostring_re);
+
+ n = 0;
+ sdb_store_lookup(m, lookup_cb, &n);
+ fail_unless(n == golden_data[i].expected,
+ "sdb_store_lookup(matcher{%s}) found %d hosts; expected: %d",
+ golden_data[i].query, n, golden_data[i].expected);
+ sdb_object_deref(SDB_OBJ(m));
+ }
}
END_TEST
diff --git a/t/coverage.sh b/t/coverage.sh
index 29f8c99a7ad7b7f914dea601aa93ccfde413cda4..6acf8c96faa2ec520fb6ba0c64c1ae24db6f3423 100755 (executable)
--- a/t/coverage.sh
+++ b/t/coverage.sh
cp -a "$srcdir"/.git .
# reset all files which are not part of the tarball
- git checkout HEAD .gitignore .travis.yml
+ git checkout HEAD .gitignore .travis.yml t/cibuild.sh
fi
./configure --enable-gcov --disable-shared CFLAGS="-O0 -g"
index 74075b3a6c8de866840891e52d975fdc0fdc35ba..f64b9ebca95b05e66bb568a9c6535f72cc7f7462 100644 (file)
--- a/t/frontend/parser_test.c
+++ b/t/frontend/parser_test.c
/* valid expressions */
{ "host.name = 'localhost'", -1, MATCHER_HOST },
+ { "host.name != 'localhost'", -1, MATCHER_NOT },
+ { "host.name =~ 'host'", -1, MATCHER_HOST },
+ { "host.name !~ 'host'", -1, MATCHER_NOT },
{ "host.name = 'localhost' -- foo", -1, MATCHER_HOST },
{ "host.name = 'host' <garbage>", 18, MATCHER_HOST },
+ /* match hosts by service */
+ { "service.name = 'name'", -1, MATCHER_HOST },
+ { "service.name != 'name'", -1, MATCHER_NOT },
+ { "service.name =~ 'pattern'", -1, MATCHER_HOST },
+ { "service.name !~ 'pattern'", -1, MATCHER_NOT },
+ /* match hosts by attribute */
+ { "attribute.name = 'name'", -1, MATCHER_HOST },
+ { "attribute.name != 'name'", -1, MATCHER_NOT },
+ { "attribute.name =~ 'pattern'", -1, MATCHER_HOST },
+ { "attribute.name !~ 'pattern'", -1, MATCHER_NOT },
+ /* composite expressions */
{ "host.name =~ 'pattern' AND "
"service.name =~ 'pattern'", -1, MATCHER_AND },
{ "host.name =~ 'pattern' OR "
diff --git a/t/libsysdb_test.h b/t/libsysdb_test.h
index 3357260f6a52559ac0d70906aff2e5a927cd08cf..5f0e1b486eda09647e1fdd9cbd72d38c8f7af0b2 100644 (file)
--- a/t/libsysdb_test.h
+++ b/t/libsysdb_test.h
#include "sysdb.h"
#include "core/object.h"
+#include "libsysdb_testutils.h"
+
#include <check.h>
#include <string.h>
diff --git a/t/libsysdb_testutils.c b/t/libsysdb_testutils.c
--- /dev/null
+++ b/t/libsysdb_testutils.c
@@ -0,0 +1,54 @@
+/*
+ * SysDB - t/libsysdb_testutils.c
+ * Copyright (C) 2014 Sebastian 'tokkee' Harl <sh@tokkee.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * 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 HOLDERS 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.
+ */
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include "libsysdb_testutils.h"
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <regex.h>
+
+int
+sdb_regmatches(const char *regex, const char *string)
+{
+ regex_t reg;
+ int status;
+
+ status = regcomp(®, regex, REG_EXTENDED | REG_NOSUB);
+ if (status)
+ return status;
+
+ status = regexec(®, string, /* matches = */ 0, NULL, /* flags = */ 0);
+ regfree(®);
+ return status;
+} /* sdb_regmatches */
+
+/* vim: set tw=78 sw=4 ts=4 noexpandtab : */
+
diff --git a/t/libsysdb_testutils.h b/t/libsysdb_testutils.h
--- /dev/null
+++ b/t/libsysdb_testutils.h
@@ -0,0 +1,49 @@
+/*
+ * SysDB - t/libsysdb_testutils.h
+ * Copyright (C) 2014 Sebastian 'tokkee' Harl <sh@tokkee.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * 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 HOLDERS 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.
+ */
+
+/*
+ * Utility functions for test suites.
+ */
+
+#ifndef T_LIBSYSDB_UTILS_H
+#define T_LIBSYSDB_UTILS_H 1
+
+/*
+ * sdb_regmatches:
+ * Check if a regex matches a string.
+ *
+ * Returns:
+ * - 0 if the regex matches
+ * - a non-zero error value else (see regcomp(3) for details)
+ */
+int
+sdb_regmatches(const char *regex, const char *string);
+
+#endif /* T_LIBSYSDB_UTILS_H */
+
+/* vim: set tw=78 sw=4 ts=4 noexpandtab : */
+