BuildRequires: pkgconfig(capi-system-info)
BuildRequires: pkgconfig(glib-2.0)
BuildRequires: pkgconfig(rpm)
+BuildRequires: pkgconfig(libzip)
BuildRequires: cmake
BuildRequires: pkgconfig(pkgmgr-info)
BuildRequires: pkgconfig(libunwind-generic)
%attr(-,root,root) %{_unitdir}/crash-service.service
%attr(-,root,root) %{_sysconfdir}/dbus-1/system.d/crash-service.conf
%attr(-,root,root) %{_datadir}/dbus-1/system-services/org.tizen.system.crash.livedump.service
+%attr(-,root,root) %{_datadir}/dbus-1/system-services/org.tizen.system.diagnostics.service
+%attr(0644,root,root) %{_libdir}/tmpfiles.d/diagnostics-run.conf
%endif
#upgrade script
SET(CRASH_SERVICE_SRCS
crash-service.c
+ diagnostics/diagnostics.c
)
INCLUDE(GNUInstallDirs)
pkg_check_modules(crash-service_pkgs REQUIRED
dlog
gio-2.0
+ gio-unix-2.0
+ libzip
)
FOREACH(flag ${crash-service_pkgs_CFLAGS})
INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/org.tizen.system.crash.livedump.service
DESTINATION /usr/share/dbus-1/system-services)
+INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/diagnostics/org.tizen.system.diagnostics.service
+ DESTINATION /usr/share/dbus-1/system-services)
+
INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/crash-service.conf
DESTINATION /etc/dbus-1/system.d)
INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/crash-service.pc
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
+
+INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/diagnostics/diagnostics-run.conf
+ DESTINATION ${CMAKE_INSTALL_LIBDIR}/tmpfiles.d/
+ PERMISSIONS OWNER_READ OWNER_WRITE)
* limitations under the License.
*/
+#include <assert.h>
#include <gio/gio.h>
+#include <gio/gunixfdlist.h>
#include <stdbool.h>
#include <stdlib.h>
#include <sys/select.h>
#include "crash-manager/crash-manager.h"
#include "libcrash-service.h"
#include "shared/log.h"
+#include "diagnostics/diagnostics.h"
/* Dbus activation */
#define CRASH_BUS_NAME "org.tizen.system.crash.livedump"
#define CRASH_OBJECT_PATH "/Org/Tizen/System/Crash/Livedump"
+#define CRASH_INTERFACE_NAME CRASH_BUS_NAME
+
+#define DIAGNOSTICS_BUS_NAME "org.tizen.system.diagnostics"
+#define DIAGNOSTICS_OBJECT_PATH "/Org/Tizen/System/Diagnostics"
+#define DIAGNOSTICS_INTERFACE_NAME DIAGNOSTICS_BUS_NAME
#define TIMEOUT_INTERVAL_SEC 60
#define TIMEOUT_LIVEDUMP_SEC 50
static GMainLoop *loop;
static GMutex timeout_mutex;
static guint timeout_id;
-static GDBusNodeInfo *introspection_data;
+static GDBusNodeInfo *introspection_data, *introspection_diagnostics_data;
static const gchar introspection_xml[] =
"<node>"
" <interface name='org.tizen.system.crash.livedump'>"
" </interface>"
"</node>";
+static const gchar introspection_diagnostics_xml[] =
+"<node>"
+" <interface name='org.tizen.system.diagnostics'>"
+" <method name='get_file'>"
+" <arg type='s' name='report_path' direction='in'/>"
+" <arg type='i' name='type' direction='in'/>"
+" <arg type='i' name='result' direction='out'/>"
+" </method>"
+" </interface>"
+"</node>";
+
void child_exit(int sig)
{
wait(NULL);
}
}
-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)
+static void crash_interface_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)
{
- remove_timeout();
-
+ _D("crash iface method: %s", method_name);
if (g_strcmp0(method_name, "livedump_pid") == 0) {
gchar *dump_reason;
const pid_t pid;
}
}
+}
+
+static GUnixFDList* prepare_unix_fd_list(int fd)
+{
+ assert(fd >= 0);
+
+ GError *error = NULL;
+ GUnixFDList *fd_list = g_unix_fd_list_new();
+
+ assert(fd_list);
+
+ if (g_unix_fd_list_append(fd_list, fd, &error) == -1) {
+ _E("g_unix_fd_list_append error: %s\n", error ? error->message : "unspecified error");
+ return NULL;
+ }
+ return fd_list;
+}
+
+static void diagnostics_get_file_handler(GDBusConnection *conn,
+ GDBusMethodInvocation *invocation,
+ const gchar *report_path,
+ enum diagnostics_entry entry)
+{
+ int fd = diagnostics_report_get_file(report_path, entry);
+ if (fd < 0) {
+ g_dbus_method_invocation_return_error(invocation,
+ BR_ERROR,
+ -fd,
+ "report_get_file() failed: %d", fd);
+ return;
+ }
+
+ GUnixFDList *fd_list = prepare_unix_fd_list(fd);
+ if (fd_list == NULL) {
+ close(fd);
+ g_dbus_method_invocation_return_error(invocation,
+ BR_ERROR,
+ BR_ERR_INTERNAL,
+ "Internal error");
+ return;
+ }
+
+ GDBusMessage *incoming_message = g_dbus_method_invocation_get_message(invocation);
+ GDBusMessage *message = g_dbus_message_new_method_reply(incoming_message);
+ g_dbus_message_set_unix_fd_list(message, fd_list);
+
+ GError *error = NULL;
+ if (!g_dbus_connection_send_message(conn,
+ message,
+ G_DBUS_SEND_MESSAGE_FLAGS_NONE,
+ NULL,
+ &error)) {
+ _E("Send reply message error: %s\n", error ? error->message : "");
+ if (error)
+ g_error_free(error);
+ }
+
+ g_object_unref(message);
+}
+
+static void diagnostics_interface_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)
+{
+ _D("some diagnostics method xD: %s", method_name);
+ if (g_strcmp0(method_name, "get_file") == 0) {
+ if (g_variant_is_of_type(parameters, G_VARIANT_TYPE("(si)"))) {
+ gchar *report_path;
+ enum diagnostics_entry entry;
+ g_variant_get(parameters, "(si)", &report_path, &entry);
+ diagnostics_get_file_handler(conn, invocation, report_path, entry);
+ } else {
+ _E("Parameters are not of the correct type (si)");
+ g_dbus_method_invocation_return_error(invocation,
+ CS_ERROR,
+ CS_ERR_PARAM,
+ "Parameters are not of the correct type (is)");
+ }
+ }
+ _D("after return");
+}
+
+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)
+{
+ remove_timeout();
+
+ _D("iface name: %s method: %s", iface_name, method_name);
+ if (g_strcmp0(iface_name, CRASH_INTERFACE_NAME) == 0)
+ crash_interface_handler(conn, sender, object_path, iface_name, method_name, parameters, invocation, user_data);
+ else if (g_strcmp0(iface_name, DIAGNOSTICS_INTERFACE_NAME) == 0)
+ diagnostics_interface_handler(conn, sender, object_path, iface_name, method_name, parameters, invocation, user_data);
+ else
+ _E("unsuppoerted interface: %s", iface_name);
+
add_timeout();
}
const gchar *name,
gpointer user_data)
{
+ const char *object_path;
+ GDBusInterfaceInfo *interface_info;
guint registration_id;
-
GError *error = NULL;
+
+ if (strcmp(name, CRASH_BUS_NAME) == 0) {
+ object_path = CRASH_OBJECT_PATH;
+ interface_info = introspection_data->interfaces[0];
+ } else if (strcmp(name, DIAGNOSTICS_BUS_NAME) == 0) {
+ object_path = DIAGNOSTICS_OBJECT_PATH;
+ interface_info = introspection_diagnostics_data->interfaces[0];
+ } else {
+ _E("on_bus_acquired: unknown name: %s", name);
+ return;
+ }
+
registration_id = g_dbus_connection_register_object(conn,
- CRASH_OBJECT_PATH,
- introspection_data->interfaces[0],
+ object_path,
+ interface_info,
&interface_vtable, NULL, NULL, &error);
if (registration_id == 0 || error) {
- _E("Failed to g_dbus_connection_register_object: %s", error ? error->message : "");
+ _E("Failed to g_dbus_connection_register_object for %s: %s", name, error ? error->message : "");
if (error)
g_error_free(error);
}
return false;
}
+ introspection_diagnostics_data =
+ g_dbus_node_info_new_for_xml(introspection_diagnostics_xml, NULL);
+ if (introspection_diagnostics_data == NULL) {
+ _E("Failed to init g_dbus_info_new_for_xml for diagnostics");
+ return false;
+ }
+
GDBusConnection *conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
if (!conn || error) {
_E("Failed to get dbus: %s", error ? error->message : "");
G_BUS_NAME_OWNER_FLAGS_NONE, on_bus_acquired,
on_name_acquired, on_name_lost, NULL, NULL);
+ g_bus_own_name(G_BUS_TYPE_SYSTEM, DIAGNOSTICS_BUS_NAME,
+ G_BUS_NAME_OWNER_FLAGS_NONE, on_bus_acquired,
+ on_name_acquired, on_name_lost, NULL, NULL);
+
return true;
}
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>
<policy user="root">
+ <allow own="org.tizen.system.diagnostics"/>
+ <allow send_destination="org.tizen.system.diagnostics"
+ send_interface="org.tizen.system.diagnostics"
+ send_member="get_file"/>
+ </policy>
+ <policy user="root">
<allow own="org.tizen.system.crash.livedump"/>
<allow send_destination="org.tizen.system.crash.livedump"
send_interface="org.tizen.system.crash.livedump"
send_member="livedump_pid"/>
</policy>
<policy user="crash_worker">
+ <allow own="org.tizen.system.diagnostics"/>
+ <allow send_destination="org.tizen.system.diagnostics"
+ send_interface="org.tizen.system.diagnostics"
+ send_member="get_file"/>
+ </policy>
+ <policy user="crash_worker">
<allow own="org.tizen.system.crash.livedump"/>
<allow send_destination="org.tizen.system.crash.livedump"
send_interface="org.tizen.system.crash.livedump"
</policy>
<policy context="default">
<deny own="org.tizen.system.crash.livedump"/>
+ <deny own="org.tizen.system.diagnostics"/>
<check privilege="http://tizen.org/privilege/internal/livecoredump"
send_destination="org.tizen.system.crash.livedump"
send_interface="org.tizen.system.crash.livedump"
send_member="livedump_pid"/>
+ <deny send_destination="org.tizen.system.diagnostics"/>
<deny send_destination="org.tizen.system.crash.livedump"/>
+ <check send_destination="org.tizen.system.diagnostics"
+ send_interface="org.tizen.system.diagnostics"
+ send_member="get_file"
+ privilege="http://tizen.org/privilege/internal/default/platform"/>
</policy>
</busconfig>
--- /dev/null
+d /run/diagnostics 0755 log log - -
+d /run/diagnostics/priv 0700 log log - -
+t /run/diagnostics/priv 0700 log log - security.SMACK64=System
+d /run/diagnostics/priv/fifo 0700 log log - -
+t /run/diagnostics/priv/fifo 0700 log log - security.SMACK64TRANSMUTE=TRUE
+t /run/diagnostics/priv/fifo 0700 log log - security.SMACK64=User::App::Shared
--- /dev/null
+/*
+ * crash-manager
+ *
+ * Copyright (c) 2020 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 <fcntl.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <zip.h>
+#include <errno.h>
+#include <dirent.h>
+#include "diagnostics/diagnostics.h"
+
+#define LOG_TAG "CRASH_MANAGER"
+
+#include "defs.h"
+#include "shared/log.h"
+#include "shared/util.h"
+#include "shared/config.h"
+
+#define SHARE_BASE_DIR "/run/diagnostics/priv/fifo"
+#define TMP_FILE_TEMPLATE "file_XXXXXX"
+
+#define JSON_FILE_EXT ".json"
+#define ZIP_FILE_EXT ".zip"
+
+enum diagnostics_type {
+ BT_UNKNOWN,
+ BT_FULL_REPORT,
+ BT_INFO_JSON,
+ BT_DIR
+};
+
+static char *type_to_str(enum diagnostics_entry entry) {
+ switch (entry) {
+ case FULL_REPORT:
+ return "FULL_REPORT";
+ case INFO_JSON:
+ return "INFO_JSON";
+ default:
+ return "UKNOWN";
+ }
+}
+
+static char *get_temp_file_name()
+{
+ char *result;
+ if (asprintf(&result, "%s/%s", SHARE_BASE_DIR, TMP_FILE_TEMPLATE) == -1) {
+ _E("asprintf() error: %m\n");
+ return NULL;
+ }
+
+ if (mktemp(result) == NULL || result[0] == '\0') {
+ _E("mktemp() error: %m\n");
+ free(result);
+ return NULL;
+ }
+
+ return result;
+}
+
+static bool is_report_file(const char *path, const char *reports_dir)
+{
+ assert(path);
+ assert(reports_dir);
+
+ char *r_path = realpath(path, NULL);
+ if (r_path == NULL) {
+ _E("realpath() for %s error: %m\n", path);
+ return false;
+ }
+
+ if (access(r_path, F_OK) == -1) {
+ _E("access() for %s error: %m\n", path);
+ return false;
+ }
+
+ char *start = strstr(r_path, reports_dir);
+
+ if (start == NULL) {
+ _I("%s is not within %s\n", r_path, reports_dir);
+ return false;
+ }
+
+ return true;
+}
+
+static enum diagnostics_type check_report_type(const char *path)
+{
+ assert(path);
+
+ if (strstr(path, JSON_FILE_EXT) == &path[strlen(path) - strlen(JSON_FILE_EXT)]) {
+ _D("Report type of %s is JSON_FILE\n", path);
+ return BT_INFO_JSON;
+ }
+
+ if (strstr(path, ZIP_FILE_EXT) == &path[strlen(path) - strlen(ZIP_FILE_EXT)]) {
+ _D("Report type of %s is FULL_REPORT\n", path);
+ return BT_FULL_REPORT;
+ }
+
+ struct stat file_stat;
+ if (stat(path, &file_stat) == -1) {
+ _E("stat() for %s error: %m\n", path);
+ return BT_UNKNOWN;
+ }
+
+ if (stat(path, &file_stat) == 0 && S_ISDIR(file_stat.st_mode)) {
+ _D("Report type of %s is DIR", path);
+ return BT_DIR;
+ }
+
+ _I("Report type of %s is UNKNOWN", path);
+ return BT_UNKNOWN;
+}
+
+static bool ends_with(const char *string, const char *end)
+{
+ assert(string);
+ assert(end);
+
+ ssize_t end_len = strlen(end);
+ ssize_t string_len = strlen(string);
+
+ if (end_len == 0 || end_len > string_len)
+ return false;
+
+ return strcasecmp(&string[string_len - end_len], end) == 0;
+}
+
+static bool file_match(const char *file_name, enum diagnostics_entry entry)
+{
+ assert(file_name);
+
+ switch(entry) {
+ case INFO_JSON:
+ return ends_with(file_name, JSON_FILE_EXT);
+ default:
+ return false;
+ }
+}
+
+static bool extract_file(zip_t *archive, int index, const char *out_file_name)
+{
+ bool result = false;
+ zip_file_t *zfile = NULL;
+
+ int extracted_fd = open(out_file_name, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
+ if (extracted_fd < 0) {
+ _E("open() file \"%s\" for write error: %m\n", out_file_name);
+ goto out;
+ }
+
+ struct zip_stat stat;
+ if (zip_stat_index(archive, index, ZIP_FL_UNCHANGED, &stat) == -1) {
+ printf("zip_stat_index() error\n");
+ goto out;
+ }
+
+ zfile = zip_fopen_index(archive, index, ZIP_FL_UNCHANGED);
+ if (zfile == NULL) {
+ _E("zip_fopen_index() error\n");
+ goto out;
+ }
+
+ char buff[0x1000];
+ zip_uint64_t sum = 0;
+
+ while (sum < stat.size) {
+ zip_int64_t len = zip_fread(zfile, buff, sizeof(buff));
+ if (len < 0) {
+ _E("zip_fread() error\n");
+ goto out;
+ }
+ if (write(extracted_fd, buff, len) == -1) {
+ _E("write() error: %m\n");
+ goto out;
+ }
+ sum += len;
+ }
+
+ result = true;
+out:
+ if (zfile != NULL)
+ zip_fclose(zfile);
+
+ if (extracted_fd >= 0)
+ close(extracted_fd);
+
+ return result;
+}
+
+static int search_file_in_zip(zip_t *archive, enum diagnostics_entry entry)
+{
+ zip_int64_t count = zip_get_num_entries(archive, ZIP_FL_UNCHANGED);
+
+ for (zip_int64_t i = 0; i < count; i++) {
+ const char *entry_name = zip_get_name(archive, i, ZIP_FL_ENC_GUESS);
+ if (entry_name == NULL) {
+ _E("zip_get_name() error\n");
+ continue;
+ }
+
+ if (!file_match(entry_name, entry))
+ continue;
+
+ return i;
+ }
+ return -1;
+}
+
+static int share_compressed_file(const char *path, enum diagnostics_entry entry)
+{
+ assert(path);
+
+ int err = 0;
+ int fd = -BR_ERR_INTERNAL;
+
+ char *out_file = get_temp_file_name();
+
+ if (out_file == NULL)
+ return -BR_ERR_INTERNAL;
+
+ zip_t *archive = zip_open(path, ZIP_RDONLY, &err);
+ if (err != 0) {
+ _E("zip_open() %s error: %d\n", path, err);
+ archive = NULL;
+ goto out;
+ }
+
+ int file_index = search_file_in_zip(archive, entry);
+ if (file_index < 0) {
+ _I("Archive \"%s\" doesn't contain file type: %s", path, type_to_str(entry));
+ fd = -BR_ERR_PARAM;
+ goto out;
+ }
+
+ if (extract_file(archive, file_index, out_file)) {
+ fd = open(out_file, O_RDONLY);
+ if (fd == -1) {
+ _E("open() file \"%s\" for read error: %m", out_file);
+ goto out;
+ }
+ _D("share file %s from \"%s\" as \"%s\"", type_to_str(entry), path, out_file);
+ }
+
+out:
+ if (archive)
+ zip_close(archive);
+ unlink(out_file);
+ free(out_file);
+ return fd;
+}
+
+static int share_file(const char *path)
+{
+ assert(path);
+
+ const char *dest_file = get_temp_file_name();
+
+ if (dest_file == NULL)
+ return -BR_ERR_INTERNAL;
+
+ _D("share file \"%s\" as \"%s\"", path, dest_file);
+
+ if (copy_file(dest_file, path) == -1) {
+ _E("copy_file() error");
+ return -BR_ERR_INTERNAL;
+ }
+
+ int fd = open(dest_file, O_RDONLY);
+ if (fd == -1) {
+ _E("open() file: \"%s\" error: %m\n", path);
+ return -BR_ERR_INTERNAL;
+ }
+ unlink(dest_file);
+
+ return fd;
+}
+
+static int share_uncompressed_file(const char *path, enum diagnostics_entry entry)
+{
+ assert(path);
+
+ struct dirent *ent;
+ DIR *dir = NULL;
+ int result = -BR_ERR_PARAM;
+ if ((dir = opendir(path)) == NULL) {
+ _E("opendir() for \"%s\" error: %m\n", path);
+ result = -BR_ERR_INTERNAL;
+ goto out;
+ }
+
+ while((ent = readdir(dir)) != NULL) {
+ if (file_match(ent->d_name, entry)) {
+ char file_path[PATH_MAX];
+ int ret = snprintf(file_path, PATH_MAX, "%s/%s", path, ent->d_name);
+
+ if (ret < 0) {
+ _E("sprintf() error: %m");
+ result = -BR_ERR_INTERNAL;
+ goto out;
+ } else if (ret >= PATH_MAX) {
+ _E("sprintf(): result string is too long");
+ result = -BR_ERR_INTERNAL;
+ goto out;
+ }
+ result = share_file(file_path);
+ break;
+ }
+ }
+
+ if (result < 0)
+ _I("Report \"%s\" doesn't contain requested entry type.", path);
+
+out:
+ if (dir != NULL)
+ closedir(dir);
+
+ return result;
+}
+
+static int share_simple_file(const char *path, enum diagnostics_entry entry)
+{
+ assert(path);
+
+ if (entry != INFO_JSON) {
+ _E("Unsupported file type for report \"%s\" (%s)\n", path, type_to_str(entry));
+ return -BR_ERR_PARAM;
+ }
+
+ return share_file(path);
+}
+
+int diagnostics_report_get_file(const char *report_path,
+ const enum diagnostics_entry entry)
+{
+ assert(report_path);
+
+ config_t config;
+ if (!config_init(&config, CRASH_MANAGER_CONFIG_PATH))
+ return -BR_ERR_INTERNAL;
+
+ bool is_report = is_report_file(report_path, config.crash_root_path);
+ config_free(&config);
+
+ if (!is_report) {
+ _E("File \"%s\" doesn't look like a report.", report_path);
+ return -BR_ERR_PARAM;
+ }
+
+ enum diagnostics_type rtype = check_report_type(report_path);
+
+ switch(rtype) {
+ case BT_INFO_JSON:
+ return share_simple_file(report_path, entry);
+ break;
+ case BT_FULL_REPORT:
+ if (entry == FULL_REPORT)
+ return share_file(report_path);
+ return share_compressed_file(report_path, entry);
+ break;
+ case BT_DIR:
+ return share_uncompressed_file(report_path, entry);
+ break;
+ default:
+ _E("%s is an unsupported report file.", report_path);
+ return -BR_ERR_PARAM;
+ }
+}
--- /dev/null
+/*
+ * crash-manager
+ *
+ * Copyright (c) 2020 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 __DIAGNOSTICS_H__
+#define __DIAGNOSTICS_H__
+
+#define BR_ERROR 1
+#define BR_OK 0
+#define BR_ERR_PARAM 1
+#define BR_ERR_INTERNAL 2
+
+enum diagnostics_entry {
+ FULL_REPORT = 0,
+ INFO_JSON
+};
+
+enum diagnostics_metadata {
+ APPID,
+ CMDLINE,
+ SIGNAL,
+};
+
+struct diagnostics_report;
+
+int diagnostics_report_get_file(const char *report_path,
+ const enum diagnostics_entry entry);
+
+#endif // __DIAGNOSTICS_H__
--- /dev/null
+[D-BUS Service]
+Name=org.tizen.system.diagnostics
+Exec=/bin/false
+SystemdService=crash-service.service