Imported Upstream version 3 submit/upstream/20140818.211611 submit/upstream/20140818.213510 upstream/3
authorBrad Peters <brad.t.peters@intel.com>
Mon, 18 Aug 2014 20:39:36 +0000 (13:39 -0700)
committerBrad Peters <brad.t.peters@intel.com>
Mon, 18 Aug 2014 20:39:36 +0000 (13:39 -0700)
30 files changed:
HACKING [new file with mode: 0644]
Makefile.am
Makefile.in
TODO
config.h.in
configure
configure.ac
data/buxton.conf
demo/gtk_client.c
demo/helloget.c
docs/buxton.7
docs/buxton.conf.5
docs/buxton_key_create.3
docs/buxton_open.3
src/cli/client.c
src/core/daemon.c
src/core/daemon.h
src/core/main.c
src/db/gdbm.c
src/libbuxton/lbuxton.c
src/security/smack.c
src/shared/backend.c
src/shared/backend.h
src/shared/configurator.c
src/shared/configurator.h
src/shared/direct.c
src/shared/protocol.c
src/shared/protocol.h
test/check_buxton.c
test/check_daemon.c

diff --git a/HACKING b/HACKING
new file mode 100644 (file)
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
+
index f949a4d..6242f7a 100644 (file)
@@ -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 \
index 3d7bb1f..389215e 100644 (file)
@@ -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 (file)
--- 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
index 884cdb9..c0ccad3 100644 (file)
    */
 #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
 
index e1f7eb1..b536ec9 100755 (executable)
--- 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; }
index f60b4a7..f5a638b 100644 (file)
@@ -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}
 ])
index c70d438..bb3c79c 100644 (file)
@@ -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]
index 254db17..df828c9 100644 (file)
@@ -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;
index 27cf132..aceeec1 100644 (file)
@@ -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;
index 1e4ff8c..3c3daac 100644 (file)
@@ -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
index 968d862..d3a2485 100644 (file)
@@ -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\&.
index b7080d0..928dc0f 100644 (file)
@@ -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
index e7a4d83..6e4d7ad 100644 (file)
@@ -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
index 74deb25..decb4dd 100644 (file)
@@ -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);
 
index f3b3660..ae5ba9c 100644 (file)
@@ -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) {
index 5c6ceaa..4156f92 100644 (file)
@@ -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
index f3ad523..94bbb6a 100644 (file)
@@ -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;
 }
index 0892b54..e8988c4 100644 (file)
@@ -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:
index 56376bf..3def14b 100644 (file)
@@ -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);
index 2f85b3f..8927236 100644 (file)
@@ -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;
index 0c5b90c..29eb8f6 100644 (file)
@@ -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:
index 24c2b63..edcde53 100644 (file)
@@ -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;
 
 /**
index 51306b0..9aa0160 100644 (file)
@@ -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;
index e6f3cef..be25a1a 100644 (file)
@@ -40,6 +40,7 @@ typedef struct ConfigLayer {
        char *type;
        char *backend;
        char *description;
+       char *access;
        int priority;
 } ConfigLayer;
 
index e93e290..67d3dbd 100644 (file)
@@ -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;
        }
index fdf73c4..3842399 100644 (file)
@@ -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;
        }
 
index b3e789e..1e2aea6 100644 (file)
@@ -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
  *
index 883ae7e..0033899 100644 (file)
@@ -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);
index 72a6d66..90775a8 100644 (file)
@@ -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);