summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrad Peters <brad.t.peters@intel.com>2014-08-18 13:39:36 -0700
committerBrad Peters <brad.t.peters@intel.com>2014-08-18 13:39:36 -0700
commit67cae288fd4ac44aca7f7950bb0942ecf3261d0f (patch)
tree42a16ce4d4c9bc51f12cd6efe20c37ad1ea514df
parent7d6949fb6514ec849a57ee0dac9ff51021f8876e (diff)
downloadbuxton-67cae288fd4ac44aca7f7950bb0942ecf3261d0f.tar.gz
buxton-67cae288fd4ac44aca7f7950bb0942ecf3261d0f.tar.bz2
buxton-67cae288fd4ac44aca7f7950bb0942ecf3261d0f.zip
-rw-r--r--HACKING127
-rw-r--r--Makefile.am3
-rw-r--r--Makefile.in61
-rw-r--r--TODO25
-rw-r--r--config.h.in6
-rwxr-xr-xconfigure57
-rw-r--r--configure.ac12
-rw-r--r--data/buxton.conf2
-rw-r--r--demo/gtk_client.c16
-rw-r--r--demo/helloget.c4
-rw-r--r--docs/buxton.78
-rw-r--r--docs/buxton.conf.56
-rw-r--r--docs/buxton_key_create.36
-rw-r--r--docs/buxton_open.34
-rw-r--r--src/cli/client.c17
-rw-r--r--src/core/daemon.c161
-rw-r--r--src/core/daemon.h8
-rw-r--r--src/core/main.c11
-rw-r--r--src/db/gdbm.c49
-rw-r--r--src/libbuxton/lbuxton.c27
-rw-r--r--src/security/smack.c2
-rw-r--r--src/shared/backend.c6
-rw-r--r--src/shared/backend.h1
-rw-r--r--src/shared/configurator.c35
-rw-r--r--src/shared/configurator.h1
-rw-r--r--src/shared/direct.c40
-rw-r--r--src/shared/protocol.c17
-rw-r--r--src/shared/protocol.h7
-rw-r--r--test/check_buxton.c10
-rw-r--r--test/check_daemon.c222
30 files changed, 799 insertions, 152 deletions
diff --git a/HACKING b/HACKING
new file mode 100644
index 0000000..a4750b8
--- /dev/null
+++ b/HACKING
@@ -0,0 +1,127 @@
+Buxton Hacking
+--------------
+
+Note that in order to contribute to Buxton you should first fork the
+repository on GitHub [1], and create a pull request to master from your
+feature branch.
+
+Indentation
+-----------
+Buxton uses tabs for indentation, with a tab width of 8. Ensure you do
+not mix spaces with tabs, all source files within Buxton provide modelines,
+please ensure your editor complies.
+
+Coding Style
+------------
+Always use a fail-first approach, ensuring you exit from your function if
+there is erroneous input, for example, and not deep within a function.
+
+Buxton does not use spaces after function invocations, example:
+
+ buxton_function(x, y, z);
+
+Whereas this is considered invalid:
+
+ buxton_function (x, y, z);
+
+Spaces should still be used for loops, if-checks, etc:
+
+ while (someCondition) {
+ }
+
+And not:
+
+ while(someCondition) {
+ }
+
+When using internal (core/library) functionality, and not the *public API*,
+you should use helpers/workflow that already exist. For example we have
+automatic macros for freeing various types of data:
+
+ _cleanup_buxton_key_ BuxtonKey key;
+
+This ensures that where appropriate, your memory is automatically free'd
+when it is out of scope. For more information please consult src/shared/util.h
+
+All if-blocks should have curly braces (brackets) and parentheses, even if
+they are single line checks.
+A valid example:
+
+ if (connected) {
+ /* Do something */
+ }
+ dosomethingelse();
+
+Invalid:
+ if (connected)
+ /* Do something */
+ dosomethingelse();
+
+Additionally, curly braces should always be on the same line as the conditional,
+and are only on separate lines in the opening body of a function declaration.
+A valid example in a conditional check:
+
+
+ if (someCondition) {
+ /* Do something */
+ }
+
+An invalid conditional check:
+
+ if (someCondition)
+ {
+ /* Do something */
+ }
+
+An invalid function declaration:
+
+ void doSomething(void) {
+ /* Body */
+ }
+
+Whereas this would be a valid example:
+
+ void doSomething(void)
+ {
+ /* Body */
+ }
+
+Always use C style comments (/* */) unless it is a FIXME (also try
+to avoid these where possible.)
+
+ /* Valid comment */
+ // Invalid comment
+ //FIXME: Valid FIXME statement with short description
+
+A word on data types:
+----------
+When using the public API please ensure you keep your data types consistent
+with those publicly accessible. This means ensuring you are using uint64_t,
+uint32_t, etc.
+When using internal APIs, ensure that you use all available internal data
+types, such as BuxtonList, BuxtonArray, taking note of the pros and cons
+of vector approaches versus linked-list, etc. In order of degrading performance
+and resource usage:
+
+ BuxtonArray (simple vector)
+ BuxtonList (doubly linked list)
+ Hashmap (key,value hashmap)
+
+Mixing APIs
+-----------
+Note that internal library APIs may not be mixed with the public consumable
+API, as only the public API has guarantee of stability, and is unlikely
+to change. This means you should not use the cleanup helpers, etc, within
+your public components.
+
+Final note
+---------
+If changing "core" (daemon/library/cli) functionality, ensure that you
+run "make check" and "make distcheck" to validate changes. Always aim
+to provide maximum coverage (as checked by gcov), which may mean providing
+extra unit tests within test/ - Provide these as a separate commit if
+necessary.
+
+---
+ * [1] https://github.com/sofar/buxton
+
diff --git a/Makefile.am b/Makefile.am
index f949a4d..6242f7a 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -65,6 +65,7 @@ pkgconfiglibdir=$(libdir)/pkgconfig
pkgconfiglib_DATA = \
data/libbuxton.pc
+if MANPAGE
dist_man_MANS = \
docs/buxton.7 \
docs/buxtonctl.1 \
@@ -95,6 +96,7 @@ dist_man_MANS = \
docs/buxton_set_value.3 \
docs/buxton_unregister_notification.3 \
docs/buxton_unset_value.3
+endif
TESTS = \
check_db_clean \
@@ -116,6 +118,7 @@ endif
EXTRA_DIST = \
Doxyfile \
LICENSE.LGPL2.1 \
+ HACKING \
check_db_clean \
data/libbuxton.pc.in \
docs/LICENSE.MIT \
diff --git a/Makefile.in b/Makefile.in
index 3d7bb1f..389215e 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -894,42 +894,43 @@ pkgconfiglibdir = $(libdir)/pkgconfig
pkgconfiglib_DATA = \
data/libbuxton.pc
-dist_man_MANS = \
- docs/buxton.7 \
- docs/buxtonctl.1 \
- docs/buxton-api.7 \
- docs/buxton.conf.5 \
- docs/buxtond.8 \
- docs/buxton-protocol.7 \
- docs/buxton-security.7 \
- docs/buxton_client_handle_response.3 \
- docs/buxton_close.3 \
- docs/buxton_create_group.3 \
- docs/buxton_get_value.3 \
- docs/buxton_key_create.3 \
- docs/buxton_key_free.3 \
- docs/buxton_key_get_group.3 \
- docs/buxton_key_get_layer.3 \
- docs/buxton_key_get_name.3 \
- docs/buxton_key_get_type.3 \
- docs/buxton_open.3 \
- docs/buxton_register_notification.3 \
- docs/buxton_remove_group.3 \
- docs/buxton_response_key.3 \
- docs/buxton_response_status.3 \
- docs/buxton_response_type.3 \
- docs/buxton_response_value.3 \
- docs/buxton_set_conf_file.3 \
- docs/buxton_set_label.3 \
- docs/buxton_set_value.3 \
- docs/buxton_unregister_notification.3 \
- docs/buxton_unset_value.3
+@MANPAGE_TRUE@dist_man_MANS = \
+@MANPAGE_TRUE@ docs/buxton.7 \
+@MANPAGE_TRUE@ docs/buxtonctl.1 \
+@MANPAGE_TRUE@ docs/buxton-api.7 \
+@MANPAGE_TRUE@ docs/buxton.conf.5 \
+@MANPAGE_TRUE@ docs/buxtond.8 \
+@MANPAGE_TRUE@ docs/buxton-protocol.7 \
+@MANPAGE_TRUE@ docs/buxton-security.7 \
+@MANPAGE_TRUE@ docs/buxton_client_handle_response.3 \
+@MANPAGE_TRUE@ docs/buxton_close.3 \
+@MANPAGE_TRUE@ docs/buxton_create_group.3 \
+@MANPAGE_TRUE@ docs/buxton_get_value.3 \
+@MANPAGE_TRUE@ docs/buxton_key_create.3 \
+@MANPAGE_TRUE@ docs/buxton_key_free.3 \
+@MANPAGE_TRUE@ docs/buxton_key_get_group.3 \
+@MANPAGE_TRUE@ docs/buxton_key_get_layer.3 \
+@MANPAGE_TRUE@ docs/buxton_key_get_name.3 \
+@MANPAGE_TRUE@ docs/buxton_key_get_type.3 \
+@MANPAGE_TRUE@ docs/buxton_open.3 \
+@MANPAGE_TRUE@ docs/buxton_register_notification.3 \
+@MANPAGE_TRUE@ docs/buxton_remove_group.3 \
+@MANPAGE_TRUE@ docs/buxton_response_key.3 \
+@MANPAGE_TRUE@ docs/buxton_response_status.3 \
+@MANPAGE_TRUE@ docs/buxton_response_type.3 \
+@MANPAGE_TRUE@ docs/buxton_response_value.3 \
+@MANPAGE_TRUE@ docs/buxton_set_conf_file.3 \
+@MANPAGE_TRUE@ docs/buxton_set_label.3 \
+@MANPAGE_TRUE@ docs/buxton_set_value.3 \
+@MANPAGE_TRUE@ docs/buxton_unregister_notification.3 \
+@MANPAGE_TRUE@ docs/buxton_unset_value.3
# set flags
EXTRA_DIST = \
Doxyfile \
LICENSE.LGPL2.1 \
+ HACKING \
check_db_clean \
data/libbuxton.pc.in \
docs/LICENSE.MIT \
diff --git a/TODO b/TODO
index d3559e9..3a54878 100644
--- a/TODO
+++ b/TODO
@@ -5,13 +5,6 @@ Time to complete: (estimate in days)
Target: Version to be released in
Status: If multi part change, what has been done so far
-Description: Update logic for smack access checks
-Difficulty: Medium
-Time to complete: 6
-Target: v1
-Status: In progress. Refer to https://github.com/sofar/buxton/wiki/Smack-TODO
- for details.
-
Description: Test multi-part messaging in the client-side of the library,
mirroring changes made to buxtond's protocol handling
Difficulty: Complex
@@ -26,17 +19,11 @@ Time to complete: 4
Target: ??
Status:
-Description: Tests for nonblocking calls between client and server
-Difficulty: Simple
-Time to complete: 4
-Target: ??
-Status:
-
Description: Fixup list keys
Difficulty: Medium
Time to complete: 5
Target: ??
-Status:
+Status: In Progress
Description: Bulk send receive messages
Difficulty: Complex
@@ -48,7 +35,7 @@ Description: Complete code coverage (minus exceptional cases)
Difficulty: Simple
Time to complete: 10
Target: after v1
-Status: 79.6% of lines covered
+Status: 79.1% of lines covered (Update should be file list which has complete, minus exception, coverage)
Description: Use BuxtonArray for message deserialization
Difficulty: Medium
@@ -66,7 +53,7 @@ Description: Tizen programs converted to use Buxton
Difficulty: Complex
Time to complete: 10
Target: v1
-Status:
+Status: In Progress
Description: Allow notification registration for non existant keys
Difficulty: Simple
@@ -80,12 +67,6 @@ Time to complete: 3
Target: ??
Status:
-Description: Ensure all public apis give copies of data
-Difficulty: Simple
-Time to complete: 1
-Target: ??
-Status: All done aside from list_keys which needs to be updated for the new api
-
Description: Add Wextra to compiler flags once iniparser is gone
Difficulty: Simple
Time to complete: 1
diff --git a/config.h.in b/config.h.in
index 884cdb9..c0ccad3 100644
--- a/config.h.in
+++ b/config.h.in
@@ -180,9 +180,15 @@
*/
#undef LT_OBJDIR
+/* Man pages will be included */
+#undef MANPAGE
+
/* Debugging and assertions disabled */
#undef NDEBUG
+/* Man pages will not be included */
+#undef NMANPAGE
+
/* Name of package */
#undef PACKAGE
diff --git a/configure b/configure
index e1f7eb1..b536ec9 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for buxton 2.
+# Generated by GNU Autoconf 2.69 for buxton 3.
#
# Report bugs to <william.douglas@intel.com>.
#
@@ -590,8 +590,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='buxton'
PACKAGE_TARNAME='buxton'
-PACKAGE_VERSION='2'
-PACKAGE_STRING='buxton 2'
+PACKAGE_VERSION='3'
+PACKAGE_STRING='buxton 3'
PACKAGE_BUGREPORT='william.douglas@intel.com'
PACKAGE_URL='https://github.com/sofar/buxton'
@@ -645,6 +645,8 @@ BUILD_DEMOS_TRUE
COVERAGE_FALSE
COVERAGE_TRUE
lcov_found
+MANPAGE_FALSE
+MANPAGE_TRUE
DEBUG_FALSE
DEBUG_TRUE
SMACK_LOAD_FILE
@@ -803,6 +805,7 @@ with_db_path
with_socket_path
with_smack_load_file
enable_debug
+enable_manpages
enable_coverage
enable_demos
enable_gtk_demo
@@ -1367,7 +1370,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures buxton 2 to adapt to many kinds of systems.
+\`configure' configures buxton 3 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1437,7 +1440,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of buxton 2:";;
+ short | recursive ) echo "Configuration of buxton 3:";;
esac
cat <<\_ACEOF
@@ -1457,6 +1460,7 @@ Optional Features:
speeds up one-time build
--disable-libtool-lock avoid locking (might break parallel builds)
--enable-debug enable debug mode [default=no]
+ --enable-manpages enable man pages [default=yes]
--enable-coverage enable test coverage
--enable-demos enable demos [default=no]
--enable-gtk-demo enable demos [default=no]
@@ -1579,7 +1583,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-buxton configure 2
+buxton configure 3
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2132,7 +2136,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by buxton $as_me 2, which was
+It was created by buxton $as_me 3, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@@ -2995,7 +2999,7 @@ fi
# Define the identity of the package.
PACKAGE='buxton'
- VERSION='2'
+ VERSION='3'
cat >>confdefs.h <<_ACEOF
@@ -14000,7 +14004,7 @@ if test "x$ac_cv_header_attr_xattr_h" = xyes; then :
_ACEOF
else
- as_fn_error $? "Unable to fin xattr headers" "$LINENO" 5
+ as_fn_error $? "Unable to find xattr headers" "$LINENO" 5
fi
done
@@ -14452,6 +14456,31 @@ else
fi
+# Check whether --enable-manpages was given.
+if test "${enable_manpages+set}" = set; then :
+ enableval=$enable_manpages;
+else
+ enable_manpages=yes
+fi
+
+if test "x$enable_manpages" = "xyes"; then :
+
+$as_echo "#define MANPAGE 1" >>confdefs.h
+
+else
+
+$as_echo "#define NMANPAGE 1" >>confdefs.h
+
+fi
+ if test x$enable_manpages = x"yes"; then
+ MANPAGE_TRUE=
+ MANPAGE_FALSE='#'
+else
+ MANPAGE_TRUE='#'
+ MANPAGE_FALSE=
+fi
+
+
have_coverage=no
# Check whether --enable-coverage was given.
if test "${enable_coverage+set}" = set; then :
@@ -14812,6 +14841,10 @@ if test -z "${DEBUG_TRUE}" && test -z "${DEBUG_FALSE}"; then
as_fn_error $? "conditional \"DEBUG\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
+if test -z "${MANPAGE_TRUE}" && test -z "${MANPAGE_FALSE}"; then
+ as_fn_error $? "conditional \"MANPAGE\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
if test -z "${COVERAGE_TRUE}" && test -z "${COVERAGE_FALSE}"; then
as_fn_error $? "conditional \"COVERAGE\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
@@ -15221,7 +15254,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by buxton $as_me 2, which was
+This file was extended by buxton $as_me 3, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -15288,7 +15321,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
-buxton config.status 2
+buxton config.status 3
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
@@ -17084,6 +17117,7 @@ fi
debug: ${enable_debug}
demos: ${enable_demos}
coverage: ${have_coverage}
+ manpages: ${enable_manpages}
" >&5
$as_echo "
buxton $VERSION
@@ -17106,4 +17140,5 @@ $as_echo "
debug: ${enable_debug}
demos: ${enable_demos}
coverage: ${have_coverage}
+ manpages: ${enable_manpages}
" >&6; }
diff --git a/configure.ac b/configure.ac
index f60b4a7..f5a638b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,6 +1,6 @@
AC_PREREQ([2.68])
-AC_INIT([buxton],[2],[william.douglas@intel.com],[buxton],[https://github.com/sofar/buxton])
+AC_INIT([buxton],[3],[william.douglas@intel.com],[buxton],[https://github.com/sofar/buxton])
AM_INIT_AUTOMAKE([foreign -Wall -Werror -Wno-portability silent-rules subdir-objects color-tests no-dist-gzip dist-xz])
AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_FILES([Makefile])
@@ -77,7 +77,7 @@ PKG_CHECK_MODULES([SYSTEMD], [libsystemd-daemon])
# Checks for header files.
AC_FUNC_ALLOCA
AC_HEADER_STDBOOL
-AC_CHECK_HEADERS([attr/xattr.h], [], [AC_MSG_ERROR([Unable to fin xattr headers])])
+AC_CHECK_HEADERS([attr/xattr.h], [], [AC_MSG_ERROR([Unable to find xattr headers])])
AC_CHECK_HEADERS([fcntl.h])
AC_CHECK_HEADERS([gdbm.h], [], [AC_MSG_ERROR([Unable to find gdbm headers])])
AC_CHECK_HEADERS([inttypes.h])
@@ -161,6 +161,13 @@ AS_IF([test "x$enable_debug" = "xyes"],
[AC_DEFINE([NDEBUG], [1], [Debugging and assertions disabled])])
AM_CONDITIONAL([DEBUG], [test x$enable_debug = x"yes"])
+AC_ARG_ENABLE(manpages, AS_HELP_STRING([--enable-manpages], [enable man pages @<:@default=yes@:>@]),
+ [], [enable_manpages=yes])
+AS_IF([test "x$enable_manpages" = "xyes"],
+ [AC_DEFINE([MANPAGE], [1], [Man pages will be included])],
+ [AC_DEFINE([NMANPAGE], [1], [Man pages will not be included])])
+AM_CONDITIONAL([MANPAGE], [test x$enable_manpages = x"yes"])
+
have_coverage=no
AC_ARG_ENABLE(coverage, AS_HELP_STRING([--enable-coverage], [enable test coverage]))
if test "x$enable_coverage" = "xyes" ; then
@@ -232,4 +239,5 @@ AC_MSG_RESULT([
debug: ${enable_debug}
demos: ${enable_demos}
coverage: ${have_coverage}
+ manpages: ${enable_manpages}
])
diff --git a/data/buxton.conf b/data/buxton.conf
index c70d438..bb3c79c 100644
--- a/data/buxton.conf
+++ b/data/buxton.conf
@@ -26,7 +26,7 @@ Priority=1
Type=System
Backend=memory
Priority=99
-Description=A termporary layer for scratch settings and data
+Description=A temporary layer for scratch settings and data
# This will not end up in any file
[user]
diff --git a/demo/gtk_client.c b/demo/gtk_client.c
index 254db17..df828c9 100644
--- a/demo/gtk_client.c
+++ b/demo/gtk_client.c
@@ -78,7 +78,7 @@ static void buxton_test_class_init(BuxtonTestClass *klass)
static void buxton_test_init(BuxtonTest *self)
{
- GtkWidget *header, *info, *layout;
+ GtkWidget *info, *layout;
GtkWidget *label, *container, *box, *box2;
GtkWidget *entry, *button;
GtkStyleContext *style;
@@ -136,12 +136,6 @@ static void buxton_test_init(BuxtonTest *self)
g_signal_connect(button, "clicked", G_CALLBACK(update_key), self);
gtk_box_pack_start(GTK_BOX(box2), button, FALSE, FALSE, 0);
- /* Integrate with Mutter userd desktops */
- header = gtk_header_bar_new();
- gtk_header_bar_set_title(GTK_HEADER_BAR(header), "BuxtonTest");
- gtk_header_bar_set_show_close_button(GTK_HEADER_BAR(header), TRUE);
- gtk_window_set_titlebar(GTK_WINDOW(self), header);
-
gtk_widget_show_all(GTK_WIDGET(self));
gtk_widget_grab_focus(button);
@@ -167,7 +161,10 @@ static void buxton_test_dispose(GObject *object)
g_source_remove(self->tag);
self->tag = 0;
}
- buxton_close(self->client);
+ if (self->client) {
+ buxton_close(self->client);
+ self->client = NULL;
+ }
/* Destruct */
G_OBJECT_CLASS (buxton_test_parent_class)->dispose (object);
}
@@ -245,8 +242,7 @@ static void update_value(BuxtonTest *self)
if (buxton_get_value(self->client, key,
buxton_callback, self, false)) {
- /* Buxton disconnects us when this happens. ##FIXME##
- * We force a reconnect */
+ //FIXME: We force reconnect as Buxton disconnects us here
report_error(self, "Cannot retrieve value");
buxton_close(self->client);
self->fd = -1;
diff --git a/demo/helloget.c b/demo/helloget.c
index 27cf132..aceeec1 100644
--- a/demo/helloget.c
+++ b/demo/helloget.c
@@ -58,6 +58,10 @@ int main(void)
return -1;
}
+/*
+ * A fully qualified key-name is being created since both group and key-name are not null.
+ * Group: "hello", Key-name: "test", Layer: "user", DataType: INT
+ */
key = buxton_key_create("hello", "test", "user", INT32);
if (!key) {
return -1;
diff --git a/docs/buxton.7 b/docs/buxton.7
index 1e4ff8c..3c3daac 100644
--- a/docs/buxton.7
+++ b/docs/buxton.7
@@ -39,10 +39,6 @@ client applications to use\&. Internally, buxton uses
MAC\&. Also, \fBbuxtonctl\fR(1) is provided for interactive use and
for use in shell scripts\&.
-Minimal examples of client API usage are found in
-\fBbuxton\-examples\fR(7), and an in\-depth overview of buxton is
-found in \fBbuxton\-overview\fR(7)\&.
-
.SH "COPYRIGHT"
.PP
Copyright 2014 Intel Corporation\&. License: Creative Commons
@@ -52,9 +48,7 @@ Attribution\-ShareAlike 3.0 Unported\s-2\u[2]\d\s+2\&.
.PP
\fBbuxtonctl\fR(1),
\fBbuxtond\fR(8),
-\fBbuxton\-api\fR(7),
-\fBbuxton\-examples\fR(7),
-\fBbuxton\-overview\fR(7)
+\fBbuxton\-api\fR(7)
.SH "NOTES"
.IP " 1." 4
diff --git a/docs/buxton.conf.5 b/docs/buxton.conf.5
index 968d862..d3a2485 100644
--- a/docs/buxton.conf.5
+++ b/docs/buxton.conf.5
@@ -92,6 +92,12 @@ The priority of the layer\&. Accepted values are integers greater
than or equal to 0 (zero), where 0 is the lowest\-priority value\&.
.RE
.PP
+\fIAccess=\fR
+.RS 4
+The access type of the layer\&. Accepted values are "read\-write" and
+"read\-only"\&. This is an optional field that defaults to "read\-write"\&.
+.RE
+.PP
\fIDescription=\fR
.RS 4
A human\-readable description for the given layer\&.
diff --git a/docs/buxton_key_create.3 b/docs/buxton_key_create.3
index b7080d0..928dc0f 100644
--- a/docs/buxton_key_create.3
+++ b/docs/buxton_key_create.3
@@ -86,9 +86,9 @@ return STRING, since buxton treats groups as strings internally\&.
Calling \fBbuxton_key_get_name\fR(3) for a group will return NULL,
since the name field is not used for groups\&.
-When the client no longer needs a BuxtonKey, its memory should freed
-by calling \fBbuxton_key_free\fR(3)\&. This function takes a single
-argument, the BuxtonKey to be freed\&.
+All BuxtonKey's are freed automatically on buxton_close, but can
+be freed manually if desired by calling \fBbuxton_key_free\fR(3)\&.
+This function takes a single argument, the BuxtonKey to be freed\&.
.SH "COPYRIGHT"
.PP
diff --git a/docs/buxton_open.3 b/docs/buxton_open.3
index e7a4d83..6e4d7ad 100644
--- a/docs/buxton_open.3
+++ b/docs/buxton_open.3
@@ -43,8 +43,8 @@ buxton daemon, \fBbuxtond\fR(8)\&. Clients must call \fBbuxton_open\fR(3), to
create a new connection to the daemon\&. Effectively, creating this connection
registers the client with the daemon, allowing the client to make configuration
changes, queries, etc\&. This function requires one argument, \fIclient\fR, a
-pointer to a BuxtonClient owned by the client\&. It returns 0 on success,
-and a non-zero status code on failure\&.
+pointer to a BuxtonClient owned by the client\&. It returns a file descriptor >=0 on success,
+and a negative status code on failure\&.
To terminate this connection, the client must call \fBbuxton_close\fR(3)\&. The
required argument is a reference to the same BuxtonClient passed to
diff --git a/src/cli/client.c b/src/cli/client.c
index 74deb25..decb4dd 100644
--- a/src/cli/client.c
+++ b/src/cli/client.c
@@ -162,7 +162,7 @@ bool cli_set_value(BuxtonControl *control, BuxtonDataType type,
char *one, char *two, char *three, char *four)
{
BuxtonString value;
- _cleanup_buxton_key_ BuxtonKey key;
+ BuxtonKey key;
BuxtonData set;
bool ret = false;
@@ -402,7 +402,7 @@ void get_value_callback(BuxtonResponse response, void *data)
bool cli_get_value(BuxtonControl *control, BuxtonDataType type,
char *one, char *two, char *three, __attribute__((unused)) char * four)
{
- _cleanup_buxton_key_ BuxtonKey key;
+ BuxtonKey key;
BuxtonData get;
_cleanup_free_ char *prefix = NULL;
_cleanup_free_ char *group = NULL;
@@ -410,14 +410,21 @@ bool cli_get_value(BuxtonControl *control, BuxtonDataType type,
BuxtonString dlabel;
bool ret = false;
int32_t ret_val;
+ int r;
memzero((void*)&get, sizeof(BuxtonData));
if (three != NULL) {
key = buxton_key_create(two, three, one, type);
- asprintf(&prefix, "[%s] ", one);
+ r = asprintf(&prefix, "[%s] ", one);
+ if (!r) {
+ abort();
+ }
} else {
key = buxton_key_create(one, two, NULL, type);
- asprintf(&prefix, " ");
+ r = asprintf(&prefix, " ");
+ if (!r) {
+ abort();
+ }
}
if (!key) {
@@ -549,7 +556,7 @@ bool cli_unset_value(BuxtonControl *control,
char *one, char *two, char *three,
__attribute__((unused)) char *four)
{
- _cleanup_buxton_key_ BuxtonKey key;
+ BuxtonKey key;
key = buxton_key_create(two, three, one, type);
diff --git a/src/core/daemon.c b/src/core/daemon.c
index f3b3660..ae5ba9c 100644
--- a/src/core/daemon.c
+++ b/src/core/daemon.c
@@ -266,9 +266,7 @@ bool buxtond_handle_message(BuxtonDaemon *self, client_list_item *client, size_t
abort();
}
buxton_log("Failed to serialize set response message\n");
- //FIXME abort here because serialization
- //failed for a message generated by the daemon
- goto end;
+ abort();
}
break;
case BUXTON_CONTROL_SET_LABEL:
@@ -280,7 +278,7 @@ bool buxtond_handle_message(BuxtonDaemon *self, client_list_item *client, size_t
abort();
}
buxton_log("Failed to serialize set_label response message\n");
- goto end;
+ abort();
}
break;
case BUXTON_CONTROL_CREATE_GROUP:
@@ -292,7 +290,7 @@ bool buxtond_handle_message(BuxtonDaemon *self, client_list_item *client, size_t
abort();
}
buxton_log("Failed to serialize create_group response message\n");
- goto end;
+ abort();
}
break;
case BUXTON_CONTROL_REMOVE_GROUP:
@@ -304,7 +302,7 @@ bool buxtond_handle_message(BuxtonDaemon *self, client_list_item *client, size_t
abort();
}
buxton_log("Failed to serialize remove_group response message\n");
- goto end;
+ abort();
}
break;
case BUXTON_CONTROL_GET:
@@ -319,7 +317,7 @@ bool buxtond_handle_message(BuxtonDaemon *self, client_list_item *client, size_t
abort();
}
buxton_log("Failed to serialize get response message\n");
- goto end;
+ abort();
}
break;
case BUXTON_CONTROL_UNSET:
@@ -331,7 +329,7 @@ bool buxtond_handle_message(BuxtonDaemon *self, client_list_item *client, size_t
abort();
}
buxton_log("Failed to serialize unset response message\n");
- goto end;
+ abort();
}
break;
case BUXTON_CONTROL_LIST:
@@ -351,7 +349,7 @@ bool buxtond_handle_message(BuxtonDaemon *self, client_list_item *client, size_t
abort();
}
buxton_log("Failed to serialize list response message\n");
- goto end;
+ abort();
}
break;
case BUXTON_CONTROL_NOTIFY:
@@ -363,7 +361,7 @@ bool buxtond_handle_message(BuxtonDaemon *self, client_list_item *client, size_t
abort();
}
buxton_log("Failed to serialize notify response message\n");
- goto end;
+ abort();
}
break;
case BUXTON_CONTROL_UNNOTIFY:
@@ -380,7 +378,7 @@ bool buxtond_handle_message(BuxtonDaemon *self, client_list_item *client, size_t
abort();
}
buxton_log("Failed to serialize unnotify response message\n");
- goto end;
+ abort();
}
break;
default:
@@ -440,11 +438,6 @@ void buxtond_notify_clients(BuxtonDaemon *self, client_list_item *client,
}
BUXTON_LIST_FOREACH(list, elem) {
- if (!elem) {
- //FIXME abort here since NULL elements
- //shouldn't be added to the list
- break;
- }
nitem = elem->data;
int c = 1;
__attribute__((unused)) bool unused;
@@ -496,7 +489,7 @@ void buxtond_notify_clients(BuxtonDaemon *self, client_list_item *client,
break;
default:
buxton_log("Internal state corruption: Notification data type invalid\n");
- return;
+ abort();
}
}
@@ -537,8 +530,7 @@ void buxtond_notify_clients(BuxtonDaemon *self, client_list_item *client,
abort();
}
buxton_log("Failed to serialize notification\n");
- //FIXME abort here serialize message error
- return;
+ abort();
}
buxton_debug("Notification to %d of key change (%s)\n", nitem->client->fd,
key_name);
@@ -747,11 +739,14 @@ void register_notification(BuxtonDaemon *self, client_list_item *client,
int32_t *status)
{
BuxtonList *n_list = NULL;
+ BuxtonList *key_list = NULL;
BuxtonNotification *nitem;
BuxtonData *old_data = NULL;
int32_t key_status;
char *key_name;
int r;
+ uint64_t *fd = NULL;
+ char *key_name_copy = NULL;
assert(self);
assert(client);
@@ -780,8 +775,13 @@ void register_notification(BuxtonDaemon *self, client_list_item *client,
if (r == -1) {
abort();
}
- n_list = hashmap_get(self->notify_mapping, key_name);
+ key_name_copy = strdup(key_name);
+ if (!key_name_copy) {
+ abort();
+ }
+
+ n_list = hashmap_get(self->notify_mapping, key_name);
if (!n_list) {
if (!buxton_list_append(&n_list, nitem)) {
abort();
@@ -796,6 +796,28 @@ void register_notification(BuxtonDaemon *self, client_list_item *client,
abort();
}
}
+
+ fd = malloc0(sizeof(uint64_t));
+ if (!fd) {
+ abort();
+ }
+ *fd = (uint64_t)client->fd;
+
+ key_list = hashmap_get(self->client_key_mapping, fd);
+ if (!key_list) {
+ if (!buxton_list_append(&key_list, key_name_copy)) {
+ abort();
+ }
+ if(hashmap_put(self->client_key_mapping, fd, key_list) < 0) {
+ abort();
+ }
+ } else {
+ if (!buxton_list_append(&key_list, key_name_copy)) {
+ abort();
+ }
+ free(fd);
+ }
+
*status = 0;
}
@@ -803,12 +825,16 @@ uint32_t unregister_notification(BuxtonDaemon *self, client_list_item *client,
_BuxtonKey *key, int32_t *status)
{
BuxtonList *n_list = NULL;
+ BuxtonList *key_list = NULL;
BuxtonList *elem = NULL;
BuxtonNotification *nitem, *citem = NULL;
uint32_t msgid = 0;
_cleanup_free_ char *key_name = NULL;
void *old_key_name;
int r;
+ char *client_keyname = NULL;
+ uint64_t fd = 0;
+ void *old_fd = NULL;
assert(self);
assert(client);
@@ -831,8 +857,8 @@ uint32_t unregister_notification(BuxtonDaemon *self, client_list_item *client,
/* Find the list item for this client */
if (nitem->client == client) {
citem = nitem;
+ break;
}
- break;
};
/* Client hasn't registered for notifications on this key */
@@ -840,6 +866,29 @@ uint32_t unregister_notification(BuxtonDaemon *self, client_list_item *client,
return 0;
}
+ fd = (uint64_t)client->fd;
+ /* Remove key name from client hashmap */
+ key_list = hashmap_get2(self->client_key_mapping, &fd, &old_fd);
+
+ if (!key_list || !old_fd) {
+ abort();
+ }
+
+ BUXTON_LIST_FOREACH(key_list, elem) {
+ if (!strcmp(elem->data, key_name)) {
+ client_keyname = elem->data;
+ break;
+ }
+ };
+
+ if (client_keyname) {
+ buxton_list_remove(&key_list, client_keyname, true);
+ if (!key_list) {
+ hashmap_remove(self->client_key_mapping, &fd);
+ free(old_fd);
+ }
+ }
+
msgid = citem->msgid;
/* Remove client from notifications */
free_buxton_data(&(citem->old_data));
@@ -900,19 +949,20 @@ bool identify_client(client_list_item *cl)
cmhp = CMSG_FIRSTHDR(&msgh);
if (cmhp == NULL || cmhp->cmsg_len != CMSG_LEN(sizeof(struct ucred))) {
- //FIXME figure out if abort here since socket setup
- //didn't work quite right
- return false;
+ buxton_log("Invalid cmessage header from kernel\n");
+ abort();
}
if (cmhp->cmsg_level != SOL_SOCKET || cmhp->cmsg_type != SCM_CREDENTIALS) {
- return false;
+ buxton_log("Missing credentials on socket\n");
+ abort();
}
ucredp = (struct ucred *) CMSG_DATA(cmhp);
if (getsockopt(cl->fd, SOL_SOCKET, SO_PEERCRED, &cl->cred, &len) == -1) {
- return false;
+ buxton_log("Missing label on socket\n");
+ abort();
}
return true;
@@ -965,7 +1015,7 @@ void del_pollfd(BuxtonDaemon *self, nfds_t i)
self->nfds--;
}
-static void handle_smack_label(client_list_item *cl)
+void handle_smack_label(client_list_item *cl)
{
socklen_t slabel_len = 1;
char *buf = NULL;
@@ -1080,8 +1130,11 @@ bool handle_client(BuxtonDaemon *self, client_list_item *cl, nfds_t i)
abort();
}
}
- if (cl->size != cl->offset) {
+ if (cl->size > cl->offset) {
continue;
+ } else if (cl->size < cl->offset) {
+ buxton_log("Somehow read more bytes than from client requested\n");
+ abort();
}
if (!buxtond_handle_message(self, cl, cl->size)) {
buxton_log("Communication failed with client %d\n", cl->fd);
@@ -1090,6 +1143,8 @@ bool handle_client(BuxtonDaemon *self, client_list_item *cl, nfds_t i)
message_limit--;
if (message_limit) {
+ cl->size = BUXTON_MESSAGE_HEADER_LENGTH;
+ cl->offset = 0;
continue;
}
if (recv(cl->fd, &peek, sizeof(uint16_t), MSG_PEEK | MSG_DONTWAIT) > 0) {
@@ -1112,6 +1167,56 @@ terminate:
void terminate_client(BuxtonDaemon *self, client_list_item *cl, nfds_t i)
{
+ BuxtonList *key_list = NULL;
+ BuxtonList *elem, *notify_elem;
+ char *key_name;
+ void *old_key_name = NULL;
+ void *old_fd = NULL;
+ uint64_t fd = (uint64_t)cl->fd;
+
+ key_list = hashmap_get2(self->client_key_mapping, &fd, &old_fd);
+
+ if (key_list) {
+ buxton_debug("Removing notifications for client before terminating\n");
+ BUXTON_LIST_FOREACH(key_list, elem) {
+ key_name = elem->data;
+ BuxtonList *n_list = NULL;
+
+ n_list = hashmap_get2(self->notify_mapping, key_name, &old_key_name);
+ if (!n_list || !old_key_name) {
+ abort();
+ }
+
+ BuxtonNotification *nitem, *citem = NULL;
+
+ BUXTON_LIST_FOREACH(n_list, notify_elem) {
+ nitem = notify_elem->data;
+ if (nitem->client == cl) {
+ citem = nitem;
+ break;
+ }
+ };
+
+ if (!citem) {
+ abort();
+ }
+
+ /* Remove client from notifications */
+ free_buxton_data(&(citem->old_data));
+ buxton_list_remove(&n_list, citem, true);
+
+ /* If we removed the last item, remove the mapping too */
+ if (!n_list) {
+ (void)hashmap_remove(self->notify_mapping, key_name);
+ free(old_key_name);
+ }
+ };
+ /* Remove key from client hashmap */
+ hashmap_remove(self->client_key_mapping, &fd);
+ free(old_fd);
+ buxton_list_free_all(&key_list);
+ }
+
del_pollfd(self, i);
close(cl->fd);
if (cl->smack_label) {
diff --git a/src/core/daemon.h b/src/core/daemon.h
index 5c6ceaa..4156f92 100644
--- a/src/core/daemon.h
+++ b/src/core/daemon.h
@@ -63,6 +63,7 @@ typedef struct BuxtonDaemon {
struct pollfd *pollfds;
client_list_item *client_list;
Hashmap *notify_mapping;
+ Hashmap *client_key_mapping;
BuxtonControl buxton;
} BuxtonDaemon;
@@ -228,6 +229,13 @@ void add_pollfd(BuxtonDaemon *self, int fd, short events, bool a);
void del_pollfd(BuxtonDaemon *self, nfds_t i);
/**
+ * Setup a client's smack label
+ * @param cl Client to set smack label on
+ * @return None
+ */
+void handle_smack_label(client_list_item *cl);
+
+/**
* Handle a client connection
* @param self buxtond instance being run
* @param cl The currently activate client
diff --git a/src/core/main.c b/src/core/main.c
index f3ad523..94bbb6a 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -81,6 +81,8 @@ int main(int argc, char *argv[])
BuxtonList *map_list = NULL;
Iterator iter;
char *notify_key;
+ BuxtonList *key_list = NULL;
+ uint64_t *client_fd;
static struct option opts[] = {
{ "config-file", 1, NULL, 'c' },
@@ -168,6 +170,8 @@ int main(int argc, char *argv[])
/* For client notifications */
self.notify_mapping = hashmap_new(string_hash_func, string_compare_func);
+ /* For keeping track of keys a client is registered to*/
+ self.client_key_mapping = hashmap_new(uint64_hash_func, uint64_compare_func);
/* Store a list of connected clients */
LIST_HEAD_INIT(client_list_item, self.client_list);
@@ -389,7 +393,14 @@ int main(int argc, char *argv[])
buxton_list_free_all(&map_list);
}
+ /* Clean up key lists */
+ HASHMAP_FOREACH_KEY(key_list, client_fd, self.client_key_mapping, iter) {
+ hashmap_remove(self.client_key_mapping, client_fd);
+ buxton_list_free_all(&key_list);
+ free(client_fd);
+ }
hashmap_free(self.notify_mapping);
+ hashmap_free(self.client_key_mapping);
buxton_direct_close(&self.buxton);
return EXIT_SUCCESS;
}
diff --git a/src/db/gdbm.c b/src/db/gdbm.c
index 0892b54..e8988c4 100644
--- a/src/db/gdbm.c
+++ b/src/db/gdbm.c
@@ -47,6 +47,25 @@ static char *key_get_name(BuxtonString *key)
return c;
}
+static GDBM_FILE try_open_database(char *path, const int oflag)
+{
+ GDBM_FILE db = gdbm_open(path, 0, oflag, S_IRUSR | S_IWUSR, NULL);
+ /* handle open under write mode failing by falling back to
+ reader mode */
+ if (!db && (gdbm_errno == GDBM_FILE_OPEN_ERROR)) {
+ db = gdbm_open(path, 0, GDBM_READER, S_IRUSR | S_IWUSR, NULL);
+ buxton_debug("Attempting to fallback to opening db as read-only\n");
+ errno = EROFS;
+ } else {
+ if (!db) {
+ abort();
+ }
+ /* Must do this as gdbm_open messes with errno */
+ errno = 0;
+ }
+ return db;
+}
+
/* Open or create databases on the fly */
static GDBM_FILE db_for_resource(BuxtonLayer *layer)
{
@@ -54,6 +73,8 @@ static GDBM_FILE db_for_resource(BuxtonLayer *layer)
_cleanup_free_ char *path = NULL;
char *name = NULL;
int r;
+ int oflag = layer->readonly ? GDBM_READER : GDBM_WRCREAT;
+ int save_errno = 0;
assert(layer);
assert(_resources);
@@ -73,7 +94,9 @@ static GDBM_FILE db_for_resource(BuxtonLayer *layer)
if (!path) {
abort();
}
- db = gdbm_open(path, 0, GDBM_WRCREAT, 0600, NULL);
+
+ db = try_open_database(path, oflag);
+ save_errno = errno;
if (!db) {
free(name);
buxton_log("Couldn't create db for path: %s\n", path);
@@ -88,6 +111,7 @@ static GDBM_FILE db_for_resource(BuxtonLayer *layer)
free(name);
}
+ errno = save_errno;
return db;
}
@@ -133,8 +157,8 @@ static int set_value(BuxtonLayer *layer, _BuxtonKey *key, BuxtonData *data,
}
db = db_for_resource(layer);
- if (!db) {
- ret = ENOENT;
+ if (!db || errno) {
+ ret = errno;
goto end;
}
@@ -158,6 +182,9 @@ static int set_value(BuxtonLayer *layer, _BuxtonKey *key, BuxtonData *data,
value.dptr = (char *)data_store;
value.dsize = (int)size;
ret = gdbm_store(db, key_data, value, GDBM_REPLACE);
+ if (ret && gdbm_errno == GDBM_READER_CANT_STORE) {
+ ret = EROFS;
+ }
assert(ret == 0);
end:
@@ -282,16 +309,22 @@ static int unset_value(BuxtonLayer *layer,
key_data.dsize = (int)key->group.length;
}
+ errno = 0;
db = db_for_resource(layer);
- if (!db) {
- ret = ENOENT;
+ if (!db || gdbm_errno) {
+ ret = EROFS;
goto end;
}
- /* Negative value means the key wasn't found */
ret = gdbm_delete(db, key_data);
- if (ret == -1) {
- ret = ENOENT;
+ if (ret) {
+ if (gdbm_errno == GDBM_READER_CANT_DELETE) {
+ ret = EROFS;
+ } else if (gdbm_errno == GDBM_ITEM_NOT_FOUND) {
+ ret = ENOENT;
+ } else {
+ abort();
+ }
}
end:
diff --git a/src/libbuxton/lbuxton.c b/src/libbuxton/lbuxton.c
index 56376bf..3def14b 100644
--- a/src/libbuxton/lbuxton.c
+++ b/src/libbuxton/lbuxton.c
@@ -41,6 +41,7 @@
#include "protocol.h"
#include "util.h"
+static Hashmap *key_hash = NULL;
int buxton_set_conf_file(char *path)
{
@@ -113,6 +114,19 @@ int buxton_open(BuxtonClient *client)
void buxton_close(BuxtonClient client)
{
_BuxtonClient *c;
+ BuxtonKey key = NULL;
+ Iterator i;
+
+ /* Free all remaining allocated keys */
+ HASHMAP_FOREACH_KEY(key, key, key_hash, i) {
+ hashmap_remove_value(key_hash, key, key);
+ buxton_key_free(key);
+ }
+
+ hashmap_free(key_hash);
+
+ key_hash = NULL;
+
if (!client) {
return;
}
@@ -442,6 +456,14 @@ BuxtonKey buxton_key_create(char *group, char *name, char *layer,
goto fail;
}
+ if (!key_hash) {
+ /* Create on hashmap on first call to key_create */
+ key_hash = hashmap_new(trivial_hash_func, trivial_compare_func);
+ if (!key_hash) {
+ return NULL;
+ }
+ }
+
g = strdup(group);
if (!g) {
goto fail;
@@ -484,6 +506,9 @@ BuxtonKey buxton_key_create(char *group, char *name, char *layer,
}
key->type = type;
+ /* Add new keys to internal hash for cleanup on close */
+ hashmap_put(key_hash, key, key);
+
return (BuxtonKey)key;
fail:
@@ -545,6 +570,8 @@ void buxton_key_free(BuxtonKey key)
return;
}
+ hashmap_remove_value(key_hash, key, key);
+
free(k->group.value);
free(k->name.value);
free(k->layer.value);
diff --git a/src/security/smack.c b/src/security/smack.c
index 2f85b3f..8927236 100644
--- a/src/security/smack.c
+++ b/src/security/smack.c
@@ -59,7 +59,7 @@ bool buxton_cache_smack_rules(void)
abort();
}
- /* FIXME: should check for a proper mount point instead */
+ //FIXME: should check for a proper mount point instead
if ((stat(SMACK_MOUNT_DIR, &buf) == -1) || !S_ISDIR(buf.st_mode)) {
buxton_log("Smack filesystem not detected; disabling Smack checks\n");
have_smack = false;
diff --git a/src/shared/backend.c b/src/shared/backend.c
index 0c5b90c..29eb8f6 100644
--- a/src/shared/backend.c
+++ b/src/shared/backend.c
@@ -67,6 +67,11 @@ void buxton_init_layers(BuxtonConfig *config)
free(config_layers);
}
+static bool is_read_only(ConfigLayer *conf_layer)
+{
+ return strcmp(conf_layer->access, "read-only") == 0;
+}
+
static BuxtonLayer *buxton_layer_new(ConfigLayer *conf_layer)
{
BuxtonLayer *out;
@@ -111,6 +116,7 @@ static BuxtonLayer *buxton_layer_new(ConfigLayer *conf_layer)
}
}
+ out->readonly = is_read_only(conf_layer);
out->priority = conf_layer->priority;
return out;
fail:
diff --git a/src/shared/backend.h b/src/shared/backend.h
index 24c2b63..edcde53 100644
--- a/src/shared/backend.h
+++ b/src/shared/backend.h
@@ -61,6 +61,7 @@ typedef struct BuxtonLayer {
uid_t uid; /**<User ID for layers of type LAYER_USER */
int priority; /**<Priority of this layer */
char *description; /**<Description of this layer */
+ bool readonly; /**<Layer is readonly or not */
} BuxtonLayer;
/**
diff --git a/src/shared/configurator.c b/src/shared/configurator.c
index 51306b0..9aa0160 100644
--- a/src/shared/configurator.c
+++ b/src/shared/configurator.c
@@ -114,6 +114,8 @@ static inline char *_strdup(const char* string)
*
* @param section the section of the ini file
* @param name the name of the key
+ * @param required if key required or not
+ * @param def default value for nonrequired setting
*
* @note This function may abort()
*
@@ -122,15 +124,16 @@ static inline char *_strdup(const char* string)
* Something is really wrong and even if we could recover, the system
* is not working correctly.
*/
-static char *get_ini_string(char *section, char *name)
+static char *get_ini_string(char *section, char *name, bool required,
+ char *def)
{
char buf[PATH_MAX];
char *s;
assert(conf.ini);
snprintf(buf, sizeof(buf), "%s:%s", section, name);
- s = iniparser_getstring(conf.ini, buf, NULL);
- if (s == NULL) {
+ s = iniparser_getstring(conf.ini, buf, def);
+ if (s == NULL && required) {
abort();
}
return s;
@@ -141,18 +144,26 @@ static char *get_ini_string(char *section, char *name)
*
* @param section the section of the ini file
* @param name the name of the key
+ * @param required if key required or not
+ * @param def default value for nonrequired setting
*
* @note inlined b/c only used once and why not.
*
* @return the value
*/
-static inline int get_ini_int(char *section, char *name)
+static inline int get_ini_int(char *section, char *name, bool required,
+ int def)
{
char buf[PATH_MAX];
+ int exists;
assert(conf.ini);
snprintf(buf, sizeof(buf), "%s:%s", section, name);
- return iniparser_getint(conf.ini, buf, -1);
+ exists = iniparser_find_entry(conf.ini, buf);
+ if (!exists && required) {
+ abort();
+ }
+ return iniparser_getint(conf.ini, buf, def);
}
/**
@@ -299,10 +310,16 @@ int buxton_key_get_layers(ConfigLayer **layers)
continue;
}
_layers[j].name = section_name;
- _layers[j].description = get_ini_string(section_name, "Description");
- _layers[j].backend = get_ini_string(section_name, "Backend");
- _layers[j].type = get_ini_string(section_name, "Type");
- _layers[j].priority = get_ini_int(section_name, "Priority");
+ _layers[j].description = get_ini_string(section_name,
+ "Description", true, NULL);
+ _layers[j].backend = get_ini_string(section_name, "Backend",
+ true, NULL);
+ _layers[j].type = get_ini_string(section_name, "Type", true,
+ NULL);
+ _layers[j].priority = get_ini_int(section_name, "Priority",
+ true, 0);
+ _layers[j].access = get_ini_string(section_name, "Access",
+ false, "read-write");
j++;
}
*layers = _layers;
diff --git a/src/shared/configurator.h b/src/shared/configurator.h
index e6f3cef..be25a1a 100644
--- a/src/shared/configurator.h
+++ b/src/shared/configurator.h
@@ -40,6 +40,7 @@ typedef struct ConfigLayer {
char *type;
char *backend;
char *description;
+ char *access;
int priority;
} ConfigLayer;
diff --git a/src/shared/direct.c b/src/shared/direct.c
index e93e290..67d3dbd 100644
--- a/src/shared/direct.c
+++ b/src/shared/direct.c
@@ -287,13 +287,18 @@ bool buxton_direct_set_value(BuxtonControl *control,
goto fail;
}
+ if (layer->readonly) {
+ buxton_debug("Read-only layer!\n");
+ goto fail;
+ }
+
backend = backend_for_layer(config, layer);
assert(backend);
layer->uid = control->client.uid;
ret = backend->set_value(layer, key, data, l);
if (ret) {
- buxton_debug("set value failed\n");
+ buxton_debug("set value failed: %s\n", strerror(ret));
} else {
r = true;
}
@@ -323,11 +328,16 @@ bool buxton_direct_set_label(BuxtonControl *control,
goto fail;
}
+ if (layer->readonly) {
+ buxton_debug("Read-only layer!\n");
+ goto fail;
+ }
+
if (layer->type == LAYER_SYSTEM) {
char *root_check = getenv(BUXTON_ROOT_CHECK_ENV);
bool skip_check = (root_check && streq(root_check, "0"));
- /* FIXME: should check client's capability set instead of UID */
+ //FIXME: should check client's capability set instead of UID
if (control->client.uid != 0 && !skip_check) {
buxton_debug("Not permitted to create group '%s'\n", key->group.value);
goto fail;
@@ -343,7 +353,7 @@ bool buxton_direct_set_label(BuxtonControl *control,
layer->uid = control->client.uid;
ret = backend->set_value(layer, key, NULL, label);
if (ret) {
- buxton_debug("set label failed\n");
+ buxton_debug("set label failed: %s\n", strerror(ret));
} else {
r = true;
}
@@ -393,11 +403,16 @@ bool buxton_direct_create_group(BuxtonControl *control,
goto fail;
}
+ if (layer->readonly) {
+ buxton_debug("Read-only layer!\n");
+ goto fail;
+ }
+
if (layer->type == LAYER_SYSTEM) {
char *root_check = getenv(BUXTON_ROOT_CHECK_ENV);
bool skip_check = (root_check && streq(root_check, "0"));
- /* FIXME: should check client's capability set instead of UID */
+ //FIXME: should check client's capability set instead of UID
if (control->client.uid != 0 && !skip_check) {
buxton_debug("Not permitted to create group '%s'\n", key->group.value);
goto fail;
@@ -434,7 +449,7 @@ bool buxton_direct_create_group(BuxtonControl *control,
layer->uid = control->client.uid;
ret = backend->set_value(layer, key, data, dlabel);
if (ret) {
- buxton_debug("create group failed\n");
+ buxton_debug("create group failed: %s\n", strerror(ret));
} else {
r = true;
}
@@ -473,11 +488,16 @@ bool buxton_direct_remove_group(BuxtonControl *control,
goto fail;
}
+ if (layer->readonly) {
+ buxton_debug("Read-ony layer!\n");
+ goto fail;
+ }
+
if (layer->type == LAYER_SYSTEM) {
char *root_check = getenv(BUXTON_ROOT_CHECK_ENV);
bool skip_check = (root_check && streq(root_check, "0"));
- /* FIXME: should check client's capability set instead of UID */
+ //FIXME: should check client's capability set instead of UID
if (control->client.uid != 0 && !skip_check) {
buxton_debug("Not permitted to remove group '%s'\n", key->group.value);
goto fail;
@@ -502,7 +522,7 @@ bool buxton_direct_remove_group(BuxtonControl *control,
ret = backend->unset_value(layer, key, NULL, NULL);
if (ret) {
- buxton_debug("remove group failed\n");
+ buxton_debug("remove group failed: %s\n", strerror(ret));
} else {
r = true;
}
@@ -603,13 +623,17 @@ bool buxton_direct_unset_value(BuxtonControl *control,
return false;
}
+ if (layer->readonly) {
+ buxton_debug("Read-only layer!\n");
+ return false;
+ }
backend = backend_for_layer(config, layer);
assert(backend);
layer->uid = control->client.uid;
ret = backend->unset_value(layer, key, NULL, NULL);
if (ret) {
- buxton_debug("Unset value failed\n");
+ buxton_debug("Unset value failed: %s\n", strerror(ret));
} else {
r = true;
}
diff --git a/src/shared/protocol.c b/src/shared/protocol.c
index fdf73c4..3842399 100644
--- a/src/shared/protocol.c
+++ b/src/shared/protocol.c
@@ -237,6 +237,17 @@ fail:
return false;
}
+void lock_mutex(void)
+{
+ buxton_debug("Value of mutex %d", callback_guard.__data.__lock);
+ pthread_mutex_lock(&callback_guard);
+}
+
+void unlock_mutex(void)
+{
+ pthread_mutex_unlock(&callback_guard);
+}
+
void handle_callback_response(BuxtonControlMessage msg, uint32_t msgid,
BuxtonData *list, size_t count)
{
@@ -253,8 +264,14 @@ void handle_callback_response(BuxtonControlMessage msg, uint32_t msgid,
return;
}
+ /*
+ * unlocking mutex to be able to call other client api's
+ * in notification callbacks
+ */
+ (void)pthread_mutex_unlock(&callback_guard);
run_callback((BuxtonCallback)(nv->cb), nv->data, count, list,
BUXTON_CONTROL_CHANGED, nv->key);
+ (void)pthread_mutex_lock(&callback_guard);
return;
}
diff --git a/src/shared/protocol.h b/src/shared/protocol.h
index b3e789e..1e2aea6 100644
--- a/src/shared/protocol.h
+++ b/src/shared/protocol.h
@@ -230,6 +230,13 @@ bool buxton_wire_unregister_notification(_BuxtonClient *client,
void include_protocol(void);
+/**
+ * These functions are internal and are used in the test cases only for handle_client_check
+ */
+void lock_mutex(void);
+void unlock_mutex(void);
+
+
/*
* Editor modelines - http://www.wireshark.org/tools/modelines.html
*
diff --git a/test/check_buxton.c b/test/check_buxton.c
index 883ae7e..0033899 100644
--- a/test/check_buxton.c
+++ b/test/check_buxton.c
@@ -161,7 +161,7 @@ START_TEST(buxton_direct_get_value_for_layer_check)
"Retrieving value from buxton gdbm backend failed.");
fail_if(result.type != STRING,
"Buxton gdbm backend returned incorrect result type.");
- //FIXME get label test figured out
+ //FIXME: get label test figured out
fail_if(strcmp(result.store.d_string.value, "bxt_test_value") != 0,
"Buxton gdbm returned a different value to that set.");
if (result.store.d_string.value)
@@ -195,7 +195,7 @@ START_TEST(buxton_direct_get_value_check)
"Retrieving value from buxton gdbm backend failed.");
fail_if(result.type != STRING,
"Buxton gdbm backend returned incorrect result type.");
- //FIXME figure out label check
+ //FIXME: figure out label check
fail_if(strcmp(result.store.d_string.value, "bxt_test_value2") != 0,
"Buxton gdbm returned a different value to that set.");
if (result.store.d_string.value)
@@ -619,13 +619,17 @@ START_TEST(handle_callback_response_check)
fail_if(test_data, "Failed to set notify duplicate msgid");
test_data = true;
+ lock_mutex();
handle_callback_response(BUXTON_CONTROL_CHANGED, msgid, good, 1);
fail_if(test_data, "Failed to set changed data");
+ unlock_mutex();
/* ensure we don't remove callback on changed */
test_data = true;
+ lock_mutex();
handle_callback_response(BUXTON_CONTROL_CHANGED, msgid, good, 1);
fail_if(test_data, "Failed to set changed data");
+ unlock_mutex();
test_data = true;
msgid = 6;
@@ -653,8 +657,10 @@ START_TEST(handle_callback_response_check)
test_data = true;
msgid = 4;
+ lock_mutex();
handle_callback_response(BUXTON_CONTROL_CHANGED, msgid, good, 1);
fail_if(!test_data, "Didn't remove changed callback");
+ unlock_mutex();
cleanup_callbacks();
free(dest);
diff --git a/test/check_daemon.c b/test/check_daemon.c
index 72a6d66..90775a8 100644
--- a/test/check_daemon.c
+++ b/test/check_daemon.c
@@ -38,6 +38,7 @@
#include "log.h"
#include "smack.h"
#include "util.h"
+#include "buxtonlist.h"
#ifdef NDEBUG
#error "re-run configure with --enable-debug"
@@ -882,15 +883,14 @@ START_TEST(set_label_check)
else
client.smack_label = NULL;
server.buxton.client.uid = 0;
- key.layer = buxton_string_pack("test-gdbm-user");
+ key.layer = buxton_string_pack("test-gdbm");
key.group = buxton_string_pack("daemon-check");
key.type = STRING;
value.type = STRING;
value.store.d_string = buxton_string_pack("*");
- key.layer = buxton_string_pack("test-gdbm");
set_label(&server, &client, &key, &value, &status);
- fail_if(status != 0, "Failed to set label 2");
+ fail_if(status != 0, "Failed to set label");
buxton_direct_close(&server.buxton);
}
END_TEST
@@ -1002,6 +1002,8 @@ START_TEST(register_notification_check)
"Failed to open buxton direct connection");
server.notify_mapping = hashmap_new(string_hash_func, string_compare_func);
fail_if(!server.notify_mapping, "Failed to allocate hashmap");
+ server.client_key_mapping = hashmap_new(uint64_hash_func, uint64_compare_func);
+ fail_if(!server.client_key_mapping, "Failed to allocate hashmap");
key.group = buxton_string_pack("group");
key.name = buxton_string_pack("name");
@@ -1030,6 +1032,7 @@ START_TEST(register_notification_check)
fail_if(status == 0, "Registered notification with key not in db");
hashmap_free(server.notify_mapping);
+ hashmap_free(server.client_key_mapping);
buxton_direct_close(&server.buxton);
}
END_TEST
@@ -1131,6 +1134,8 @@ START_TEST(buxtond_handle_message_create_group_check)
"Failed to open buxton direct connection");
daemon.notify_mapping = hashmap_new(string_hash_func, string_compare_func);
fail_if(!daemon.notify_mapping, "Failed to allocate hashmap");
+ daemon.client_key_mapping = hashmap_new(uint64_hash_func, uint64_compare_func);
+ fail_if(!daemon.client_key_mapping, "Failed to allocate hashmap");
out_list1 = buxton_array_new();
fail_if(!out_list1, "Failed to allocate list");
@@ -1195,6 +1200,7 @@ START_TEST(buxtond_handle_message_create_group_check)
cleanup_callbacks();
close(client);
hashmap_free(daemon.notify_mapping);
+ hashmap_free(daemon.client_key_mapping);
buxton_direct_close(&daemon.buxton);
buxton_array_free(&out_list1, NULL);
buxton_array_free(&out_list2, NULL);
@@ -1239,6 +1245,8 @@ START_TEST(buxtond_handle_message_remove_group_check)
"Failed to open buxton direct connection");
daemon.notify_mapping = hashmap_new(string_hash_func, string_compare_func);
fail_if(!daemon.notify_mapping, "Failed to allocate hashmap");
+ daemon.client_key_mapping = hashmap_new(uint64_hash_func, uint64_compare_func);
+ fail_if(!daemon.client_key_mapping, "Failed to allocate hashmap");
data1.type = STRING;
data1.store.d_string = buxton_string_pack("base");
@@ -1272,6 +1280,7 @@ START_TEST(buxtond_handle_message_remove_group_check)
cleanup_callbacks();
close(client);
hashmap_free(daemon.notify_mapping);
+ hashmap_free(daemon.client_key_mapping);
buxton_direct_close(&daemon.buxton);
buxton_array_free(&out_list, NULL);
}
@@ -1315,6 +1324,8 @@ START_TEST(buxtond_handle_message_set_label_check)
"Failed to open buxton direct connection");
daemon.notify_mapping = hashmap_new(string_hash_func, string_compare_func);
fail_if(!daemon.notify_mapping, "Failed to allocate hashmap");
+ daemon.client_key_mapping = hashmap_new(uint64_hash_func, uint64_compare_func);
+ fail_if(!daemon.client_key_mapping, "Failed to allocate hashmap");
data1.type = STRING;
data1.store.d_string = buxton_string_pack("base");
@@ -1352,6 +1363,7 @@ START_TEST(buxtond_handle_message_set_label_check)
cleanup_callbacks();
close(client);
hashmap_free(daemon.notify_mapping);
+ hashmap_free(daemon.client_key_mapping);
buxton_direct_close(&daemon.buxton);
buxton_array_free(&out_list, NULL);
}
@@ -1395,6 +1407,8 @@ START_TEST(buxtond_handle_message_set_value_check)
"Failed to open buxton direct connection");
daemon.notify_mapping = hashmap_new(string_hash_func, string_compare_func);
fail_if(!daemon.notify_mapping, "Failed to allocate hashmap");
+ daemon.client_key_mapping = hashmap_new(uint64_hash_func, uint64_compare_func);
+ fail_if(!daemon.client_key_mapping, "Failed to allocate hashmap");
data1.type = STRING;
data1.store.d_string = buxton_string_pack("base");
@@ -1442,6 +1456,7 @@ START_TEST(buxtond_handle_message_set_value_check)
cleanup_callbacks();
close(client);
hashmap_free(daemon.notify_mapping);
+ hashmap_free(daemon.client_key_mapping);
buxton_direct_close(&daemon.buxton);
buxton_array_free(&out_list, NULL);
}
@@ -1590,6 +1605,8 @@ START_TEST(buxtond_handle_message_notify_check)
daemon.buxton.client.uid = 1001;
daemon.notify_mapping = hashmap_new(string_hash_func, string_compare_func);
fail_if(!daemon.notify_mapping, "Failed to allocate hashmap");
+ daemon.client_key_mapping = hashmap_new(uint64_hash_func, uint64_compare_func);
+ fail_if(!daemon.client_key_mapping, "Failed to allocate hashmap");
fail_if(!buxton_cache_smack_rules(), "Failed to cache Smack rules");
fail_if(!buxton_direct_open(&daemon.buxton),
"Failed to open buxton direct connection");
@@ -1653,6 +1670,7 @@ START_TEST(buxtond_handle_message_notify_check)
free(list);
close(client);
hashmap_free(daemon.notify_mapping);
+ hashmap_free(daemon.client_key_mapping);
buxton_direct_close(&daemon.buxton);
buxton_array_free(&out_list, NULL);
}
@@ -1692,6 +1710,8 @@ START_TEST(buxtond_handle_message_unset_check)
"Failed to open buxton direct connection");
daemon.notify_mapping = hashmap_new(string_hash_func, string_compare_func);
fail_if(!daemon.notify_mapping, "Failed to allocate hashmap");
+ daemon.client_key_mapping = hashmap_new(uint64_hash_func, uint64_compare_func);
+ fail_if(!daemon.client_key_mapping, "Failed to allocate hashmap");
data1.type = STRING;
data1.store.d_string = buxton_string_pack("base");
@@ -1731,6 +1751,7 @@ START_TEST(buxtond_handle_message_unset_check)
free(list);
close(client);
hashmap_free(daemon.notify_mapping);
+ hashmap_free(daemon.client_key_mapping);
buxton_direct_close(&daemon.buxton);
buxton_array_free(&out_list, NULL);
}
@@ -1765,6 +1786,8 @@ START_TEST(buxtond_notify_clients_check)
daemon.notify_mapping = hashmap_new(string_hash_func,
string_compare_func);
fail_if(!daemon.notify_mapping, "Failed to allocate hashmap");
+ daemon.client_key_mapping = hashmap_new(uint64_hash_func, uint64_compare_func);
+ fail_if(!daemon.client_key_mapping, "Failed to allocate hashmap");
fail_if(!buxton_cache_smack_rules(),
"Failed to cache Smack rules");
fail_if(!buxton_direct_open(&daemon.buxton),
@@ -2125,8 +2148,199 @@ START_TEST(del_pollfd_check)
}
END_TEST
+START_TEST(handle_smack_label_check)
+{
+ client_list_item client;
+ int server;
+
+ setup_socket_pair(&client.fd, &server);
+ handle_smack_label(&client);
+
+ close(client.fd);
+ close(server);
+}
+END_TEST
+
+START_TEST(terminate_client_check)
+{
+ client_list_item *client;
+ BuxtonDaemon daemon;
+ int dummy;
+ BuxtonList *n_list = NULL;
+ BuxtonList *key_list = NULL;
+ char *key_name = strdup("groupkey");
+ char *key_name_copy = strdup("groupkey");
+ int ret = -1;
+ uint64_t *fd = NULL;
+ BuxtonNotification *nitem = NULL;
+
+ client = malloc0(sizeof(client_list_item));
+ fail_if(!client, "client malloc failed");
+ client->smack_label = malloc0(sizeof(BuxtonString));
+ fail_if(!client->smack_label, "smack label malloc failed");
+ daemon.client_list = client;
+ setup_socket_pair(&client->fd, &dummy);
+ daemon.nfds_alloc = 0;
+ daemon.accepting_alloc = 0;
+ daemon.nfds = 0;
+ daemon.pollfds = NULL;
+ daemon.accepting = NULL;
+ add_pollfd(&daemon, client->fd, 2, false);
+ fail_if(daemon.nfds != 1, "Failed to add pollfd");
+ client->smack_label->value = strdup("dummy");
+ client->smack_label->length = 6;
+ fail_if(!client->smack_label->value, "label strdup failed");
+ daemon.notify_mapping = hashmap_new(string_hash_func, string_compare_func);
+ fail_if(!daemon.notify_mapping, "Failed to allocate hashmap");
+ daemon.client_key_mapping = hashmap_new(uint64_hash_func, uint64_compare_func);
+ fail_if(!daemon.client_key_mapping, "Failed to allocate hashmap");
+
+ nitem = malloc0(sizeof(BuxtonNotification));
+ fail_if(!nitem,"Failed to allocate notification item\n");
+ nitem->client = client;
+ nitem->old_data = NULL;
+ nitem->msgid = 0;
+
+ ret = buxton_list_append(&n_list, nitem);
+ fail_if(!ret, "Failed to append to list\n");
+ ret = buxton_list_append(&key_list, key_name_copy);
+ fail_if(!ret, "Failed to append to list\n");
+
+ fd = malloc0(sizeof(uint64_t));
+ fail_if(!fd, "Failed to allocate fd\n");
+ *fd = (uint64_t)client->fd;
+
+ ret = hashmap_put(daemon.notify_mapping, key_name, n_list);
+ fail_if(ret < 0,"Failed to put in hashmap\n");
+ ret = hashmap_put(daemon.client_key_mapping, fd, key_list);
+ fail_if(ret < 0,"Failed to put in hashmap\n");
+
+ terminate_client(&daemon, client, 0);
+ fail_if(daemon.client_list, "Failed to set client list item to NULL");
+
+ hashmap_free(daemon.notify_mapping);
+ hashmap_free(daemon.client_key_mapping);
+ close(dummy);
+}
+END_TEST
+
START_TEST(handle_client_check)
{
+ BuxtonDaemon daemon;
+ int dummy;
+ uint8_t buf[4096];
+ uint8_t *message = NULL;
+ BuxtonData data1, data2, data3, data4;
+ BuxtonArray *list = NULL;
+ bool r;
+ size_t ret;
+ uint32_t bsize;
+
+ list = buxton_array_new();
+ data1.type = STRING;
+ data1.store.d_string = buxton_string_pack("test-gdbm-user");
+ data2.type = STRING;
+ data2.store.d_string = buxton_string_pack("daemon-check");
+ data3.type = STRING;
+ data3.store.d_string = buxton_string_pack("name");
+ data4.type = UINT32;
+ data4.store.d_uint32 = STRING;
+ r = buxton_array_add(list, &data1);
+ fail_if(!r, "Failed to add data to array");
+ r = buxton_array_add(list, &data2);
+ fail_if(!r, "Failed to add data to array");
+ r = buxton_array_add(list, &data3);
+ fail_if(!r, "Failed to add data to array");
+ r = buxton_array_add(list, &data4);
+ fail_if(!r, "Failed to add data to array");
+ ret = buxton_serialize_message(&message, BUXTON_CONTROL_GET, 0, list);
+ fail_if(ret == 0, "Failed to serialize string data");
+ daemon.client_list = malloc0(sizeof(client_list_item));
+ fail_if(!daemon.client_list, "client malloc failed");
+ setup_socket_pair(&daemon.client_list->fd, &dummy);
+ fcntl(daemon.client_list->fd, F_SETFL, O_NONBLOCK);
+ daemon.nfds_alloc = 0;
+ daemon.accepting_alloc = 0;
+ daemon.nfds = 0;
+ daemon.pollfds = NULL;
+ daemon.accepting = NULL;
+ daemon.notify_mapping = hashmap_new(string_hash_func, string_compare_func);
+ fail_if(!daemon.notify_mapping, "Failed to allocate hashmap");
+ daemon.client_key_mapping = hashmap_new(uint64_hash_func, uint64_compare_func);
+ fail_if(!daemon.client_key_mapping, "Failed to allocate hashmap");
+
+ add_pollfd(&daemon, daemon.client_list->fd, 2, false);
+ fail_if(daemon.nfds != 1, "Failed to add pollfd 1");
+ fail_if(handle_client(&daemon, daemon.client_list, 0), "More data available 1");
+ fail_if(daemon.client_list, "Failed to terminate client with no data");
+ close(dummy);
+
+ daemon.client_list = malloc0(sizeof(client_list_item));
+ fail_if(!daemon.client_list, "client malloc failed");
+ setup_socket_pair(&daemon.client_list->fd, &dummy);
+ fcntl(daemon.client_list->fd, F_SETFL, O_NONBLOCK);
+ add_pollfd(&daemon, daemon.client_list->fd, 2, false);
+ fail_if(daemon.nfds != 1, "Failed to add pollfd 2");
+ write(dummy, buf, 1);
+ fail_if(handle_client(&daemon, daemon.client_list, 0), "More data available 2");
+ fail_if(!daemon.client_list, "Terminated client with insufficient data");
+ fail_if(daemon.client_list->data, "Didn't clean up left over client data 1");
+
+ bsize = 0;
+ memcpy(message + BUXTON_LENGTH_OFFSET, &bsize, sizeof(uint32_t));
+ write(dummy, message, BUXTON_MESSAGE_HEADER_LENGTH);
+ fail_if(handle_client(&daemon, daemon.client_list, 0), "More data available 3");
+ fail_if(daemon.client_list, "Failed to terminate client with bad size 1");
+ close(dummy);
+
+ daemon.client_list = malloc0(sizeof(client_list_item));
+ fail_if(!daemon.client_list, "client malloc failed");
+ setup_socket_pair(&daemon.client_list->fd, &dummy);
+ fcntl(daemon.client_list->fd, F_SETFL, O_NONBLOCK);
+ add_pollfd(&daemon, daemon.client_list->fd, 2, false);
+ fail_if(daemon.nfds != 1, "Failed to add pollfd 3");
+ bsize = BUXTON_MESSAGE_MAX_LENGTH + 1;
+ memcpy(message + BUXTON_LENGTH_OFFSET, &bsize, sizeof(uint32_t));
+ write(dummy, message, BUXTON_MESSAGE_HEADER_LENGTH);
+ fail_if(handle_client(&daemon, daemon.client_list, 0), "More data available 4");
+ fail_if(daemon.client_list, "Failed to terminate client with bad size 2");
+ close(dummy);
+
+ daemon.client_list = malloc0(sizeof(client_list_item));
+ fail_if(!daemon.client_list, "client malloc failed");
+ setup_socket_pair(&daemon.client_list->fd, &dummy);
+ fcntl(daemon.client_list->fd, F_SETFL, O_NONBLOCK);
+ add_pollfd(&daemon, daemon.client_list->fd, 2, false);
+ fail_if(daemon.nfds != 1, "Failed to add pollfd 4");
+ bsize = (uint32_t)ret;
+ memcpy(message + BUXTON_LENGTH_OFFSET, &bsize, sizeof(uint32_t));
+ write(dummy, message, ret);
+ fail_if(handle_client(&daemon, daemon.client_list, 0), "More data available 5");
+ fail_if(!daemon.client_list, "Terminated client with correct data length");
+
+ for (int i = 0; i < 33; i++) {
+ write(dummy, message, ret);
+ }
+ fail_if(!handle_client(&daemon, daemon.client_list, 0), "No more data available");
+ fail_if(!daemon.client_list, "Terminated client with correct data length");
+ terminate_client(&daemon, daemon.client_list, 0);
+ fail_if(daemon.client_list, "Failed to remove client 1");
+ close(dummy);
+
+ //FIXME: add SIGPIPE handler
+ /* daemon.client_list = malloc0(sizeof(client_list_item)); */
+ /* fail_if(!daemon.client_list, "client malloc failed"); */
+ /* setup_socket_pair(&daemon.client_list->fd, &dummy); */
+ /* fcntl(daemon.client_list->fd, F_SETFL, O_NONBLOCK); */
+ /* add_pollfd(&daemon, daemon.client_list->fd, 2, false); */
+ /* fail_if(daemon.nfds != 1, "Failed to add pollfd 5"); */
+ /* write(dummy, message, ret); */
+ /* close(dummy); */
+ /* fail_if(handle_client(&daemon, daemon.client_list, 0), "More data available 6"); */
+ /* fail_if(daemon.client_list, "Failed to terminate client"); */
+
+ hashmap_free(daemon.notify_mapping);
+ hashmap_free(daemon.client_key_mapping);
}
END_TEST
@@ -2550,6 +2764,8 @@ daemon_suite(void)
tcase_add_test(tc, identify_client_check);
tcase_add_test(tc, add_pollfd_check);
tcase_add_test(tc, del_pollfd_check);
+ tcase_add_test(tc, handle_smack_label_check);
+ tcase_add_test(tc, terminate_client_check);
tcase_add_test(tc, handle_client_check);
suite_add_tcase(s, tc);