diff options
author | Brad Peters <brad.t.peters@intel.com> | 2014-08-18 13:39:36 -0700 |
---|---|---|
committer | Brad Peters <brad.t.peters@intel.com> | 2014-08-18 13:39:36 -0700 |
commit | 67cae288fd4ac44aca7f7950bb0942ecf3261d0f (patch) | |
tree | 42a16ce4d4c9bc51f12cd6efe20c37ad1ea514df | |
parent | 7d6949fb6514ec849a57ee0dac9ff51021f8876e (diff) | |
download | buxton-67cae288fd4ac44aca7f7950bb0942ecf3261d0f.tar.gz buxton-67cae288fd4ac44aca7f7950bb0942ecf3261d0f.tar.bz2 buxton-67cae288fd4ac44aca7f7950bb0942ecf3261d0f.zip |
Imported Upstream version 3upstream/3submit/upstream/20140818.213510submit/upstream/20140818.211611
-rw-r--r-- | HACKING | 127 | ||||
-rw-r--r-- | Makefile.am | 3 | ||||
-rw-r--r-- | Makefile.in | 61 | ||||
-rw-r--r-- | TODO | 25 | ||||
-rw-r--r-- | config.h.in | 6 | ||||
-rwxr-xr-x | configure | 57 | ||||
-rw-r--r-- | configure.ac | 12 | ||||
-rw-r--r-- | data/buxton.conf | 2 | ||||
-rw-r--r-- | demo/gtk_client.c | 16 | ||||
-rw-r--r-- | demo/helloget.c | 4 | ||||
-rw-r--r-- | docs/buxton.7 | 8 | ||||
-rw-r--r-- | docs/buxton.conf.5 | 6 | ||||
-rw-r--r-- | docs/buxton_key_create.3 | 6 | ||||
-rw-r--r-- | docs/buxton_open.3 | 4 | ||||
-rw-r--r-- | src/cli/client.c | 17 | ||||
-rw-r--r-- | src/core/daemon.c | 161 | ||||
-rw-r--r-- | src/core/daemon.h | 8 | ||||
-rw-r--r-- | src/core/main.c | 11 | ||||
-rw-r--r-- | src/db/gdbm.c | 49 | ||||
-rw-r--r-- | src/libbuxton/lbuxton.c | 27 | ||||
-rw-r--r-- | src/security/smack.c | 2 | ||||
-rw-r--r-- | src/shared/backend.c | 6 | ||||
-rw-r--r-- | src/shared/backend.h | 1 | ||||
-rw-r--r-- | src/shared/configurator.c | 35 | ||||
-rw-r--r-- | src/shared/configurator.h | 1 | ||||
-rw-r--r-- | src/shared/direct.c | 40 | ||||
-rw-r--r-- | src/shared/protocol.c | 17 | ||||
-rw-r--r-- | src/shared/protocol.h | 7 | ||||
-rw-r--r-- | test/check_buxton.c | 10 | ||||
-rw-r--r-- | test/check_daemon.c | 222 |
30 files changed, 799 insertions, 152 deletions
@@ -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 \ @@ -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 @@ -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); |