From e7e5010e3bcc171d580461982e16b0993441f62a Mon Sep 17 00:00:00 2001 From: Mateusz Moscicki Date: Mon, 15 Feb 2021 13:09:34 +0100 Subject: [PATCH 01/16] dump_systemstate: Extract the function to read ini files Change-Id: I53b79be8953bfc1d6c3c420913d8afa47cac5004 --- src/dump_systemstate/extras.c | 63 ++++++++++++++++++++----------------------- src/dump_systemstate/extras.h | 23 +++++++++++++++- 2 files changed, 51 insertions(+), 35 deletions(-) diff --git a/src/dump_systemstate/extras.c b/src/dump_systemstate/extras.c index 016acf6..88e42d8 100644 --- a/src/dump_systemstate/extras.c +++ b/src/dump_systemstate/extras.c @@ -45,15 +45,6 @@ static inline void cleanup_dictionary(dictionary **ini) iniparser_freedict(*ini); } -enum ini_fields { - INI_FIELD_TITLE = 0, - INI_FIELD_PATH, - INI_FIELD_ARGS, - INI_FIELD_ENV, - INI_FIELD_FLAG, - COUNT_INI_FIELDS, -}; - static const char *const INI_KEYS[COUNT_INI_FIELDS] = { [INI_FIELD_TITLE] = "title", [INI_FIELD_PATH] = "path", @@ -64,23 +55,12 @@ static const char *const INI_KEYS[COUNT_INI_FIELDS] = { }; static const size_t MAX_INI_KEY_LEN = 7; -struct extra_dump_item { - // not separate named fields, for convenient iteration - char *fields[COUNT_INI_FIELDS]; - int order; -}; - void cleanup_extra_dump_item(struct extra_dump_item *edi) { for (size_t i = 0; i < ARRAY_SIZE(edi->fields); ++i) free(edi->fields[i]); } -struct extra_items_vector { - size_t size; - struct extra_dump_item *data; -}; - bool check_cmdflag(const char *const flag, int argc, char **argv) { if (!flag) @@ -241,11 +221,6 @@ static int config_entry_filter(const struct dirent *de) int handle_items_vector(struct extra_items_vector *eiv, int out_fd, handle_ini_section_t handle_ini_section, int argc, char **argv) { - inline int cmp(const void *a, const void *b) { - return ((struct extra_dump_item *)a)->order - ((struct extra_dump_item *)b)->order; - } - qsort(eiv->data, eiv->size, sizeof *eiv->data, cmp); - int ret = 0; for (size_t i = 0; i < eiv->size; ++i) ret |= handle_ini_section(out_fd, eiv->data + i, argc, argv); @@ -259,11 +234,11 @@ void free_items_vector(struct extra_items_vector *eiv) free(eiv->data); } -int handle_extra_dir(int out_fd, char *dir_path, handle_ini_section_t handle_ini_section, int argc, char **argv) +int read_ini_files(int out_fd, char *dir_path, struct extra_items_vector *eiv) { assert(out_fd >= 0); assert(dir_path); - assert(handle_ini_section); + assert(eiv); const int dir_fd = open(dir_path, O_DIRECTORY | O_RDONLY); if (dir_fd < 0) { @@ -279,11 +254,6 @@ int handle_extra_dir(int out_fd, char *dir_path, handle_ini_section_t handle_ini return EXIT_ERR; } - __attribute__((cleanup(free_items_vector))) struct extra_items_vector eiv = { - .size = 0, - .data = NULL, - }; - int ret = 0; for (int i = 0; i < entry_count; ++i) { struct dirent *const de = entries[i]; @@ -296,12 +266,37 @@ int handle_extra_dir(int out_fd, char *dir_path, handle_ini_section_t handle_ini snprintf(ini_path, sizeof ini_path, "%s/%s", dir_path, de->d_name); free(de); - ret |= handle_extra_ini(out_fd, &eiv, ini_path); + ret |= handle_extra_ini(out_fd, eiv, ini_path); + } + + if (ret) { + inline int cmp(const void *a, const void *b) { + return ((struct extra_dump_item *)a)->order - ((struct extra_dump_item *)b)->order; + } + qsort(eiv->data, eiv->size, sizeof *eiv->data, cmp); } - ret |= handle_items_vector(&eiv, out_fd, handle_ini_section, argc, argv); free(entries); close(dir_fd); + + return ret; +} + +int handle_extra_dir(int out_fd, char *dir_path, handle_ini_section_t handle_ini_section, int argc, char **argv) +{ + assert(out_fd >= 0); + assert(dir_path); + assert(handle_ini_section); + + __attribute__((cleanup(free_items_vector))) struct extra_items_vector eiv = { + .size = 0, + .data = NULL, + }; + + int ret = 0; + ret |= read_ini_files(out_fd, dir_path, &eiv); + ret |= handle_items_vector(&eiv, out_fd, handle_ini_section, argc, argv); + return ret; } diff --git a/src/dump_systemstate/extras.h b/src/dump_systemstate/extras.h index 392bff0..3544cab 100644 --- a/src/dump_systemstate/extras.h +++ b/src/dump_systemstate/extras.h @@ -18,6 +18,7 @@ #pragma once +#include #include "defs.h" #define DUMP_SYSTEMSTATE_CONFIG_DIR_PROGRAMS_PATH \ @@ -25,11 +26,31 @@ #define DUMP_SYSTEMSTATE_CONFIG_DIR_FILES_PATH \ DUMP_SYSTEMSTATE_CONFIG_DIR_PATH "/files" -struct extra_dump_item; +enum ini_fields { + INI_FIELD_TITLE = 0, + INI_FIELD_PATH, + INI_FIELD_ARGS, + INI_FIELD_ENV, + INI_FIELD_FLAG, + COUNT_INI_FIELDS, +}; + +struct extra_items_vector { + size_t size; + struct extra_dump_item *data; +}; + +struct extra_dump_item { + // not separate named fields, for convenient iteration + char *fields[COUNT_INI_FIELDS]; + int order; +}; + typedef int (*handle_ini_section_t)(int out_fd, struct extra_dump_item *, int argc, char **argv); int handle_extra_dir(int out_fd, char *dir_path, handle_ini_section_t handle_ini_section, int argc, char **argv); int handle_extra_file(int out_fd, struct extra_dump_item *item, int argc, char **argv); int handle_extra_program(int out_fd, struct extra_dump_item *item, int argc, char **argv); +int read_ini_files(int out_fd, char *dir_path, struct extra_items_vector *eiv); -- 2.7.4 From 7cc390e1b4c5f4246b27671cc98a2f027d47d93d Mon Sep 17 00:00:00 2001 From: Mateusz Moscicki Date: Mon, 15 Feb 2021 13:16:53 +0100 Subject: [PATCH 02/16] Add dump_systemstate-service The service registers with the name org.tizen.systemstate and provides the output of defined commands via dumpsys interface. The registration of commands is done by adding dumpsyscmd parameter to the extra program configuration file. For example, the following configuration in /etc/dump_systemstate.conf.d/programs/crash-worker-programs.conf: ... [buxton system] order=141 cmdflag=b title=System configuration path=/usr/bin/buxton2ctl args=dump system dumpsyscmd=buxton_system allowdumpsysargs=yes ... allows to get the output of the command: /usr/bin/buxton2ctl dump system by calling: dumpsys org.tizen.systemstate buxton_system The allowdumpsysargs parameter is responsible for the possibility to provide custom parameters via dumpsys (disallowed by default). Change-Id: Iff9569d4975ab97addfcf32ea6c22d7237275b35 --- CMakeLists.txt | 4 + packaging/crash-worker.spec | 23 ++ src/dump_systemstate-service/CMakeLists.txt | 49 +++ .../dump_systemstate-service.c | 392 +++++++++++++++++++++ .../dump_systemstate.service | 15 + ...dumpsys.providers.org.tizen.systemstate.service | 4 + src/dump_systemstate/extras.c | 11 +- src/dump_systemstate/extras.h | 3 + .../programs/crash-worker-programs.conf | 17 + .../programs/programs.conf.example | 2 + 10 files changed, 518 insertions(+), 2 deletions(-) create mode 100644 src/dump_systemstate-service/CMakeLists.txt create mode 100644 src/dump_systemstate-service/dump_systemstate-service.c create mode 100644 src/dump_systemstate-service/dump_systemstate.service create mode 100644 src/dump_systemstate-service/org.tizen.dumpsys.providers.org.tizen.systemstate.service diff --git a/CMakeLists.txt b/CMakeLists.txt index 8b9605f..3893dad 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,5 +25,9 @@ IF("${CRASH_SERVICE}" STREQUAL "ON") ADD_SUBDIRECTORY(src/bugreport-service) ENDIF() +IF("${DUMP_SYSTEMSTATE_SERVICE}" STREQUAL "ON") + ADD_SUBDIRECTORY(src/dump_systemstate-service) +ENDIF() + ADD_SUBDIRECTORY(tests) diff --git a/packaging/crash-worker.spec b/packaging/crash-worker.spec index 30905dd..98064ef 100644 --- a/packaging/crash-worker.spec +++ b/packaging/crash-worker.spec @@ -4,11 +4,13 @@ %define _with_tests on %define _with_livedumper on %define _with_bugreportservice on +%define _with_dumpsystemstateservice on %bcond_with doc %bcond_with tests %bcond_with livedumper %bcond_with bugreportservice +%bcond_with dumpsystemstateservice %if %{?_with_bugreportservice} == on %define _with_livedumper on @@ -37,6 +39,9 @@ BuildRequires: pkgconfig(libunwind-generic) BuildRequires: libcap-devel BuildRequires: pkgconfig(json-c) BuildRequires: pkgconfig(openssl1.1) +%if %{with dumpsystemstateservice} +BuildRequires: pkgconfig(dumpsys-system) +%endif %if %{with doc} BuildRequires: doxygen @@ -64,6 +69,7 @@ Requires: %{_bindir}/buxton2ctl %if %{with bugreportservice} Requires: %{name}-livedumper = %{version}-%{release} %endif + %description -n crash-manager-core %package -n libcrash-manager-devel @@ -84,6 +90,13 @@ Summary: package provides headers needed to develop programs using bugrep %description -n libbugreport-devel %endif +%if %{with dumpsystemstateservice} +%package -n dumpsystemstate-service +Summary: service provides dumpsys provider to system state information +Requires: %{name}-dumpsystemstate-config = %{version}-%{release} +%description -n dumpsystemstate-service +%endif + %if %{with doc} %package doc Summary: Documentation package for crash-worker @@ -170,6 +183,7 @@ export CFLAGS+=" -Werror" -DCRASH_SYSTEM_TESTS_PATH=%{_libexecdir}/crash-worker/system-tests \ -DLIVEDUMPER=%{on_off livedumper} \ -DCRASH_SERVICE=%{on_off bugreportservice} \ + -DDUMP_SYSTEMSTATE_SERVICE=%{on_off dumpsystemstateservice} \ -DUPGRADE_SCRIPT_PATH=%{upgrade_script_path} \ -DLOGGER=dlog \ -DDLOG_LOG_LEVEL=DLOG_INFO \ @@ -260,6 +274,15 @@ fi %{_libdir}/pkgconfig/bugreport.pc %endif +%if %{with dumpsystemstateservice} +%files -n dumpsystemstate-service +%license LICENSE +%manifest crash-worker.manifest +%attr(0750,crash_worker,crash_worker) %{_bindir}/dump_systemstate-service +%attr(-,root,root) %{_unitdir}/dump_systemstate.service +%attr(-,root,root) %{_datadir}/dbus-1/system-services/org.tizen.dumpsys.providers.org.tizen.systemstate.service +%endif + %if %{with doc} %files doc %{_datadir}/doc/crash-worker diff --git a/src/dump_systemstate-service/CMakeLists.txt b/src/dump_systemstate-service/CMakeLists.txt new file mode 100644 index 0000000..e8bedac --- /dev/null +++ b/src/dump_systemstate-service/CMakeLists.txt @@ -0,0 +1,49 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +PROJECT(dump_systemstate-service C) + +INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/src/) + +SET(DUMP_SYSTEMSTATE_SERVICE_SRC + dump_systemstate-service.c + ${CMAKE_SOURCE_DIR}/src/shared/util.c + ${CMAKE_SOURCE_DIR}/src/shared/spawn.c + ${CMAKE_SOURCE_DIR}/src/dump_systemstate/extras.c + ) + + +INCLUDE(GNUInstallDirs) + +INCLUDE(FindPkgConfig) + +pkg_check_modules(dump_systemstate-service_pkgs REQUIRED + dlog + gio-2.0 + gio-unix-2.0 + iniparser + dumpsys-system + ) + +FOREACH(flag ${dump_systemstate-service_pkgs_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) + +SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -g -fno-omit-frame-pointer -finstrument-functions") + +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -fPIE -Wno-unused-function -Wno-unused-const-variable") + +INCLUDE(${CMAKE_SOURCE_DIR}/cmake/ProcessM4.cmake) + +ADD_EXECUTABLE(${PROJECT_NAME} ${DUMP_SYSTEMSTATE_SERVICE_SRC}) +TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${dump_systemstate-service_pkgs_LDFLAGS} -pie) + +INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/org.tizen.dumpsys.providers.org.tizen.systemstate.service + DESTINATION /usr/share/dbus-1/system-services + PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ) + +INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/dump_systemstate.service + DESTINATION /usr/lib/systemd/system + PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ) + +INSTALL(TARGETS ${PROJECT_NAME} DESTINATION bin + PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE + GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) diff --git a/src/dump_systemstate-service/dump_systemstate-service.c b/src/dump_systemstate-service/dump_systemstate-service.c new file mode 100644 index 0000000..6635429 --- /dev/null +++ b/src/dump_systemstate-service/dump_systemstate-service.c @@ -0,0 +1,392 @@ +/* + * dump_systemstate + * + * Copyright (c) 2021 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 +#include +#include +#include +#include + +#include "dump_systemstate/dump_systemstate.h" +#include "dump_systemstate/extras.h" +#include "shared/log.h" +#include "shared/spawn.h" +#include "shared/util.h" + +#define DUMP_SYSTEMSTATE_BUS_NAME "org.tizen.systemstate" +#define DUMP_SYSTEMSTATE_OBJECT_PATH "/Org/Tizen/Systemstate" +#define DUMP_SYSTEMSTATE_INTERFACE_NAME DUMP_SYSTEMSTATE_BUS_NAME +#define TIMEOUT_INTERVAL_SEC 30 + +static GMainLoop *loop = NULL; +static GMutex timeout_mutex; +static guint timeout_id; +static GHashTable *commands = NULL; +struct extra_items_vector commands_list = { .size = 0, .data = NULL }; + +static int timeout_cb(gpointer data) +{ + assert(data); + _I("Time out!"); + g_main_loop_quit((GMainLoop *)data); + + return 0; +} + +static void add_timeout(void) +{ + g_mutex_lock(&timeout_mutex); + + if (timeout_id) + g_source_remove(timeout_id); + timeout_id = g_timeout_add_seconds(TIMEOUT_INTERVAL_SEC, timeout_cb, loop); + + g_mutex_unlock(&timeout_mutex); + _D("Add loop timeout (%d)", TIMEOUT_INTERVAL_SEC); +} + +static void remove_timeout(void) +{ + g_mutex_lock(&timeout_mutex); + + if (timeout_id) { + g_source_remove(timeout_id); + timeout_id = 0; + } + + g_mutex_unlock(&timeout_mutex); + _D("Remove loop timeout"); +} + +static char* join(int argc, char **argv, int offset) +{ + assert(argv); + + if (offset <= argc) + return strdup(""); + + ssize_t length = 0; + for (int i = offset; i < argc; i++) + length += strlen(argv[i]) + 1; + + char *result = malloc(length + 1); + if (result == NULL) { + _E("Out of memory"); + return NULL; + } + char *pointer = result; + + for (int i = offset; i < argc; i++) { + int printed = snprintf(pointer, strlen(argv[i]) + 2, "%s ", argv[i]); + if (printed < 0) { + free(result); + _E("Cannot concatenate strings: %m"); + return NULL; + } + + pointer += printed; + } + result[length-1] = '\0'; + return result; +} + +char** split(const char *str, size_t *size) +{ + assert(str); + + char **result = NULL; + char *str_tmp = strdup(str); + if (str_tmp == NULL) { + _E("Out of memory"); + return NULL; + } + + char *chunk = strtok(str_tmp, " "); + *size = 0; + + while (chunk != NULL) { + char **result_tmp = realloc(result, (*size + 1) * sizeof(char *)); + char *chunk_copy = strdup(chunk); + + if (result_tmp == NULL || chunk_copy == NULL) { + _E("Out of memory"); + if (result_tmp != NULL) + free(result_tmp); + if (chunk_copy != NULL) + free(chunk_copy); + free(result); + result = NULL; + goto out; + } + + result = result_tmp; + result[(*size)++] = chunk_copy; + chunk = strtok(NULL, " "); + } + + char **result_tmp = realloc(result, (*size + 1) * sizeof(char *)); + if (result_tmp == NULL) { + _E("Out of memory"); + free(result); + result = NULL; + goto out; + } + + result = result_tmp; + result[*size] = NULL; + +out: + free(str_tmp); + return result; +} + +static void free_array(char **array) +{ + if (array != NULL) { + for (size_t i = 0; array[i] != NULL; i++) + free(array[i]); + free(array); + } +} + +static char** build_argv_array(const char *path, int argc, char **argv) +{ + char **av = malloc((argc + 2) * sizeof(char *)); + if (av == NULL) { + _E("Out of memory"); + return NULL; + } + + av[0] = strdup(path); + if (av[0] == NULL) { + _E("Out of memory"); + free(av); + return NULL; + } + + for (int i = 0; i < argc; i++) { + av[i + 1] = strdup(argv[i]); + if (av[i + 1] == NULL) { + _E("Out of memory"); + free_array(av); + return NULL; + } + } + + av[argc + 1] = NULL; + + return av; +} + +static char** prepare_dumpsys_args(const char *path, int dumpsys_argc, char **dumpsys_argv) +{ + return build_argv_array(path, dumpsys_argc - 1, dumpsys_argv+1); +} + +static char** prepare_config_args(const char *path, char *args) +{ + size_t argc = 0; + char **argv = split(args, &argc); + return build_argv_array(path, argc, argv); +} + +static char** prepare_args(struct extra_dump_item *item, const int dumpsys_argc, char **dumpsys_argv) +{ + bool allow_dumpsys_args = false; + if (item->fields[INI_FIELD_ALLOWDUMPSYSARGS] != NULL) + allow_dumpsys_args = strncasecmp(item->fields[INI_FIELD_ALLOWDUMPSYSARGS], "yes", 4) == 0; + + if (allow_dumpsys_args && dumpsys_argc > 1) + return prepare_dumpsys_args(item->fields[INI_FIELD_PATH], dumpsys_argc, dumpsys_argv); + else + return prepare_config_args(item->fields[INI_FIELD_PATH], item->fields[INI_FIELD_ARGS]); +} + +static char** prepare_env(const char *config_env) +{ + char **ev = NULL; + + if (config_env != NULL) { + size_t size = 0; + ev = split(config_env, &size); + } + + return ev; +} + +static int dump_item(int fd, struct extra_dump_item *item, const int dumpsys_argc, char **dumpsys_argv) +{ + assert(item); + + int result = TIZEN_ERROR_NONE; + + char **av = prepare_args(item, dumpsys_argc, dumpsys_argv); + + if (av == NULL) + goto out; + + char **ev = prepare_env(item->fields[INI_FIELD_ENV]); + int err; + spawn_param_s param_stdout = { .fn = spawn_setstdout, .u.int_val = fd }; + spawn_param_s param_stderr = { .fn = spawn_setstderr, .u.int_val = fd, .next = ¶m_stdout }; + + if (!spawn_wait(av, ev, ¶m_stderr, DEFAULT_COMMAND_TIMEOUT_MS, &err)) + result = TIZEN_ERROR_INVALID_OPERATION; + + free_array(ev); +out: + free_array(av); + + return result; +} + +static bool dumpsys_enabled(struct extra_dump_item *item) +{ + assert(item); + + return item->fields[INI_FIELD_DUMPSYSCMD] != NULL && *(item->fields[INI_FIELD_DUMPSYSCMD]) != '\0'; +} + +static void print_header(int fd, struct extra_dump_item *item) +{ + assert(item); + dprintf(fd, + "\n==== %s (%s %s)\n", + item->fields[INI_FIELD_TITLE] ?: "", + item->fields[INI_FIELD_PATH] ?: "", + item->fields[INI_FIELD_ARGS] ?: ""); +} + +static int dump_all_items(int fd) +{ + int result = TIZEN_ERROR_NONE; + + for (size_t i = 0; i < commands_list.size; i++) { + if (dumpsys_enabled(&commands_list.data[i])) { + print_header(fd, &commands_list.data[i]); + result |= dump_item(fd, &commands_list.data[i], 0, NULL); + } + } + + return result; +} + +static int dumpsys_cb(const int fd, const int argc, char **argv) +{ + assert(fd >= 0); + assert(argv); + + if (commands == NULL) { + _E("Commands not initialized"); + return TIZEN_ERROR_INVALID_OPERATION; + } + + int result = TIZEN_ERROR_NONE; + if (argc == 0) { + result = dump_all_items(fd); + } else { + struct extra_dump_item *item = g_hash_table_lookup(commands, argv[0]); + if (item == NULL) { + _E("Command not found: %s", argv[0]); + return TIZEN_ERROR_INVALID_PARAMETER; + } + result = dump_item(fd, item, argc, argv); + } + + return result; +} + +static void free_item(struct extra_dump_item *item) +{ + assert(item); + + for (size_t i = 0; i < ARRAY_SIZE(item->fields); i++) + free(item->fields[i]); +} + +static int fill_commands() +{ + int result = read_ini_files(STDOUT_FILENO, DUMP_SYSTEMSTATE_CONFIG_DIR_PROGRAMS_PATH, &commands_list); + + if (result != EXIT_OK) + return result; + + commands = g_hash_table_new(g_str_hash, g_str_equal); + if (commands == NULL) { + _E("Out of memory"); + return EXIT_ERR; + } + + struct extra_dump_item *item = commands_list.data; + + for (size_t i = 0; i < commands_list.size; i++, item++) { + char *dumpcmd = item->fields[INI_FIELD_DUMPSYSCMD]; + + if (dumpcmd != NULL && strlen(dumpcmd) > 0) { + if (g_hash_table_lookup(commands, dumpcmd) != NULL) { + _I("Duplicated command: %s", dumpcmd); + free_item(item); + } else { + _D("New dumpsys command: %s", dumpcmd); + g_hash_table_insert(commands, dumpcmd, item); + } + } + } + + return result; +} + +int main() +{ + void *handler = NULL; + int exit_code = EXIT_SUCCESS; + + if (fill_commands() != EXIT_OK) { + exit_code = EXIT_FAILURE; + goto out; + } + + loop = g_main_loop_new(NULL, false); + + if (dumpsys_system_register_dump_cb(dumpsys_cb, DUMP_SYSTEMSTATE_BUS_NAME, &handler) != TIZEN_ERROR_NONE) { + _E("Callback registration error"); + exit_code = EXIT_FAILURE; + goto out; + } + + g_mutex_init(&timeout_mutex); + add_timeout(); + g_main_loop_run(loop); + + g_mutex_clear(&timeout_mutex); + +out: + if (loop != NULL) + g_main_loop_unref(loop); + + if (handler != NULL) + dumpsys_system_unregister_dump_cb(handler); + + if (commands != NULL) + g_hash_table_destroy(commands); + + for (size_t i = 0; i < commands_list.size; i++) + free_item(&commands_list.data[i]); + + return exit_code; +} diff --git a/src/dump_systemstate-service/dump_systemstate.service b/src/dump_systemstate-service/dump_systemstate.service new file mode 100644 index 0000000..8b1c101 --- /dev/null +++ b/src/dump_systemstate-service/dump_systemstate.service @@ -0,0 +1,15 @@ +[Unit] +Description=dump_systemstate service + +[Service] +Type=dbus +User=crash_worker +Group=crash_worker +Capabilities=cap_dac_read_search,cap_sys_ptrace,cap_syslog=i +SecureBits=keep-caps +BusName=org.tizen.systemstate +ExecStart=/usr/bin/dump_systemstate-service +SupplementaryGroups=log systemd-journal system_share +SmackProcessLabel=System +Nice=-5 +KillMode=mixed diff --git a/src/dump_systemstate-service/org.tizen.dumpsys.providers.org.tizen.systemstate.service b/src/dump_systemstate-service/org.tizen.dumpsys.providers.org.tizen.systemstate.service new file mode 100644 index 0000000..4cac3f1 --- /dev/null +++ b/src/dump_systemstate-service/org.tizen.dumpsys.providers.org.tizen.systemstate.service @@ -0,0 +1,4 @@ +[D-BUS Service] +Name=org.tizen.dumpsys.providers.org.tizen.systemstate +Exec=/bin/false +SystemdService=dump_systemstate.service diff --git a/src/dump_systemstate/extras.c b/src/dump_systemstate/extras.c index 88e42d8..42d3345 100644 --- a/src/dump_systemstate/extras.c +++ b/src/dump_systemstate/extras.c @@ -51,9 +51,12 @@ static const char *const INI_KEYS[COUNT_INI_FIELDS] = { [INI_FIELD_ARGS] = "args", [INI_FIELD_ENV] = "env", [INI_FIELD_FLAG] = "cmdflag", + [INI_FIELD_DUMPSYSCMD] = "dumpsyscmd", + [INI_FIELD_ALLOWDUMPSYSARGS] = "allowdumpsysargs", + [INI_FIELD_ALLOWCOMMANDLINE] = "allowcommandline", // non-string field: "order" }; -static const size_t MAX_INI_KEY_LEN = 7; +static const size_t MAX_INI_KEY_LEN = 16; void cleanup_extra_dump_item(struct extra_dump_item *edi) { @@ -86,6 +89,10 @@ int handle_extra_program(int out_fd, struct extra_dump_item *item, int argc, cha assert(out_fd >= 0); assert(item); + if (item->fields[INI_FIELD_ALLOWCOMMANDLINE] != NULL && + strncasecmp(item->fields[INI_FIELD_ALLOWCOMMANDLINE], "no", 3) == 0) + return 0; + const char *const title = item->fields[INI_FIELD_TITLE]; const char *const path = item->fields[INI_FIELD_PATH]; const char *const args = item->fields[INI_FIELD_ARGS] ?: ""; @@ -269,7 +276,7 @@ int read_ini_files(int out_fd, char *dir_path, struct extra_items_vector *eiv) ret |= handle_extra_ini(out_fd, eiv, ini_path); } - if (ret) { + if (ret == 0) { inline int cmp(const void *a, const void *b) { return ((struct extra_dump_item *)a)->order - ((struct extra_dump_item *)b)->order; } diff --git a/src/dump_systemstate/extras.h b/src/dump_systemstate/extras.h index 3544cab..ee0d421 100644 --- a/src/dump_systemstate/extras.h +++ b/src/dump_systemstate/extras.h @@ -32,6 +32,9 @@ enum ini_fields { INI_FIELD_ARGS, INI_FIELD_ENV, INI_FIELD_FLAG, + INI_FIELD_DUMPSYSCMD, + INI_FIELD_ALLOWDUMPSYSARGS, + INI_FIELD_ALLOWCOMMANDLINE, COUNT_INI_FIELDS, }; diff --git a/src/dump_systemstate/programs/crash-worker-programs.conf b/src/dump_systemstate/programs/crash-worker-programs.conf index c8980ac..a96e2af 100644 --- a/src/dump_systemstate/programs/crash-worker-programs.conf +++ b/src/dump_systemstate/programs/crash-worker-programs.conf @@ -22,6 +22,8 @@ order=130 title=System memory statistics path=/usr/bin/memps args=-v +dumpsyscmd=memory +allowdumpsysargs=yes [buxton memory] order=140 @@ -57,6 +59,8 @@ title=Kernel messages path=/bin/dmesg args=-T env=TZ=UTC +dumpsyscmd=klog +allowdumpsysargs=yes [dlog] order=210 @@ -64,6 +68,8 @@ cmdflag=d title=Log messages path=/usr/bin/dlogutil args=-d -v threadtime -u 16384 +dumpsyscmd=dlog +allowdumpsysargs=yes [journal] order=220 @@ -71,3 +77,14 @@ cmdflag=j title=Journal messages path=/usr/bin/journalctl args=-b -n 1024 +dumpsyscmd=journal +allowdumpsysargs=yes + +[disk] +order=1000 +title=Disk +path=/bin/df +args=-h +dumpsyscmd=disk +allowdumpsysargs=yes +allowcommandline=no diff --git a/src/dump_systemstate/programs/programs.conf.example b/src/dump_systemstate/programs/programs.conf.example index b44b9ce..b28d326 100644 --- a/src/dump_systemstate/programs/programs.conf.example +++ b/src/dump_systemstate/programs/programs.conf.example @@ -10,3 +10,5 @@ env=POSIXLY_CORRECT=1 title=dump dlog contents path=/usr/bin/dlogutil args=-d +dumpsyscmd=dlogutil +allowdumpsysargs=yes -- 2.7.4 From c5c7a9db8ffa19295a891abe5e1b3579bd37f43a Mon Sep 17 00:00:00 2001 From: Karol Lewandowski Date: Thu, 11 Mar 2021 10:39:18 +0100 Subject: [PATCH 03/16] bugreport: Ensure library is linked to libraries we actually need We always link to libcrash-manager but it might not be needed, if livecoredump suport is disabled. This commit prepares bugreport-service to be libcrash-manager-independent. Change-Id: I4d506e517ce2da22daa047741187a15f91da4180 --- src/bugreport-service/CMakeLists.txt | 5 ++++- src/bugreport-service/bugreport-service.c | 1 + src/crash-manager/CMakeLists.txt | 1 + src/crash-manager/crash-manager.c | 5 ----- src/crash-manager/crash-manager.h | 1 - src/shared/util.c | 6 ++++++ src/shared/util.h | 2 ++ 7 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/bugreport-service/CMakeLists.txt b/src/bugreport-service/CMakeLists.txt index 5f6c045..4bdeb18 100644 --- a/src/bugreport-service/CMakeLists.txt +++ b/src/bugreport-service/CMakeLists.txt @@ -6,6 +6,8 @@ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/src/) SET(CRASH_SERVICE_SRCS bugreport-service.c diagnostics/diagnostics.c + ${CMAKE_SOURCE_DIR}/src/shared/util.c + ${CMAKE_SOURCE_DIR}/src/shared/config.c ) INCLUDE(GNUInstallDirs) @@ -17,6 +19,7 @@ pkg_check_modules(bugreport-service_pkgs REQUIRED gio-2.0 gio-unix-2.0 libzip + iniparser ) FOREACH(flag ${bugreport-service_pkgs_CFLAGS}) @@ -30,7 +33,7 @@ INCLUDE(${CMAKE_SOURCE_DIR}/cmake/ProcessM4.cmake) LINK_DIRECTORIES(${CMAKE_SOURCE_DIR}/src/crash-manager) ADD_EXECUTABLE(${PROJECT_NAME} ${CRASH_SERVICE_SRCS}) ADD_DEPENDENCIES(${PROJECT_NAME} crash-manager) -TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${bugreport-service_pkgs_LDFLAGS} -pie -lrt -lcrash-manager) +TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${bugreport-service_pkgs_LDFLAGS} -pie -Wl,--as-needed -lrt -lcrash-manager) ADD_LIBRARY(libbugreport SHARED libbugreport-service.c) SET_TARGET_PROPERTIES(libbugreport PROPERTIES diff --git a/src/bugreport-service/bugreport-service.c b/src/bugreport-service/bugreport-service.c index 36c9a59..b869140 100644 --- a/src/bugreport-service/bugreport-service.c +++ b/src/bugreport-service/bugreport-service.c @@ -32,6 +32,7 @@ #include "crash-manager/crash-manager.h" #include "libbugreport.h" #include "shared/log.h" +#include "shared/util.h" #include "diagnostics/diagnostics.h" /* Dbus activation */ diff --git a/src/crash-manager/CMakeLists.txt b/src/crash-manager/CMakeLists.txt index 4a2fb3b..2c08cdb 100644 --- a/src/crash-manager/CMakeLists.txt +++ b/src/crash-manager/CMakeLists.txt @@ -12,6 +12,7 @@ SET(LIB_CRASH_MANAGER_SRCS SET(CRASH_MANAGER_SRCS main.c + ${CMAKE_SOURCE_DIR}/src/shared/util.c ) INCLUDE(GNUInstallDirs) diff --git a/src/crash-manager/crash-manager.c b/src/crash-manager/crash-manager.c index d4fb782..1554f34 100644 --- a/src/crash-manager/crash-manager.c +++ b/src/crash-manager/crash-manager.c @@ -92,11 +92,6 @@ config_t config; static char* crash_dump_path; static char* crash_temp_path; -bool have_livecoredumper(void) -{ - return access(LIVEDUMPER_BIN_PATH, X_OK) == 0; -} - /* pkgmgrinfo filter list function for getting application ID */ static int appinfo_get_appid_func(pkgmgrinfo_appinfo_h handle, void *user_data) diff --git a/src/crash-manager/crash-manager.h b/src/crash-manager/crash-manager.h index e5db78f..c511043 100644 --- a/src/crash-manager/crash-manager.h +++ b/src/crash-manager/crash-manager.h @@ -61,5 +61,4 @@ bool crash_manager_livedump_pid(pid_t pid, const char *dump_reason, char *report void crash_info_init(struct crash_info *cinfo); void crash_manager_free(struct crash_info *cinfo); -bool have_livecoredumper(void); #endif diff --git a/src/shared/util.c b/src/shared/util.c index a8d6ba9..e26d261 100644 --- a/src/shared/util.c +++ b/src/shared/util.c @@ -36,9 +36,15 @@ #include #include +#include "defs.h" #include "util.h" #include "log.h" +bool have_livecoredumper(void) +{ + return access(LIVEDUMPER_BIN_PATH, X_OK) == 0; +} + int write_fd(int fd, const void *buf, int len) { int count; diff --git a/src/shared/util.h b/src/shared/util.h index 5a79806..85dd15f 100644 --- a/src/shared/util.h +++ b/src/shared/util.h @@ -32,6 +32,8 @@ extern "C" { #endif +bool have_livecoredumper(void); + int write_fd(int fd, const void *buf, int len); int copy_bytes(int destfd, int srcfd, off_t *ncopied); -- 2.7.4 From ff22f8325d3bad4afc09cd297ae7874f1bd490ef Mon Sep 17 00:00:00 2001 From: Karol Lewandowski Date: Thu, 11 Mar 2021 12:23:33 +0100 Subject: [PATCH 04/16] libcrash-service: Do not export unneeded symbols Change-Id: I5584761b83f386568b869be921f667d18c6cfd3e --- src/crash-manager/CMakeLists.txt | 2 +- src/crash-manager/crash-manager.c | 10 +++++----- src/crash-manager/crash-manager.h | 5 ++++- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/crash-manager/CMakeLists.txt b/src/crash-manager/CMakeLists.txt index 2c08cdb..70930cd 100644 --- a/src/crash-manager/CMakeLists.txt +++ b/src/crash-manager/CMakeLists.txt @@ -36,7 +36,7 @@ FOREACH(flag ${crash-manager_pkgs_CFLAGS} ${helper_pkgs_CFLAGS}) SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") ENDFOREACH(flag) -SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -fPIE") +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -fPIE -fvisibility=hidden") ADD_LIBRARY(libcrash-manager SHARED ${LIB_CRASH_MANAGER_SRCS}) SET_TARGET_PROPERTIES(libcrash-manager PROPERTIES SOVERSION 1) diff --git a/src/crash-manager/crash-manager.c b/src/crash-manager/crash-manager.c index 1554f34..1db35b9 100644 --- a/src/crash-manager/crash-manager.c +++ b/src/crash-manager/crash-manager.c @@ -1252,7 +1252,7 @@ static int wait_for_opt(unsigned int timeout) return 1; } -static void free_crash_info(struct crash_info *cinfo) +EXPORT void free_crash_info(struct crash_info *cinfo) { free(cinfo->cmd_line); free(cinfo->cmd_path); @@ -1273,7 +1273,7 @@ static void free_crash_info(struct crash_info *cinfo) free(cinfo->call_stack_hash); } -void crash_info_init(struct crash_info *cinfo) +EXPORT void crash_info_init(struct crash_info *cinfo) { cinfo->prstatus_fd = -1; cinfo->livedump = false; @@ -1453,7 +1453,7 @@ static void crash_manager_cleanup(struct crash_info *cinfo) clean_temp(crash_temp_path); } -void crash_manager_free(struct crash_info *cinfo) +EXPORT void crash_manager_free(struct crash_info *cinfo) { if (cinfo->prstatus_fd >= 0) close(cinfo->prstatus_fd); @@ -1464,7 +1464,7 @@ void crash_manager_free(struct crash_info *cinfo) free_crash_info(cinfo); } -bool crash_manager_direct(struct crash_info *cinfo) +EXPORT bool crash_manager_direct(struct crash_info *cinfo) { if (!crash_manager_prepare(cinfo)) return false; @@ -1475,7 +1475,7 @@ bool crash_manager_direct(struct crash_info *cinfo) return result; } -bool crash_manager_livedump_pid(pid_t pid, const char *dump_reason, char *report_path, size_t report_path_len) +EXPORT bool crash_manager_livedump_pid(pid_t pid, const char *dump_reason, char *report_path, size_t report_path_len) { bool result = false; struct crash_info cinfo; diff --git a/src/crash-manager/crash-manager.h b/src/crash-manager/crash-manager.h index c511043..a12f03e 100644 --- a/src/crash-manager/crash-manager.h +++ b/src/crash-manager/crash-manager.h @@ -23,6 +23,8 @@ #include #include +#define EXPORT __attribute__ ((visibility ("default"))) + /* Paths and variables */ struct crash_info { bool livedump; @@ -58,7 +60,8 @@ struct crash_info { bool crash_manager_direct(struct crash_info *cinfo); bool crash_manager_livedump_pid(pid_t pid, const char *dump_reason, char *report_path, size_t report_path_len); -void crash_info_init(struct crash_info *cinfo); void crash_manager_free(struct crash_info *cinfo); +void crash_info_init(struct crash_info *cinfo); +void free_crash_info(struct crash_info *cinfo); #endif -- 2.7.4 From 9d12e110f5f6b1499f8c1334f1cabf612a8cea96 Mon Sep 17 00:00:00 2001 From: Mateusz Moscicki Date: Wed, 10 Mar 2021 11:30:39 +0100 Subject: [PATCH 05/16] bugreport-service: Independence from the crash-manager The changes that this commit makes allow to install the bugreport-service without having to install crash-manager. Change-Id: If448436c0dff6a69f1bef6b4d249c199f549dec8 --- CMakeLists.txt | 7 +- include/defs.h.in | 5 + src/bugreport-service/CMakeLists.txt | 2 + src/bugreport-service/bugreport-service.c | 54 ++++++--- src/bugreport-service/systemdump.c | 185 ++++++++++++++++++++++++++++++ src/bugreport-service/systemdump.h | 32 ++++++ src/crash-manager/crash-manager.c | 62 +--------- src/shared/util.c | 62 ++++++++-- src/shared/util.h | 6 +- tests/system/CMakeLists.txt | 2 + 10 files changed, 327 insertions(+), 90 deletions(-) create mode 100644 src/bugreport-service/systemdump.c create mode 100644 src/bugreport-service/systemdump.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 3893dad..0288a17 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,6 +5,10 @@ SET(PREFIX ${CMAKE_INSTALL_PREFIX}) ADD_DEFINITIONS(-D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE=1) +IF("${LIVEDUMPER}" STREQUAL "ON") + ADD_DEFINITIONS(-DLIVEDUMPER=ON) +ENDIF() + # Sub modules ADD_SUBDIRECTORY(include) INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/src/bugreport-service) @@ -19,9 +23,6 @@ IF("${LIVEDUMPER}" STREQUAL "ON") ENDIF() IF("${CRASH_SERVICE}" STREQUAL "ON") - if (NOT "${LIVEDUMPER}" STREQUAL "ON") - message(FATAL_ERROR "Livedumper is required to build bugreport-service") - ENDIF() ADD_SUBDIRECTORY(src/bugreport-service) ENDIF() diff --git a/include/defs.h.in b/include/defs.h.in index 906b649..ad5ca3a 100644 --- a/include/defs.h.in +++ b/include/defs.h.in @@ -21,4 +21,9 @@ #define LIVEDUMPER_BIN_PATH "@LIVEDUMPER_BIN_PATH@" #define DLOG_LOG_LEVEL @DLOG_LOG_LEVEL@ +#define CRASH_TEMP_SUBDIR "/temp/" +#define CRASH_PATH_SUBDIR "/dump/" +#define LIVE_PATH_SUBDIR "/livedump/" +#define APP_PATH_SUBDIR "/app/" + #endif /* __DEFS_H__ */ diff --git a/src/bugreport-service/CMakeLists.txt b/src/bugreport-service/CMakeLists.txt index 4bdeb18..4d7c849 100644 --- a/src/bugreport-service/CMakeLists.txt +++ b/src/bugreport-service/CMakeLists.txt @@ -5,8 +5,10 @@ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/src/) SET(CRASH_SERVICE_SRCS bugreport-service.c + systemdump.c diagnostics/diagnostics.c ${CMAKE_SOURCE_DIR}/src/shared/util.c + ${CMAKE_SOURCE_DIR}/src/shared/spawn.c ${CMAKE_SOURCE_DIR}/src/shared/config.c ) diff --git a/src/bugreport-service/bugreport-service.c b/src/bugreport-service/bugreport-service.c index b869140..e5d2d2d 100644 --- a/src/bugreport-service/bugreport-service.c +++ b/src/bugreport-service/bugreport-service.c @@ -34,6 +34,7 @@ #include "shared/log.h" #include "shared/util.h" #include "diagnostics/diagnostics.h" +#include "systemdump.h" /* Dbus activation */ #define CRASH_BUS_NAME "org.tizen.system.crash.livedump" @@ -52,6 +53,7 @@ #define CS_ERR_TIMEOUT 2 #define CS_ERR_READ 3 #define CS_ERR_INTERNAL 4 +#define CS_ERR_UNSUPPORTED 5 static GMainLoop *loop; static GMutex timeout_mutex; @@ -117,7 +119,7 @@ static void remove_timeout(void) _D("Remove loop timeout"); } -struct livedump_cb_data { +struct callback_data { int read_fd; GDBusMethodInvocation *invocation; GSource* source; @@ -138,7 +140,7 @@ static bool data_ready(int fd) static gboolean read_result_cb(gpointer data) { - struct livedump_cb_data *cb_data = (struct livedump_cb_data*)data; + struct callback_data *cb_data = (struct callback_data*)data; char report_path[PATH_MAX] = {0}; if (!data_ready(cb_data->read_fd)) { @@ -170,26 +172,27 @@ end: return G_SOURCE_REMOVE; } -static bool livedump_run(int write_fd, pid_t pid, const gchar *dump_reason) +static bool livedump_run(struct dump_operation_data *data) { + assert(data); char report_path[PATH_MAX]; - if (!crash_manager_livedump_pid(pid, dump_reason, report_path, sizeof(report_path))) { + if (!crash_manager_livedump_pid(data->pid, data->dump_reason, report_path, sizeof(report_path))) { _E("crash_manager_livedump_pid error"); return false; } - if (write(write_fd, report_path, strlen(report_path) + 1) == -1) { + if (write(data->write_fd, report_path, strlen(report_path) + 1) == -1) { _E("Write report_path error: %m"); - close(write_fd); + close(data->write_fd); return false; } - close(write_fd); + close(data->write_fd); return true; } -static void livedump_pid_handler(GDBusMethodInvocation *invocation, pid_t pid, gchar *dump_reason) +static void dump_handler(GDBusMethodInvocation *invocation, bool (*operation)(struct dump_operation_data *), struct dump_operation_data *data) { /* * We want to run the livedump in different process so as not to @@ -207,7 +210,7 @@ static void livedump_pid_handler(GDBusMethodInvocation *invocation, pid_t pid, g return; } - struct livedump_cb_data *cb_data = (struct livedump_cb_data*)malloc(sizeof(struct livedump_cb_data)); + struct callback_data *cb_data = (struct callback_data*)malloc(sizeof(struct callback_data)); if (cb_data == NULL) { _E("cb_data malloc() error: %m"); exit(EXIT_FAILURE); @@ -224,7 +227,8 @@ static void livedump_pid_handler(GDBusMethodInvocation *invocation, pid_t pid, g pid_t child_pid = fork(); if (child_pid == 0) { close(fds[0]); - if (livedump_run(fds[1], pid, dump_reason)) + data->write_fd = fds[1]; + if (operation(data)) exit(EXIT_SUCCESS); else exit(EXIT_FAILURE); @@ -251,14 +255,29 @@ static void crash_interface_handler(GDBusConnection *conn, GDBusMethodInvocation *invocation, gpointer user_data) { - _D("crash iface method: %s", method_name); if (g_strcmp0(method_name, "livedump_pid") == 0) { gchar *dump_reason; pid_t pid; if (g_variant_is_of_type(parameters, G_VARIANT_TYPE("(is)"))) { g_variant_get(parameters, "(is)", &pid, &dump_reason); - livedump_pid_handler(invocation, pid, dump_reason); + struct dump_operation_data data = { .write_fd = -1, .pid = pid, .dump_reason = dump_reason }; + + if (pid <= 0) { + dump_handler(invocation, &systemstate_dump_run, &data); + } else { +#ifdef LIVEDUMPER + if (!have_livecoredumper()) { + _E("livecoredumper not available - can not provide livedump API. Terminating."); + goto unsupported; + } + + dump_handler(invocation, &livedump_run, &data); +#else + _W("Unsupported livedump_pid() call with PID=%d. No livedumper support for processes.", pid); + goto unsupported; +#endif + } } else { _E("Parameters are not of the correct type (is)"); g_dbus_method_invocation_return_error(invocation, @@ -268,6 +287,12 @@ static void crash_interface_handler(GDBusConnection *conn, } } + return; +unsupported: + g_dbus_method_invocation_return_error(invocation, + CS_ERROR, + CS_ERR_UNSUPPORTED, + "Unsupported"); } static GUnixFDList* prepare_unix_fd_list(int fd) @@ -470,11 +495,6 @@ int main(void) /* Have consinsent umask across invocations - from shell, bugreport-service, kernel */ umask(DEFAULT_UMASK); - if (!have_livecoredumper()) { - _E("livecoredumper not available - can not provide livedump API. Terminating.\n"); - return EXIT_FAILURE; - } - loop = g_main_loop_new(NULL, false); if (!dbus_init()) { diff --git a/src/bugreport-service/systemdump.c b/src/bugreport-service/systemdump.c new file mode 100644 index 0000000..012bcc9 --- /dev/null +++ b/src/bugreport-service/systemdump.c @@ -0,0 +1,185 @@ +/* + * systemdump + * + * Copyright (c) 2021 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 +#include +#include +#include +#include +#include + +#include "systemdump.h" +#include "defs.h" +#include "shared/spawn.h" +#include "shared/util.h" +#include "shared/log.h" + +#define DUMP_SYSTEMSTATE_TIMEOUT_MS 1000*60*2 + +struct systemstate_info { + char *report_name; + char *log_path; + char *zip_path; + char *temp_path; + char *temp_report_dir; + char *reports_dir; + char *report_path; +}; + +static void systemstate_info_init(struct systemstate_info *sinfo) +{ + sinfo->report_name = NULL; + sinfo->log_path = NULL; + sinfo->zip_path = NULL; + sinfo->temp_path = NULL; + sinfo->temp_report_dir = NULL; + sinfo->reports_dir = NULL; + sinfo->report_path = NULL; +} + +static void systemstate_info_free(struct systemstate_info *sinfo) +{ + free(sinfo->report_name); + free(sinfo->log_path); + free(sinfo->zip_path); + free(sinfo->temp_path); + free(sinfo->temp_report_dir); + free(sinfo->reports_dir); + free(sinfo->report_path); +} + +static bool prepare_paths(struct systemstate_info *sinfo) +{ + char date[16]; + + struct tm loc_tm; + time_t time_info = time(NULL); + localtime_r(&time_info, &loc_tm); + strftime(date, sizeof(date), "%Y%m%d%H%M%S", &loc_tm); + + if (!make_dir(CRASH_TEMP, DEFAULT_CRASH_DIR_PERM)) + return false; + + if (asprintf(&sinfo->temp_path, "%s/crash.XXXXXX", CRASH_TEMP) == -1) + goto out_of_memory; + + if (mkdtemp(sinfo->temp_path) == NULL || access(sinfo->temp_path, F_OK)) { + _E("Failed to create temporary directory %s: %m", sinfo->temp_path); + return false; + } + + if (asprintf(&sinfo->report_name, "system_0_%s", date) == -1 || + asprintf(&sinfo->temp_report_dir, "%s/%s", sinfo->temp_path, sinfo->report_name) == -1 || + asprintf(&sinfo->log_path, "%s/%s.log", sinfo->temp_report_dir, sinfo->report_name) == -1 || + asprintf(&sinfo->reports_dir, "%s%s", CRASH_ROOT_PATH, LIVE_PATH_SUBDIR) == -1 || + asprintf(&sinfo->zip_path, "%s/report.zip", sinfo->temp_path) == -1 || + asprintf(&sinfo->report_path, "%s%s.%s", sinfo->reports_dir, sinfo->report_name, "zip") == -1) + goto out_of_memory; + + if (!make_dir(sinfo->temp_report_dir, 0775)) { + _E("Failed to make_dir %s: %m", sinfo->temp_report_dir); + return false; + } + + if (!make_dir(sinfo->reports_dir, DEFAULT_CRASH_DIR_PERM)) { + _E("Failed to make_dir %s: %m", sinfo->reports_dir); + return false; + } + + return true; + +out_of_memory: + _E("Out of memory"); + return false; +} + +static void systemstate_dump(struct systemstate_info *sinfo) +{ + char *av[] = {DUMP_SYSTEMSTATE_BIN_PATH, "-d", "-k", "-j", "-p", "-e", "-f", sinfo->log_path, "-b", NULL}; + spawn_param_s param = { .fn = spawn_setstdout, .u.int_val = STDERR_FILENO }; + (void)spawn_wait(av, NULL, ¶m, DUMP_SYSTEMSTATE_TIMEOUT_MS, NULL); +} + +static void zip_report(struct systemstate_info *sinfo) +{ + char *args[] = {"/bin/zip", "-qyr", sinfo->zip_path, sinfo->report_name, NULL}; + spawn_param_s param1 = { .fn = spawn_nullstdfds }; + spawn_param_s param0 = { .fn = spawn_chdir, .u.char_ptr = sinfo->temp_path, .next = ¶m1 }; + (void)spawn_wait(args, NULL, ¶m0, DEFAULT_COMMAND_TIMEOUT_MS, NULL); +} + +static void write_reason(struct systemstate_info *sinfo, const char *reason) +{ + char *reason_name; + + if (asprintf(&reason_name, "%s.dump_reason", sinfo->report_name) == -1) { + _E("Failed to asprintf for reason_name: %m"); + } else { + write_to_file(reason, sinfo->temp_report_dir, reason_name); + free(reason_name); + } +} + +static bool move_report(struct systemstate_info *sinfo) +{ + bool is_ok = true; + int fdlock = lock_dir(sinfo->reports_dir, false); + + if (fdlock < 0) + return false; + + if (rename(sinfo->zip_path, sinfo->report_path) == -1) { + _E("Rename %s to %s error: %m", sinfo->zip_path, sinfo->report_path); + is_ok = false; + } + + unlock_dir(fdlock); + return is_ok; +} + +bool systemstate_dump_run(struct dump_operation_data *data) +{ + bool is_ok = true; + + struct systemstate_info sinfo; + systemstate_info_init(&sinfo); + if (!prepare_paths(&sinfo)) { + is_ok = false; + goto exit; + } + + systemstate_dump(&sinfo); + write_reason(&sinfo, data->dump_reason); + zip_report(&sinfo); + + if (!move_report(&sinfo)) { + is_ok = false; + goto exit; + } + + if (write(data->write_fd, sinfo.report_path, strlen(sinfo.report_path)) == -1) { + _E("Write report_path error: %m"); + is_ok = false; + goto exit; + } + +exit: + close(data->write_fd); + remove_dir(sinfo.temp_path, true); + systemstate_info_free(&sinfo); + return is_ok; +} diff --git a/src/bugreport-service/systemdump.h b/src/bugreport-service/systemdump.h new file mode 100644 index 0000000..72172f3 --- /dev/null +++ b/src/bugreport-service/systemdump.h @@ -0,0 +1,32 @@ +/* + * systemdump + * + * Copyright (c) 2021 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 __SYSTEMDUMP_H +#define __SYSTEMDUMP_H + +#include +#include + +struct dump_operation_data { + int write_fd; + pid_t pid; + const char *dump_reason; +}; + +bool systemstate_dump_run(struct dump_operation_data *dump); + +#endif // __SYSTEMDUMP_H diff --git a/src/crash-manager/crash-manager.c b/src/crash-manager/crash-manager.c index 1db35b9..c6e0eb0 100644 --- a/src/crash-manager/crash-manager.c +++ b/src/crash-manager/crash-manager.c @@ -57,11 +57,6 @@ /* Parsing */ #define KEY_MAX 255 -#define CRASH_TEMP_SUBDIR "/temp/" -#define CRASH_PATH_SUBDIR "/dump/" -#define LIVE_PATH_SUBDIR "/livedump/" -#define APP_PATH_SUBDIR "/app/" - #define WAIT_FOR_OPT_TIMEOUT_SEC 60 #define SPACE_REQUIRED_KB 1024 #define HASH_LEN_MAX 0x100 @@ -247,43 +242,13 @@ static int prepare_paths(struct crash_info* cinfo) return 1; } -static void unlock_dir(int fd) -{ - if (flock(fd, LOCK_UN) < 0) - _E("Failed to unlock file descriptor: %m"); - close(fd); -} - static bool make_dump_dir(void) { const char *dirs[] = {crash_dump_path, crash_temp_path}; for (size_t i = 0; i < ARRAY_SIZE(dirs); i++) { - const char *dirname = dirs[i]; - - int r = mkdir(dirname, 0775); - - if (r < 0 && errno != EEXIST) { - _E("Unable to create directory %s: %m", dirname); + if (!make_dir(dirs[i], DEFAULT_CRASH_DIR_PERM)) return false; - } - - chmod(dirname, DEFAULT_CRASH_DIR_PERM); // Fixup permissions for directories created with bad umask - - if (r >= 0) - continue; - - struct stat st = {0}; - r = stat(dirname, &st); - bool isdir = !!(st.st_mode & S_IFDIR); - - if (!r && isdir) - continue; - else if (!r && !isdir) - errno = ENOTDIR; - - _E("Failure while trying to ensure %s exists and it is directory: %m", dirname); - return false; } return true; @@ -998,31 +963,6 @@ static bool execute_crash_modules(struct crash_info *cinfo) return true; } -static int lock_dir(const char *path, bool block) -{ - assert(path); - - int fd; - - if ((fd = open(path, O_RDONLY | O_DIRECTORY)) == -1) { - _E("Failed to open %s: %m", path); - return -1; - } - - int flock_flags = LOCK_EX; - - if (!block) - flock_flags |= LOCK_NB; - - if (flock(fd, flock_flags) == -1) { - _E("Failed to lock %s for exclusive access: %m", path); - close(fd); - return -1; - } - - return fd; -} - static int mtime_cmp(const void *_a, const void *_b) { const struct file_info *a = _a; diff --git a/src/shared/util.c b/src/shared/util.c index e26d261..59644b2 100644 --- a/src/shared/util.c +++ b/src/shared/util.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -197,18 +198,31 @@ int fsync_path(char *const path) return ret; } -int make_dir(const char *path, const char *name, int mode) +bool make_dir(const char *path, int mode) { - int r = -1; + int r = mkdir(path, mode); - DIR *dir = opendir(path); - if (dir) { - int dfd = dirfd(dir); - r = mkdirat(dfd, name, mode); - closedir(dir); + if (r < 0 && errno != EEXIST) { + _E("Unable to create directory %s: %m", path); + return false; } - return r == 0 || (r == -1 && errno == EEXIST) ? 0 : -1; + chmod(path, mode); // Fixup permissions for directories created with bad umask + + if (r >= 0) + return true; + + struct stat st = {0}; + r = stat(path, &st); + bool isdir = !!(st.st_mode & S_IFDIR); + + if (!r && isdir) + return true; + else if (!r && !isdir) + errno = ENOTDIR; + + _E("Failure while trying to ensure %s exists and it is directory: %m", path); + return false; } static bool remove_dir_internal(int fd) @@ -274,6 +288,38 @@ bool remove_dir(const char *path, bool del_dir) return ret; } +int lock_dir(const char *path, bool block) +{ + assert(path); + + int fd; + + if ((fd = open(path, O_RDONLY | O_DIRECTORY)) == -1) { + _E("Failed to open %s: %m", path); + return -1; + } + + int flock_flags = LOCK_EX; + + if (!block) + flock_flags |= LOCK_NB; + + if (flock(fd, flock_flags) == -1) { + _E("Failed to lock %s for exclusive access: %m", path); + close(fd); + return -1; + } + + return fd; +} + +void unlock_dir(int fd) +{ + if (flock(fd, LOCK_UN) < 0) + _E("Failed to unlock file descriptor: %m"); + close(fd); +} + int get_exec_pid(const char *execpath) { DIR *dp; diff --git a/src/shared/util.h b/src/shared/util.h index 85dd15f..32609e0 100644 --- a/src/shared/util.h +++ b/src/shared/util.h @@ -46,10 +46,14 @@ int dump_file_write_fd(int dfd, char *src); int fsync_path(char *const path); -int make_dir(const char *path, const char *name, int mode); +bool make_dir(const char *path, int mode); bool remove_dir(const char *path, bool del_dir); +int lock_dir(const char *path, bool block); + +void unlock_dir(int fd); + int get_exec_pid(const char *execpath); int get_file_count(char *path); diff --git a/tests/system/CMakeLists.txt b/tests/system/CMakeLists.txt index 47e1c23..8505fed 100644 --- a/tests/system/CMakeLists.txt +++ b/tests/system/CMakeLists.txt @@ -32,7 +32,9 @@ configure_test("full_core") configure_test("info_file") configure_test("libbugreport-service") configure_test("libbugreport-service_systemstate") +IF("${LIVEDUMPER}" STREQUAL "ON") configure_test("livedumper") +ENDIF() configure_test("log_file") configure_test("output_param") configure_test("report_basic") -- 2.7.4 From 158339d9a3a6ac22af2705ddebb84097d680f6ca Mon Sep 17 00:00:00 2001 From: Karol Lewandowski Date: Thu, 11 Mar 2021 14:59:12 +0100 Subject: [PATCH 06/16] spec: redesign Change-Id: I5b2b2337413c4ea019be4c876449263d8ef72257 --- CMakeLists.txt | 4 +- packaging/crash-worker.spec | 169 +++++++++++++++++++++++++++++++------------- 2 files changed, 122 insertions(+), 51 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0288a17..cea1e14 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,5 +30,7 @@ IF("${DUMP_SYSTEMSTATE_SERVICE}" STREQUAL "ON") ADD_SUBDIRECTORY(src/dump_systemstate-service) ENDIF() -ADD_SUBDIRECTORY(tests) +IF("${TESTS}" STREQUAL "ON") + ADD_SUBDIRECTORY(tests) +ENDIF() diff --git a/packaging/crash-worker.spec b/packaging/crash-worker.spec index 98064ef..4a30187 100644 --- a/packaging/crash-worker.spec +++ b/packaging/crash-worker.spec @@ -2,20 +2,18 @@ %define on_off() %{expand:%%{?with_%{1}:ON}%%{!?with_%{1}:OFF}} %define _with_tests on +%define _with_regdumper on %define _with_livedumper on %define _with_bugreportservice on %define _with_dumpsystemstateservice on %bcond_with doc %bcond_with tests +%bcond_with regdumper %bcond_with livedumper %bcond_with bugreportservice %bcond_with dumpsystemstateservice -%if %{?_with_bugreportservice} == on -%define _with_livedumper on -%endif - # NOTE: To disable coredump set DumpCore=0 in configuration file Name: crash-worker @@ -54,23 +52,57 @@ BuildRequires: boost-devel Requires(post): coreutils Requires(post): tar Requires(post): gzip -Requires: minicoredumper >= 2.1.0 + +Requires: %{name}-dumpsystemstate-util = %{version}-%{release} +%if %{with dumpsystemstateservice} +Requires: %{name}-dumpsystemstate-service = %{version}-%{release} +%endif +%if %{with bugreportservice} +Requires: bugreport-service = %{version}-%{release} +%endif +%if %{with regdumper} +Requires: %{name}-support-regdump = %{version}-%{release} +%endif %description %package dumpsystemstate-config Summary: common configuration for dump_systemstate utility and bugreport-service %description dumpsystemstate-config -%package -n crash-manager-core -Summary: package provides core crash-manager functionality - needed utilities and library +%package dumpsystemstate-util +Summary: dump_systemstate utility used for dumping basic system information Requires: %{name}-dumpsystemstate-config = %{version}-%{release} -Requires: zip Requires: %{_bindir}/buxton2ctl -%if %{with bugreportservice} -Requires: %{name}-livedumper = %{version}-%{release} +%description dumpsystemstate-util + +%if %{with dumpsystemstateservice} +%package dumpsystemstate-service +Summary: service provides dumpsys provider to system state information +Requires: %{name}-dumpsystemstate-config = %{version}-%{release} +%description dumpsystemstate-service +%endif + +%if %{with regdumper} +%package support-regdump +Summary: package provides components needed to support kernel-invoked coredump handling +Requires: %{name}-support-common = %{version}-%{release} +Requires: minicoredumper >= 2.1.0 +%description support-regdump +%endif + +%if %{with livedumper} +%package support-livecoredump +Summary: package provides components needed to support livecoredumps +Requires: %{name}-support-common = %{version}-%{release} +Provides: %{name}-livedumper = %{version}-%{release} +%description support-livecoredump %endif -%description -n crash-manager-core +%package support-common +Summary: package provides common components needed to support both kernel-invoked coredump and livedump +Requires: %{name}-dumpsystemstate-util = %{version}-%{release} +Requires: zip +%description support-common %package -n libcrash-manager-devel Summary: package provides headers needed to develop programs using libcrash-manager @@ -83,18 +115,16 @@ Summary: libbugreport provides API to communicate with bugreport-service %package -n bugreport-service Summary: bugreport provides dumpsys provider for diagnostics data +Requires: %{name}-dumpsystemstate-util = %{version}-%{release} +%if %{with livedumper} +Requires: %{name}-support-livecoredump = %{version}-%{release} +%endif %description -n bugreport-service %package -n libbugreport-devel Summary: package provides headers needed to develop programs using bugreport-service %description -n libbugreport-devel -%endif - -%if %{with dumpsystemstateservice} -%package -n dumpsystemstate-service -Summary: service provides dumpsys provider to system state information -Requires: %{name}-dumpsystemstate-config = %{version}-%{release} -%description -n dumpsystemstate-service +%description -n libbugreport-devel %endif %if %{with doc} @@ -110,12 +140,6 @@ Summary: Package with binaries and data for crash-worker tests %description tests %endif -%if %{with livedumper} -%package livedumper -Summary: Livedumper allows to dump core of live process -%description livedumper -%endif - %package system-tests Summary: System tests for crash-worker components Requires: diff @@ -127,8 +151,8 @@ Requires: /usr/bin/unzip Requires: /usr/bin/mcookie Requires: %{_sbindir}/minicoredumper Requires: %{name}-system-tests-debuginfo = %{version}-%{release} -Requires: %{name} -Requires: %{name}-livecoredumper = %{version}-%{release} +Requires: %{name}-support-livecoredump = %{version}-%{release} +Requires: %{name}-support-regdump = %{version}-%{release} %description system-tests %prep @@ -187,6 +211,7 @@ export CFLAGS+=" -Werror" -DUPGRADE_SCRIPT_PATH=%{upgrade_script_path} \ -DLOGGER=dlog \ -DDLOG_LOG_LEVEL=DLOG_INFO \ + -DTESTS=%{on_off tests} \ -DVERSION=%{version} make %{?jobs:-j%jobs} @@ -201,6 +226,34 @@ rm -rf %{buildroot} mkdir -p %{buildroot}%{crash_root_path} mkdir -p %{buildroot}%{crash_path} +%if ! %{with regdumper} +rm -f %{buildroot}%{_prefix}/lib/sysctl.d/70-crash-manager.conf +rm -f %{buildroot}%{_bindir}/crash-manager +rm -f %{buildroot}%{_libexecdir}/crash-popup-launch +rm -f %{buildroot}%{_libexecdir}/crash-notify-send +rm -f %{buildroot}%{_prefix}/lib/debug/usr/bin/crash-manager.debug +rm -f %{buildroot}%{_prefix}/lib/debug/usr/libexec/crash-notify-send.debug +rm -f %{buildroot}%{_prefix}/lib/debug/usr/libexec/crash-popup-launch.debug +%endif + +%if ! %{with livedumper} +rm -f %{buildroot}%{_bindir}/livedumper +rm -f %{buildroot}%{_prefix}/lib/debug/usr/bin/livedumper.debug +%endif + +%if ! %{with regdumper} && ! %{with livedumper} +rm -f %{buildroot}%{_libdir}/libcrash-manager.so* +rm -f %{buildroot}%{_bindir}/crash-json2info +rm -f %{buildroot}%{_libexecdir}/crash-stack +rm -f %{buildroot}%{_sysconfdir}/crash-manager.conf +rm -f %{buildroot}%{_sysconfdir}/crash-manager.conf.d/crash-manager.conf.example +rm -f %{buildroot}%{_prefix}/lib/debug/usr/bin/crash-json2info.debug +rm -f %{buildroot}%{_prefix}/lib/debug/usr/libexec/crash-stack.debug +rm -f %{buildroot}%{_prefix}/lib/debug/usr/lib/libcrash-manager.so* +rm -f %{buildroot}%{_includedir}/crash-manager.h +rm -f %{buildroot}%{_prefix}/lib/pkgconfig/crash-manager.pc +%endif + %post chsmack -a "System" -t %{crash_root_path} chsmack -a "System" -t %{crash_path} @@ -219,27 +272,55 @@ fi %files %license LICENSE %manifest crash-worker.manifest -%defattr(-,crash_worker,crash_worker,-) %dir %{crash_root_path} %attr(0775,crash_worker,crash_worker) %{crash_path} -%attr(-,root,root) %{_prefix}/lib/sysctl.d/70-crash-manager.conf -%attr(0750,crash_worker,crash_worker) %{_bindir}/crash-manager %attr(-,root,root) %{upgrade_script_path}/500.crash-manager-upgrade.sh +%files dumpsystemstate-util +%manifest crash-worker.manifest +%license LICENSE +%attr(0750,crash_worker,crash_worker) %{_bindir}/dump_systemstate + +%if %{with dumpsystemstateservice} +%files dumpsystemstate-service +%license LICENSE +%manifest crash-worker.manifest +%attr(0750,crash_worker,crash_worker) %{_bindir}/dump_systemstate-service +%attr(-,root,root) %{_unitdir}/dump_systemstate.service +%attr(-,root,root) %{_datadir}/dbus-1/system-services/org.tizen.dumpsys.providers.org.tizen.systemstate.service +%endif + %files dumpsystemstate-config +%manifest crash-worker.manifest %license LICENSE %{_sysconfdir}/dump_systemstate.conf.d/files/*.conf* %{_sysconfdir}/dump_systemstate.conf.d/programs/*.conf* -%files -n crash-manager-core +%if %{with regdumper} +%files support-regdump +%license LICENSE +%manifest crash-worker.manifest +%attr(-,root,root) %{_prefix}/lib/sysctl.d/70-crash-manager.conf +%attr(0750,crash_worker,crash_worker) %{_bindir}/crash-manager +%{_libexecdir}/crash-popup-launch +%{_libexecdir}/crash-notify-send +%endif + +%if %{with livedumper} +%files support-livecoredump +%license LICENSE +%manifest crash-worker.manifest +%manifest %{name}.manifest +%{_bindir}/livedumper +%endif + +%if %{with livedumper} || %{with regdumper} +%files support-common %license LICENSE LICENSE.BSD LICENSE.MIT %manifest crash-worker.manifest %{_libdir}/libcrash-manager.so.* %{_bindir}/crash-json2info -%attr(0750,crash_worker,crash_worker) %{_bindir}/dump_systemstate %{_libexecdir}/crash-stack -%{_libexecdir}/crash-popup-launch -%{_libexecdir}/crash-notify-send %{_sysconfdir}/crash-manager.conf %{_sysconfdir}/crash-manager.conf.d/crash-manager.conf.example @@ -249,6 +330,7 @@ fi %{_includedir}/crash-manager.h %{_libdir}/libcrash-manager.so %{_libdir}/pkgconfig/crash-manager.pc +%endif %if %{with bugreportservice} %files -n bugreport-service @@ -274,15 +356,6 @@ fi %{_libdir}/pkgconfig/bugreport.pc %endif -%if %{with dumpsystemstateservice} -%files -n dumpsystemstate-service -%license LICENSE -%manifest crash-worker.manifest -%attr(0750,crash_worker,crash_worker) %{_bindir}/dump_systemstate-service -%attr(-,root,root) %{_unitdir}/dump_systemstate.service -%attr(-,root,root) %{_datadir}/dbus-1/system-services/org.tizen.dumpsys.providers.org.tizen.systemstate.service -%endif - %if %{with doc} %files doc %{_datadir}/doc/crash-worker @@ -302,14 +375,6 @@ fi %{_libexecdir}/crash-worker/tests/tests_common.sh %{_libexecdir}/crash-worker/tests/crash_common.sh -%endif - -%if %{with livedumper} -%files livedumper -%manifest %{name}.manifest -%{_bindir}/livedumper -%endif - %files system-tests %manifest %{name}.manifest %{_bindir}/crash-worker-system-tests-run @@ -329,8 +394,10 @@ fi %{_libexecdir}/crash-worker/system-tests/extra_script/extra_script.sh %{_libexecdir}/crash-worker/system-tests/full_core/full_core.sh %{_libexecdir}/crash-worker/system-tests/info_file/info_file.sh +%if %{with bugreportservice} %{_libexecdir}/crash-worker/system-tests/libbugreport-service/libbugreport-service.sh %{_libexecdir}/crash-worker/system-tests/libbugreport-service_systemstate/libbugreport-service_systemstate.sh +%endif %{_libexecdir}/crash-worker/system-tests/log_file/log_file.sh %{_libexecdir}/crash-worker/system-tests/output_param/output_param.sh %{_libexecdir}/crash-worker/system-tests/report_basic/report_basic.sh @@ -350,3 +417,5 @@ fi %if %{with livedumper} %{_libexecdir}/crash-worker/system-tests/livedumper/livedumper.sh %endif + +%endif -- 2.7.4 From 15e78af58e90069dff13201dfcc89035664ba650 Mon Sep 17 00:00:00 2001 From: Karol Lewandowski Date: Thu, 11 Mar 2021 23:00:42 +0100 Subject: [PATCH 07/16] packaging: Package only bugreport-service and dumpsystemstate-service for TV Change-Id: Ia2b330a71d6775821dce0db5f2076074dfe396c1 --- packaging/crash-worker.spec | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packaging/crash-worker.spec b/packaging/crash-worker.spec index 4a30187..52b2f52 100644 --- a/packaging/crash-worker.spec +++ b/packaging/crash-worker.spec @@ -1,11 +1,19 @@ # "on_off foo" wil turn into "ON" or "OFF" %define on_off() %{expand:%%{?with_%{1}:ON}%%{!?with_%{1}:OFF}} +%if "%{?profile}" == "tv" +%define _without_tests on +%define _without_regdumper on +%define _without_livedumper on +%define _with_bugreportservice on +%define _with_dumpsystemstateservice on +%else %define _with_tests on %define _with_regdumper on %define _with_livedumper on %define _with_bugreportservice on %define _with_dumpsystemstateservice on +%endif %bcond_with doc %bcond_with tests -- 2.7.4 From cde69ca27169c47ce27a7df48dad3eb881079856 Mon Sep 17 00:00:00 2001 From: Karol Lewandowski Date: Fri, 12 Mar 2021 17:44:49 +0100 Subject: [PATCH 08/16] spec: Provide libcrash-service to ease transition to libbugreport Change-Id: I33d83f9d5e40e6d6d1940597424bba87fcc4552d --- packaging/crash-worker.spec | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packaging/crash-worker.spec b/packaging/crash-worker.spec index 52b2f52..2338cd7 100644 --- a/packaging/crash-worker.spec +++ b/packaging/crash-worker.spec @@ -119,6 +119,8 @@ Summary: package provides headers needed to develop programs using libcra %if %{with bugreportservice} %package -n libbugreport Summary: libbugreport provides API to communicate with bugreport-service +# remove following when libbugreport is added to building-blocks +Provides: libcrash-service = %{version}-%{release} %description -n libbugreport %package -n bugreport-service -- 2.7.4 From fe8def63f8d2a8d1a9bbbadb84ce9c77b2d65373 Mon Sep 17 00:00:00 2001 From: Karol Lewandowski Date: Mon, 15 Mar 2021 15:00:47 +0100 Subject: [PATCH 09/16] spec: Santize programs' permissions Use default only where necessary and clearly write the reason behind it. Change-Id: I96b696c4b8268a9548be3f105dc827a67b436742 --- packaging/crash-worker.spec | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/packaging/crash-worker.spec b/packaging/crash-worker.spec index 2338cd7..85558f9 100644 --- a/packaging/crash-worker.spec +++ b/packaging/crash-worker.spec @@ -283,21 +283,23 @@ fi %license LICENSE %manifest crash-worker.manifest %dir %{crash_root_path} +# attr() needed because: crash-worker running as crash_worker:crash_worker (user:group) creates files/dir under this path %attr(0775,crash_worker,crash_worker) %{crash_path} -%attr(-,root,root) %{upgrade_script_path}/500.crash-manager-upgrade.sh +%{upgrade_script_path}/500.crash-manager-upgrade.sh %files dumpsystemstate-util %manifest crash-worker.manifest %license LICENSE -%attr(0750,crash_worker,crash_worker) %{_bindir}/dump_systemstate +# attr() needed because: dump_systemstate has Smack exec_label(=System) set and we don't want to allow everyone to abuse it +%attr(0750,root,crash_worker) %{_bindir}/dump_systemstate %if %{with dumpsystemstateservice} %files dumpsystemstate-service %license LICENSE %manifest crash-worker.manifest -%attr(0750,crash_worker,crash_worker) %{_bindir}/dump_systemstate-service -%attr(-,root,root) %{_unitdir}/dump_systemstate.service -%attr(-,root,root) %{_datadir}/dbus-1/system-services/org.tizen.dumpsys.providers.org.tizen.systemstate.service +%{_bindir}/dump_systemstate-service +%{_unitdir}/dump_systemstate.service +%{_datadir}/dbus-1/system-services/org.tizen.dumpsys.providers.org.tizen.systemstate.service %endif %files dumpsystemstate-config @@ -310,8 +312,9 @@ fi %files support-regdump %license LICENSE %manifest crash-worker.manifest -%attr(-,root,root) %{_prefix}/lib/sysctl.d/70-crash-manager.conf -%attr(0750,crash_worker,crash_worker) %{_bindir}/crash-manager +%{_prefix}/lib/sysctl.d/70-crash-manager.conf +# attr() needed because: crash-worker has Smack exec_label(=System::Privileged) set and we don't want to allow everyone to abuse it +%attr(0750,root,crash_worker) %{_bindir}/crash-manager %{_libexecdir}/crash-popup-launch %{_libexecdir}/crash-notify-send %endif @@ -374,7 +377,6 @@ fi %if %{with tests} %files tests %manifest %{name}.manifest -%defattr(-,root,root) %{_libexecdir}/crash-worker/tests/test1-default-crash %{_libexecdir}/crash-worker/tests/test1-default-sleep %{_libexecdir}/crash-worker/tests/test1-default-ill -- 2.7.4 From bf64c0292a3c5dff0cd7265f2beeb8cdf7d125ed Mon Sep 17 00:00:00 2001 From: Karol Lewandowski Date: Fri, 12 Mar 2021 13:21:22 +0100 Subject: [PATCH 10/16] Release 6.5.12 * Add new dumpsystemstate-service * Rename crash-service to bugreport-service * Decouple bugreport-service from crash-worker dependencies * Rework packaging to make it possible to complile out/disable crash-worker/livedumper/etc. Change-Id: I7b3bdd9156e786d7bbba1d49ef6db36659eb7c48 --- packaging/crash-worker.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/crash-worker.spec b/packaging/crash-worker.spec index 85558f9..11a85f6 100644 --- a/packaging/crash-worker.spec +++ b/packaging/crash-worker.spec @@ -26,7 +26,7 @@ Name: crash-worker Summary: Coredump handler and report generator for Tizen -Version: 6.5.11 +Version: 6.5.12 Release: 1 Group: Framework/system License: Apache-2.0 and BSD-2-Clause and MIT -- 2.7.4 From a1efd48ed7e4fed822259342643ded05a9da6e8b Mon Sep 17 00:00:00 2001 From: Mateusz Moscicki Date: Tue, 16 Mar 2021 12:15:58 +0100 Subject: [PATCH 11/16] Move the libbugreport library to the separate spec A separate spec is needed because diagnostics depends on libbugreport, while bugreport-service requires diagnostics. Change-Id: I809e21be045ca6d29d5851032d135a308e816c16 --- CMakeLists.txt | 4 +- packaging/crash-worker.spec | 40 ++-------------- packaging/libbugreport.spec | 54 ++++++++++++++++++++++ src/bugreport-service/CMakeLists.txt | 14 ------ src/bugreport/CMakeLists.txt | 41 ++++++++++++++++ .../bugreport.pc.in | 0 .../libbugreport-service.c | 0 .../libbugreport.h | 0 tests/system/utils/CMakeLists.txt | 3 +- 9 files changed, 102 insertions(+), 54 deletions(-) create mode 100644 packaging/libbugreport.spec create mode 100644 src/bugreport/CMakeLists.txt rename src/{bugreport-service => bugreport}/bugreport.pc.in (100%) rename src/{bugreport-service => bugreport}/libbugreport-service.c (100%) rename src/{bugreport-service => bugreport}/libbugreport.h (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index cea1e14..dbaf959 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,9 +22,7 @@ IF("${LIVEDUMPER}" STREQUAL "ON") ADD_SUBDIRECTORY(src/livedumper) ENDIF() -IF("${CRASH_SERVICE}" STREQUAL "ON") - ADD_SUBDIRECTORY(src/bugreport-service) -ENDIF() +ADD_SUBDIRECTORY(src/bugreport-service) IF("${DUMP_SYSTEMSTATE_SERVICE}" STREQUAL "ON") ADD_SUBDIRECTORY(src/dump_systemstate-service) diff --git a/packaging/crash-worker.spec b/packaging/crash-worker.spec index 11a85f6..043eaf8 100644 --- a/packaging/crash-worker.spec +++ b/packaging/crash-worker.spec @@ -5,13 +5,11 @@ %define _without_tests on %define _without_regdumper on %define _without_livedumper on -%define _with_bugreportservice on %define _with_dumpsystemstateservice on %else %define _with_tests on %define _with_regdumper on %define _with_livedumper on -%define _with_bugreportservice on %define _with_dumpsystemstateservice on %endif @@ -19,7 +17,6 @@ %bcond_with tests %bcond_with regdumper %bcond_with livedumper -%bcond_with bugreportservice %bcond_with dumpsystemstateservice # NOTE: To disable coredump set DumpCore=0 in configuration file @@ -45,6 +42,9 @@ BuildRequires: pkgconfig(libunwind-generic) BuildRequires: libcap-devel BuildRequires: pkgconfig(json-c) BuildRequires: pkgconfig(openssl1.1) +%if %{with tests} +BuildRequires: pkgconfig(bugreport) +%endif %if %{with dumpsystemstateservice} BuildRequires: pkgconfig(dumpsys-system) %endif @@ -61,13 +61,11 @@ Requires(post): coreutils Requires(post): tar Requires(post): gzip +Requires: bugreport-service = %{version}-%{release} Requires: %{name}-dumpsystemstate-util = %{version}-%{release} %if %{with dumpsystemstateservice} Requires: %{name}-dumpsystemstate-service = %{version}-%{release} %endif -%if %{with bugreportservice} -Requires: bugreport-service = %{version}-%{release} -%endif %if %{with regdumper} Requires: %{name}-support-regdump = %{version}-%{release} %endif @@ -116,13 +114,6 @@ Requires: zip Summary: package provides headers needed to develop programs using libcrash-manager %description -n libcrash-manager-devel -%if %{with bugreportservice} -%package -n libbugreport -Summary: libbugreport provides API to communicate with bugreport-service -# remove following when libbugreport is added to building-blocks -Provides: libcrash-service = %{version}-%{release} -%description -n libbugreport - %package -n bugreport-service Summary: bugreport provides dumpsys provider for diagnostics data Requires: %{name}-dumpsystemstate-util = %{version}-%{release} @@ -131,12 +122,6 @@ Requires: %{name}-support-livecoredump = %{version}-%{release} %endif %description -n bugreport-service -%package -n libbugreport-devel -Summary: package provides headers needed to develop programs using bugreport-service -%description -n libbugreport-devel -%description -n libbugreport-devel -%endif - %if %{with doc} %package doc Summary: Documentation package for crash-worker @@ -216,7 +201,6 @@ export CFLAGS+=" -Werror" -DCRASH_TESTS_PATH=%{_libexecdir}/crash-worker/tests \ -DCRASH_SYSTEM_TESTS_PATH=%{_libexecdir}/crash-worker/system-tests \ -DLIVEDUMPER=%{on_off livedumper} \ - -DCRASH_SERVICE=%{on_off bugreportservice} \ -DDUMP_SYSTEMSTATE_SERVICE=%{on_off dumpsystemstateservice} \ -DUPGRADE_SCRIPT_PATH=%{upgrade_script_path} \ -DLOGGER=dlog \ @@ -345,7 +329,6 @@ fi %{_libdir}/pkgconfig/crash-manager.pc %endif -%if %{with bugreportservice} %files -n bugreport-service %license LICENSE %manifest crash-worker.manifest @@ -356,19 +339,6 @@ fi %attr(-,root,root) %{_datadir}/dbus-1/system-services/org.tizen.system.diagnostics.service %attr(0644,root,root) %{_prefix}/lib/tmpfiles.d/diagnostics-run.conf -%files -n libbugreport -%license LICENSE -%manifest crash-worker.manifest -%{_libdir}/libbugreport.so.* - -%files -n libbugreport-devel -%license LICENSE -%manifest crash-worker.manifest -%{_includedir}/libbugreport.h -%{_libdir}/libbugreport.so -%{_libdir}/pkgconfig/bugreport.pc -%endif - %if %{with doc} %files doc %{_datadir}/doc/crash-worker @@ -406,10 +376,8 @@ fi %{_libexecdir}/crash-worker/system-tests/extra_script/extra_script.sh %{_libexecdir}/crash-worker/system-tests/full_core/full_core.sh %{_libexecdir}/crash-worker/system-tests/info_file/info_file.sh -%if %{with bugreportservice} %{_libexecdir}/crash-worker/system-tests/libbugreport-service/libbugreport-service.sh %{_libexecdir}/crash-worker/system-tests/libbugreport-service_systemstate/libbugreport-service_systemstate.sh -%endif %{_libexecdir}/crash-worker/system-tests/log_file/log_file.sh %{_libexecdir}/crash-worker/system-tests/output_param/output_param.sh %{_libexecdir}/crash-worker/system-tests/report_basic/report_basic.sh diff --git a/packaging/libbugreport.spec b/packaging/libbugreport.spec new file mode 100644 index 0000000..f1d7d83 --- /dev/null +++ b/packaging/libbugreport.spec @@ -0,0 +1,54 @@ +# "on_off foo" wil turn into "ON" or "OFF" +%define on_off() %{expand:%%{?with_%{1}:ON}%%{!?with_%{1}:OFF}} + +Name: libbugreport +Summary: libbugreport provides API to communicate with bugreport-service +Version: 1.0.0 +Release: 1 +Provides: libcrash-service = %{version}-%{release} +Group: Framework/system +License: Apache-2.0 +Source0: %{name}-%{version}.tar.gz +Source1001: crash-worker.manifest +BuildRequires: pkgconfig(dlog) +BuildRequires: pkgconfig(glib-2.0) +BuildRequires: cmake + +%description + +%package -n libbugreport-devel +Summary: package provides headers needed to develop programs using bugreport-service +%description -n libbugreport-devel +%description -n libbugreport-devel + +%prep +%setup -q + +%build +cp %{SOURCE1001} . + +export CFLAGS+=" -Werror" + +%cmake src/bugreport/ \ + -DCMAKE_INSTALL_PREFIX=%{_prefix} \ + -DLOGGER=dlog \ + -DDLOG_LOG_LEVEL=DLOG_INFO \ + -DVERSION=%{version} + +make %{?jobs:-j%jobs} + +%install +rm -rf %{buildroot} +%make_install + +%files +%license LICENSE +%manifest crash-worker.manifest +%{_libdir}/libbugreport.so.* + +%files -n libbugreport-devel +%license LICENSE +%manifest crash-worker.manifest +%{_includedir}/libbugreport.h +%{_libdir}/libbugreport.so +%{_libdir}/pkgconfig/bugreport.pc diff --git a/src/bugreport-service/CMakeLists.txt b/src/bugreport-service/CMakeLists.txt index 4d7c849..dbcf9bd 100644 --- a/src/bugreport-service/CMakeLists.txt +++ b/src/bugreport-service/CMakeLists.txt @@ -37,18 +37,10 @@ ADD_EXECUTABLE(${PROJECT_NAME} ${CRASH_SERVICE_SRCS}) ADD_DEPENDENCIES(${PROJECT_NAME} crash-manager) TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${bugreport-service_pkgs_LDFLAGS} -pie -Wl,--as-needed -lrt -lcrash-manager) -ADD_LIBRARY(libbugreport SHARED libbugreport-service.c) -SET_TARGET_PROPERTIES(libbugreport PROPERTIES - SOVERSION 1 - PUBLIC_HEADER libbugreport.h - OUTPUT_NAME bugreport) - PROCESS_M4("${M4_DEFINES}" "${CMAKE_CURRENT_SOURCE_DIR}/bugreport.service.m4" "${CMAKE_CURRENT_SOURCE_DIR}/bugreport.service") -CONFIGURE_FILE(bugreport.pc.in bugreport.pc @ONLY) - INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/org.tizen.system.crash.livedump.service DESTINATION /usr/share/dbus-1/system-services) @@ -66,12 +58,6 @@ INSTALL(TARGETS ${PROJECT_NAME} DESTINATION bin PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) -INSTALL(TARGETS libbugreport LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) - -INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/bugreport.pc - DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) - INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/diagnostics/diagnostics-run.conf DESTINATION /usr/lib/tmpfiles.d/ PERMISSIONS OWNER_READ OWNER_WRITE) diff --git a/src/bugreport/CMakeLists.txt b/src/bugreport/CMakeLists.txt new file mode 100644 index 0000000..e31a833 --- /dev/null +++ b/src/bugreport/CMakeLists.txt @@ -0,0 +1,41 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +PROJECT(bugreport C) + +ADD_SUBDIRECTORY(${CMAKE_SOURCE_DIR}/../../include include/) + +INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/../../src/ ${CMAKE_SOURCE_DIR}/../../include) + +INCLUDE(GNUInstallDirs) + +INCLUDE(FindPkgConfig) + +pkg_check_modules(bugreport_pkgs REQUIRED + dlog + gio-2.0 + gio-unix-2.0 + ) + +FOREACH(flag ${bugreport_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") + +INCLUDE(${CMAKE_SOURCE_DIR}/../../cmake/ProcessM4.cmake) + +LINK_DIRECTORIES(${CMAKE_SOURCE_DIR}/src/crash-manager) + +ADD_LIBRARY(libbugreport SHARED libbugreport-service.c) +SET_TARGET_PROPERTIES(libbugreport PROPERTIES + SOVERSION 1 + PUBLIC_HEADER libbugreport.h + OUTPUT_NAME bugreport) + +CONFIGURE_FILE(bugreport.pc.in ${CMAKE_SOURCE_DIR}/bugreport.pc @ONLY) + +INSTALL(TARGETS libbugreport LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) + +INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/bugreport.pc + DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) + diff --git a/src/bugreport-service/bugreport.pc.in b/src/bugreport/bugreport.pc.in similarity index 100% rename from src/bugreport-service/bugreport.pc.in rename to src/bugreport/bugreport.pc.in diff --git a/src/bugreport-service/libbugreport-service.c b/src/bugreport/libbugreport-service.c similarity index 100% rename from src/bugreport-service/libbugreport-service.c rename to src/bugreport/libbugreport-service.c diff --git a/src/bugreport-service/libbugreport.h b/src/bugreport/libbugreport.h similarity index 100% rename from src/bugreport-service/libbugreport.h rename to src/bugreport/libbugreport.h diff --git a/tests/system/utils/CMakeLists.txt b/tests/system/utils/CMakeLists.txt index 45e08ab..f8b7d6a 100644 --- a/tests/system/utils/CMakeLists.txt +++ b/tests/system/utils/CMakeLists.txt @@ -13,9 +13,10 @@ add_executable(libbugreport-servicetest libbugreport-servicetest.c) INCLUDE(FindPkgConfig) pkg_check_modules(helper_pkgs REQUIRED gio-2.0 + bugreport dlog) -TARGET_LINK_LIBRARIES(libbugreport-servicetest libbugreport ${helper_pkgs_LDFLAGS}) +TARGET_LINK_LIBRARIES(libbugreport-servicetest bugreport ${helper_pkgs_LDFLAGS}) install(TARGETS kenny DESTINATION ${CRASH_SYSTEM_TESTS_PATH}/utils) install(TARGETS btee DESTINATION ${CRASH_SYSTEM_TESTS_PATH}/utils) -- 2.7.4 From 999767c14e45ba0d90c200354c60eda3b7aa3dc8 Mon Sep 17 00:00:00 2001 From: Karol Lewandowski Date: Tue, 16 Mar 2021 09:53:01 +0100 Subject: [PATCH 12/16] spec: Ensure needed crash_worker user is available during package installation Some system users are created by security-config package %post script, thus we need to ensure this package is installed and configured before we install packages containing, in our case, crash_worker-user owned files/dirs. Change-Id: I122e992936f4569cbb5f42f0f38f4ce9f5fb2100 --- packaging/crash-worker.spec | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packaging/crash-worker.spec b/packaging/crash-worker.spec index 043eaf8..18d8860 100644 --- a/packaging/crash-worker.spec +++ b/packaging/crash-worker.spec @@ -69,6 +69,8 @@ Requires: %{name}-dumpsystemstate-service = %{version}-%{release} %if %{with regdumper} Requires: %{name}-support-regdump = %{version}-%{release} %endif +# Ensure crash_worker user is available (created by security-config, package provides crash_worker-owned files) +Requires: security-config %description %package dumpsystemstate-config @@ -79,6 +81,8 @@ Summary: common configuration for dump_systemstate utility and bugreport- Summary: dump_systemstate utility used for dumping basic system information Requires: %{name}-dumpsystemstate-config = %{version}-%{release} Requires: %{_bindir}/buxton2ctl +# Ensure crash_worker user is available (created by security-config, package provides crash_worker-owned files) +Requires: security-config %description dumpsystemstate-util %if %{with dumpsystemstateservice} @@ -93,6 +97,8 @@ Requires: %{name}-dumpsystemstate-config = %{version}-%{release} Summary: package provides components needed to support kernel-invoked coredump handling Requires: %{name}-support-common = %{version}-%{release} Requires: minicoredumper >= 2.1.0 +# Ensure crash_worker user is available (created by security-config, package provides crash_worker-owned files) +Requires: security-config %description support-regdump %endif -- 2.7.4 From a80c182048a8b880783b142fb66955db6e2808d0 Mon Sep 17 00:00:00 2001 From: Mateusz Moscicki Date: Thu, 18 Mar 2021 12:57:46 +0100 Subject: [PATCH 13/16] spec: Fix crash_root directory permission Change-Id: Id2f1f4ac5fb2f160011d5ccb1976645f8b853d55 --- packaging/crash-worker.spec | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/packaging/crash-worker.spec b/packaging/crash-worker.spec index 18d8860..d52aac1 100644 --- a/packaging/crash-worker.spec +++ b/packaging/crash-worker.spec @@ -69,8 +69,6 @@ Requires: %{name}-dumpsystemstate-service = %{version}-%{release} %if %{with regdumper} Requires: %{name}-support-regdump = %{version}-%{release} %endif -# Ensure crash_worker user is available (created by security-config, package provides crash_worker-owned files) -Requires: security-config %description %package dumpsystemstate-config @@ -114,6 +112,8 @@ Provides: %{name}-livedumper = %{version}-%{release} Summary: package provides common components needed to support both kernel-invoked coredump and livedump Requires: %{name}-dumpsystemstate-util = %{version}-%{release} Requires: zip +# Ensure crash_worker user is available (created by security-config, package provides crash_worker-owned files) +Requires: security-config %description support-common %package -n libcrash-manager-devel @@ -224,7 +224,6 @@ make doc rm -rf %{buildroot} %make_install mkdir -p %{buildroot}%{crash_root_path} -mkdir -p %{buildroot}%{crash_path} %if ! %{with regdumper} rm -f %{buildroot}%{_prefix}/lib/sysctl.d/70-crash-manager.conf @@ -254,9 +253,8 @@ rm -f %{buildroot}%{_includedir}/crash-manager.h rm -f %{buildroot}%{_prefix}/lib/pkgconfig/crash-manager.pc %endif -%post +%post support-common chsmack -a "System" -t %{crash_root_path} -chsmack -a "System" -t %{crash_path} if [ $1 -eq 2 ] ; then # All directories are created with appropriate permissions by @@ -272,10 +270,6 @@ fi %files %license LICENSE %manifest crash-worker.manifest -%dir %{crash_root_path} -# attr() needed because: crash-worker running as crash_worker:crash_worker (user:group) creates files/dir under this path -%attr(0775,crash_worker,crash_worker) %{crash_path} -%{upgrade_script_path}/500.crash-manager-upgrade.sh %files dumpsystemstate-util %manifest crash-worker.manifest @@ -321,11 +315,14 @@ fi %files support-common %license LICENSE LICENSE.BSD LICENSE.MIT %manifest crash-worker.manifest +# attr() needed because: crash-worker running as crash_worker:crash_worker (user:group) creates files/dir under this path +%attr(0775,crash_worker,crash_worker) %{crash_root_path} %{_libdir}/libcrash-manager.so.* %{_bindir}/crash-json2info %{_libexecdir}/crash-stack %{_sysconfdir}/crash-manager.conf %{_sysconfdir}/crash-manager.conf.d/crash-manager.conf.example +%{upgrade_script_path}/500.crash-manager-upgrade.sh %files -n libcrash-manager-devel %license LICENSE @@ -338,6 +335,8 @@ fi %files -n bugreport-service %license LICENSE %manifest crash-worker.manifest +# attr() needed because: crash-worker running as crash_worker:crash_worker (user:group) creates files/dir under this path +%attr(0775,crash_worker,crash_worker) %{crash_root_path} %attr(0750,crash_worker,crash_worker) %{_bindir}/bugreport-service %attr(-,root,root) %{_unitdir}/bugreport.service %attr(-,root,root) %{_sysconfdir}/dbus-1/system.d/bugreport-service.conf -- 2.7.4 From aaeefa6d889208fb57917a6c5f5a75c048196a97 Mon Sep 17 00:00:00 2001 From: Karol Lewandowski Date: Thu, 18 Mar 2021 12:26:43 +0100 Subject: [PATCH 14/16] libbugreport: Drop needless -service suffix Change-Id: I1f7c0d4b021c5bee76d2325649c55bdc6478eac1 --- src/bugreport/bugreport.pc.in | 2 +- src/bugreport/libbugreport-service.c | 2 +- src/bugreport/libbugreport.h | 5 ++--- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/bugreport/bugreport.pc.in b/src/bugreport/bugreport.pc.in index 1869cb2..1ccd264 100644 --- a/src/bugreport/bugreport.pc.in +++ b/src/bugreport/bugreport.pc.in @@ -3,7 +3,7 @@ exec_prefix=${prefix} includedir=${prefix}/include libdir=${exec_prefix}/lib -Name: bugreport-service +Name: bugreport Description: The bugreport library Version: @VERSION@ Cflags: -I${includedir} diff --git a/src/bugreport/libbugreport-service.c b/src/bugreport/libbugreport-service.c index 98d8fc0..671ecb3 100644 --- a/src/bugreport/libbugreport-service.c +++ b/src/bugreport/libbugreport-service.c @@ -20,7 +20,7 @@ #include #include -#define LOG_TAG "LIBBUGREPORT-SERVICE" +#define LOG_TAG "LIBBUGREPORT" #include "shared/log.h" diff --git a/src/bugreport/libbugreport.h b/src/bugreport/libbugreport.h index 23d05a4..cfa6d5b 100644 --- a/src/bugreport/libbugreport.h +++ b/src/bugreport/libbugreport.h @@ -13,8 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef LIBCRASH_SERVICE_H -#define LIBCRASH_SERVICE_H +#pragma once + #include #include @@ -27,4 +27,3 @@ * @return true on success and false on error. */ extern bool livedump_pid(pid_t pid, const char *dump_reason, char *report_path, size_t report_path_len); -#endif /* LIBCRASH_SERVICE_H */ -- 2.7.4 From 5888dac32ffd6da28bef2c2e96fba0c5d5d6c0b9 Mon Sep 17 00:00:00 2001 From: Mateusz Moscicki Date: Fri, 19 Mar 2021 17:51:35 +0100 Subject: [PATCH 15/16] Send diagnostics event (BugreportCreated) when new bugreport is created Change-Id: I0fe77932bec656e1abbf0a1fd79eb68ae233ea3d --- packaging/crash-worker.spec | 2 ++ src/bugreport-service/CMakeLists.txt | 2 +- src/bugreport-service/bugreport-service.c | 6 ++++++ src/bugreport-service/systemdump.c | 2 ++ src/crash-manager/CMakeLists.txt | 3 ++- src/crash-manager/crash-manager.c | 5 ++++- src/crash-manager/main.c | 2 ++ 7 files changed, 19 insertions(+), 3 deletions(-) diff --git a/packaging/crash-worker.spec b/packaging/crash-worker.spec index d52aac1..52ef210 100644 --- a/packaging/crash-worker.spec +++ b/packaging/crash-worker.spec @@ -97,6 +97,7 @@ Requires: %{name}-support-common = %{version}-%{release} Requires: minicoredumper >= 2.1.0 # Ensure crash_worker user is available (created by security-config, package provides crash_worker-owned files) Requires: security-config +BuildRequires: pkgconfig(diagnostics) %description support-regdump %endif @@ -122,6 +123,7 @@ Summary: package provides headers needed to develop programs using libcra %package -n bugreport-service Summary: bugreport provides dumpsys provider for diagnostics data +BuildRequires: pkgconfig(diagnostics) Requires: %{name}-dumpsystemstate-util = %{version}-%{release} %if %{with livedumper} Requires: %{name}-support-livecoredump = %{version}-%{release} diff --git a/src/bugreport-service/CMakeLists.txt b/src/bugreport-service/CMakeLists.txt index dbcf9bd..3d493be 100644 --- a/src/bugreport-service/CMakeLists.txt +++ b/src/bugreport-service/CMakeLists.txt @@ -35,7 +35,7 @@ INCLUDE(${CMAKE_SOURCE_DIR}/cmake/ProcessM4.cmake) LINK_DIRECTORIES(${CMAKE_SOURCE_DIR}/src/crash-manager) ADD_EXECUTABLE(${PROJECT_NAME} ${CRASH_SERVICE_SRCS}) ADD_DEPENDENCIES(${PROJECT_NAME} crash-manager) -TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${bugreport-service_pkgs_LDFLAGS} -pie -Wl,--as-needed -lrt -lcrash-manager) +TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${bugreport-service_pkgs_LDFLAGS} -pie -Wl,--as-needed -lrt -lcrash-manager -ldiagnostics) PROCESS_M4("${M4_DEFINES}" "${CMAKE_CURRENT_SOURCE_DIR}/bugreport.service.m4" diff --git a/src/bugreport-service/bugreport-service.c b/src/bugreport-service/bugreport-service.c index e5d2d2d..3bea418 100644 --- a/src/bugreport-service/bugreport-service.c +++ b/src/bugreport-service/bugreport-service.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "bugreport-service.h" @@ -162,6 +163,10 @@ static gboolean read_result_cb(gpointer data) } } + int res = diagnostics_send_event("BugreportCreated", NULL); + if (res != DIAGNOSTICS_ERROR_NONE) + _E("Send diagnostics event error: %d", res); + g_dbus_method_invocation_return_value(cb_data->invocation, g_variant_new("(s)", report_path)); end: @@ -505,6 +510,7 @@ int main(void) g_mutex_init(&timeout_mutex); add_timeout(); + diagnostics_set_client_id("org.tizen.bugreport-service"); g_main_loop_run(loop); if (introspection_data) diff --git a/src/bugreport-service/systemdump.c b/src/bugreport-service/systemdump.c index 012bcc9..b9a7a10 100644 --- a/src/bugreport-service/systemdump.c +++ b/src/bugreport-service/systemdump.c @@ -22,6 +22,8 @@ #include #include +#include "bugreport-service.h" + #include "systemdump.h" #include "defs.h" #include "shared/spawn.h" diff --git a/src/crash-manager/CMakeLists.txt b/src/crash-manager/CMakeLists.txt index 70930cd..d76671e 100644 --- a/src/crash-manager/CMakeLists.txt +++ b/src/crash-manager/CMakeLists.txt @@ -25,6 +25,7 @@ pkg_check_modules(crash-manager_pkgs REQUIRED pkgmgr-info rpm libcrypto1.1 + diagnostics ) pkg_check_modules(helper_pkgs REQUIRED @@ -45,7 +46,7 @@ SET_TARGET_PROPERTIES(libcrash-manager PROPERTIES OUTPUT_NAME crash-manager) TARGET_LINK_LIBRARIES(libcrash-manager ${crash-manager_pkgs_LDFLAGS}) ADD_EXECUTABLE(${PROJECT_NAME} ${CRASH_MANAGER_SRCS}) -TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${crash-manager_pkgs_LDFLAGS} -pie -lcap -lrt libcrash-manager) +TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${crash-manager_pkgs_LDFLAGS} -pie -lcap -lrt libcrash-manager -ldiagnostics) set(CRASH_POPUP crash-popup-launch) ADD_EXECUTABLE(${CRASH_POPUP} ${CRASH_POPUP}.c) diff --git a/src/crash-manager/crash-manager.c b/src/crash-manager/crash-manager.c index c6e0eb0..beeb59d 100644 --- a/src/crash-manager/crash-manager.c +++ b/src/crash-manager/crash-manager.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -1318,8 +1319,10 @@ static bool run(struct crash_info *cinfo) } else temp_report = cinfo->info_path; - if (move_dump_data(temp_report, cinfo)) + if (move_dump_data(temp_report, cinfo)) { _I("Report for pid %d created at %s", cinfo->pid_info, cinfo->result_path); + diagnostics_send_event("BugreportCreated", NULL); + } if (cinfo->print_result_path) printf("REPORT_PATH=%s\n", cinfo->result_path); diff --git a/src/crash-manager/main.c b/src/crash-manager/main.c index 6080bfe..def780c 100644 --- a/src/crash-manager/main.c +++ b/src/crash-manager/main.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -304,6 +305,7 @@ int main(int argc, char *argv[]) if (!parse_args(&cinfo, argc, argv)) return EXIT_FAILURE; + diagnostics_set_client_id("org.tizen.bugreport-service"); res = crash_manager_direct(&cinfo) ? EXIT_SUCCESS : EXIT_FAILURE; crash_manager_free(&cinfo); -- 2.7.4 From 58d9de2f1de06b58ed63b453ef6fbc5074b0b8f2 Mon Sep 17 00:00:00 2001 From: Mateusz Moscicki Date: Fri, 19 Mar 2021 17:53:49 +0100 Subject: [PATCH 16/16] Allow to get bugreports using the diagnostics API bugreport-service registers as a org.tizen.bugreport-service and allows to get bugreport and crash-info report by dumpsys. For example: to get all bugreports created in the last hour run: dumpsys org.tizen.bugreport-service -- --type bugreport --last 3600 Supported parameters: --type Get specified report --last Get reports created in the last --from Get reports created after a specified time --to Get reports created before a specified time Change-Id: I0d3e04c34b63f3a559c8bde9af703eeabeb4e7ae --- packaging/crash-worker.spec | 1 + src/bugreport-service/CMakeLists.txt | 5 + src/bugreport-service/bugreport-service.c | 8 +- src/bugreport-service/diagnostics/diagnostics.c | 22 ++ src/bugreport-service/diagnostics/diagnostics.h | 4 +- .../diagnostics/diagnostics_dump.c | 355 +++++++++++++++++++++ .../diagnostics/diagnostics_dump.h | 19 ++ ...s.providers.org.tizen.bugreport-service.service | 4 + 8 files changed, 415 insertions(+), 3 deletions(-) create mode 100644 src/bugreport-service/diagnostics/diagnostics_dump.c create mode 100644 src/bugreport-service/diagnostics/diagnostics_dump.h create mode 100644 src/bugreport-service/org.tizen.dumpsys.providers.org.tizen.bugreport-service.service diff --git a/packaging/crash-worker.spec b/packaging/crash-worker.spec index 52ef210..4db8056 100644 --- a/packaging/crash-worker.spec +++ b/packaging/crash-worker.spec @@ -344,6 +344,7 @@ fi %attr(-,root,root) %{_sysconfdir}/dbus-1/system.d/bugreport-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(-,root,root) %{_datadir}/dbus-1/system-services/org.tizen.dumpsys.providers.org.tizen.bugreport-service.service %attr(0644,root,root) %{_prefix}/lib/tmpfiles.d/diagnostics-run.conf %if %{with doc} diff --git a/src/bugreport-service/CMakeLists.txt b/src/bugreport-service/CMakeLists.txt index 3d493be..b289d70 100644 --- a/src/bugreport-service/CMakeLists.txt +++ b/src/bugreport-service/CMakeLists.txt @@ -7,6 +7,7 @@ SET(CRASH_SERVICE_SRCS bugreport-service.c systemdump.c diagnostics/diagnostics.c + diagnostics/diagnostics_dump.c ${CMAKE_SOURCE_DIR}/src/shared/util.c ${CMAKE_SOURCE_DIR}/src/shared/spawn.c ${CMAKE_SOURCE_DIR}/src/shared/config.c @@ -22,6 +23,7 @@ pkg_check_modules(bugreport-service_pkgs REQUIRED gio-unix-2.0 libzip iniparser + diagnostics ) FOREACH(flag ${bugreport-service_pkgs_CFLAGS}) @@ -47,6 +49,9 @@ INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/org.tizen.system.crash.livedump.servic 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}/org.tizen.dumpsys.providers.org.tizen.bugreport-service.service + DESTINATION /usr/share/dbus-1/system-services) + INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/bugreport-service.conf DESTINATION /etc/dbus-1/system.d) diff --git a/src/bugreport-service/bugreport-service.c b/src/bugreport-service/bugreport-service.c index 3bea418..002149b 100644 --- a/src/bugreport-service/bugreport-service.c +++ b/src/bugreport-service/bugreport-service.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "bugreport-service.h" @@ -35,6 +36,7 @@ #include "shared/log.h" #include "shared/util.h" #include "diagnostics/diagnostics.h" +#include "diagnostics/diagnostics_dump.h" #include "systemdump.h" /* Dbus activation */ @@ -510,8 +512,10 @@ int main(void) g_mutex_init(&timeout_mutex); add_timeout(); - diagnostics_set_client_id("org.tizen.bugreport-service"); - g_main_loop_run(loop); + if (diagnostics_init()) + g_main_loop_run(loop); + else + _E("Diagnostics API init error."); if (introspection_data) g_dbus_node_info_unref(introspection_data); diff --git a/src/bugreport-service/diagnostics/diagnostics.c b/src/bugreport-service/diagnostics/diagnostics.c index e66394f..defee17 100644 --- a/src/bugreport-service/diagnostics/diagnostics.c +++ b/src/bugreport-service/diagnostics/diagnostics.c @@ -41,12 +41,16 @@ #define TMP_FILE_TEMPLATE "file_XXXXXX" #define JSON_FILE_EXT ".json" +#define INFO_FILE_EXT ".info" +#define LOG_FILE_EXT ".log" #define ZIP_FILE_EXT ".zip" enum diagnostics_type { BT_UNKNOWN, BT_FULL_REPORT, BT_INFO_JSON, + BT_INFO_FILE, + BT_LOG, BT_DIR }; @@ -56,6 +60,10 @@ static char *type_to_str(enum diagnostics_entry entry) { return "FULL_REPORT"; case INFO_JSON: return "INFO_JSON"; + case INFO_FILE: + return "INFO_FILE"; + case LOG_FILE: + return "LOG_FILE"; default: return "UKNOWN"; } @@ -113,6 +121,16 @@ static enum diagnostics_type check_report_type(const char *path) return BT_INFO_JSON; } + if (strstr(path, INFO_FILE_EXT) == &path[strlen(path) - strlen(INFO_FILE_EXT)]) { + _D("Report type of %s is INFO_FILE\n", path); + return BT_INFO_FILE; + } + + if (strstr(path, LOG_FILE_EXT) == &path[strlen(path) - strlen(LOG_FILE_EXT)]) { + _D("Report type of %s is LOG_FILE\n", path); + return BT_LOG; + } + 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; @@ -154,6 +172,10 @@ static bool file_match(const char *file_name, enum diagnostics_entry entry) switch(entry) { case INFO_JSON: return ends_with(file_name, JSON_FILE_EXT); + case INFO_FILE: + return ends_with(file_name, INFO_FILE_EXT); + case LOG_FILE: + return ends_with(file_name, LOG_FILE_EXT); default: return false; } diff --git a/src/bugreport-service/diagnostics/diagnostics.h b/src/bugreport-service/diagnostics/diagnostics.h index 8b2bea9..376ac54 100644 --- a/src/bugreport-service/diagnostics/diagnostics.h +++ b/src/bugreport-service/diagnostics/diagnostics.h @@ -25,7 +25,9 @@ enum diagnostics_entry { FULL_REPORT = 0, - INFO_JSON + INFO_JSON, + INFO_FILE, + LOG_FILE, }; enum diagnostics_metadata { diff --git a/src/bugreport-service/diagnostics/diagnostics_dump.c b/src/bugreport-service/diagnostics/diagnostics_dump.c new file mode 100644 index 0000000..f1fb212 --- /dev/null +++ b/src/bugreport-service/diagnostics/diagnostics_dump.c @@ -0,0 +1,355 @@ +/* + * Copyright (c) 2021 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "diagnostics/diagnostics.h" +#include "diagnostics/diagnostics_dump.h" +#include "shared/log.h" +#include "shared/util.h" + +enum BUGREPORT_REPORT_TYPE { BR_UNKNOWN, BR_BUGREPORT, BR_CRASHINFO }; + +struct report_file { + char *file_name; + char *file_path; + struct timespec ctime; +}; + +static bool get_reports_list(const char *path, struct report_file **list, size_t *list_count) +{ + assert(list); + assert(list_count); + + DIR *dp; + struct dirent *ep; + dp = opendir(path); + if (dp == NULL) { + _E("Open directory %s error: %m", path); + return false; + } + + while ((ep = readdir(dp))) { + if (ep->d_type != 8) + continue; + struct stat st; + char *file_path = NULL; + if (asprintf(&file_path, "%s/%s", path, ep->d_name) == -1) { + _E("Memory allocation error: %m"); + return false; + } + if (stat(file_path, &st) != 0) { + _E("Get stats about %s error: %m", path); + return false; + } + struct tm t; + if (localtime_r(&(st.st_ctim.tv_sec), &t) == NULL) { + _E("localtime_r error: %m"); + return false; + } + + *list = realloc(*list, sizeof(struct report_file)*(*list_count + 1)); + (*list)[*list_count].file_name = strdup(ep->d_name); + (*list)[*list_count].file_path = strdup(file_path); + (*list)[*list_count].ctime = st.st_ctim; + (*list_count)++; + } + closedir(dp); + return true; +} + +static void free_record(struct report_file *record) +{ + free(record->file_name); + free(record->file_path); +} + +static void filter_time(struct report_file *list, size_t *list_count, long time_from, long time_to) +{ + size_t dest = 0; + size_t n_list_count = *list_count; + + struct timespec current_ts; + clock_gettime(CLOCK_REALTIME, ¤t_ts); + + for (int i = 0; i < *list_count; i++) { + if (list[i].ctime.tv_sec >= time_from && list[i].ctime.tv_sec < time_to) { + if (dest != i) + list[dest] = list[i]; + dest++; + } else { + free_record(&list[i]); + n_list_count--; + } + } + *list_count = n_list_count; +} + +static int ctime_compare(const void *a, const void *b) +{ + return ((struct report_file*)a)->ctime.tv_sec - ((struct report_file*)b)->ctime.tv_sec; +} + +static struct report_file* get_reports(long time_from, long time_to, size_t *count) +{ + struct report_file *list = NULL; + *count = 0; + + const char *dirs[] = { + CRASH_ROOT_PATH CRASH_PATH_SUBDIR, + CRASH_ROOT_PATH LIVE_PATH_SUBDIR + }; + + for (int i = 0; i < ARRAY_SIZE(dirs); i++) { + if (file_exists(dirs[i]) && !get_reports_list(dirs[i], &list, count)) { + _E("Can not read reports from: %s", dirs[i]); + return NULL; + } + } + + filter_time(list, count, time_from, time_to); + + qsort(list, *count, sizeof(struct report_file), ctime_compare); + return list; +} + +static void write_bugreport_log_file(int out_fd, const char *report_path) +{ + int in_fd = diagnostics_report_get_file(report_path, LOG_FILE); + if (in_fd < 0) { + _D("No LOG_FILE report in %s file", report_path); + return; + } + + if (dprintf(out_fd, "Begin systemtate-log\n") == -1) { + _E("Write error: %m"); + goto out; + } + + if (copy_bytes(out_fd, in_fd, NULL) == -1) { + _E("Copy data error"); + goto out; + } + +out: + close(in_fd); + if (dprintf(out_fd, "End systemtate-log\n") == -1) + _E("Write error: %m"); +} + +static bool write_bugreport(int fd, long time_from, long time_to) +{ + size_t list_count = 0; + bool result = true; + + struct report_file *list = get_reports(time_from, time_to, &list_count); + if (list == NULL) { + dprintf(fd, "Internal error.\n"); + return false; + } + + for (int i = 0; i < list_count; i++) { + if (dprintf(fd, "%sBegin bugreport <%s>\n", (i > 0) ? "\n" : "", list[i].file_path) == -1) { + _E("Write error: %m"); + result = false; + goto out; + } + + write_bugreport_log_file(fd, list[i].file_path); + + if (dprintf(fd, "End bugreport <%s>\n", list[i].file_path) == -1) { + _E("Write error: %m"); + result = false; + goto out; + } + } + +out: + for (int i = 0; i < list_count; i++) + free_record(&list[i]); + free(list); + return result; +} + +static bool write_crash_info(int fd, long time_from, long time_to) +{ + bool result = true; + size_t list_count = 0; + + struct report_file *list = get_reports(time_from, time_to, &list_count); + if (list == NULL) { + dprintf(fd, "Internal error.\n"); + return false; + } + + for (int i = 0; i < list_count; i++) { + int nfd = diagnostics_report_get_file(list[i].file_path, INFO_FILE); + if (nfd <= 0) { + _I("No INFO_FILE in %s file", list[i].file_path); + dprintf(nfd, "No INFO_FILE in %s\n", list[i].file_path); + continue; + } + + if (dprintf(fd, "%sBegin crash-info <%s>\n", (i > 0) ? "\n" : "", list[i].file_path) == -1) { + _E("Write error: %m"); + result = false; + goto out; + } + + if (copy_bytes(fd, nfd, NULL) == -1) { + _E("Copy data error"); + close(nfd); + result = false; + goto out; + } + + close(nfd); + + if (dprintf(fd, "End crash-info <%s>\n", list[i].file_path) == -1) { + _E("Write error: %m"); + result = false; + goto out; + } + } + +out: + for (int i = 0; i < list_count; i++) + free_record(&list[i]); + free(list); + return result; +} + +struct diagnostics_call_options { + enum BUGREPORT_REPORT_TYPE report_type; + long from, to; + bool last_set, from_set, to_set; +}; + +static bool diagnostics_call_parse_options(int out_fd, char **params, int params_size, struct diagnostics_call_options *dco) +{ + struct timespec cur_time; + clock_gettime(CLOCK_REALTIME, &cur_time); + dco->report_type = BR_UNKNOWN; + dco->from = 0; + dco->to = cur_time.tv_sec; + dco->last_set = false; + dco->from_set = false; + dco->to_set = false; + + enum PARAM_NAME { PN_TYPE = 1, PN_LAST, PN_TO, PN_FROM}; + + struct option long_options[] = { + {"type", required_argument, NULL, PN_TYPE}, + {"last", required_argument, NULL, PN_LAST}, + {"to", required_argument, NULL, PN_TO}, + {"from", required_argument, NULL, PN_FROM}, + }; + + int opt; + optind = 0; + + char **nparams = alloca((params_size+1)*sizeof(char*)); + memcpy(&nparams[1], params, params_size*sizeof(char*)); + nparams[0] = "n"; + while ((opt = getopt_long_only(params_size+1, nparams, "", long_options, NULL)) != -1) { + switch(opt) { + case PN_TYPE: + if (strcmp(optarg, "bugreport") == 0) { + dco->report_type = BR_BUGREPORT; + } else if (strcmp(optarg, "crash-info") == 0) { + dco->report_type = BR_CRASHINFO; + } else { + _E("Incorrect report type: %s", optarg); + dprintf(out_fd, "Incorrect report type: %s\n", optarg); + return false; + } + break; + case PN_LAST: + dco->last_set = true; + dco->from = cur_time.tv_sec - strtol(optarg, NULL, 10); + break; + case PN_FROM: + dco->from_set = true; + dco->from = strtol(optarg, NULL, 10); + break; + case PN_TO: + dco->to_set = true; + dco->to = strtol(optarg, NULL, 10); + break; + default: + _E("Incorrect option: %s", (optind > 0 && optind + 1 < params_size) ? params[optind-1] : ""); + dprintf(out_fd, "Incorrect option: %s\n", (optind > 0 && optind + 1 < params_size) ? params[optind-1] : ""); + return false; + } + } + + return true; +} + +static void diagnostics_callback(diagnostics_data_h data, char **params, int params_size, diagnostics_ctx_h ctx, void *user_data) +{ + int fd; + int ret = diagnostics_data_get_fd(data, &fd); + if (ret < 0) { + _E("Get data file descriptor error: %d", ret); + return; + } + struct diagnostics_call_options dco; + + if (!diagnostics_call_parse_options(fd, params, params_size, &dco)) + return; + + if ((dco.last_set && (dco.from_set || dco.from_set)) || (dco.to_set && !dco.from_set)) { + _E("Incorrect parameters set"); + dprintf(fd, "Incorrect parameters set.\n"); + return; + } + + switch(dco.report_type) { + case BR_CRASHINFO: + write_crash_info(fd, dco.from, dco.to); + break; + case BR_BUGREPORT: + write_bugreport(fd, dco.from, dco.to); + break; + default: + _E("Unknown report type\n"); + } +} + +bool diagnostics_init() +{ + diagnostics_set_client_id("org.tizen.bugreport-service"); + if (diagnostics_set_data_request_cb(&diagnostics_callback, NULL) != DIAGNOSTICS_ERROR_NONE) { + _E("Unable to register diagnostics callback"); + return false; + } + + return true; +} + diff --git a/src/bugreport-service/diagnostics/diagnostics_dump.h b/src/bugreport-service/diagnostics/diagnostics_dump.h new file mode 100644 index 0000000..a277463 --- /dev/null +++ b/src/bugreport-service/diagnostics/diagnostics_dump.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2021 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. + */ +#pragma once +#define LOG_TAG "BUGREPORT-SERVICE" + +bool diagnostics_init(); diff --git a/src/bugreport-service/org.tizen.dumpsys.providers.org.tizen.bugreport-service.service b/src/bugreport-service/org.tizen.dumpsys.providers.org.tizen.bugreport-service.service new file mode 100644 index 0000000..8317dea --- /dev/null +++ b/src/bugreport-service/org.tizen.dumpsys.providers.org.tizen.bugreport-service.service @@ -0,0 +1,4 @@ +[D-BUS Service] +Name=org.tizen.dumpsys.providers.org.tizen.bugreport-service +Exec=/bin/false +SystemdService=bugreport.service -- 2.7.4