Rewrite and re-enable log_dump 12/189812/23
authorKarol Lewandowski <k.lewandowsk@samsung.com>
Fri, 21 Sep 2018 07:48:21 +0000 (09:48 +0200)
committerKarol Lewandowski <k.lewandowsk@samsung.com>
Thu, 28 Feb 2019 11:12:30 +0000 (12:12 +0100)
This is major change which brings following changes:

 - port log_dump to spawn() API

 - fix: allow creating multiple log_dump reports at once
   (by using separate/unique temporary directory)

   NOTE: There is no guarantee that dump scripts are able to handle parallell
         invocation!

 - fix: always broadcast the signal about finished dump - even in case of
   error (client should not wait indifinitely for status)

 - move logic of moving crash-dump reports to separate script

Change-Id: I78585b9c3c6bfb9e12950985b389c0edf0eac7f0

dump_scripts/module_log.sh
dump_scripts/move_dump.sh [new file with mode: 0755]
dump_scripts/system_log.sh
packaging/crash-worker.spec
src/log_dump/CMakeLists.txt
src/log_dump/log_dump.c
src/log_dump/log_dump.h [new file with mode: 0644]
src/log_dump/log_dump.h.in [deleted file]

index 8e1a18791d9991df0725ca33721e425b366601d5..4c73e339f98730e8abcd9b292c6df60f2faf1789 100755 (executable)
@@ -4,7 +4,7 @@
 #
 PATH=/bin:/usr/bin:/sbin:/usr/sbin
 
-DUMP_DEST=$1/module_log
+DUMP_DEST=$1/log/module_log
 DUMP_SCRIPT_DIR=/opt/etc/dump.d/module.d
 
 mkdir -p ${DUMP_DEST}
diff --git a/dump_scripts/move_dump.sh b/dump_scripts/move_dump.sh
new file mode 100755 (executable)
index 0000000..50f7198
--- /dev/null
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+PATH=/bin:/usr/sbin
+
+. /etc/tizen-platform.conf
+
+set -ex
+
+DEST="$1/dump"
+mkdir -p "$DEST"
+mv -f "${TZ_SYS_CRASH}"/* "$DEST"/
+
index 6d57f642d2c687e386bc7a663a21325b29a1c554..36beeb10b881bda476c46cb95372304ff04c99d9 100755 (executable)
@@ -4,7 +4,7 @@
 #
 PATH=/bin:/usr/bin:/sbin:/usr/sbin
 
-DUMP_DEST=$1/system_log
+DUMP_DEST=$1/log/system_log
 
 mkdir -p ${DUMP_DEST}
 
index e3bec87feb7d22ff4a20d656865d0104a928796f..abab0e420f75692d3942e911f56cec122e1ba4a2 100644 (file)
@@ -2,6 +2,7 @@
 %define on_off() %{expand:%%{?with_%{1}:ON}%%{!?with_%{1}:OFF}}
 
 %define _with_tests on
+%define _with_logdump on
 %bcond_with doc
 %bcond_with sys_assert
 %bcond_with tests
index e43654d29b9718405b71c0ca871c3dfde6c6a38b..c3b684328af5e03ae8dc6fd271c66a093b336dbb 100644 (file)
@@ -6,6 +6,7 @@ SET(LOG_DUMP_SRCS
        log_dump.c
        dbus-handler.c
        ${CMAKE_SOURCE_DIR}/src/shared/util.c
+       ${CMAKE_SOURCE_DIR}/src/shared/spawn.c
    )
 
 INCLUDE(FindPkgConfig)
@@ -24,7 +25,6 @@ ENDFOREACH(flag)
 
 SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -fPIE")
 
-CONFIGURE_FILE(log_dump.h.in log_dump.h @ONLY)
 ADD_EXECUTABLE(${PROJECT_NAME} ${LOG_DUMP_SRCS})
 TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${log_dump_pkgs_LDFLAGS} -pie)
 
index 5ea5095e486610c8b713751d2efa969b9c988132..566c257c6cf17ab26c54ae99159280fd5fe0ff38 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * log_dump: dump current system states
  *
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * 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.
  * limitations under the License.
  */
 
-#include <stdio.h>
-#include <stdlib.h>
+#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 <dirent.h>
-#include <libgen.h>
+
 #include <system_info.h>
-#include "shared/util.h"
+#include <tzplatform_config.h>
+
 #include "log_dump.h"
 #include "dbus-handler.h"
+#include "shared/spawn.h"
+#include "shared/util.h"
 
-#undef LOG_TAG
-#define LOG_TAG          "LOG_DUMP"
 #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 },
@@ -40,245 +46,251 @@ static const struct option opts[] = {
        { 0, 0, 0, 0 }
 };
 
