--- /dev/null
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+PROJECT(dumpsys-project C)
+
+SET(PREFIX ${CMAKE_INSTALL_PREFIX})
+
+ADD_DEFINITIONS(-D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE=1)
+
+# Sub modules
+ADD_SUBDIRECTORY(src/client-api)
+ADD_SUBDIRECTORY(src/dumpsys)
--- /dev/null
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+
+
--- /dev/null
+Name: dumpsys-system_tests
+Summary: Dumpsys is a framework to get logs from services and applications.
+Version: 0.0.2
+Release: 1
+Group: Framework/system
+License: Apache-2.0
+Source0: %{name}-%{version}.tar.gz
+BuildRequires: pkgconfig(pkgmgr-info)
+BuildRequires: pkgconfig(glib-2.0)
+BuildRequires: pkgconfig(dlog)
+BuildRequires: pkgconfig(capi-base-common)
+BuildRequires: pkgconfig(dumpsys-system)
+BuildRequires: cmake
+
+%description
+This package provides dumpsys utility and libraries to allow collecting logs from services and applications.
+
+%prep
+%setup -q
+
+%build
+export CFLAGS+=" -Werror"
+cd tests
+%cmake . \
+ -DDUMPSYS_SYSTEM_TESTS_PATH=%{_libdir}/dumpsys_system_tests/
+make %{?jobs:-j%jobs}
+
+%install
+rm -rf %{buildroot}
+cd tests
+%make_install
+
+%files
+%license LICENSE
+%attr(755,root,root) %{_libdir}/dumpsys_system_tests/utils/test-app
--- /dev/null
+Name: dumpsys
+Summary: Dumpsys is a framework to get logs from services and applications.
+Version: 0.0.2
+Release: 1
+Group: Framework/system
+License: Apache-2.0
+Source0: %{name}-%{version}.tar.gz
+BuildRequires: pkgconfig(glib-2.0)
+BuildRequires: pkgconfig(dlog)
+# BuildRequires: pkgconfig(capi-base-common)
+BuildRequires: cmake
+
+%description
+This package provides dumpsys utility and libraries to allow collecting logs from services and applications.
+
+%package -n libdumpsys-system
+Summary: Package with dumpsys API library for services.
+%description -n libdumpsys-system
+This pakcage provides dumpsys API library for services.
+
+%package -n libdumpsys-system-devel
+Requires: libdumpsys-system
+Summary: libdumpsys-system development package.
+%description -n libdumpsys-system-devel
+This package provides library and header files.
+
+%prep
+%setup -q
+
+%build
+export CFLAGS+=" -Werror -fvisibility=hidden"
+
+%cmake . \
+ -DVERSION=%{version}
+
+make %{?jobs:-j%jobs}
+
+%install
+rm -rf %{buildroot}
+%make_install
+
+%files -n libdumpsys-system
+%{_libdir}/libdumpsys-system.so.*
+
+%files -n libdumpsys-system-devel
+%{_includedir}/dumpsys-system.h
+%{_libdir}/libdumpsys-system.so
+%{_libdir}/pkgconfig/dumpsys-system.pc
+
+%files
+%license LICENSE
+%defattr(-,root,root)
+%{_bindir}/dumpsys
+%attr(0644,root,root) /usr/lib/tmpfiles.d/dumpsys-run.conf
+%attr(0644,root,root) /etc/dbus-1/system.d/dumpsys.conf
--- /dev/null
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+PROJECT(dumpsys-system C)
+
+INCLUDE(GNUInstallDirs)
+INCLUDE(FindPkgConfig)
+pkg_check_modules(dumpsys-system_pkgs REQUIRED
+ dlog
+ gio-2.0
+ gio-unix-2.0)
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/src/shared)
+FOREACH(flag ${dumpsys-system_pkgs_CFLAGS})
+ SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -fPIE -Wno-unused-function -Wno-unused-const-variable")
+
+SET(DCA_SRCS dumpsys-system.c)
+
+ADD_LIBRARY(libdumpsys-system SHARED dumpsys-system.c)
+SET_TARGET_PROPERTIES(libdumpsys-system PROPERTIES
+ SOVERSION 1
+ PUBLIC_HEADER dumpsys-system.h
+ OUTPUT_NAME dumpsys-system)
+TARGET_LINK_LIBRARIES(libdumpsys-system PUBLIC ${dumpsys-system_pkgs_LIBRARIES})
+
+LINK_DIRECTORIES(${CMAKE_BINARY_DIR})
+
+CONFIGURE_FILE(dumpsys-system.pc.in dumpsys-system.pc @ONLY)
+
+INSTALL(TARGETS libdumpsys-system LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
+INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/dumpsys-system.pc
+ DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
--- /dev/null
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <assert.h>
+#include <gio/gio.h>
+#include <gio/gunixfdlist.h>
+#include <libgen.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <tizen_error.h>
+#include <unistd.h>
+
+#include "dumpsys-system.h"
+#include "common.h"
+
+#ifndef LOG_TAG
+#define LOG_TAG "DUMPSYS_SYSTEM"
+#endif
+
+#include <dlog.h>
+
+#define DBUS_BUS_NAME_MAX_LEN 255
+
+#define DCA_ERROR 1
+#define DCA_ERROR_UNSPECIFIED_ERROR 1
+#define DCA_ERROR_GETEXEPATH 2
+#define DCA_ERROR_GETAPPID 3
+#define DCA_ERROR_UNIXFDLISTEMPTY 4
+
+static dumpsys_dump_cb dump_cb;
+static GDBusNodeInfo *introspection_data;
+static GDBusConnection *connection;
+static guint reg_id, own_id;
+static char *service_name;
+
+#define ERROR_OK 0
+#define ERROR_INTERNAL 1
+#define ERROR_BINARY_NAME_ERROR 2
+#define ERROR_APPLICATION_NAME_ERROR 3
+
+#define API_FUNCTION __attribute__((visibility("default")))
+
+static const gchar introspection_xml[] =
+"<node>"
+ "<interface name='org.tizen.dumpsys'>"
+ "<method name='Dump'>"
+ "<arg type='as' name='args' direction='in'/>"
+ "<arg type='i' name='result' direction='out'/>"
+ "</method>"
+ "</interface>"
+"</node>";
+
+struct DumpData {
+ int fd;
+ int argc;
+ char **argv;
+};
+
+static int get_name(char **name)
+{
+ assert(name);
+
+ if (service_name != NULL) {
+ *name = strdup(service_name);
+ return ERROR_OK;
+ }
+
+ return ERROR_APPLICATION_NAME_ERROR;
+}
+
+static void dump_thread_cb(GTask *task, gpointer source_object, gpointer task_data, GCancellable *cancellable)
+{
+ assert(task_data);
+
+ struct DumpData *dump_data = (struct DumpData*)task_data;
+
+ int result = dump_cb(dump_data->fd, dump_data->argc, dump_data->argv);
+
+ close(dump_data->fd);
+ free(dump_data);
+ g_task_return_int(task, result);
+}
+
+static int get_args(GVariant *vargs, gchar ***argv)
+{
+ assert(vargs);
+ assert(argv);
+
+ gsize count = -1;
+
+ GVariant *array = g_variant_get_child_value(vargs, 0);
+ *argv = g_variant_dup_strv(array, &count);
+ return count;
+}
+
+static void dump_handler(GDBusMethodInvocation *invocation)
+{
+ assert(invocation);
+ assert(dump_cb);
+
+ GDBusMessage *msg = g_dbus_method_invocation_get_message(invocation);
+ if (msg == NULL) {
+ LOGE("g_dbus_method_invocation_get_message() error");
+ return;
+ }
+
+ GUnixFDList *fd_list = g_dbus_message_get_unix_fd_list(msg);
+ if (fd_list == NULL) {
+ LOGE("No file descriptor provided");
+ g_dbus_method_invocation_return_error(invocation,
+ DCA_ERROR,
+ DCA_ERROR_UNIXFDLISTEMPTY,
+ "No file descriptor provided");
+ return;
+ }
+
+ GError *error = NULL;
+
+ int fd = g_unix_fd_list_get(fd_list, 0, &error);
+ if (fd == -1) {
+ LOGE("g_unix_fd_list_get() error: %s", error ? error->message : "(none)");
+ g_dbus_method_invocation_return_gerror(invocation, error);
+ if (error)
+ g_error_free(error);
+ return;
+ }
+
+ GVariant *body = g_dbus_message_get_body(msg);
+
+ struct DumpData *dump_data = malloc(sizeof(struct DumpData));
+ dump_data->fd = fd;
+ dump_data->argc = get_args(body, &dump_data->argv);
+
+ GTask *task = g_task_new(NULL, NULL, NULL, NULL);
+ g_task_set_task_data(task, dump_data, NULL);
+ g_task_run_in_thread(task, dump_thread_cb);
+ g_object_unref(task);
+ g_dbus_method_invocation_return_value(invocation, g_variant_new("(i)", ERROR_OK));
+}
+
+static void method_call_handler(GDBusConnection *conn,
+ const gchar *sender,
+ const gchar *object_path,
+ const gchar *iface_name,
+ const gchar *method_name,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data)
+{
+ if (g_strcmp0(method_name, "Dump") == 0)
+ dump_handler(invocation);
+}
+
+static const GDBusInterfaceVTable interface_vtable = {
+ method_call_handler, NULL, NULL
+};
+
+static bool register_object(GDBusConnection *conn)
+{
+ GError *error = NULL;
+ reg_id = g_dbus_connection_register_object(conn,
+ DUMPSYS_PATH,
+ introspection_data->interfaces[0],
+ &interface_vtable,
+ NULL,
+ NULL,
+ &error);
+
+ if (!reg_id) {
+ LOGE("g_dbus_connection_register_object() error: %s", error ? error->message : "(none)");
+ if (error)
+ g_error_free(error);
+ return false;
+ }
+ return true;
+}
+
+static bool dbus_init()
+{
+ introspection_data = g_dbus_node_info_new_for_xml(introspection_xml, NULL);
+ if (introspection_data == NULL) {
+ LOGE("g_dbus_node_info_new_for_xml() error");
+ return false;
+ }
+
+ GError *error = NULL;
+
+ GBusType default_bus_type = G_BUS_TYPE_SYSTEM;
+ connection = g_bus_get_sync(default_bus_type, NULL, &error);
+
+ if (!connection || error != NULL) {
+ LOGE("connect to the bus error: %s", error ? error->message : "(none)");
+ if (error)
+ g_error_free(error);
+ return false;
+ }
+
+ char name_with_prefix[DBUS_BUS_NAME_MAX_LEN];
+ int ret = sprintf(name_with_prefix, "%s.%s", DUMPSYS_SERVICE_NAME_PREFIX, service_name);
+ if (ret < 0 || ret >= sizeof(name_with_prefix)) {
+ LOGE("sprintf error: %m");
+ return false;
+ }
+
+ own_id = g_bus_own_name_on_connection(connection,
+ name_with_prefix,
+ G_BUS_NAME_OWNER_FLAGS_NONE,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+
+ return register_object(connection);
+}
+
+static bool dbus_close()
+{
+ if (!connection)
+ return false;
+
+ bool res = g_dbus_connection_unregister_object(connection, reg_id);
+ g_bus_unown_name(own_id);
+ g_object_unref(connection);
+ g_dbus_node_info_unref(introspection_data);
+ connection = NULL;
+ reg_id = 0;
+ own_id = 0;
+ return res;
+}
+
+static int register_callback(dumpsys_dump_cb callback, const char *name)
+{
+ assert(callback);
+ if (name == NULL) {
+ int ret = get_name(&service_name);
+ if (ret != ERROR_OK) {
+ LOGE("get_name error");
+ return TIZEN_ERROR_INVALID_OPERATION;
+ }
+ } else {
+ service_name = strdup(name);
+ if (service_name == NULL) {
+ LOGE("strdup error: %m");
+ return TIZEN_ERROR_INVALID_OPERATION;
+ }
+ }
+
+ bool result = dbus_init();
+ if (result)
+ dump_cb = callback;
+ return result ? TIZEN_ERROR_NONE : TIZEN_ERROR_IO_ERROR;
+
+}
+
+int API_FUNCTION dumpsys_system_register_dump_cb(dumpsys_dump_cb callback, const char *name, void **handler)
+{
+ if (dump_cb != NULL) {
+ LOGE("register_dump_cb(): already registered");
+ return TIZEN_ERROR_ALREADY_IN_PROGRESS;
+ }
+
+ if (callback == NULL || name == NULL || handler == NULL) {
+ LOGE("register_me(): invalid parameter");
+ return TIZEN_ERROR_INVALID_PARAMETER;
+ }
+
+ int res = register_callback(callback, name);
+ if (res == TIZEN_ERROR_NONE)
+ *handler = (void*)callback;
+ return res;
+}
+
+int API_FUNCTION dumpsys_system_unregister_dump_cb(void *handler)
+{
+ if (handler == NULL) {
+ LOGE("unregister_dump_cb(): parameter is NULL");
+ return TIZEN_ERROR_INVALID_PARAMETER;
+ }
+
+ if (handler != (void*)dump_cb) {
+ LOGE("unregister_dump_cb(): handler not registered");
+ return TIZEN_ERROR_ALREADY_IN_PROGRESS;
+ }
+
+ dump_cb = NULL;
+ service_name = NULL;
+ return dbus_close() ? TIZEN_ERROR_NONE : TIZEN_ERROR_IO_ERROR;
+}
--- /dev/null
+/*
+ * Copyright (c) 2016-2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __DUMPSYS_SYSTEM_H__
+#define __DUMPSYS_SYSTEM_H__
+
+/**
+ * @brief Callback function
+ * @param[in] fd File descriptor to write
+ * @param[in] argc Argument count
+ * @param[in] argv Array of arguments
+ */
+typedef int (*dumpsys_dump_cb)(const int fd, const int argc, char **argv);
+
+/**
+ * @brief Register the callback.
+ * @param[in] callback A callback for data retrieval
+ * @param[in] name Service name
+ * @param[out] handler Handler to unregister specific callback
+ * @retval TIZEN_ERROR_NONE Success
+ * @retval TIZEN_ERROR_ALREADY_IN_PROGRESS Callback already registered
+ * @retval TIZEN_ERROR_INVALID_PARAMETER Provided paramter is invalid
+ * @retval TIZEN_ERROR_INVALID_OPERATION Internal error
+ * @retval TIZEN_ERROR_IO_ERROR Error during DBus registration
+ */
+extern int dumpsys_system_register_dump_cb(dumpsys_dump_cb callback, const char *name, void **handler);
+
+/**
+ * @brief Unregister the callback.
+ * @param[in] handler Handler returned by dumpsys_system_register_dump_cb()
+ * @retval TIZEN_ERROR_NONE Success
+ * @retval TIZEN_ERROR_INVALID_PARAMETER Invalid handler
+ * @retval TIZEN_ERROR_ALREADY_IN_PROGRESS Handler is not registered
+ * @retval TIZEN_ERROR_IO_ERROR Error during DBus deregistration
+ */
+extern int dumpsys_system_unregister_dump_cb(void *handler);
+
+#endif // __DUMPSYS_SYSTEM_H__
--- /dev/null
+prefix=/usr
+exec_prefix=${prefix}
+includedir=${prefix}/include
+libdir=${exec_prefix}/lib
+
+Name: dumpsys-system
+Description: The crash-manager library
+Version: @VERSION@
+Cflags: -I${includedir}
+Libs: -L${libdir} -ldumpsys-system
+
--- /dev/null
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+PROJECT(dumpsys C)
+
+INCLUDE(GNUInstallDirs)
+INCLUDE(FindPkgConfig)
+find_package(PkgConfig REQUIRED)
+pkg_check_modules(dumpsys_pkgs REQUIRED
+ gio-2.0
+ glib-2.0
+ gio-unix-2.0)
+
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/src/shared)
+FOREACH(flag ${dumpsys_pkgs_CFLAGS})
+ SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+FOREACH(flag ${dumpsys_pkgs_LDFLAGS})
+ SET(EXTRA_LDFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -fPIE -Wno-unused-function -Wno-unused-const-variable")
+
+SET(DUMPSYS dumpsys.c)
+
+LINK_DIRECTORIES(${CMAKE_BINARY_DIR})
+ADD_EXECUTABLE(dumpsys ${DUMPSYS})
+TARGET_LINK_LIBRARIES(dumpsys PUBLIC ${dumpsys_pkgs_LIBRARIES})
+
+INSTALL (TARGETS dumpsys DESTINATION ${CMAKE_INSTALL_BINDIR}
+ PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE)
+INSTALL (FILES dumpsys-run.conf DESTINATION /usr/lib/tmpfiles.d/
+ PERMISSIONS OWNER_READ OWNER_WRITE)
+INSTALL (FILES dumpsys.conf DESTINATION /etc/dbus-1/system.d/
+ PERMISSIONS OWNER_READ OWNER_WRITE)
--- /dev/null
+d /run/dumpsys 0755 log log - -
+d /run/dumpsys/priv 0700 log log - -
+t /run/dumpsys/priv 0700 log log - security.SMACK64=System
+d /run/dumpsys/priv/fifo 0700 log log - -
+t /run/dumpsys/priv/fifo 0700 log log - security.SMACK64TRANSMUTE=TRUE
+t /run/dumpsys/priv/fifo 0700 log log - security.SMACK64=User::App::Shared
--- /dev/null
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <gio/gio.h>
+#include <gio/gunixfdlist.h>
+#include <linux/limits.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <errno.h>
+#include <dirent.h>
+#include <ctype.h>
+
+#include "common.h"
+
+#define BUFF_SIZE 4096
+#define FIFO_BASE_DIR "/run/dumpsys/priv/fifo"
+#define METHOD_DUMP "Dump"
+#define SERVICE_NAME_MAX_LEN 255
+
+static int out_fd = -1;
+static GVariant *dump_args;
+
+static void* copy_data(void *arg)
+{
+ int source_fd = ((int*)arg)[0];
+ int dest_fd = ((int*)arg)[1];
+
+ ssize_t read_count = 0;
+ while (read_count >= 0) {
+ char buff[BUFF_SIZE];
+ read_count = read(source_fd, buff, sizeof(buff));
+ if (read_count == 0)
+ break;
+
+ if (read_count == -1) {
+ if (errno == EAGAIN) {
+ read_count = 0;
+ sleep(0.1);
+ continue;
+ }
+ printf("read error: %m\n");
+ goto out;
+ }
+ ssize_t bytes_to_write = read_count;
+ while (bytes_to_write > 0) {
+ ssize_t write_count = write(dest_fd, buff, read_count);
+ if (write_count == -1) {
+ printf("write error: %m\n");
+ goto out;
+ }
+ bytes_to_write -= write_count;
+ }
+ }
+out:
+ return NULL;
+}
+
+static bool make_fifo(int *write_fd, int *read_fd)
+{
+ bool result = false;
+ char *fifo_path = NULL;
+
+ if (asprintf(&fifo_path, "%s/dumpsys_XXXXXX", FIFO_BASE_DIR) == -1) {
+ printf("asprintf error: %m\n");
+ return result;
+ }
+ uid_t ruid, euid, suid;
+ if (getresuid(&ruid, &euid, &suid) == -1) {
+ printf("getresuid error: %m\n");
+ return false;
+ }
+
+ if (seteuid(suid) == -1) {
+ printf("setuid error: %m\n");
+ return false;
+ }
+
+ if (mktemp(fifo_path) == NULL) {
+ printf("mktemp error: %m\n");
+ goto end;
+ }
+
+ if (mkfifo(fifo_path, 0600) == -1) {
+ printf("mkfifo error: %m\n");
+ goto end;
+ }
+
+ /*
+ * We must open for reading before open for writing, because of "No such device or address" error.
+ * Read must have O_NONBLOCK flag, otherwise open will block us until
+ * someone open fifo for writing.
+ */
+ *read_fd = open(fifo_path, O_RDONLY | O_NONBLOCK);
+ if (*read_fd == -1) {
+ printf("open fifo for reading error: %m\n");
+ goto end;
+ }
+
+ *write_fd = open(fifo_path, O_WRONLY | O_NONBLOCK);
+ if (*write_fd == -1) {
+ printf("open fifo for writing error: %m\n");
+ close(*read_fd);
+ goto end;
+ }
+
+ if (unlink(fifo_path) == -1) {
+ printf("unlink '%s' error: %m\n", fifo_path);
+ close(*read_fd);
+ close(*write_fd);
+ goto end;
+ }
+
+ int old_flags = fcntl(*read_fd, F_GETFL);
+ if (old_flags == -1) {
+ printf("fcntl() GETFL error: %m\n");
+ close(*read_fd);
+ close(*write_fd);
+ goto end;
+ }
+
+ fcntl(*read_fd, F_SETFL, old_flags & ~O_NONBLOCK);
+
+ result = true;
+end:
+ free(fifo_path);
+ if (seteuid(euid) == -1) {
+ printf("setuid error: %m\n");
+ result = false;
+ }
+ return result;
+}
+
+static void call_dump(const gchar *name, const gchar *application_name, GDBusConnection *connection)
+{
+ GError *error = NULL;
+
+ GDBusMessage *method_call_message = g_dbus_message_new_method_call(name,
+ DUMPSYS_PATH,
+ DUMPSYS_NAME,
+ METHOD_DUMP);
+
+ g_dbus_message_set_body(method_call_message, dump_args);
+
+ GUnixFDList *fd_list = g_unix_fd_list_new();
+
+ int write_fd, read_fd;
+ if (!make_fifo(&write_fd, &read_fd)) {
+ return;
+ }
+
+ pthread_t copy_thread;
+ int fd_pair2[2];
+ fd_pair2[0] = read_fd;
+ fd_pair2[1] = out_fd;
+ if (pthread_create(©_thread, NULL, copy_data, &fd_pair2[0]) != 0) {
+ printf("pthread_create error: %m\n");
+ return;
+ }
+ g_unix_fd_list_append(fd_list, write_fd, &error);
+ close(write_fd);
+ if (error != NULL) {
+ dprintf(STDERR_FILENO, "g_unix_fd_list_append() error: %s\n", error->message);
+ return;
+ }
+
+ g_dbus_message_set_unix_fd_list(method_call_message, fd_list);
+
+ GDBusMessage *repl = g_dbus_connection_send_message_with_reply_sync(connection,
+ method_call_message,
+ G_DBUS_SEND_MESSAGE_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ &error);
+
+ if (repl != NULL && g_dbus_message_get_message_type(repl) == G_DBUS_MESSAGE_TYPE_ERROR)
+ g_dbus_message_to_gerror(repl, &error);
+
+ if (error != NULL) {
+ printf("Send message error: %s\n", error ? error->message : "(unspecified)");
+ g_error_free(error);
+ }
+
+ g_object_unref(fd_list);
+ g_object_unref(method_call_message);
+ g_object_unref(repl);
+
+ if (pthread_join(copy_thread, NULL) != 0)
+ printf("pthread_join error: %m\n");
+
+ close(read_fd);
+}
+
+static void call_dump_for_list_of_services(GDBusConnection *connection, GList* list_of_services)
+{
+ GList *element = g_list_first(list_of_services);
+
+ while (element != NULL) {
+ char *name = (gchar *)element->data;
+ char service_name[SERVICE_NAME_MAX_LEN];
+
+ snprintf(service_name, sizeof(service_name), "%s.%s", DUMPSYS_SERVICE_NAME_PREFIX, name);
+ call_dump(service_name, name, connection);
+
+ element = g_list_next(element);
+ }
+}
+
+
+static GDBusConnection* make_connection(GBusType bus_type)
+{
+ GError *error = NULL;
+ GDBusConnection *connection = NULL;
+
+ connection = g_bus_get_sync(bus_type, NULL, &error);
+ if (connection == NULL || error != NULL)
+ printf("make_connection error: %s\n", error->message);
+
+ return connection;
+}
+
+static void process_bus(GBusType bus_type, GList *list_of_services)
+{
+ GDBusConnection *connection = make_connection(bus_type);
+ if (connection == NULL) {
+ printf("can't connect\n");
+ return;
+ }
+
+ call_dump_for_list_of_services(connection, list_of_services);
+
+ g_object_unref(connection);
+}
+
+static void process_each_bus(GList *list_of_services)
+{
+ uid_t ruid, euid, suid;
+ if (getresuid(&ruid, &euid, &suid) == -1) {
+ printf("getresuid error: %m\n");
+ return;
+ }
+
+ process_bus(G_BUS_TYPE_SYSTEM, list_of_services);
+}
+
+static void set_dump_args(int start, int argc, char *argv[])
+{
+ GVariantBuilder builder;
+ g_variant_builder_init(&builder, G_VARIANT_TYPE("(as)"));
+ g_variant_builder_open(&builder, G_VARIANT_TYPE("as"));
+
+ for (int i = start; i < argc; i++)
+ g_variant_builder_add(&builder, "s", argv[i]);
+
+ g_variant_builder_close(&builder);
+ dump_args = g_variant_builder_end(&builder);
+}
+
+static void print_help(char **argv)
+{
+ printf("Usage:\n");
+ printf("\t%s [-o filename] <service_name> -- [service arguments]\n\n", argv[0]);
+}
+
+int main(int argc, char *argv[])
+{
+ int opt;
+ char *filename = NULL;
+ out_fd = STDOUT_FILENO;
+
+ while ((opt = getopt(argc, argv, "o:")) != -1) {
+ switch(opt) {
+ case 'o':
+ filename = optarg;
+ break;
+ }
+ }
+
+ if (optind >= argc) {
+ print_help(argv);
+ return EXIT_FAILURE;
+ }
+
+ if (filename != NULL) {
+ out_fd = open(filename, O_WRONLY | O_CREAT, 0600);
+ if (out_fd == -1) {
+ printf("Can not open file '%s': %m\n", filename);
+ return EXIT_FAILURE;
+ }
+ }
+
+ GList *list_of_services = NULL;
+
+ int i = optind;
+
+ if (i < argc)
+ list_of_services = g_list_append(list_of_services, strdup(argv[i]));
+
+ set_dump_args(i+1, argc, argv);
+
+ process_each_bus(list_of_services);
+
+ g_list_free_full(list_of_services, free);
+
+ return EXIT_SUCCESS;
+}
--- /dev/null
+<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<busconfig>
+ <policy context="default">
+ <check own_prefix="org.tizen.dumpsys" privilege="http://tizen.org/privilege/internal/default/platform"/>
+ <check send_destination_prefix="org.tizen.dumpsys" privilege="http://tizen.org/privilege/internal/default/platform"/>
+ </policy>
+</busconfig>
+
--- /dev/null
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __COMMON_H__
+#define __COMMON_H__
+
+#define DUMPSYS_PATH "/Org/Tizen/Dumpsys"
+#define DUMPSYS_NAME "org.tizen.dumpsys"
+#define DUMPSYS_INTERFACE DUMPSYS_NAME
+#define DUMPSYS_SERVICE_NAME_PREFIX DUMPSYS_NAME
+
+#endif
--- /dev/null
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+PROJECT(dumpsys-project C)
+
+SET(PREFIX ${CMAKE_INSTALL_PREFIX})
+
+ADD_DEFINITIONS(-D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE=1)
+
+# Sub modules
+ADD_SUBDIRECTORY(system/util)
--- /dev/null
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+PROJECT(tests-utils C)
+
+INCLUDE(GNUInstallDirs)
+INCLUDE(FindPkgConfig)
+pkg_check_modules(dumpsys-system_pkgs REQUIRED
+ capi-base-common
+ dlog
+ gio-2.0
+ gio-unix-2.0
+ dumpsys-system
+ pkgmgr-info)
+
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/../src/shared)
+FOREACH(flag ${dumpsys-system_pkgs_CFLAGS})
+ SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -fPIE -Wno-unused-function -Wno-unused-const-variable")
+
+ADD_EXECUTABLE(test-app test-app.c)
+
+TARGET_LINK_LIBRARIES(test-app PUBLIC ${dumpsys-system_pkgs_LIBRARIES})
+
+LINK_DIRECTORIES(${CMAKE_BINARY_DIR})
+
+INSTALL(TARGETS test-app DESTINATION ${DUMPSYS_SYSTEM_TESTS_PATH}/utils
+ PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE)
--- /dev/null
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdbool.h>
+#include <gio/gio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <tizen_error.h>
+#include "common.h"
+
+#include <dumpsys-system.h>
+
+char *message;
+GMainLoop *loop;
+
+int dump(const int fd, const int argc, char **argv)
+{
+ for (int i = 0; i < argc; i++)
+ printf("[%d] arg: %s\n", i+1, argv[i]);
+ g_main_loop_quit(loop);
+ return write(fd, message, strlen(message));
+}
+
+int main(int argc, char *argv[])
+{
+ char *name = NULL;
+
+ for (int i = optind; i < argc; i++) {
+ if (i == argc-2)
+ name = argv[i];
+ else if (i == argc-1)
+ message = argv[i];
+ }
+
+ if (name == NULL || message == NULL) {
+ printf("Why didn't you specify a required arguments?! ;~~~()\n");
+ printf("\t%s <name> <message>\n", argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ int *handler;
+ int ret = dumpsys_system_register_dump_cb(dump, name, (void**)&handler);
+ if (ret != TIZEN_ERROR_NONE) {
+ printf("Some error :(. Check dlog.\n");
+ return EXIT_FAILURE;
+ }
+
+ loop = g_main_loop_new(NULL, false);
+ g_main_loop_run(loop);
+ g_main_loop_unref(loop);
+
+ dumpsys_system_unregister_dump_cb((void*)handler);
+
+ return EXIT_SUCCESS;
+}