[][openwrt][mt7988][tops][refactor tops-tool and add logger suuport]
[Description]
Refactor tops-tool and add logger support
add menu config for tops-tool
move common code into common part
save log cmd will open log relayfs and save
its data(log) as file in the filesystem
log relayfs path :
/sys/kernel/debug/tops/log-mgmt0
/sys/kernel/debug/tops/log-offload0
log file path :
<LOG_DIR>/log-mgmt-<time>
<LOG_DIR>/log-offload-<time>
[Release-log]
N/A
Change-Id: I1c563efbb584540eeb1b78c2a438c0173c4cdbba
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/7988095
diff --git a/feed/app/tops-tool/Config.in b/feed/app/tops-tool/Config.in
new file mode 100644
index 0000000..6733c1b
--- /dev/null
+++ b/feed/app/tops-tool/Config.in
@@ -0,0 +1,14 @@
+menu "TOPS Tool Configurations"
+ depends on PACKAGE_tops-tool
+
+config MTK_TOPS_TOOL_SAVE_LOG
+ bool "Save Log"
+ depends on MTK_TOPS_LOGGER
+ default y
+ help
+ Set y to enable tops-tool logging feature to save
+ TOPS firmware log to file system for further
+ debugging purpose.
+ Use command echo ON to start collecting log and
+ echo OFF to stop collecting log.
+endmenu
diff --git a/feed/app/tops-tool/Makefile b/feed/app/tops-tool/Makefile
index 67f5995..b7387d7 100644
--- a/feed/app/tops-tool/Makefile
+++ b/feed/app/tops-tool/Makefile
@@ -12,6 +12,16 @@
include $(INCLUDE_DIR)/package.mk
include $(INCLUDE_DIR)/package-defaults.mk
+
+TOPS_TOOL_CONFIGS += \
+ CONFIG_MTK_TOPS_TOOL_SAVE_LOG=$(CONFIG_MTK_TOPS_TOOL_SAVE_LOG)
+
+MAKE_VARS += $(TOPS_TOOL_CONFIGS)
+
+EXTRA_CFLAGS += \
+ -I$(PKG_BUILD_DIR)/inc \
+ $(patsubst CONFIG_%=y, -DCONFIG_%=1, $(filter %=y,$(TOPS_TOOL_CONFIGS)))
+
define Package/tops-tool
TITLE:=Mediatek Tunnel Offload Processor System User Tool
SECTION:=MTK Properties
@@ -28,14 +38,8 @@
it to start. The tool will support logging functionality in the future.
endef
-TARGET_CFLAGS += \
- -I$(PKG_BUILD_DIR)/inc
-
-define Build/Compile
- $(MAKE) -C $(PKG_BUILD_DIR) \
- CC="$(TARGET_CC)" \
- CFLAGS="$(TARGET_CFLAGS) -Wall -Wextra" \
- LDFLAGS="$(TARGET_LDFLAGS)"
+define Package/tops-tool/config
+ source "$(SOURCE)/Config.in"
endef
define Package/tops-tool/install
@@ -57,9 +61,18 @@
boot up.
endef
+TOPS_TOOL_INIT_FILES := \
+ ./files/tops-tool.init \
+ ./files/tops-tool-dump.init
+ifeq ($(CONFIG_MTK_TOPS_TOOL_SAVE_LOG), y)
+TOPS_TOOL_INIT_FILES += \
+ ./files/tops-tool-log.init
+endif
+
define Package/tops-tool-autoload/install
$(INSTALL_DIR) $(1)/etc/init.d
- $(INSTALL_BIN) ./files/tops-tool.init $(1)/etc/init.d/tops-tool
+ $(foreach file, $(TOPS_TOOL_INIT_FILES), \
+ $(INSTALL_BIN) $(file) $(1)/etc/init.d/$(notdir $(basename $(file)));)
endef
$(eval $(call BuildPackage,tops-tool))
diff --git a/feed/app/tops-tool/files/tops-tool-dump.init b/feed/app/tops-tool/files/tops-tool-dump.init
new file mode 100644
index 0000000..a0c6320
--- /dev/null
+++ b/feed/app/tops-tool/files/tops-tool-dump.init
@@ -0,0 +1,9 @@
+#!/bin/sh /etc/rc.common
+
+USE_PROCD=1
+PROG=/usr/sbin/tops-tool
+
+procd_open_instance
+procd_set_param command "${PROG}" save_dump /log/tops
+procd_set_param respawn
+procd_close_instance
diff --git a/feed/app/tops-tool/files/tops-tool-log.init b/feed/app/tops-tool/files/tops-tool-log.init
new file mode 100644
index 0000000..cdd0e84
--- /dev/null
+++ b/feed/app/tops-tool/files/tops-tool-log.init
@@ -0,0 +1,8 @@
+#!/bin/sh /etc/rc.common
+
+USE_PROCD=1
+PROG=/usr/sbin/tops-tool
+
+procd_open_instance
+procd_set_param command "${PROG}" save_log /log/tops
+procd_close_instance
diff --git a/feed/app/tops-tool/files/tops-tool.init b/feed/app/tops-tool/files/tops-tool.init
index 57ec788..f4da790 100644
--- a/feed/app/tops-tool/files/tops-tool.init
+++ b/feed/app/tops-tool/files/tops-tool.init
@@ -8,10 +8,11 @@
PROG=/usr/sbin/tops-tool
start_service() {
- procd_open_instance
- procd_set_param command "${PROG}" save_dump /log/tops
- procd_set_param respawn
- procd_close_instance
+ for script in /etc/init.d/tops-tool*; do
+ if [[ -f "$script" && -x "$script" ]]; then
+ source "$script"
+ fi
+ done
}
stop_service() {
diff --git a/feed/app/tops-tool/src/Makefile b/feed/app/tops-tool/src/Makefile
index b125bdb..3d03c51 100644
--- a/feed/app/tops-tool/src/Makefile
+++ b/feed/app/tops-tool/src/Makefile
@@ -5,15 +5,18 @@
# Author: Alvin Kuo <Alvin.Kuo@mediatek.com>
#
-PROJECT := tops-tool
-OBJECTS := tops-tool.o dump.o
+PROJECT:= tops-tool
+
+OBJECTS-$(CONFIG_MTK_TOPS_TOOL_SAVE_LOG)+= logger.o
+
+OBJECTS:= tops-tool.o common.o dump.o $(OBJECTS-y)
all: $(PROJECT)
$(PROJECT): $(OBJECTS) Makefile
$(CC) $(CFLAGS) $(LDFLAGS) $(OBJECTS) -o $@
-%.o: %.c %.h Makefile
+%.o: %.c inc/%.h Makefile
$(CC) $(CFLAGS) -c $< -o $@
.PHONY : clean
diff --git a/feed/app/tops-tool/src/common.c b/feed/app/tops-tool/src/common.c
new file mode 100644
index 0000000..d88e59b
--- /dev/null
+++ b/feed/app/tops-tool/src/common.c
@@ -0,0 +1,106 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2022 MediaTek Incorporation. All Rights Reserved.
+ *
+ * Author: Alvin Kuo <Alvin.Kuo@mediatek.com>
+ */
+
+#include <limits.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <time.h>
+#include <poll.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "common.h"
+
+int time_to_str(time_t *time_sec, char *time_str, unsigned int time_str_size)
+{
+ struct tm *ptm;
+ int ret;
+
+ ptm = gmtime(time_sec);
+ if (!ptm)
+ return -1;
+
+ ret = strftime(time_str, time_str_size, "%Y%m%d%H%M%S", ptm);
+ if (!ret)
+ return -2;
+
+ return 0;
+}
+
+int mkdir_p(const char *path, mode_t mode)
+{
+ size_t path_len;
+ char *cpy_path;
+ char *cur_path;
+ char *tmp_path;
+ char *dir;
+ int ret;
+
+ path_len = strlen(path) + 1;
+ if (path_len == 0)
+ return -EINVAL;
+
+ cpy_path = malloc(path_len);
+ if (!cpy_path)
+ return -ENOMEM;
+ strncpy(cpy_path, path, path_len);
+
+ cur_path = calloc(1, path_len);
+ if (!cur_path) {
+ ret = -ENOMEM;
+ goto free_cpy_path;
+ }
+
+ tmp_path = malloc(path_len);
+ if (!tmp_path) {
+ ret = -ENOMEM;
+ goto free_cur_path;
+ }
+
+ for (dir = strtok(cpy_path, "/");
+ dir != NULL;
+ dir = strtok(NULL, "/")) {
+ /* keep current path */
+ strncpy(tmp_path, cur_path, path_len);
+
+ /* append directory in current path */
+ ret = snprintf(cur_path, path_len, "%s/%s", tmp_path, dir);
+ if (ret < 0) {
+ fprintf(stderr,
+ LOG_FMT("append dir(%s) in cur_path(%s) fail(%d)\n"),
+ dir, cur_path, ret);
+ goto free_tmp_path;
+ }
+
+ ret = mkdir(cur_path, mode);
+ if (ret && errno != EEXIST) {
+ fprintf(stderr,
+ LOG_FMT("mkdir(%s) fail(%s)\n"),
+ cur_path, strerror(errno));
+ goto free_tmp_path;
+ }
+ }
+
+ ret = 0;
+
+free_tmp_path:
+ free(tmp_path);
+
+free_cur_path:
+ free(cur_path);
+
+free_cpy_path:
+ free(cpy_path);
+
+ return ret;
+}
diff --git a/feed/app/tops-tool/src/dump.c b/feed/app/tops-tool/src/dump.c
index e037eff..4169f5a 100644
--- a/feed/app/tops-tool/src/dump.c
+++ b/feed/app/tops-tool/src/dump.c
@@ -19,24 +19,9 @@
#include <sys/types.h>
#include <sys/stat.h>
+#include "common.h"
#include "dump.h"
-static int time_to_str(time_t *time_sec, char *time_str, unsigned int time_str_size)
-{
- struct tm *ptm;
- int ret;
-
- ptm = gmtime(time_sec);
- if (!ptm)
- return -1;
-
- ret = strftime(time_str, time_str_size, "%Y%m%d%H%M%S", ptm);
- if (!ret)
- return -2;
-
- return 0;
-}
-
static int save_dump_data(char *dump_root_dir,
struct dump_data_header *dd_hdr,
char *dd)
@@ -54,7 +39,7 @@
dump_time_str, sizeof(dump_time_str));
if (ret < 0) {
fprintf(stderr,
- DUMP_LOG_FMT("time_to_str(%lu) fail(%d)\n"),
+ LOG_FMT("time_to_str(%lu) fail(%d)\n"),
dd_hdr->info.dump_time_sec, ret);
return ret;
}
@@ -72,7 +57,7 @@
ret = mkdir(dump_dir, 0775);
if (ret && errno != EEXIST) {
fprintf(stderr,
- DUMP_LOG_FMT("mkdir(%s) fail(%s)\n"),
+ LOG_FMT("mkdir(%s) fail(%s)\n"),
dump_dir, strerror(errno));
goto free_dump_dir;
}
@@ -94,7 +79,7 @@
fd = open(dump_file, O_WRONLY | O_CREAT, 0664);
if (fd < 0) {
fprintf(stderr,
- DUMP_LOG_FMT("open(%s) fail(%s)\n"),
+ LOG_FMT("open(%s) fail(%s)\n"),
dump_file, strerror(errno));
ret = fd;
goto free_dump_file;
@@ -104,7 +89,7 @@
ret = lseek(fd, 0, SEEK_SET);
if (ret < 0) {
fprintf(stderr,
- DUMP_LOG_FMT("lseek fail(%s)\n"),
+ LOG_FMT("lseek fail(%s)\n"),
strerror(errno));
goto close_dump_file;
}
@@ -115,7 +100,7 @@
ret = lseek(fd, dd_hdr->data_offset, SEEK_CUR);
if (ret < 0) {
fprintf(stderr,
- DUMP_LOG_FMT("lseek fail(%s)\n"),
+ LOG_FMT("lseek fail(%s)\n"),
strerror(errno));
goto close_dump_file;
}
@@ -126,14 +111,14 @@
ret = stat(dump_file, &st);
if (ret < 0) {
fprintf(stderr,
- DUMP_LOG_FMT("stat(%s) fail(%s)\n"),
+ LOG_FMT("stat(%s) fail(%s)\n"),
dump_file, strerror(errno));
goto close_dump_file;
}
if ((size_t)st.st_size != dump_file_size) {
fprintf(stderr,
- DUMP_LOG_FMT("file(%s) size %zu != %zu\n"),
+ LOG_FMT("file(%s) size %zu != %zu\n"),
dump_file, st.st_size, dump_file_size);
ret = -EINVAL;
goto close_dump_file;
@@ -179,77 +164,9 @@
return out_len;
}
-static int mkdir_p(char *path, mode_t mode)
+int tops_tool_save_dump_data(int argc, char *argv[])
{
- size_t path_len;
- char *cpy_path;
- char *cur_path;
- char *tmp_path;
- char *dir;
- int ret;
-
- path_len = strlen(path) + 1;
- if (path_len == 0)
- return -EINVAL;
-
- cpy_path = malloc(path_len);
- if (!cpy_path)
- return -ENOMEM;
- strncpy(cpy_path, path, path_len);
-
- cur_path = calloc(1, path_len);
- if (!cur_path) {
- ret = -ENOMEM;
- goto free_cpy_path;
- }
-
- tmp_path = malloc(path_len);
- if (!tmp_path) {
- ret = -ENOMEM;
- goto free_cur_path;
- }
-
- for (dir = strtok(cpy_path, "/");
- dir != NULL;
- dir = strtok(NULL, "/")) {
- /* keep current path */
- strncpy(tmp_path, cur_path, path_len);
-
- /* append directory in current path */
- ret = snprintf(cur_path, path_len, "%s/%s", tmp_path, dir);
- if (ret < 0) {
- fprintf(stderr,
- DUMP_LOG_FMT("append dir(%s) in cur_path(%s) fail(%d)\n"),
- dir, cur_path, ret);
- goto free_tmp_path;
- }
-
- ret = mkdir(cur_path, mode);
- if (ret && errno != EEXIST) {
- fprintf(stderr,
- DUMP_LOG_FMT("mkdir(%s) fail(%s)\n"),
- cur_path, strerror(errno));
- goto free_tmp_path;
- }
- }
-
- ret = 0;
-
-free_tmp_path:
- free(tmp_path);
-
-free_cur_path:
- free(cur_path);
-
-free_cpy_path:
- free(cpy_path);
-
- return ret;
-}
-
-int tops_save_dump_data(char *dump_root_dir)
-{
- struct stat st = { 0 };
+ char *dump_root_dir = argv[2];
int ret = 0;
int fd;
@@ -259,7 +176,7 @@
/* reserve 256 bytes for saving name of dump directory and dump file */
if (strlen(dump_root_dir) > (PATH_MAX - 256)) {
fprintf(stderr,
- DUMP_LOG_FMT("dump_root_dir(%s) length %zu > %u\n"),
+ LOG_FMT("dump_root_dir(%s) length %zu > %u\n"),
dump_root_dir, strlen(dump_root_dir), PATH_MAX - 256);
return -EINVAL;
}
@@ -267,7 +184,7 @@
ret = mkdir_p(dump_root_dir, 0775);
if (ret < 0) {
fprintf(stderr,
- DUMP_LOG_FMT("mkdir_p(%s) fail(%d)\n"),
+ LOG_FMT("mkdir_p(%s) fail(%d)\n"),
dump_root_dir, ret);
return ret;
}
@@ -275,7 +192,7 @@
fd = open(DUMP_DATA_PATH, O_RDONLY);
if (fd < 0) {
fprintf(stderr,
- DUMP_LOG_FMT("open(%s) fail(%s)\n"),
+ LOG_FMT("open(%s) fail(%s)\n"),
DUMP_DATA_PATH, strerror(errno));
return fd;
}
@@ -291,7 +208,7 @@
ret = poll(&pfd, 1, -1);
if (ret < 0) {
fprintf(stderr,
- DUMP_LOG_FMT("poll fail(%s)\n"),
+ LOG_FMT("poll fail(%s)\n"),
strerror(errno));
break;
}
@@ -299,7 +216,7 @@
ret = read_retry(fd, &dd_hdr, sizeof(struct dump_data_header));
if (ret < 0) {
fprintf(stderr,
- DUMP_LOG_FMT("read dd_hdr fail(%d)\n"), ret);
+ LOG_FMT("read dd_hdr fail(%d)\n"), ret);
break;
}
@@ -308,13 +225,13 @@
if (dd_hdr.data_len == 0) {
fprintf(stderr,
- DUMP_LOG_FMT("read empty data\n"));
+ LOG_FMT("read empty data\n"));
continue;
}
if (dd_hdr.data_len > sizeof(dd)) {
fprintf(stderr,
- DUMP_LOG_FMT("data length %u > %lu\n"),
+ LOG_FMT("data length %u > %lu\n"),
dd_hdr.data_len, sizeof(dd));
ret = -ENOMEM;
break;
@@ -323,13 +240,13 @@
ret = read_retry(fd, dd, dd_hdr.data_len);
if (ret < 0) {
fprintf(stderr,
- DUMP_LOG_FMT("read dd fail(%d)\n"), ret);
+ LOG_FMT("read dd fail(%d)\n"), ret);
break;
}
if ((uint32_t)ret != dd_hdr.data_len) {
fprintf(stderr,
- DUMP_LOG_FMT("read dd length %u != %u\n"),
+ LOG_FMT("read dd length %u != %u\n"),
(uint32_t)ret, dd_hdr.data_len);
ret = -EAGAIN;
break;
@@ -338,7 +255,7 @@
ret = save_dump_data(dump_root_dir, &dd_hdr, dd);
if (ret) {
fprintf(stderr,
- DUMP_LOG_FMT("save_dump_data(%s) fail(%d)\n"),
+ LOG_FMT("save_dump_data(%s) fail(%d)\n"),
dump_root_dir, ret);
break;
}
diff --git a/feed/app/tops-tool/src/inc/common.h b/feed/app/tops-tool/src/inc/common.h
new file mode 100644
index 0000000..339b8e1
--- /dev/null
+++ b/feed/app/tops-tool/src/inc/common.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2021 MediaTek Incorporation. All Rights Reserved.
+ *
+ * Author: Alvin Kuo <Alvin.Kuo@mediatek.com>
+ */
+
+#ifndef __COMMON_H__
+#define __COMMON_H__
+
+#include <sys/types.h>
+#include <time.h>
+
+#define LOG_FMT(FMT) "[TOPS_TOOL] [%s]: " FMT, __func__
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
+int time_to_str(time_t *time_sec, char *time_str, unsigned int time_str_size);
+int mkdir_p(const char *path, mode_t mode);
+
+#endif /* __COMMON_H__ */
diff --git a/feed/app/tops-tool/src/inc/dump.h b/feed/app/tops-tool/src/inc/dump.h
index 69b4340..4aa09ac 100644
--- a/feed/app/tops-tool/src/inc/dump.h
+++ b/feed/app/tops-tool/src/inc/dump.h
@@ -14,8 +14,6 @@
#define RELAY_DUMP_SUBBUF_SIZE 2048
#define DUMP_DATA_PATH "/sys/kernel/debug/tops/trm/dump-data"
-#define DUMP_LOG_FMT(FMT) "[TOPS_TOOL] [%s]: " FMT, __func__
-
struct dump_info {
char name[DUMP_INFO_NAME_MAX_LEN];
uint64_t dump_time_sec;
@@ -38,6 +36,6 @@
uint8_t last_frag;
};
-int tops_save_dump_data(char *dump_dir);
+int tops_tool_save_dump_data(int argc, char *argv[]);
#endif /* __DUMP_H__ */
diff --git a/feed/app/tops-tool/src/inc/logger.h b/feed/app/tops-tool/src/inc/logger.h
new file mode 100644
index 0000000..27a802a
--- /dev/null
+++ b/feed/app/tops-tool/src/inc/logger.h
@@ -0,0 +1,41 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2023 MediaTek Incorporation. All Rights Reserved.
+ *
+ * Author: Alvin Kuo <Alvin.Kuo@mediatek.com>
+ */
+
+#ifndef __LOGGER_H__
+#define __LOGGER_H__
+
+#include <glob.h>
+
+#define LOG_MGMT_RELAYFS_PATH "/sys/kernel/debug/tops/log-mgmt*"
+#define LOG_MGMT_NAME "log-mgmt"
+
+#define LOG_OFFLOAD_RELAYFS_PATH "/sys/kernel/debug/tops/log-offload*"
+#define LOG_OFFLOAD_NAME "log-offload"
+
+#define LOGGER_DEBUGFS_PATH "/sys/kernel/debug/tops/logger"
+
+#define BUFFER_LEN (0x1000)
+
+enum log_num {
+ LOG_NUM_MGMT = 0,
+ LOG_NUM_OFFLOAD,
+
+ __LOG_NUM_MAX
+};
+#define LOG_NUM_MAX __LOG_NUM_MAX
+
+struct logger_runtime_info {
+ const char *relayfs_path;
+ glob_t relayfs_glob;
+ int relayfs_fd;
+ const char *log_name;
+ char *log_file_path;
+};
+
+int tops_tool_run_logger(int argc, char *argv[]);
+
+#endif /* __LOGGER_H__ */
diff --git a/feed/app/tops-tool/src/inc/tops-tool-cmds.h b/feed/app/tops-tool/src/inc/tops-tool-cmds.h
new file mode 100644
index 0000000..bbcd48e
--- /dev/null
+++ b/feed/app/tops-tool/src/inc/tops-tool-cmds.h
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2023 MediaTek Incorporation. All Rights Reserved.
+ *
+ * Author: Alvin Kuo <Alvin.Kuo@mediatek.com>
+ */
+#ifndef __TOPS_TOOL_CMDS_H__
+#define __TOPS_TOOL_CMDS_H__
+
+#include "dump.h"
+#include "logger.h"
+
+#define TOPS_TOOL_CMD_SAVE_DUMP \
+ { \
+ .name = "save_dump", \
+ .usage = "save_dump [DUMP DIRECTORY PATH]", \
+ .desc = "save dump data as file in dump directory", \
+ .func = tops_tool_save_dump_data, \
+ .num_of_parms = 1, \
+ },
+
+#if defined(CONFIG_MTK_TOPS_TOOL_SAVE_LOG)
+#define TOPS_TOOL_CMD_SAVE_LOG \
+ { \
+ .name = "save_log", \
+ .usage = "save_log [LOG DIRECTORY PATH]", \
+ .desc = "save log as file in log directory", \
+ .func = tops_tool_run_logger, \
+ .num_of_parms = 1, \
+ },
+#else
+#define TOPS_TOOL_CMD_SAVE_LOG
+#endif
+#endif /* __TOPS_TOOL_CMDS_H__ */
diff --git a/feed/app/tops-tool/src/inc/tops-tool.h b/feed/app/tops-tool/src/inc/tops-tool.h
new file mode 100644
index 0000000..f7a394a
--- /dev/null
+++ b/feed/app/tops-tool/src/inc/tops-tool.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2023 MediaTek Incorporation. All Rights Reserved.
+ *
+ * Author: Alvin Kuo <Alvin.Kuo@mediatek.com>
+ */
+
+#ifndef __TOPS_TOOL_H__
+#define __TOPS_TOOL_H__
+
+#include "tops-tool-cmds.h"
+
+#define TOPS_TOOL_CMD(cmd_name) TOPS_TOOL_CMD_ ## cmd_name
+
+typedef int (*tops_tool_cmd_func_t)(int argc, char *argv[]);
+
+struct tops_tool_cmd {
+ char *name;
+ char *usage;
+ char *desc;
+ tops_tool_cmd_func_t func;
+ uint8_t num_of_parms;
+};
+
+#endif /* __TOPS_TOOL_H__ */
diff --git a/feed/app/tops-tool/src/logger.c b/feed/app/tops-tool/src/logger.c
new file mode 100644
index 0000000..8ab75fd
--- /dev/null
+++ b/feed/app/tops-tool/src/logger.c
@@ -0,0 +1,340 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2023 MediaTek Incorporation. All Rights Reserved.
+ *
+ * Author: Alvin Kuo <Alvin.Kuo@mediatek.com>
+ */
+
+#include <stdbool.h>
+#include <signal.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <time.h>
+#include <poll.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "common.h"
+#include "logger.h"
+
+static struct logger_runtime_info runtime_infos[LOG_NUM_MAX] = {
+ [LOG_NUM_MGMT] = {
+ .relayfs_path = LOG_MGMT_RELAYFS_PATH,
+ .log_name = LOG_MGMT_NAME,
+ },
+ [LOG_NUM_OFFLOAD] = {
+ .relayfs_path = LOG_OFFLOAD_RELAYFS_PATH,
+ .log_name = LOG_OFFLOAD_NAME,
+ },
+};
+
+static bool sig_rcv;
+
+static void __tops_logger_runtime_info_deinit(int log_num)
+{
+ struct logger_runtime_info *ri;
+
+ for (; log_num >= 0; log_num--) {
+ ri = &runtime_infos[log_num];
+
+ free(ri->log_file_path);
+ close(ri->relayfs_fd);
+ globfree(&ri->relayfs_glob);
+ }
+}
+
+static void tops_logger_runtime_info_deinit(void)
+{
+ __tops_logger_runtime_info_deinit(LOG_NUM_MAX - 1);
+}
+
+static int __tops_logger_runtime_info_init(struct logger_runtime_info *ri,
+ const char *log_file_dir,
+ char *log_time_str)
+{
+ int ret;
+
+ ret = glob(ri->relayfs_path, 0, NULL, &ri->relayfs_glob);
+ if (ret != 0) {
+ fprintf(stderr,
+ LOG_FMT("glob(%s) fail(%d)\n"),
+ ri->relayfs_path, ret);
+ goto out;
+ } else if (ri->relayfs_glob.gl_pathc > 1) {
+ fprintf(stderr,
+ LOG_FMT("glob(%s) match %lu paths\n"),
+ ri->relayfs_path, ri->relayfs_glob.gl_pathc);
+ ret = -EINVAL;
+ goto free_glob;
+ }
+
+ ri->relayfs_fd = open(ri->relayfs_glob.gl_pathv[0], O_RDONLY);
+ if (ri->relayfs_fd < 0) {
+ fprintf(stderr,
+ LOG_FMT("open(%s) fail(%s)\n"),
+ ri->relayfs_glob.gl_pathv[0], strerror(errno));
+ ret = ri->relayfs_fd;
+ goto free_glob;
+ }
+
+ ri->log_file_path = malloc(strlen(log_file_dir) + 1 +
+ strlen(ri->log_name) + 1 +
+ strlen(log_time_str) + 1);
+ if (!ri->log_file_path) {
+ ret = -ENOMEM;
+ goto close_fd;
+ }
+
+ sprintf(ri->log_file_path, "%s/%s-%s", log_file_dir, ri->log_name, log_time_str);
+
+out:
+ return ret;
+
+close_fd:
+ close(ri->relayfs_fd);
+
+free_glob:
+ globfree(&ri->relayfs_glob);
+
+ return ret;
+}
+
+static int tops_logger_runtime_info_init(const char *log_file_dir)
+{
+ char log_time_str[32];
+ time_t log_time;
+ int log_num;
+ int ret;
+
+ time(&log_time);
+ ret = time_to_str(&log_time, log_time_str, sizeof(log_time_str));
+ if (ret < 0) {
+ fprintf(stderr,
+ LOG_FMT("time_to_str(%lu) fail(%d)\n"),
+ log_time, ret);
+ goto out;
+ }
+
+ for (log_num = 0; log_num < LOG_NUM_MAX; log_num++) {
+ ret = __tops_logger_runtime_info_init(
+ &runtime_infos[log_num],
+ log_file_dir,
+ log_time_str);
+ if (ret)
+ goto deinit_logger_runtime_info;
+ }
+
+out:
+ return ret;
+
+deinit_logger_runtime_info:
+ __tops_logger_runtime_info_deinit(log_num - 1);
+
+ return ret;
+}
+
+static int tops_logger_log_save(char *file, char *data, uint32_t data_len)
+{
+ int ret = 0;
+ int fd;
+
+ fd = open(file, O_RDWR | O_APPEND | O_CREAT, 0664);
+ if (fd < 0) {
+ fprintf(stderr,
+ LOG_FMT("open(%s) fail(%s)\n"),
+ file, strerror(errno));
+ ret = -1;
+ goto out;
+ }
+
+ write(fd, data, data_len);
+ close(fd);
+
+out:
+ return ret;
+}
+
+static int tops_logger_log_proc(struct pollfd *pfds)
+{
+ struct logger_runtime_info *ri;
+ char buffer[BUFFER_LEN];
+ int log_num;
+ int ret = 0;
+
+ for (log_num = 0; log_num < LOG_NUM_MAX; log_num++) {
+ ri = &runtime_infos[log_num];
+ if (pfds[log_num].revents & (POLLIN | POLLHUP | POLLERR)) {
+ ret = read(pfds[log_num].fd, buffer, BUFFER_LEN);
+ if (ret < 0) {
+ fprintf(stderr,
+ LOG_FMT("read log from %s failed(%d)\n"),
+ ri->relayfs_glob.gl_pathv[0], ret);
+
+ if (errno == EINTR || errno == EAGAIN)
+ continue;
+
+ break;
+ } else if (ret == 0) {
+ continue;
+ }
+
+ ret = tops_logger_log_save(ri->log_file_path,
+ buffer, ret);
+ if (ret) {
+ fprintf(stderr,
+ LOG_FMT("save log to %s failed(%d)\n"),
+ ri->log_file_path, ret);
+ break;
+ }
+ }
+ }
+
+ return ret;
+}
+
+static void signal_handler(int sig)
+{
+ (void)sig;
+
+ fprintf(stderr,
+ LOG_FMT("killall or Ctrl+C received, stop saving log\n"));
+ sig_rcv = true;
+}
+
+static int tops_logger_is_running(bool *running)
+{
+ char result[4];
+ int ret = 0;
+ ssize_t n;
+ int fd;
+
+ fd = open(LOGGER_DEBUGFS_PATH, O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr,
+ LOG_FMT("open(%s) fail(%s)\n"),
+ LOGGER_DEBUGFS_PATH, strerror(errno));
+ ret = errno;
+ goto out;
+ }
+
+ n = read(fd, result, sizeof(result) - 1);
+ if (n == -1) {
+ fprintf(stderr,
+ LOG_FMT("read(%s) fail(%s)\n"),
+ LOGGER_DEBUGFS_PATH, strerror(errno));
+ ret = errno;
+ goto close_file;
+ }
+
+ result[n] = '\0';
+
+ if (strcmp(result, "ON") == 0) {
+ fprintf(stderr, LOG_FMT("logger is running\n"));
+ *running = true;
+ } else {
+ *running = false;
+ }
+
+close_file:
+ close(fd);
+
+out:
+ return ret;
+}
+
+int tops_tool_run_logger(int argc, char *argv[])
+{
+ const char *log_file_dir = argv[2];
+ bool running = false;
+ struct stat st;
+ int ret;
+
+ if (!log_file_dir) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* reserve 256 bytes for log file name */
+ if (strlen(log_file_dir) > (PATH_MAX - 256)) {
+ fprintf(stderr,
+ LOG_FMT("log_file_dir(%s) length %zu > %u\n"),
+ log_file_dir, strlen(log_file_dir), PATH_MAX - 256);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = tops_logger_is_running(&running);
+ if (ret || running) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (stat(log_file_dir, &st)) {
+ if (errno == ENOENT) {
+ ret = mkdir_p(log_file_dir, 0775);
+ if (ret) {
+ fprintf(stderr,
+ LOG_FMT("mkdir_p(%s) failed(%d)\n"),
+ log_file_dir, ret);
+ goto out;
+ }
+ } else {
+ fprintf(stderr,
+ LOG_FMT("stat(%s) failed(%s)\n"),
+ log_file_dir, strerror(errno));
+ ret = -EINVAL;
+ goto out;
+ }
+ }
+
+ signal(SIGTERM, signal_handler);
+ signal(SIGINT, signal_handler);
+ signal(SIGQUIT, signal_handler);
+
+ ret = tops_logger_runtime_info_init(log_file_dir);
+ if (ret)
+ goto out;
+
+ system("echo ON > " LOGGER_DEBUGFS_PATH);
+
+ while (1) {
+ struct pollfd pfds[LOG_NUM_MAX] = {
+ [LOG_NUM_MGMT] = {
+ .fd = runtime_infos[LOG_NUM_MGMT].relayfs_fd,
+ .events = POLLIN | POLLHUP | POLLERR,
+ .revents = 0,
+ },
+ [LOG_NUM_OFFLOAD] = {
+ .fd = runtime_infos[LOG_NUM_OFFLOAD].relayfs_fd,
+ .events = POLLIN | POLLHUP | POLLERR,
+ .revents = 0,
+ },
+ };
+
+ if (sig_rcv)
+ break;
+
+ poll(pfds, LOG_NUM_MAX, -1);
+
+ if (sig_rcv)
+ break;
+
+ ret = tops_logger_log_proc(pfds);
+ if (ret)
+ break;
+ }
+
+ system("echo OFF > " LOGGER_DEBUGFS_PATH);
+
+ tops_logger_runtime_info_deinit();
+
+out:
+ return ret;
+}
diff --git a/feed/app/tops-tool/src/tops-tool.c b/feed/app/tops-tool/src/tops-tool.c
index 32ab579..8dd16e9 100644
--- a/feed/app/tops-tool/src/tops-tool.c
+++ b/feed/app/tops-tool/src/tops-tool.c
@@ -9,60 +9,73 @@
#include <stdio.h>
#include <errno.h>
-#include "dump.h"
+#include "common.h"
+#include "tops-tool.h"
+
+static struct tops_tool_cmd cmds[] = {
+ TOPS_TOOL_CMD(SAVE_DUMP)
+ TOPS_TOOL_CMD(SAVE_LOG)
+};
static void print_usage(void)
{
+ unsigned int idx;
+
printf("Usage:\n");
- printf(" tops-tool [CMD] [DUMP_DIR]\n");
- printf(" [CMD] are:\n");
- printf(" save_dump save dump data as file in directory [DUMP_DIR]\n");
- printf(" [DUMP_DIR] is directory of dump file\n");
+ printf("tops-tool [CMD]\n");
+ printf("[CMD] are:\n");
+ for (idx = 0; idx < ARRAY_SIZE(cmds); idx++)
+ printf("\t%s\n\t%s\n\n", cmds[idx].usage, cmds[idx].desc);
}
-static int verify_parameters(int argc,
- char *argv[])
+static int verify_parameters(int argc, char *argv[], unsigned int *cmd_idx)
{
+ unsigned int idx;
char *cmd;
if (argc < 2) {
- fprintf(stderr, DUMP_LOG_FMT("missing cmd\n"));
+ fprintf(stderr, LOG_FMT("CMD missing\n"));
return -EINVAL;
}
cmd = argv[1];
- if (!strncmp(cmd, "save_dump", 9)) {
- if (argc < 3) {
- fprintf(stderr, DUMP_LOG_FMT("too few parameters\n"));
- return -EINVAL;
+ for (idx = 0; idx < ARRAY_SIZE(cmds); idx++) {
+ if (!strncmp(cmds[idx].name, cmd, strlen(cmds[idx].name))) {
+ if (argc - 2 < cmds[idx].num_of_parms) {
+ fprintf(stderr,
+ LOG_FMT("CMD(%s) needs %d parameter(s)\n"),
+ cmds[idx].name,
+ cmds[idx].num_of_parms);
+ return -EINVAL;
+ }
+
+ *cmd_idx = idx;
+
+ return 0;
}
}
- return 0;
+ fprintf(stderr, LOG_FMT("CMD(%s) not support\n"), cmd);
+
+ return -EINVAL;
}
int main(int argc, char *argv[])
{
+ unsigned int cmd_idx;
int ret = 0;
- char *cmd;
- ret = verify_parameters(argc, argv);
+ ret = verify_parameters(argc, argv, &cmd_idx);
if (ret) {
print_usage();
goto error;
}
- cmd = argv[1];
- if (!strncmp(cmd, "save_dump", 9)) {
- ret = tops_save_dump_data(argv[2]);
- if (ret) {
- fprintf(stderr,
- DUMP_LOG_FMT("cmd %s: save dump data fail(%d)\n"),
- cmd, ret);
- goto error;
- }
- } else {
- fprintf(stderr, DUMP_LOG_FMT("unsupported cmd %s\n"), cmd);
+ ret = cmds[cmd_idx].func(argc, argv);
+ if (ret) {
+ fprintf(stderr,
+ LOG_FMT("CMD(%s) execution failed(%d)\n"),
+ cmds[cmd_idx].name, ret);
goto error;
}