-static inline void usage(void)
+/* 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)
 {
-       printf("Usage: log_dump [OPTION]\n");
-       printf("Dump options:\n");
-       printf("  %-10s %s (%s)\n", "--normal",
-                       "dump all logs", DUMP_SCRIPTS_DIR);
-       printf("  %-10s %s\n", "--short",
-                       "dump systemstate only");
-       printf("  %-10s %s\n", "--dbus",
-                       "activate dbus interface");
+       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 strdup(tzplatform_getenv(TZ_SYS_CRASH_ROOT));
 }
 
-static int dump_scripts(void)
+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;
+
+       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(DUMP_SCRIPTS_DIR, &dir_list, NULL, NULL);
+       script_num = scandir(scriptsdir, &dir_list, NULL, NULL);
        if (script_num < 0) {
-               _E("Failed to scandir %s", DUMP_SCRIPTS_DIR);
-               return -1;
+               _E("scandir %s: %m", scriptsdir);
+               return false;
        }
 
        for (i = 0; i < script_num; i++) {
-               if (dir_list[i]->d_type != DT_REG)
+               const char *const name = dir_list[i]->d_name;
+               int type = dir_list[i]->d_type;
+
+               if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
                        continue;
 
-               snprintf(command, sizeof(command), "%s/%s %s",
-                               DUMP_SCRIPTS_DIR, dir_list[i]->d_name,
-                               LOG_DUMP_DIR);
-               _D("%s", command);
-               system_command(command);
+               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, NULL, 0, NULL);
        }
 
        for (i = 0; i < script_num; i++)
                free(dir_list[i]);
        free(dir_list);
 
-       return 0;
+       return true;
 }
 
-int log_dump(int option)
+static bool dump_systemstate(const char *const destdir, const char *const timestr, int *exit_code)
 {
-       int ret;
-       char *version_str = NULL;
-       char *dump_dirname = NULL;
-       char *crash_dirname = NULL;
-       char timestr[80];
-       char command[PATH_MAX];
-       char dump_filename[NAME_MAX];
-       time_t cur_time;
-       struct tm loc_tm;
-
-       broadcast_logdump_start();
+       char *dump_path = NULL;
 
-       /* Make debug directory */
-       if (access(LOG_DUMP_DIR, F_OK) != 0) {
-               ret = snprintf(command, sizeof(command),
-                               "/usr/bin/mkdir -p %s", LOG_DUMP_DIR);
-               if (ret < 0) {
-                       _E("Failed to mkdir");
-                       return -1;
-               }
-               system_command(command);
+       if (asprintf(&dump_path, "%s/log/dump_systemstate_%s.log", destdir, timestr) < 0) {
+               _E("asprintf: %m");
+               return false;
        }
 
-       /* Make result directory */
-       if (access(LOG_DUMP_RESULT, F_OK) != 0) {
-               ret = snprintf(command, sizeof(command),
-                               "/usr/bin/mkdir -p %s", LOG_DUMP_RESULT);
-               if (ret < 0) {
-                       _E("Failed to mkdir");
-                       return -1;
-               }
-               system_command(command);
-       }
+       char *av[] = {"/usr/bin/dump_systemstate", "-k", "-d", "-j", "-f", dump_path, NULL};
+       bool is_ok = spawn_wait(av, NULL, NULL, NULL, 0, exit_code);
 
-       /* Get timestamp */
-       cur_time = time(NULL);
-       localtime_r(&cur_time, &loc_tm);
-       strftime(timestr, sizeof(timestr), "%Y%m%d%H%M%S", &loc_tm);
-
-       /* Get version */
-       ret = system_info_get_platform_string(SYSTEM_INFO_KEY_BUILD_STRING,
-                       &version_str);
-       if (ret != SYSTEM_INFO_ERROR_NONE) {
-               _E("Failed to system_info_get_platform_string");
-               version_str = NULL;
-       }
+       free(dump_path);
 
-       /* Dump system states */
-       ret = snprintf(command, sizeof(command),
-                       "/usr/bin/dump_systemstate -k -d -j -f "
-                       "%s/dump_systemstate_%s.log", LOG_DUMP_DIR, timestr);
-       if (ret < 0) {
-               _E("Failed to snprintf for command");
-               goto exit;
-       }
-       system_command(command);
+       return is_ok;
+}
 
