Add log_dump 12/214812/2 tizen submit/tizen/20190926.172549
authorMateusz Moscicki <m.moscicki2@partner.samsung.com>
Tue, 24 Sep 2019 10:34:45 +0000 (12:34 +0200)
committerMateusz Moscicki <m.moscicki2@partner.samsung.com>
Thu, 26 Sep 2019 13:44:39 +0000 (15:44 +0200)
log_dump is command line tool which is used to dump current system
states. log_dump was previously part of the
platform/core/system/crash-worker repository

Change-Id: I4dd01f6506e93dc6b95174a649066886a9aa5d83

33 files changed:
CMakeLists.txt [new file with mode: 0644]
LICENSE [new file with mode: 0755]
cmake/ProcessM4.cmake [new file with mode: 0644]
dump_scripts/module_log.sh [new file with mode: 0755]
dump_scripts/move_dump.sh [new file with mode: 0755]
dump_scripts/system_log.sh [new file with mode: 0755]
include/CMakeLists.txt [new file with mode: 0644]
include/defs.h.in [new file with mode: 0644]
packaging/log_dump.conf [new file with mode: 0644]
packaging/log_dump.manifest [new file with mode: 0644]
packaging/log_dump.spec [new file with mode: 0644]
packaging/log_dump_system-tests.manifest [new file with mode: 0644]
packaging/log_dump_system-tests.spec [new file with mode: 0644]
src/log_dump/CMakeLists.txt [new file with mode: 0644]
src/log_dump/dbus-handler.c [new file with mode: 0644]
src/log_dump/dbus-handler.h [new file with mode: 0644]
src/log_dump/log_dump.c [new file with mode: 0644]
src/log_dump/log_dump.conf [new file with mode: 0644]
src/log_dump/log_dump.h [new file with mode: 0644]
src/log_dump/log_dump.service.m4 [new file with mode: 0644]
src/log_dump/org.tizen.system.crash.service [new file with mode: 0644]
src/shared/config.c [new file with mode: 0644]
src/shared/config.h [new file with mode: 0644]
src/shared/log.h [new file with mode: 0644]
src/shared/spawn.c [new file with mode: 0644]
src/shared/spawn.h [new file with mode: 0644]
src/shared/util.c [new file with mode: 0644]
src/shared/util.h [new file with mode: 0644]
tests/system/CMakeLists.txt [new file with mode: 0644]
tests/system/log_dump_crash_root_path/log_dump_crash_root_path.sh.template [new file with mode: 0644]
tests/system/log_dump_normal/log_dump_normal.sh.template [new file with mode: 0644]
tests/system/log_dump_service/log_dump_service.sh.template [new file with mode: 0644]
tests/system/log_dump_short/log_dump_short.sh.template [new file with mode: 0644]

diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644 (file)
index 0000000..0a6a63d
--- /dev/null
@@ -0,0 +1,11 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+PROJECT(log_dump C)
+
+SET(PREFIX ${CMAKE_INSTALL_PREFIX})
+
+ADD_DEFINITIONS(-D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE=1)
+
+ADD_SUBDIRECTORY(include)
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include)
+
+ADD_SUBDIRECTORY(src/log_dump)
diff --git a/LICENSE b/LICENSE
new file mode 100755 (executable)
index 0000000..8aa906c
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,205 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+
+
diff --git a/cmake/ProcessM4.cmake b/cmake/ProcessM4.cmake
new file mode 100644 (file)
index 0000000..09ba1c9
--- /dev/null
@@ -0,0 +1,11 @@
+MACRO(PROCESS_M4 _defines _input _output)
+  GET_FILENAME_COMPONENT(_name ${_output} NAME)
+  ADD_CUSTOM_COMMAND(
+    OUTPUT ${_output}
+    COMMAND m4
+    ARGS -P ${_defines} ${_input} > ${_output}
+    DEPENDS ${_input}
+    VERBATIM)
+  ADD_CUSTOM_TARGET(M4_${_name} DEPENDS ${_output})
+  ADD_DEPENDENCIES(${PROJECT_NAME} M4_${_name})
+ENDMACRO(PROCESS_M4)
diff --git a/dump_scripts/module_log.sh b/dump_scripts/module_log.sh
new file mode 100755 (executable)
index 0000000..4c73e33
--- /dev/null
@@ -0,0 +1,19 @@
+#!/bin/sh
+#
+# Dump module log
+#
+PATH=/bin:/usr/bin:/sbin:/usr/sbin
+
+DUMP_DEST=$1/log/module_log
+DUMP_SCRIPT_DIR=/opt/etc/dump.d/module.d
+
+mkdir -p ${DUMP_DEST}
+
+if [ -d ${DUMP_SCRIPT_DIR} ]
+then
+       SCRIPTS=`/bin/ls ${DUMP_SCRIPT_DIR}`
+
+       for SCRIPT in ${SCRIPTS}; do
+               /bin/sh ${DUMP_SCRIPT_DIR}/${SCRIPT} ${DUMP_DEST}
+       done
+fi
diff --git a/dump_scripts/move_dump.sh b/dump_scripts/move_dump.sh
new file mode 100755 (executable)
index 0000000..94d09c4
--- /dev/null
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+PATH=/bin:/usr/bin:/sbin:/usr/sbin
+
+. /etc/tizen-platform.conf
+
+set -ex
+
+DEST="$1/dump"
+mkdir -p "$DEST"
+mv -f "${TZ_SYS_CRASH}"/* "$DEST"/
+
diff --git a/dump_scripts/system_log.sh b/dump_scripts/system_log.sh
new file mode 100755 (executable)
index 0000000..36beeb1
--- /dev/null
@@ -0,0 +1,12 @@
+#!/bin/sh
+#
+# Dump system log
+#
+PATH=/bin:/usr/bin:/sbin:/usr/sbin
+
+DUMP_DEST=$1/log/system_log
+
+mkdir -p ${DUMP_DEST}
+
+/bin/cp -fr /opt/var/log/* ${DUMP_DEST}
+/bin/cp -fr /run/systemd/journal ${DUMP_DEST}
diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt
new file mode 100644 (file)
index 0000000..bc03a77
--- /dev/null
@@ -0,0 +1,4 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+PROJECT(log_dump C)
+
+CONFIGURE_FILE(defs.h.in defs.h @ONLY)
diff --git a/include/defs.h.in b/include/defs.h.in
new file mode 100644 (file)
index 0000000..50f117e
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef __DEFS_H__
+#define __DEFS_H__
+
+#define CRASH_ROOT_PATH                        "@CRASH_ROOT_PATH@"
+#define LOG_DUMP_CONFIG_PATH           "@LOG_DUMP_CONFIG_PATH@"
+#define DUMP_SYSTEMSTATE_BIN_PATH      "@DUMP_SYSTEMSTATE_BIN_PATH@"
+
+#endif /* __DEFS_H__ */
diff --git a/packaging/log_dump.conf b/packaging/log_dump.conf
new file mode 100644 (file)
index 0000000..4c82d0e
--- /dev/null
@@ -0,0 +1,26 @@
+<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-Bus Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<busconfig>
+    <policy user="root">
+        <allow own="org.tizen.system.crash"/>
+       <allow send_destination="org.tizen.system.crash"
+              send_interface="org.tizen.system.crash.Crash"
+              send_member="dump_log"/>
+       <allow send_destination="org.tizen.system.crash"
+              send_interface="org.tizen.system.crash.Crash"
+              send_member="delete_dump"/>
+    </policy>
+    <policy user="system">
+       <allow send_destination="org.tizen.system.crash"
+              send_interface="org.tizen.system.crash.Crash"
+              send_member="dump_log"/>
+       <allow send_destination="org.tizen.system.crash"
+              send_interface="org.tizen.system.crash.Crash"
+              send_member="delete_dump"/>
+    </policy>
+
+    <policy context="default">
+       <deny own="org.tizen.system.crash"/>
+       <deny send_destination="org.tizen.system.crash"/>
+    </policy>
+</busconfig>
diff --git a/packaging/log_dump.manifest b/packaging/log_dump.manifest
new file mode 100644 (file)
index 0000000..a340d2e
--- /dev/null
@@ -0,0 +1,8 @@
+<manifest>
+       <request>
+               <domain name="_"/>
+       </request>
+       <assign>
+               <filesystem path="/usr/bin/log_dump" label="System" exec_label="System"/>
+       </assign>
+</manifest>
diff --git a/packaging/log_dump.spec b/packaging/log_dump.spec
new file mode 100644 (file)
index 0000000..6b0ead0
--- /dev/null
@@ -0,0 +1,87 @@
+# "on_off foo" wil turn into "ON" or "OFF"
+%define on_off() %{expand:%%{?with_%{1}:ON}%%{!?with_%{1}:OFF}}
+
+# NOTE: To disable coredump set DumpCore=0 in configuration file
+
+Name:      log_dump
+Summary:    log_dump
+Version:    5.5.23
+Release:    1
+Group:      Framework/system
+License:    Apache-2.0
+Source0:    %{name}-%{version}.tar.gz
+Source1001:    log_dump.manifest
+Source1002:    packaging/log_dump.conf
+BuildRequires:  pkgconfig(dlog)
+BuildRequires:  pkgconfig(libtzplatform-config)
+BuildRequires:  pkgconfig(iniparser)
+BuildRequires:  pkgconfig(capi-system-info)
+BuildRequires:  pkgconfig(glib-2.0)
+BuildRequires:  cmake
+
+Requires:       crash-worker >= 5.5.23
+Conflicts:      crash-worker < 5.5.23
+
+%description
+log_dump
+
+%prep
+%setup -q
+
+#Path to store logs and coredump files
+%define crash_root_path %{TZ_SYS_CRASH_ROOT}
+
+#Path for log_dump module
+%define crash_all_log   %{TZ_SYS_ALLLOGS}
+%define crash_dump_gen  %{TZ_SYS_DUMPGEN}
+
+# %define upgrade_script_path %{TZ_SYS_RO_SHARE}/upgrade/scripts
+
+%build
+cp %{SOURCE1001} .
+export CFLAGS+=" -Werror"
+
+%cmake . \
+          -DCMAKE_INSTALL_PREFIX=%{_prefix} \
+          -DLOG_DUMP_CONFIG_PATH=%{_sysconfdir}/log_dump.conf \
+          -DDUMP_SYSTEMSTATE_BIN_PATH=%{_bindir}/dump_systemstate \
+          -DCRASH_ROOT_PATH=%{crash_root_path}
+
+make %{?jobs:-j%jobs}
+
+%install
+rm -rf %{buildroot}
+
+%make_install
+mkdir -p %{buildroot}%{crash_root_path}
+
+# log_dump dir
+mkdir -p %{buildroot}%{crash_all_log}
+mkdir -p %{buildroot}%{crash_dump_gen}
+cp dump_scripts/* %{buildroot}%{crash_dump_gen}
+install -D -m 0655 %SOURCE1002 %{buildroot}%{_sysconfdir}/dbus-1/system.d/log_dump.conf
+chmod 755 %{buildroot}%{crash_dump_gen}/*
+
+%post
+/usr/bin/chsmack -a "System" -t %{crash_dump_gen}
+/usr/bin/chsmack -a "System" -t %{crash_dump_gen}/module.d
+/usr/bin/chsmack -a "System::Shared" -t %{crash_all_log}
+/usr/bin/chsmack -a "_"  %{crash_dump_gen}/module.d/*
+
+%files
+%license LICENSE
+%manifest log_dump.manifest
+%defattr(-,system_fw,system_fw,-)
+%dir %{crash_root_path}
+%{_sysconfdir}/log_dump.conf
+
+%dir %{crash_all_log}
+%{crash_dump_gen}/*
+%attr(-,root,root) %{_unitdir}/log_dump.service
+%attr(-,root,root) %{_sysconfdir}/dbus-1/system.d/log_dump.conf
+%attr(-,root,root) %{_datadir}/dbus-1/system-services/org.tizen.system.crash.service
+%attr(0750,system_fw,system_fw) %{_bindir}/log_dump
+%attr(-,root,root) %{_sysconfdir}/log_dump.conf
+
+#upgrade script
+# %attr(-,root,root) %{upgrade_script_path}/500.log_dump-upgrade.sh
diff --git a/packaging/log_dump_system-tests.manifest b/packaging/log_dump_system-tests.manifest
new file mode 100644 (file)
index 0000000..4bce03d
--- /dev/null
@@ -0,0 +1,10 @@
+<manifest>
+       <request>
+               <domain name="_"/>
+       </request>
+       <assign>
+        <filesystem path="/usr/lib/crash-worker_system-tests/log_dump_crash_root_path/log_dump_crash_root_path.sh" label="User::Shell" exec_label="User::Shell"/>
+        <filesystem path="/usr/lib/crash-worker_system-tests/log_dump_normal/log_dump_normal.sh" label="User::Shell" exec_label="System"/>
+        <filesystem path="/usr/lib/crash-worker_system-tests/log_dump_short/log_dump_short.sh" label="User::Shell" exec_label="User::Shell"/>
+       </assign>
+</manifest>
diff --git a/packaging/log_dump_system-tests.spec b/packaging/log_dump_system-tests.spec
new file mode 100644 (file)
index 0000000..d072e49
--- /dev/null
@@ -0,0 +1,41 @@
+Name:          log_dump_system-tests
+Summary:       Package with scripts for log_dump system tests
+Version:       5.5.23
+Release:       1
+Group:         Framework/system
+License:       Apache-2.0
+Source0:       %{name}-%{version}.tar.gz
+Source1001:    log_dump_system-tests.manifest
+BuildRequires: cmake
+
+Requires:      log_dump
+Requires:      crash-worker_system-tests >= 5.5.23
+Conflicts:     crash-worker_system-tests < 5.5.23
+
+%description
+This package contains installable tests in Bash.
+
+%prep
+%setup -q
+
+%build
+cp %{SOURCE1001} .
+
+cd tests/system
+%cmake . -DCRASH_SYSTEM_TESTS_PATH=%{_libdir}/crash-worker_system-tests
+
+make %{?jobs:-j%jobs}
+
+%install
+rm -rf %{buildroot}
+cd tests/system
+
+%make_install
+
+%files -f debugfiles.list
+%manifest %{name}.manifest
+%defattr(0750,system_fw,system_fw)
+%{_libdir}/crash-worker_system-tests/log_dump_crash_root_path/log_dump_crash_root_path.sh
+%{_libdir}/crash-worker_system-tests/log_dump_normal/log_dump_normal.sh
+%{_libdir}/crash-worker_system-tests/log_dump_short/log_dump_short.sh
+%defattr(-,root,root)
diff --git a/src/log_dump/CMakeLists.txt b/src/log_dump/CMakeLists.txt
new file mode 100644 (file)
index 0000000..021823f
--- /dev/null
@@ -0,0 +1,48 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+PROJECT(log_dump C)
+
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/src)
+SET(LOG_DUMP_SRCS
+       log_dump.c
+       dbus-handler.c
+       ${CMAKE_SOURCE_DIR}/src/shared/util.c
+       ${CMAKE_SOURCE_DIR}/src/shared/spawn.c
+       ${CMAKE_SOURCE_DIR}/src/shared/config.c
+   )
+
+INCLUDE(FindPkgConfig)
+pkg_check_modules(log_dump_pkgs REQUIRED
+       dlog
+       capi-system-info
+       libtzplatform-config
+       iniparser
+       gio-2.0
+       )
+
+INCLUDE(${CMAKE_SOURCE_DIR}/cmake/ProcessM4.cmake)
+
+FOREACH(flag ${log_dump_pkgs_CFLAGS})
+       SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -fPIE")
+
+ADD_EXECUTABLE(${PROJECT_NAME} ${LOG_DUMP_SRCS})
+TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${log_dump_pkgs_LDFLAGS} -pie)
+
+PROCESS_M4("${M4_DEFINES}"
+       "${CMAKE_CURRENT_SOURCE_DIR}/log_dump.service.m4"
+       "${CMAKE_CURRENT_SOURCE_DIR}/log_dump.service")
+
+INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/org.tizen.system.crash.service
+       DESTINATION /usr/share/dbus-1/system-services)
+
+INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/log_dump.conf
+       DESTINATION /etc)
+
+INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/log_dump.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/log_dump/dbus-handler.c b/src/log_dump/dbus-handler.c
new file mode 100644 (file)
index 0000000..2eecde6
--- /dev/null
@@ -0,0 +1,238 @@
+/*
+ * log_dump
+ *
+ * Copyright (c) 2016 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 <stdbool.h>
+#include <gio/gio.h>
+#include "log_dump.h"
+#include "dbus-handler.h"
+
+/* Dbus activation */
+#define CRASH_BUS_NAME          "org.tizen.system.crash"
+#define CRASH_OBJECT_PATH       "/Org/Tizen/System/Crash/Crash"
+
+/* Log dump signal */
+#define LOG_DUMP_BUS_NAME       "org.tizen.system.logdump"
+#define LOG_DUMP_OBJECT_PATH    "/Org/Tizen/System/LogDump"
+#define LOG_DUMP_INTERFACE_NAME LOG_DUMP_BUS_NAME
+#define LOG_DUMP_START_SIGNAL   "Start"
+#define LOG_DUMP_FINISH_SIGNAL  "Finish"
+
+#define TIMEOUT_INTERVAL 30
+
+static GMainLoop *loop;
+static GMutex timeout_mutex;
+static guint timeout_id;
+static GDBusNodeInfo *introspection_data;
+static const gchar introspection_xml[] =
+"<node>"
+" <interface name='org.tizen.system.crash.Crash'>"
+"  <method name='dump_log'>"
+"   <arg type='s' name='arg' direction='in'/>"
+"   <arg type='i' name='response' direction='out'/>"
+"  </method>"
+"  <method name='delete_dump'>"
+"   <arg type='i' name='response' direction='out'/>"
+"  </method>"
+" </interface>"
+"</node>";
+
+static int timeout_cb(gpointer 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, timeout_cb, loop);
+
+       g_mutex_unlock(&timeout_mutex);
+       _I("Add loop timeout (%d)", TIMEOUT_INTERVAL);
+}
+
+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);
+       _I("Remove loop timeout");
+}
+
+static void method_call_handler(GDBusConnection *conn,
+                               const gchar *sender,
+                               const gchar *object_path,
+                               const gchar *iface_name,
+                               const gchar *method_name,
+                               GVariant *parameters,
+                               GDBusMethodInvocation *invocation,
+                               gpointer user_data)
+{
+       int ret = -1;
+       const gchar *arg;
+
+       remove_timeout();
+
+       if (g_strcmp0(method_name, "dump_log") == 0) {
+               g_variant_get(parameters, "(&s)", &arg);
+               if (g_strcmp0(arg, "normal") == 0)
+                       ret = log_dump(OPT_NORMAL);
+               else if (g_strcmp0(arg, "short") == 0)
+                       ret = log_dump(OPT_SHORT);
+               else
+                       _E("Wrong option for log_dump");
+       } else if (g_strcmp0(method_name, "delete_dump") == 0) {
+               ret = delete_dump();
+       }
+
+       g_dbus_method_invocation_return_value(invocation,
+                       g_variant_new("(i)", ret));
+
+       add_timeout();
+}
+
+static const GDBusInterfaceVTable interface_vtable = {
+       method_call_handler,
+       NULL,
+       NULL
+};
+
+static void on_bus_acquired(GDBusConnection *conn,
+                           const gchar *name,
+                           gpointer user_data)
+{
+       guint registration_id;
+
+       registration_id = g_dbus_connection_register_object(conn,
+                       CRASH_OBJECT_PATH, introspection_data->interfaces[0],
+                       &interface_vtable, NULL, NULL, NULL);
+       if (registration_id == 0)
+               _E("Failed to g_dbus_connection_register_object");
+}
+
+static void on_name_acquired(GDBusConnection *conn,
+                            const gchar *name,
+                            gpointer user_data)
+{
+       _D("Acquired the name %s on the system bus", name);
+}
+
+static void on_name_lost(GDBusConnection *conn,
+                        const gchar *name,
+                        gpointer user_data)
+{
+       _D("Lost the name %s on the system bus", name);
+}
+
+static void dbus_init(void)
+{
+       GDBusConnection *conn = NULL;
+       GError *error = NULL;
+
+       introspection_data =
+               g_dbus_node_info_new_for_xml(introspection_xml, NULL);
+       if (introspection_data == NULL) {
+               _E("Failed to init g_dbus_info_new_for_xml");
+               return;
+       }
+
+       conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
+       if (!conn) {
+               _E("Failed to get dbus");
+               return;
+       }
+
+       if (error) {
+               _E("Failed to get dbus: %s", error->message);
+               g_error_free(error);
+               return;
+       }
+
+       g_bus_own_name(G_BUS_TYPE_SYSTEM, CRASH_BUS_NAME,
+                       G_BUS_NAME_OWNER_FLAGS_NONE, on_bus_acquired,
+                       on_name_acquired, on_name_lost, NULL, NULL);
+}
+
+int log_dump_dbus(void)
+{
+       loop = g_main_loop_new(NULL, false);
+
+       dbus_init();
+
+       g_mutex_init(&timeout_mutex);
+       add_timeout();
+
+       _I("log_dump_dbus activated");
+       g_main_loop_run(loop);
+
+       if (introspection_data)
+               g_dbus_node_info_unref(introspection_data);
+       g_mutex_clear(&timeout_mutex);
+       g_main_loop_unref(loop);
+
+       return 0;
+}
+
+static int broadcast_logdump(const char *signal)
+{
+       GDBusConnection *conn;
+       GError *error = NULL;
+
+       _I("broadcast signal: %s", signal);
+       conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
+       if (error) {
+               _E("Failed to get dbus: %s", error->message);
+               g_error_free(error);
+               return -1;
+       }
+
+       g_dbus_connection_emit_signal(conn,
+                                     NULL,
+                                     LOG_DUMP_OBJECT_PATH,
+                                     LOG_DUMP_INTERFACE_NAME,
+                                     signal,
+                                     NULL,
+                                     &error);
+       if (error) {
+               _E("Failed to emit signal: %s", error->message);
+               g_error_free(error);
+               return -1;
+       }
+
+       return 0;
+}
+
+int broadcast_logdump_start(void)
+{
+       return broadcast_logdump(LOG_DUMP_START_SIGNAL);
+}
+
+int broadcast_logdump_finish(void)
+{
+       return broadcast_logdump(LOG_DUMP_FINISH_SIGNAL);
+}
diff --git a/src/log_dump/dbus-handler.h b/src/log_dump/dbus-handler.h
new file mode 100644 (file)
index 0000000..a936f31
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * log_dump
+ *
+ * Copyright (c) 2016 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 __LOGDUMP_DBUS_H__
+#define __LOGDUMP_DBUS_H__
+
+int log_dump_dbus(void);
+int broadcast_logdump_start(void);
+int broadcast_logdump_finish(void);
+
+#endif
diff --git a/src/log_dump/log_dump.c b/src/log_dump/log_dump.c
new file mode 100644 (file)
index 0000000..551900b
--- /dev/null
@@ -0,0 +1,315 @@
+/*
+ * log_dump: dump current system states
+ *
+ * Copyright (c) 2016, 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <assert.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <libgen.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <system_info.h>
+#include <tzplatform_config.h>
+
+#include "defs.h"
+#include "dbus-handler.h"
+#include "log_dump.h"
+#include "shared/config.h"
+#include "shared/spawn.h"
+#include "shared/util.h"
+
+#define SYSTEM_INFO_KEY_BUILD_STRING "http://tizen.org/system/build.string"
+#define DIR_UMASK 0022
+
+static const struct option opts[] = {
+       { "normal", no_argument, 0, OPT_NORMAL },
+       { "short",  no_argument, 0, OPT_SHORT  },
+       { "dbus",   no_argument, 0, OPT_DBUS   },
+       { 0, 0, 0, 0 }
+};
+
+/* crash worker configuration - for admin-selectable CrashRootPath */
+config_t config;
+/* tzplaform vars */
+char *dir_scripts;
+/* dynamic vars */
+char *dir_dump;
+char *dir_log;
+char *dir_debug;
+char *dir_temp;  // temp rootdir
+char *dir_temp_logdump; // rootdir for this log_dump invocation
+char *version_string;
+/* timestamp */
+const char timestamp_format[] = "%Y%m%d%H%M%S";
+char timestamp_string[20]; /* as per format above */
+
+static bool init_temp_dir(char *const temp_root, char **temp_dir)
+{
+       assert(temp_root);
+       assert(temp_dir);
+
+       char *template = NULL, *path = NULL;
+       if (asprintf(&template, "%s/log.XXXXXX", temp_root) > 0)
+               path = mkdtemp(template);
+
+       if (!path) {
+               _E("Unable to create temporary directory at mkdtemp(%s): %m", template);
+               free(template);
+               return false;
+       }
+
+       *temp_dir = path;
+       return true;
+}
+
+static char *crash_root_get(void)
+{
+       return config.crash_root_path;
+}
+
+static bool init_vars(const char *crash_root)
+{
+       if (!crash_root)
+               return false;
+
+       if (asprintf(&dir_log, "%s/log", crash_root) <= 0
+           || asprintf(&dir_debug, "%s/debug", crash_root) <= 0
+           || asprintf(&dir_dump, "%s/dump", crash_root) <= 0
+           || asprintf(&dir_temp, "%s/temp", crash_root) <= 0)
+               goto fail;
+
+       make_dir(crash_root, "temp", DIR_UMASK);
+       if (!init_temp_dir(dir_temp, &dir_temp_logdump))
+               goto fail;
+
+       make_dir(dir_temp_logdump, "log", DIR_UMASK);
+       make_dir(crash_root, "debug", DIR_UMASK);
+
+       _D("config: dir_log is %s", dir_log);
+       _D("config: dir_dump is %s", dir_dump);
+       _D("config: dir_debug is %s", dir_debug);
+       _D("config: dir_temp is %s", dir_temp);
+       _D("config: dir_temp_logdump is %s", dir_temp_logdump);
+
+       dir_scripts = strdup(tzplatform_getenv(TZ_SYS_DUMPGEN));
+       _D("config: dir_scripts is %s", dir_scripts);
+
+       if (system_info_get_platform_string(SYSTEM_INFO_KEY_BUILD_STRING, &version_string) != SYSTEM_INFO_ERROR_NONE) {
+               _W("Failed to system_info_get_platform_string for " SYSTEM_INFO_KEY_BUILD_STRING);
+               version_string = NULL;
+       }
+       _D("version_string is %s", version_string);
+
+       time_t cur_time;
+       struct tm loc_tm;
+       cur_time = time(NULL);
+       localtime_r(&cur_time, &loc_tm);
+       strftime(timestamp_string, sizeof(timestamp_string), timestamp_format, &loc_tm);
+       _D("timestamp_string is %s", timestamp_string);
+
+       assert(dir_log);
+       assert(dir_dump);
+       assert(dir_debug);
+       assert(dir_temp);
+       assert(dir_temp_logdump);
+       return true;
+
+fail:
+       free(dir_log);
+       free(dir_dump);
+       free(dir_debug);
+       free(dir_temp);
+       free(dir_temp_logdump);
+       return false;
+}
+
+static void usage(void)
+{
+       printf("Usage: log_dump {OPTION}\n"
+              "Options:\n"
+              "  --normal    dump all logs (uses scripts from %s)\n"
+              "  --short     dump_systemstate logs only\n"
+              "  --dbus      become dbus service\n",
+              dir_scripts);
+}
+
+static bool dump_scripts(char *const workdir, char *const scriptsdir)
+{
+       struct dirent **dir_list = NULL;
+       char command[PATH_MAX];
+       int script_num, i;
+
+       script_num = scandir(scriptsdir, &dir_list, NULL, NULL);
+       if (script_num < 0) {
+               _E("scandir %s: %m", scriptsdir);
+               return false;
+       }
+
+       for (i = 0; i < script_num; i++) {
+               const char *const name = dir_list[i]->d_name;
+               int type = dir_list[i]->d_type;
+
+               if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
+                       continue;
+
+               if (type != DT_REG) {
+                       _D("Ignoring: not a regular file: %s", name);
+                       continue;
+               }
+               snprintf(command, sizeof(command), "%s/%s", scriptsdir, name);
+               if (access(command, X_OK) != 0) {
+                       _W("Ignoring: file not executable: %s", command);
+                       continue;
+               }
+
+               _D("Calling scriptlet: %s", command);
+
+               char *const av[] = {command, workdir, NULL};
+               (void)spawn_wait(av, NULL, NULL, 0, NULL);
+       }
+
+       for (i = 0; i < script_num; i++)
+               free(dir_list[i]);
+       free(dir_list);
+
+       return true;
+}
+
+static bool dump_systemstate(const char *const destdir, const char *const timestr, int *exit_code)
+{
+       char *dump_path = NULL;
+
+       if (asprintf(&dump_path, "%s/log/dump_systemstate_%s.log", destdir, timestr) < 0) {
+               _E("asprintf: %m");
+               return false;
+       }
+
+       char *av[] = {DUMP_SYSTEMSTATE_BIN_PATH, "-k", "-d", "-j", "-e", "-f", dump_path, NULL};
+       spawn_param_s param = { .fn = spawn_setstdout, .u.int_val = STDERR_FILENO };
+       bool is_ok = spawn_wait(av, NULL, &param, 0, exit_code);
+
+       free(dump_path);
+
+       return is_ok;
+}
+
+static bool compress(char *const destdir, char *const tempdir, char *const versionstr, char *const timestr, int *exit_code)
+{
+       char *archive_path = NULL;
+
+       if (asprintf(&archive_path, "%s/log_dump_%s%s.zip", destdir, versionstr ?: "", timestr) < 0) {
+               _E("asprintf: %m");
+               return false;
+       }
+
+       _D("compress tempdir is %s", tempdir);
+       char *av[] = {"/bin/zip", "-qyr", archive_path, ".", NULL};
+       spawn_param_s param1 = { .fn = spawn_nullstdfds };
+       spawn_param_s param0 = { .fn = spawn_chdir, .u.char_ptr = tempdir, .next = &param1 };
+       bool is_ok = spawn_wait(av, NULL, &param0, 0, exit_code);
+
+       _I("Storing report at %s", archive_path);
+
+       fsync_path(archive_path);
+       free(archive_path);
+
+       return is_ok;
+}
+
+int log_dump(int option)
+{
+       broadcast_logdump_start();
+
+       int ret = -1;
+
+       if (!dump_systemstate(dir_temp_logdump, timestamp_string, NULL))
+               goto out;
+
+       if (option == OPT_NORMAL)
+               (void)dump_scripts(dir_temp_logdump, dir_scripts);
+
+       compress(dir_debug, dir_temp_logdump, version_string, timestamp_string, NULL);
+
+       /* cleanup */
+       ret = remove_dir(dir_temp_logdump, 1);
+       if (ret < 0)
+               _W("Failed to delete dump directory at %s", dir_temp_logdump);
+
+       ret = 0;
+out:
+       broadcast_logdump_finish();
+
+       return ret;
+}
+
+int delete_dump(void)
+{
+       _D("delete_dump called");
+
+       remove_dir(dir_log, 0);
+       remove_dir(dir_debug, 1);
+       remove_dir(dir_dump, 0);
+       remove_dir(dir_temp, 0);
+
+       return 0;
+}
+
+static void die(void)
+{
+       usage();
+       exit(EXIT_FAILURE);
+}
+
+int main(int argc, char *argv[])
+{
+       int c, ret;
+       int option;
+
+       if (!config_init(&config, LOG_DUMP_CONFIG_PATH))
+               return false;
+
+       /* need to do this first, because even usage() uses the vars */
+       if (!init_vars(crash_root_get())) {
+               printf("Unable to initialize - please check program logs");
+               exit(EXIT_FAILURE);
+       }
+
+       if (argc < 2)
+               die();
+
+       option = -1;
+       while ((c = getopt_long_only(argc, argv, "", opts, NULL)) != -1) {
+               if (option >= 0 || c < _OPT_MIN || c > _OPT_MAX)
+                       die();
+               option = c;
+       }
+
+       if (option == OPT_DBUS)
+               ret = log_dump_dbus();
+       else
+               ret = log_dump(option);
+
+       config_free(&config);
+
+       return ret < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+}
diff --git a/src/log_dump/log_dump.conf b/src/log_dump/log_dump.conf
new file mode 100644 (file)
index 0000000..e30e366
--- /dev/null
@@ -0,0 +1,3 @@
+[LogDump]
+# CrashRootPath=/usr/opt/share/crash/
+
diff --git a/src/log_dump/log_dump.h b/src/log_dump/log_dump.h
new file mode 100644 (file)
index 0000000..a6c87c7
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * log_dump
+ *
+ * Copyright (c) 2016, 2018 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 __LOGDUMP_H__
+#define __LOGDUMP_H__
+
+#define LOG_TAG "LOG_DUMP"
+#include "shared/log.h"
+
+enum {
+       _OPT_MIN,
+       OPT_NORMAL = _OPT_MIN,
+       OPT_SHORT,
+       OPT_DBUS,
+       _OPT_MAX = OPT_DBUS,
+};
+
+int log_dump(int option);
+int delete_dump(void);
+
+#endif
diff --git a/src/log_dump/log_dump.service.m4 b/src/log_dump/log_dump.service.m4
new file mode 100644 (file)
index 0000000..be46f63
--- /dev/null
@@ -0,0 +1,11 @@
+[Unit]
+Description=log_dump service
+
+[Service]
+Type=dbus
+BusName=org.tizen.system.crash
+ExecStart=/usr/bin/log_dump --dbus
+SmackProcessLabel=System
+SupplementaryGroups=log systemd-journal
+Nice=-5
+KillMode=process
diff --git a/src/log_dump/org.tizen.system.crash.service b/src/log_dump/org.tizen.system.crash.service
new file mode 100644 (file)
index 0000000..5dfa56b
--- /dev/null
@@ -0,0 +1,4 @@
+[D-BUS Service]
+Name=org.tizen.system.crash
+Exec=/bin/false
+SystemdService=log_dump.service
diff --git a/src/shared/config.c b/src/shared/config.c
new file mode 100644 (file)
index 0000000..56f930a
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * crash-manager
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <assert.h>
+#include <iniparser.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "config.h"
+#include "defs.h"
+#include "log.h"
+#include "util.h"
+
+bool config_init(config_t *c, const char *const path)
+{
+       assert(c);
+       assert(path);
+
+       dictionary *ini = iniparser_load(path);
+       if (!ini) {
+               _E("Failed to load config file %s", path);
+               return false;
+       }
+
+       bool ret = false;
+
+#define GET(type, key, defval) iniparser_get##type(ini, LOG_DUMP_SECTION ":" key, defval)
+
+       c->crash_root_path = strdup(GET(string, "CrashRootPath", CRASH_ROOT_PATH));
+       if (!c->crash_root_path)
+               goto out;
+
+#undef GET
+
+       ret = true;
+out:
+       iniparser_freedict(ini);
+       return ret;
+}
+
+void config_free(config_t *c)
+{
+       assert(c);
+
+       free(c->crash_root_path);
+}
diff --git a/src/shared/config.h b/src/shared/config.h
new file mode 100644 (file)
index 0000000..db606fc
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * crash-manager
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef __DEF_CONFIG_H_
+#define __DEF_CONFIG_H_
+
+#include <stdbool.h>
+
+#define LOG_DUMP_SECTION        "LogDump"
+
+typedef struct config {
+       char *crash_root_path;
+} config_t;
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+bool config_init(config_t *c, const char *const path);
+void config_free(config_t *c);
+
+#ifdef __cplusplus
+}
+#endif
+
+/**
+ * @}
+ */
+#endif
diff --git a/src/shared/log.h b/src/shared/log.h
new file mode 100644 (file)
index 0000000..bee783b
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * crash-manager
+ * Copyright (c) 2012-2013 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 __CRASH_LOG_H__
+#define __CRASH_LOG_H__
+
+#ifndef LOG_TAG
+#define LOG_TAG "CRASH_MANAGER"
+#endif
+#include <dlog.h>
+
+#ifdef LOG_FILE
+#include <sys/types.h>
+#include <unistd.h>
+#undef LOG_
+static inline char __dlog_prio(int prio)
+{
+       static const char pri_table[DLOG_PRIO_MAX] = {
+               [DLOG_UNKNOWN] = '?',
+               [DLOG_DEFAULT] = '?',
+               [DLOG_VERBOSE] = 'V',
+               [DLOG_DEBUG] = 'D',
+               [DLOG_INFO] = 'I',
+               [DLOG_WARN] = 'W',
+               [DLOG_ERROR] = 'E',
+               [DLOG_FATAL] = 'F',
+               [DLOG_SILENT] = 'S',
+       };
+       return pri_table[(prio >= 0 && prio < DLOG_PRIO_MAX) ? prio : DLOG_UNKNOWN];
+}
+#define LOG_(id, prio, tag, fmt, arg...) \
+       ({ do { \
+               fprintf(LOG_FILE, "%c/%-8s(%5d): %s: %s(%d) > " fmt "\n", \
+                       __dlog_prio(prio), tag, getpid(), \
+                       __MODULE__, __func__, __LINE__, ##arg); \
+       } while (0); })
+#endif
+
+#define _D(fmt, arg...) SLOGD(fmt, ##arg)
+#define _I(fmt, arg...) SLOGI(fmt, ##arg)
+#define _W(fmt, arg...) SLOGW(fmt, ##arg)
+#define _E(fmt, arg...) SLOGE(fmt, ##arg)
+#define _SD(fmt, arg...) SECURE_SLOGD(fmt, ##arg)
+#define _SI(fmt, arg...) SECURE_SLOGI(fmt, ##arg)
+#define _SW(fmt, arg...) SECURE_SLOGW(fmt, ##arg)
+#define _SE(fmt, arg...) SECURE_SLOGE(fmt, ##arg)
+
+#endif
+/* __CRASH_LOG_H__ */
diff --git a/src/shared/spawn.c b/src/shared/spawn.c
new file mode 100644 (file)
index 0000000..392a053
--- /dev/null
@@ -0,0 +1,210 @@
+/* Utilities for spawning sub-processes
+ *
+ * Copyright (c) 2018-2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <poll.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <wait.h>
+
+#include "log.h"
+#include "util.h"
+#include "spawn.h"
+
+/* spawn prepare function(s) - to be called in child process */
+
+int spawn_setstdout(spawn_param_s *param)
+{
+       assert(param);
+       return dup2(param->u.int_val, STDOUT_FILENO) < 0 ? -1 : 0;
+}
+
+int spawn_setstderr(spawn_param_s *param)
+{
+       assert(param);
+       return dup2(param->u.int_val, STDERR_FILENO) < 0 ? -1 : 0;
+}
+
+int spawn_nullstdfds(spawn_param_s *param)
+{
+       int fd = open("/dev/null", O_RDWR);
+       if (fd < 0)
+               return -1;
+
+       int ret = dup2(fd, STDIN_FILENO) < 0 || dup2(fd, STDOUT_FILENO) < 0 || dup2(fd, STDERR_FILENO) < 0 ? -1 : 0;
+       if (fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO)
+               close(fd);
+       return ret;
+}
+
+int spawn_chdir(spawn_param_s *param)
+{
+       assert(param);
+       return chdir(param->u.char_ptr);
+}
+
+int spawn_umask(spawn_param_s *param)
+{
+       assert(param);
+       (void)umask(param->u.mode_t_val);
+       return 0;
+}
+
+/* spawn api */
+
+bool wait_for_pid(pid_t pid, int *exit_code)
+{
+       int status = 0;
+       int r = 0;
+       bool is_ok;
+
+       if (pid < 0)
+               return false;
+
+       do {
+               r = waitpid(pid, &status, 0);
+               is_ok = r >= 0;
+       } while (!is_ok && errno == EINTR);
+
+       if (!is_ok) {
+               _E("Error while waiting for child %d status: %m", (int)pid);
+               return false;
+       }
+
+       /* child has terminated */
+       if (WIFEXITED(status))
+               r = WEXITSTATUS(status);
+       else if (WIFSIGNALED(status))
+               r = WTERMSIG(status);
+       else if (WIFSTOPPED(status))
+               r = WSTOPSIG(status);
+
+       _D("Child with pid %d terminated with exit code %d", (int)pid, r);
+       if (exit_code)
+               *exit_code = r;
+
+       return true;
+}
+
+static int spawn_child(char *const av[], char *const ev[], spawn_param_s *param)
+{
+       static const int spawn_error = 127;
+
+       while (param) {
+               assert(param->fn);
+
+               int r = param->fn(param);
+               if (r < 0)
+                       return spawn_error;
+
+               param = param->next;
+       };
+
+       execve(av[0], av, ev);
+       return spawn_error;
+}
+
+bool spawn(char *const av[], char *const ev[], spawn_param_s *param, pid_t *childpid, int *childfd)
+{
+       int pipefd[2];
+       if (pipe(pipefd) < 0) {
+               _E("pipe: %m");
+               return false;
+       }
+
+       pid_t pid = fork();
+       if (pid < 0) {
+               _E("fork: %m");
+               close(pipefd[0]);
+               close(pipefd[1]);
+               return false;
+       } else if (pid == 0) {
+               close(pipefd[0]);
+               _exit(spawn_child(av, ev, param));
+       }
+       close(pipefd[1]);
+
+       char *cmd = concatenate(av);
+       char *env = concatenate(ev);
+       _D("Spawned child with pid %d to execute command <%s> with environment <%s>", (int)pid, cmd, env);
+       free(cmd);
+       free(env);
+
+       // parent
+       if (childpid)
+               *childpid = pid;
+
+       if (childfd) {
+               _D("Leaving childfd status descriptor %d open for child status notification", pipefd[0]);
+               *childfd = pipefd[0];
+       } else
+               close(pipefd[0]);
+
+       return true;
+}
+
+/* returns true if child terminated */
+static bool wait_and_kill(pid_t childpid, int childfd, int timeout_ms)
+{
+       struct pollfd pfd = { .fd = childfd, .events = POLLIN | POLLERR | POLLHUP };
+       int r;
+
+       _D("Beginning to wait %dms for child pid %d", timeout_ms, (int)childpid);
+       do {
+               r = poll(&pfd, 1, timeout_ms);
+       } while (r < 0 && errno == EINTR);
+
+       if (r < 0) {
+               _E("Internal error while trying to wait for child pid %d: %m", (int)childpid);
+               return false;
+       } else if (r == 0) {
+               _W("Timeout %dms for child pid %d expired. Killing.", timeout_ms, (int)childpid);
+               kill(childpid, SIGKILL);
+       } else
+               _D("Child pid %d terminated before timeout.", (int)childpid);
+
+       return true;
+}
+
+bool spawn_wait(char *const av[], char *const ev[], spawn_param_s *param, int timeout_ms, int *exit_code)
+{
+       pid_t childpid;
+       int childfd;
+
+       if (!spawn(av, ev, param, &childpid, &childfd)) {
+               _E("spawn() returned an error - aborting waiting");
+               return false;
+       }
+
+       if (timeout_ms > 0)
+               (void)wait_and_kill(childpid, childfd, timeout_ms);
+
+       bool wait_ok = wait_for_pid(childpid, exit_code);
+
+       close(childfd);
+
+       return wait_ok;
+}
diff --git a/src/shared/spawn.h b/src/shared/spawn.h
new file mode 100644 (file)
index 0000000..431b173
--- /dev/null
@@ -0,0 +1,58 @@
+/* Utilities for spawning sub-processes
+ *
+ * Copyright (c) 2018-2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef __SPAWN_H__
+#define __SPAWN_H__
+
+#include <stdbool.h>
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define DEFAULT_COMMAND_TIMEOUT_MS (60*1000) /* 60sec */
+
+struct spawn_param;
+
+typedef int (*spawn_prepare_fn)(struct spawn_param *param);
+
+typedef struct spawn_param {
+       spawn_prepare_fn fn;
+
+       struct spawn_param *next;
+       union {
+               int int_val;
+               mode_t mode_t_val;
+               char *char_ptr;
+       } u;
+} spawn_param_s;
+
+int spawn_setstdout(spawn_param_s *param);
+int spawn_setstderr(spawn_param_s *param);
+int spawn_nullstdfds(spawn_param_s *param);
+int spawn_chdir(spawn_param_s *param);
+int spawn_umask(spawn_param_s *param);
+
+bool wait_for_pid(pid_t pid, int *exit_code);
+bool spawn(char *const av[], char *const ev[], spawn_param_s *param, pid_t *childpid, int *childfd);
+bool spawn_wait(char *const av[], char *const ev[], spawn_param_s *param, int timeout_ms, int *exit_code);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/shared/util.c b/src/shared/util.c
new file mode 100644 (file)
index 0000000..b149009
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * crash-manager
+ * Copyright (c) 2012-2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "util.h"
+#include "log.h"
+
+int fsync_path(char *const path)
+{
+       int fd, ret;
+
+       ret = fd = open(path, O_RDONLY);
+       if (fd >= 0) {
+               ret = fsync(fd);
+               close(fd);
+       }
+
+       if (ret < 0)
+               _E("Unable to fsync %s: %m", path);
+
+       return ret;
+}
+
+int make_dir(const char *path, const char *name, int mode)
+{
+       int r = -1;
+
+       DIR *dir = opendir(path);
+       if (dir) {
+               int dfd = dirfd(dir);
+               r = mkdirat(dfd, name, mode);
+               closedir(dir);
+       }
+
+       return r == 0 || (r == -1 && errno == EEXIST) ? 0 : -1;
+}
+
+static int remove_dir_internal(int fd)
+{
+       DIR *dir;
+       struct dirent *de;
+       int subfd, ret = 0;
+
+       dir = fdopendir(fd);
+       if (!dir)
+               return -1;
+
+       while ((de = readdir(dir))) {
+               if (de->d_type == DT_DIR) {
+                       if (!strncmp(de->d_name, ".", 2) || !strncmp(de->d_name, "..", 3))
+                               continue;
+                       subfd = openat(fd, de->d_name, O_RDONLY | O_DIRECTORY);
+                       if (subfd < 0) {
+                               _SE("Couldn't openat %s: %d\n", de->d_name, errno);
+                               ret = -1;
+                               continue;
+                       }
+                       if (remove_dir_internal(subfd))
+                               ret = -1;
+                       close(subfd);
+                       if (unlinkat(fd, de->d_name, AT_REMOVEDIR) < 0) {
+                               _SE("Couldn't unlinkat %s: %d\n", de->d_name, errno);
+                               ret = -1;
+                       }
+               } else {
+                       if (unlinkat(fd, de->d_name, 0) < 0) {
+                               _SE("Couldn't unlinkat %s: %d\n", de->d_name, errno);
+                               ret = -1;
+                       }
+               }
+       }
+       closedir(dir);
+       return ret;
+}
+
+int remove_dir(const char *path, int del_dir)
+{
+       int fd, ret = 0;
+
+       if (!path)
+               return -1;
+       fd = open(path, O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC | O_NOFOLLOW);
+       if (fd < 0) {
+               _SE("Couldn't opendir %s: %d\n", path, errno);
+               return -errno;
+       }
+       ret = remove_dir_internal(fd);
+       close(fd);
+
+       if (del_dir) {
+               if (rmdir(path)) {
+                       _SE("Couldn't rmdir %s: %d\n", path, errno);
+                       ret = -1;
+               }
+       }
+       return ret;
+}
+
+/* This function is supposed to accept same data as passed to execve
+ * (argv and envp), which can be arrays of strings as well as NULL
+ * pointer.
+ */
+char* concatenate(char *const vec[])
+{
+       size_t length = 0;
+       for (char *const *p = vec; p && *p; p++)
+               length += strlen(*p) + 1;
+
+       if (length == 0)
+               return strdup("");
+
+       char *str = (char *)malloc(length);
+       if (!str)
+               return NULL;
+
+       char *destp = str;
+       char *const *vecp = vec;
+       while (*vecp) {
+               destp = stpcpy(destp, *(vecp++));
+               if (*vecp)
+                       destp = stpcpy(destp, " ");
+       }
+
+       return str;
+}
+
+/**
+ * @}
+ */
diff --git a/src/shared/util.h b/src/shared/util.h
new file mode 100644 (file)
index 0000000..3b2d643
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * crash-manager
+ * Copyright (c) 2012-2013 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 __DEF_UTIL_H__
+#define __DEF_UTIL_H__
+
+#define ARRAY_SIZE(name) (sizeof(name)/sizeof(name[0]))
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int fsync_path(char *const path);
+
+int make_dir(const char *path, const char *name, int mode);
+
+int remove_dir(const char *path, int del_dir);
+
+char* concatenate(char *const vec[]);
+
+#ifdef __cplusplus
+}
+#endif
+
+/**
+ * @}
+ */
+#endif
diff --git a/tests/system/CMakeLists.txt b/tests/system/CMakeLists.txt
new file mode 100644 (file)
index 0000000..c73b933
--- /dev/null
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.6)
+
+macro(CONFIGURE_TEST_FILE dir_name file_name)
+  configure_file("${dir_name}/${file_name}.sh.template" "${dir_name}/${file_name}.sh" @ONLY)
+  INSTALL(DIRECTORY ${dir_name}/ DESTINATION ${CRASH_SYSTEM_TESTS_PATH}/${dir_name} FILES_MATCHING PATTERN "*sh")
+endmacro()
+
+macro(CONFIGURE_TEST test_name)
+  set(FILES_LIST ${test_name})
+  list(APPEND FILES_LIST ${ARGN})
+
+  foreach(test ${FILES_LIST})
+    configure_test_file(${test_name} ${test})
+  endforeach()
+endmacro()
+
+configure_test("log_dump_short")
+configure_test("log_dump_normal")
+configure_test("log_dump_crash_root_path")
diff --git a/tests/system/log_dump_crash_root_path/log_dump_crash_root_path.sh.template b/tests/system/log_dump_crash_root_path/log_dump_crash_root_path.sh.template
new file mode 100644 (file)
index 0000000..8c3604b
--- /dev/null
@@ -0,0 +1,32 @@
+#!/bin/bash
+
+# Custom report path test
+
+if [ -z "${CRASH_WORKER_SYSTEM_TESTS}" ]; then
+    CRASH_WORKER_SYSTEM_TESTS="@CRASH_SYSTEM_TESTS_PATH@"
+fi
+
+. ${CRASH_WORKER_SYSTEM_TESTS}/utils/minicore-utils.sh
+
+tmpdir=$(mktemp -d /tmp/logdump-crash-root-path-test.XXXXXX)
+
+LOG_DUMP_CONF=/etc/log_dump.conf
+mount -o rw,remount /
+backup_file ${LOG_DUMP_CONF}
+sed -ie 's,^CrashRootPath=.*,,g' ${LOG_DUMP_CONF}
+echo "CrashRootPath=$tmpdir" >> ${LOG_DUMP_CONF}
+
+log_dump --short
+
+restore_file ${LOG_DUMP_CONF}
+
+logfile="${tmpdir}"/debug/* # there shall be only one file
+
+check_file_exists "$logfile"
+
+num=`unzip -qql "$logfile" | wc -l`
+if [ $num -ne 2 ]; then
+        fail "'log_dump --short' report contains $num files - 2 expected"
+fi
+
+exit_ok
diff --git a/tests/system/log_dump_normal/log_dump_normal.sh.template b/tests/system/log_dump_normal/log_dump_normal.sh.template
new file mode 100644 (file)
index 0000000..ef70cae
--- /dev/null
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+# Custom report path test
+
+if [ -z "${CRASH_WORKER_SYSTEM_TESTS}" ]; then
+    CRASH_WORKER_SYSTEM_TESTS="@CRASH_SYSTEM_TESTS_PATH@"
+fi
+
+. ${CRASH_WORKER_SYSTEM_TESTS}/utils/minicore-utils.sh
+
+clean_logdump
+dummy=$(mktemp $CRASH_DUMP_PATH/logdump-normal-test.XXXXXX)
+
+log_dump --normal
+logfile="${LOGDUMP_RESULT_PATH}"/* # there shall be only one file
+
+check_file_exists "$logfile"
+check_zip_contains "$logfile" 'log/dump_systemstate.*log$'
+check_zip_contains "$logfile" 'log/system_log/$'
+check_zip_contains "$logfile" 'log/system_log/dlog/kernel$'
+check_zip_contains "$logfile" 'log/module_log/$'
+check_zip_contains "$logfile" 'dump/$'
+
+check_file_not_exists "$dummy"
+
+clean_logdump
+
+exit_ok
diff --git a/tests/system/log_dump_service/log_dump_service.sh.template b/tests/system/log_dump_service/log_dump_service.sh.template
new file mode 100644 (file)
index 0000000..13252f0
--- /dev/null
@@ -0,0 +1,33 @@
+#!/bin/bash
+
+# log_dump service test
+
+if [ -z "${CRASH_WORKER_SYSTEM_TESTS}" ]; then
+    CRASH_WORKER_SYSTEM_TESTS="@CRASH_SYSTEM_TESTS_PATH@"
+fi
+
+. ${CRASH_WORKER_SYSTEM_TESTS}/utils/minicore-utils.sh
+
+clean_logdump
+
+dummy=$(mktemp $CRASH_DUMP_PATH/logdump-short-test.XXXXXX)
+
+log_dump --short
+logfile="${LOGDUMP_RESULT_PATH}"/* # there shall be only one file
+
+check_file_exists "$logfile"
+
+num=`unzip -qql "$logfile" | wc -l`
+if [ $num -ne 2 ]; then
+        fail "'log_dump --short' report contains $num files - 2 expected"
+fi
+
+check_zip_contains "$logfile" 'log/dump_systemstate.*log$'
+check_zip_contains "$logfile" 'log/$'
+
+check_file_exists "$dummy"
+
+clean_logdump
+
+exit_ok
+
diff --git a/tests/system/log_dump_short/log_dump_short.sh.template b/tests/system/log_dump_short/log_dump_short.sh.template
new file mode 100644 (file)
index 0000000..38d7885
--- /dev/null
@@ -0,0 +1,32 @@
+#!/bin/bash
+
+# Custom report path test
+
+if [ -z "${CRASH_WORKER_SYSTEM_TESTS}" ]; then
+    CRASH_WORKER_SYSTEM_TESTS="@CRASH_SYSTEM_TESTS_PATH@"
+fi
+
+. ${CRASH_WORKER_SYSTEM_TESTS}/utils/minicore-utils.sh
+
+clean_logdump
+
+dummy=$(mktemp $CRASH_DUMP_PATH/logdump-short-test.XXXXXX)
+
+log_dump --short
+logfile="${LOGDUMP_RESULT_PATH}"/* # there shall be only one file
+
+check_file_exists "$logfile"
+
+num=`unzip -qql "$logfile" | wc -l`
+if [ $num -ne 2 ]; then
+        fail "'log_dump --short' report contains $num files - 2 expected"
+fi
+
+check_zip_contains "$logfile" 'log/dump_systemstate.*log$'
+check_zip_contains "$logfile" 'log/$'
+
+check_file_exists "$dummy"
+
+clean_logdump
+
+exit_ok