-       /* Dump all logs */
-       if (option == OPT_NORMAL)
-               dump_scripts();
-
-       if (version_str) {
-               ret = snprintf(dump_filename, sizeof(dump_filename), "%s_%s",
-                               "log_dump", version_str);
-               if (ret < 0) {
-                       _E("Failed to snprintf for dump path");
-                       goto exit;
-               }
-       } else {
-               ret = snprintf(dump_filename, sizeof(dump_filename), "%s",
-                               "log_dump");
-               if (ret < 0) {
-                       _E("Failed to snprintf for dump path");
-                       return -1;
-               }
-       }
+static bool compress(char *const destdir, char *const tempdir, char *const versionstr, char *const timestr, int *exit_code)
+{
+       char *archive_path = NULL;
 
-       /* Compression */
-       dump_dirname = strdup(LOG_DUMP_DIR);
-       if (!dump_dirname) {
-               _E("Failed to strdup for dump_dirname");
-               goto exit;
+       if (asprintf(&archive_path, "%s/log_dump_%s%s.zip", destdir, versionstr ?: "", timestr) < 0) {
+               _E("asprintf: %m");
+               return false;
        }
 
-       if (option == OPT_NORMAL) {
-               crash_dirname = strdup(CRASH_DUMP_DIR);
-               if (!crash_dirname) {
-                       _E("Failed to strdup for dump_dirname");
-                       goto exit;
-               }
+       _D("compress tempdir is %s", tempdir);
+       char *av[] = {"/bin/zip", "-yr", archive_path, ".", NULL};
+       bool is_ok = spawn_wait(av, NULL, spawn_chdir, (void*)tempdir, 0, exit_code);
 
-               ret = snprintf(command, sizeof(command),
-                               "cd %s && /bin/zip -r %s/%s%s.zip %s %s > /dev/null 2>&1",
-                               LOG_DUMP_ROOT,
-                               LOG_DUMP_RESULT, dump_filename, timestr,
-                               basename(dump_dirname), basename(crash_dirname));
-               if (ret < 0) {
-                       _E("Failed to snprintf for command");
-                       goto exit;
-               }
-       } else {
-               ret = snprintf(command, sizeof(command),
-                               "cd %s && /bin/zip -r %s/%s%s.zip %s > /dev/null 2>&1",
-                               LOG_DUMP_ROOT,
-                               LOG_DUMP_RESULT, dump_filename, timestr,
-                               basename(dump_dirname));
-               if (ret < 0) {
-                       _E("Failed to snprintf for command");
-                       goto exit;
-               }
-       }
-       system_command(command);
+       _I("Storing report at %s", archive_path);
 
-       sync();
+       fsync_path(archive_path);
+       free(archive_path);
 
-       /* Remove gatherd dump */
-       ret = remove_dir(LOG_DUMP_DIR, 0);
-       if (ret < 0) {
-               _E("Failed to delete dump directory");
-               goto exit;
-       }
-       if (option == OPT_NORMAL) {
-               ret = remove_dir(CRASH_DUMP_DIR, 0);
-               if (ret < 0) {
-                       _E("Failed to delete crash dump directory");
-                       goto exit;
-               }
-       }
+       return is_ok;
+}
 
-       broadcast_logdump_finish();
+int log_dump(int option)
+{
+       broadcast_logdump_start();
 
-       /* Further operations for log_dump here */
+       int ret = -1;
 
-exit:
-       if (version_str)
-               free(version_str);
-       if (dump_dirname)
-               free(dump_dirname);
-       if (crash_dirname)
-               free(crash_dirname);
+       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)
 {
-       _I("delete_dump!");
+       _D("delete_dump called");
 
-       remove_dir(LOG_DUMP_DIR, 0);
-       remove_dir(LOG_DUMP_RESULT, 1);
-       remove_dir(CRASH_DUMP_DIR, 0);
-       remove_dir(CRASH_TEMP_DIR, 0);
+       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 (argc < 2) {
-               usage();
-               exit(EXIT_SUCCESS);
+       /* 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) {
-               switch (c) {
-               case OPT_NORMAL:
-                       if (option >= 0) {
-                               usage();
-                               exit(EXIT_SUCCESS);
-                       }
-                       option = OPT_NORMAL;
-                       break;
-               case OPT_SHORT:
-                       if (option >= 0) {
-                               usage();
-                               exit(EXIT_SUCCESS);
-                       }
-                       option = OPT_SHORT;
-                       break;
-               case OPT_DBUS:
-                       if (option >= 0) {
-                               usage();
-                               exit(EXIT_SUCCESS);
-                       }
-                       option = OPT_DBUS;
-                       break;
-               default:
-                       usage();
-                       exit(EXIT_SUCCESS);
-                       break;
-               }
+               if (option >= 0 || c < _OPT_MIN || c > _OPT_MAX)
+                       die();
+               option = c;
        }
 
        if (option == OPT_DBUS)
@@ -286,8 +298,5 @@ int main(int argc, char *argv[])
        else
                ret = log_dump(option);
 
-       if (ret < 0)
-               exit(EXIT_FAILURE);
-
-       return 0;
+       return ret < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
 }
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.h.in b/src/log_dump/log_dump.h.in
deleted file mode 100644 (file)
index 9c5cfaa..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * 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_H__
-#define __LOGDUMP_H__
-
-#include <tzplatform_config.h>
-#include "shared/log.h"
-#undef LOG_TAG
-#define LOG_TAG "LOG_DUMP"
-
-#define LOG_DUMP_ROOT    tzplatform_getenv(TZ_SYS_CRASH_ROOT)
-#define LOG_DUMP_DIR     tzplatform_getenv(TZ_SYS_ALLLOGS)
-#define LOG_DUMP_RESULT  tzplatform_mkpath(TZ_SYS_CRASH_ROOT, "debug")
-#define CRASH_DUMP_DIR   "@CRASH_PATH@"
-#define CRASH_TEMP_DIR   "@CRASH_TEMP@"
-#define DUMP_SCRIPTS_DIR tzplatform_getenv(TZ_SYS_DUMPGEN)
-
-enum {
-       OPT_NORMAL,
-       OPT_SHORT,
-       OPT_DBUS,
-};
-
-int log_dump(int option);
-int delete_dump(void);
-
-#endif