[Feature]add MT2731_MP2_MR2_SVN388 baseline version
Change-Id: Ief04314834b31e27effab435d3ca8ba33b499059
diff --git a/src/devtools/mrdump/Android.mk b/src/devtools/mrdump/Android.mk
new file mode 100644
index 0000000..6c4dff5
--- /dev/null
+++ b/src/devtools/mrdump/Android.mk
@@ -0,0 +1,3 @@
+LOCAL_PATH := $(my-dir)
+
+include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/src/devtools/mrdump/Makefile b/src/devtools/mrdump/Makefile
new file mode 100644
index 0000000..d6a0f39
--- /dev/null
+++ b/src/devtools/mrdump/Makefile
@@ -0,0 +1,20 @@
+BUILT_MODULE = mrdump_tool
+
+.PHONY: all install clean
+
+all:
+ $(warning "aee makefile all")
+ $(foreach m, $(BUILT_MODULE), make -f Makefile.$(m);)
+
+clean:
+ $(warning "aee makefile clean")
+ $(foreach m, $(BUILT_MODULE), make -f Makefile.$(m) clean;)
+
+bindir ?= /usr/bin
+libdir ?= /usr/lib
+
+install:
+ # install -d ${DESTDIR}${libdir}
+ install -d ${DESTDIR}${bindir}
+
+ install -m 0755 mrdump_tool ${DESTDIR}$(bindir)
diff --git a/src/devtools/mrdump/Makefile.mrdump_tool b/src/devtools/mrdump/Makefile.mrdump_tool
new file mode 100644
index 0000000..a384a85
--- /dev/null
+++ b/src/devtools/mrdump/Makefile.mrdump_tool
@@ -0,0 +1,45 @@
+TARGET := mrdump_tool
+
+FLAGS := -Werror \
+ -D__YOCTO_OS__ \
+ -D_GNU_SOURCE
+
+INCLUDES := -I.
+
+bindir ?= /usr/bin
+
+VPATH = mrdump_tool_source
+
+SRCS := mrdump_log.c \
+ mrdump_defaults.c \
+ mrdump_common.c \
+ mrdump_status.c \
+ mrdump_support_fiemap.c \
+ mrdump_support_ext4.c \
+ mrdump_support_f2fs.c \
+ mrdump_support_mpart.c \
+ mrdump_tool.c
+
+
+OBJS := ${SRCS:%.c=%.o}
+
+LDFLAGS = -L.-lz
+
+.PHONY: all
+all : $(TARGET)
+
+${TARGET}: ${OBJS}
+ ${CC} ${OBJS} $(LDFLAGS) -o $@
+
+.PHONY: clean
+clean:
+ $(warning "makefile clean")
+ rm -rf $(OBJS) $(TARGET)
+
+%.o: %.c
+ ${CC} $(CFLAGS) -c $< -o $@ $(INCLUDES) $(FLAGS)
+
+.PHONY: install
+install:
+ install -d ${DESTDIR}${bindir}
+ install -m 0755 $(TARGET) ${DESTDIR}${bindir}
diff --git a/src/devtools/mrdump/README b/src/devtools/mrdump/README
new file mode 100644
index 0000000..ca482a3
--- /dev/null
+++ b/src/devtools/mrdump/README
@@ -0,0 +1,7 @@
+# Preliminary version: still need to clean up.
+
+This module creates the MRDUMP feature related function with source release to the customer.
+
+- mrdump_tool: binary on phone which could help to do the mrdump tasks.
+
+- mrdump_host_cmd: executable file on windows, currently to get full ram dump thru usb dump.
diff --git a/src/devtools/mrdump/mrdump_tool_source/Android.mk b/src/devtools/mrdump/mrdump_tool_source/Android.mk
new file mode 100644
index 0000000..f0eec8b
--- /dev/null
+++ b/src/devtools/mrdump/mrdump_tool_source/Android.mk
@@ -0,0 +1,21 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := \
+ mrdump_log.c \
+ mrdump_common.c \
+ mrdump_status.c \
+ mrdump_support_fiemap.c \
+ mrdump_support_ext4.c \
+ mrdump_support_f2fs.c \
+ mrdump_support_mpart.c \
+ mrdump_tool.c
+
+LOCAL_CFLAGS += -D__ANDROID__
+
+LOCAL_MODULE := mrdump_tool
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_MODULE_OWNER := mtk
+LOCAL_MODULE_TAGS := optional
+LOCAL_SHARED_LIBRARIES := libcutils libz liblog
+include $(MTK_EXECUTABLE)
diff --git a/src/devtools/mrdump/mrdump_tool_source/mrdump_common.c b/src/devtools/mrdump/mrdump_tool_source/mrdump_common.c
new file mode 100644
index 0000000..39c50af
--- /dev/null
+++ b/src/devtools/mrdump/mrdump_tool_source/mrdump_common.c
@@ -0,0 +1,205 @@
+/* uint64_t ...*/
+#include <inttypes.h>
+#include <stdbool.h>
+
+/* struct stat, open */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+/* fsync(), close() */
+#include <unistd.h>
+
+/* strerror */
+#include <string.h>
+/* errno */
+#include <errno.h>
+
+/* statfs() and statvfs() */
+#include <sys/statfs.h>
+#include <sys/statvfs.h>
+#include <sys/vfs.h>
+
+/* ioctl, BLKGETSIZE64 */
+#include <linux/fs.h>
+#include <sys/ioctl.h>
+
+#ifdef __ANDROID__
+/* Property */
+#include <cutils/properties.h>
+#include <sys/system_properties.h>
+#elif defined(__YOCTO_OS__)
+#include <stdio.h>
+#endif
+
+/* mrdump related */
+#include "mrdump_log.h"
+#include "mrdump_common.h"
+#include "mrdump_support_ext4.h"
+#include "mrdump_support_f2fs.h"
+#include "mrdump_status_private.h"
+
+void mrdump_close(int fd)
+{
+ fsync(fd);
+ close(fd);
+}
+
+int mrdump_file_is_exist(const char *path)
+{
+ struct stat s;
+ if (!path)
+ return 0;
+ if (stat(path, &s) != 0)
+ return 0;
+ return 1;
+}
+
+int mrdump_get_data_os(void)
+{
+ if (mount_as_ext4(MRDUMP_EXT4_MOUNT_POINT))
+ return MRDUMP_DATA_FS_EXT4;
+
+ if (mount_as_f2fs(MRDUMP_EXT4_MOUNT_POINT))
+ return MRDUMP_DATA_FS_F2FS;
+
+ MD_LOGI("%s: unknown os\n", __func__);
+ return MRDUMP_DATA_FS_NONE;
+}
+
+uint64_t mrdump_get_partition_free_size(const char *mountp)
+{
+ struct statvfs vfs;
+ uint64_t psize;
+
+ if(statvfs(mountp, &vfs) == 0) {
+ psize = (uint64_t) vfs.f_frsize * (uint64_t) vfs.f_bfree;
+ MD_LOGD("%s: size of %s: %" PRId64 " bytes.\n", __func__, mountp, psize);
+ return psize;
+ }
+
+ MD_LOGE("%s: statvfs of %s got failed(%d), %s\n", __func__, mountp, errno, strerror(errno));
+ return 0;
+}
+
+uint64_t mrdump_get_partition_size(char *fullpath)
+{
+ int fd = open(fullpath, O_RDONLY);
+ if (0 > fd) {
+ MD_LOGE("%s: open fullpath failed. (%s)\n", __func__, fullpath);
+ return 0;
+ }
+
+ uint64_t psize;
+ int ret = ioctl(fd, BLKGETSIZE64, &psize);
+ if (0 > ret) {
+ MD_LOGE("%s: ioctl BLKGETSIZE64 failed. (%s)\n", __func__, fullpath);
+ mrdump_close(fd);
+ return 0;
+ }
+
+ mrdump_close(fd);
+
+ return psize;
+}
+
+static char *mrdump_get_device_node_from_fstab(const char *fstab, const char *mountp)
+{
+#ifdef __ANDROID_
+ int ret;
+ FILE *fp;
+ char c, myline[1024];
+ char *delim="\x09\x20";
+ char *DeviceNode, *MountPoint;
+
+ DeviceNode = NULL;
+ fp = fopen(fstab, "r");
+ if(fp == NULL)
+ return NULL;
+
+ while(!feof(fp)) {
+
+ // getline
+ ret = fscanf(fp, "%[^\n]", myline);
+
+ // strtok strings
+ if(ret > 0) {
+ if(myline[0] == '/') {
+ DeviceNode = strtok(myline, delim);
+ MountPoint = strtok(NULL, delim);
+ if(MountPoint != NULL) {
+ if(!strcmp(MountPoint, mountp)) {
+ fclose(fp);
+ return strdup(DeviceNode);
+ }
+ }
+ }
+ }
+
+ /* clear newline character */
+ ret = fscanf(fp, "%c", &c);
+ if (ret != 1) {
+ MD_LOGE("%s: not EOL.", __func__);
+ fclose(fp);
+ return NULL;
+ }
+ }
+ fclose(fp);
+ return NULL;
+#elif defined(__YOCTO_OS__)
+#endif
+}
+
+#ifdef __ANDROID_
+static const char *fstab_path_prefix[] = {
+ "/vendor/etc/fstab",
+ "/fstab",
+ NULL
+};
+#elif defined(__YOCTO_OS__)
+static const char expdb_dev[] = "/dev/disk/by-partlabel/expdb";
+static const char preallocate_dev[] = "/dev/disk/by-partlabel/log";
+#endif
+
+char *mrdump_get_device_node(const char *mountp)
+{
+#ifdef __ANDROID_
+ int i;
+ char *DeviceNode = NULL;
+ char fstab_filename[PROPERTY_VALUE_MAX];
+
+ /* get hardware parts */
+ char propbuf[PROPERTY_VALUE_MAX];
+ if(property_get("ro.hardware", propbuf, NULL) == 0)
+ property_get("ro.board.platform", propbuf, "");
+
+ for(i = 0; fstab_path_prefix[i] != NULL; i++) {
+ snprintf(fstab_filename, sizeof(fstab_filename), "%s.%s", fstab_path_prefix[i], propbuf);
+ if(mrdump_file_is_exist(fstab_filename))
+ DeviceNode = mrdump_get_device_node_from_fstab(fstab_filename, mountp);
+ if(DeviceNode)
+ return DeviceNode;
+ }
+
+ /* search for path: /fstab */
+ DeviceNode = mrdump_get_device_node_from_fstab("/fstab", mountp);
+ char fstab_filename[PATH_MAX];
+
+ for (i = 0; fstab_path_prefix[i] != NULL; i++) {
+ snprintf(fstab_filename, sizeof(fstab_filename), "%s", fstab_path_prefix[i]);
+ if(mrdump_file_is_exist(fstab_filename))
+ DeviceNode = mrdump_get_device_node_from_fstab(fstab_filename, mountp);
+ if(DeviceNode)
+ return DeviceNode;
+ }
+ return DeviceNode;
+#elif defined(__YOCTO_OS__)
+ if (!strncmp(mountp, MRDUMP_EXPDB_NAME, sizeof(MRDUMP_EXPDB_NAME)))
+ return strdup(expdb_dev);
+
+ if (!strncmp(mountp, MRDUMP_EXT4_MOUNT_POINT, sizeof(MRDUMP_EXT4_MOUNT_POINT)))
+ return strdup(preallocate_dev);
+
+ return NULL;
+#endif
+}
diff --git a/src/devtools/mrdump/mrdump_tool_source/mrdump_common.h b/src/devtools/mrdump/mrdump_tool_source/mrdump_common.h
new file mode 100644
index 0000000..7a53b0f
--- /dev/null
+++ b/src/devtools/mrdump/mrdump_tool_source/mrdump_common.h
@@ -0,0 +1,31 @@
+#pragma once
+
+#ifdef __YOCTO_OS__
+#include <stdint.h>
+// typedef unsigned long long int uint64_t;
+#define strlcpy strncpy
+#endif
+
+/* variables definition */
+#define MRDUMP_DATA_FS_NONE 0
+#define MRDUMP_DATA_FS_EXT4 1
+#define MRDUMP_DATA_FS_F2FS 2
+#define MRDUMP_1K 1024
+#define MRDUMP_1M (MRDUMP_1K * MRDUMP_1K)
+
+/* mrdump related */
+#define MRDUMP_DATA_PARTITION "/dev/block/platform/bootdevice/by-name/userdata"
+#define MRDUMP_REST_BLOCKS 1024
+#define MRDUMP_REST_SPACE (MRDUMP_1M * MRDUMP_REST_BLOCKS)
+
+/* mrdump flow control */
+#define MRDUMP_MAX_BW_REQ 100
+#define MRDUMP_MAX_BANDWIDTH (MRDUMP_1M * MRDUMP_MAX_BW_REQ)
+
+/* Function Prototypes */
+void mrdump_close(int fd);
+int mrdump_file_is_exist(const char *path);
+int mrdump_get_data_os(void);
+uint64_t mrdump_get_partition_free_size(const char *mountp);
+uint64_t mrdump_get_partition_size(char *fullpath);
+char *mrdump_get_device_node(const char *mountp);
diff --git a/src/devtools/mrdump/mrdump_tool_source/mrdump_defaults.c b/src/devtools/mrdump/mrdump_tool_source/mrdump_defaults.c
new file mode 100644
index 0000000..e92d8db
--- /dev/null
+++ b/src/devtools/mrdump/mrdump_tool_source/mrdump_defaults.c
@@ -0,0 +1,13 @@
+#include <string.h>
+
+const char* sysenv_get(const char *name) {
+ if (!strncmp(name, "mrdump_allocate_size", sizeof("mrdump_allocate_size")))
+ return ("fullmem");
+ if (!strncmp(name, "mrdump_output", sizeof("mrdump_output")))
+ return ("internal-storage");
+ return NULL;
+}
+
+int sysenv_set(const char *name, const char *value) {
+ return 0;
+}
diff --git a/src/devtools/mrdump/mrdump_tool_source/mrdump_defaults.h b/src/devtools/mrdump/mrdump_tool_source/mrdump_defaults.h
new file mode 100644
index 0000000..2e93b26
--- /dev/null
+++ b/src/devtools/mrdump/mrdump_tool_source/mrdump_defaults.h
@@ -0,0 +1,2 @@
+extern const char* sysenv_get(const char *name);
+extern int sysenv_set(const char *name, const char *value);
diff --git a/src/devtools/mrdump/mrdump_tool_source/mrdump_log.c b/src/devtools/mrdump/mrdump_tool_source/mrdump_log.c
new file mode 100644
index 0000000..3f3972b
--- /dev/null
+++ b/src/devtools/mrdump/mrdump_tool_source/mrdump_log.c
@@ -0,0 +1,71 @@
+/* vprintf, vsnprintf */
+#include <stdio.h>
+
+/* exit(), atoi() */
+#include <stdlib.h>
+
+#ifdef __YOCTO_OS__
+#include <stdarg.h>
+#endif
+
+/* mrdump related */
+#include "mrdump_log.h"
+
+
+static int mdlog_level = LOG_INFO;
+static int mdlog_write_syslog = 1;
+
+void mdlog_init(int level, int write_syslog)
+{
+ mdlog_level = level;
+ mdlog_write_syslog = write_syslog;
+ openlog("mrdump_tool", 0, 0);
+}
+
+void mdlog_printf(int log_prio, const char *fmt, ...)
+{
+ va_list ap;
+
+ if (log_prio > mdlog_level) {
+ return;
+ }
+
+ va_start(ap, fmt);
+ if (mdlog_write_syslog) {
+ vsyslog(log_prio, fmt, ap);
+ }
+ else {
+ char prefix;
+ if (log_prio <= LOG_ERR) {
+ prefix = 'E';
+ } else if (log_prio == LOG_WARNING) {
+ prefix = 'W';
+ } else if (log_prio <= LOG_INFO) {
+ prefix = 'I';
+ } else {
+ prefix = 'D';
+ }
+ putc(prefix, stderr);
+ putc(':', stderr);
+ vfprintf(stderr, fmt, ap);
+ }
+ va_end(ap);
+}
+
+void error(const char *msg, ...)
+{
+ va_list ap;
+ char msgbuf[128];
+
+ va_start(ap, msg);
+ if (mdlog_write_syslog) {
+ vsyslog(LOG_ERR, msg, ap);
+ }
+ else {
+ vsnprintf(msgbuf, sizeof(msgbuf), msg, ap);
+ fprintf(stderr, "Error: %s", msgbuf);
+ }
+ va_end(ap);
+
+ exit(2);
+}
diff --git a/src/devtools/mrdump/mrdump_tool_source/mrdump_log.h b/src/devtools/mrdump/mrdump_tool_source/mrdump_log.h
new file mode 100644
index 0000000..b8bee70
--- /dev/null
+++ b/src/devtools/mrdump/mrdump_tool_source/mrdump_log.h
@@ -0,0 +1,26 @@
+#pragma once
+
+#include <syslog.h>
+
+void mdlog_init(int level, int write_syslog);
+
+void mdlog_printf(int log_prio, const char *fmt, ...);
+
+void error(const char *msg, ...) __attribute__((noreturn));
+
+/* LOG macro support */
+#define DEBUG_BY_CONSOLE
+#include <stdio.h>
+#if defined(DEBUG_BY_CONSOLE)
+#define MD_LOGV(...) printf(__VA_ARGS__)
+#define MD_LOGD(...) printf(__VA_ARGS__)
+#define MD_LOGI(...) printf(__VA_ARGS__)
+#define MD_LOGW(...) printf(__VA_ARGS__)
+#define MD_LOGE(...) printf(__VA_ARGS__)
+#else
+#define MD_LOGV(...) mdlog_printf(LOG_DEBUG, __VA_ARGS__)
+#define MD_LOGD(...) mdlog_printf(LOG_DEBUG, __VA_ARGS__)
+#define MD_LOGI(...) mdlog_printf(LOG_INFO, __VA_ARGS__)
+#define MD_LOGW(...) mdlog_printf(LOG_WARNING, __VA_ARGS__)
+#define MD_LOGE(...) mdlog_printf(LOG_ERR, __VA_ARGS__)
+#endif
diff --git a/src/devtools/mrdump/mrdump_tool_source/mrdump_status.c b/src/devtools/mrdump/mrdump_tool_source/mrdump_status.c
new file mode 100644
index 0000000..edc4a2e
--- /dev/null
+++ b/src/devtools/mrdump/mrdump_tool_source/mrdump_status.c
@@ -0,0 +1,265 @@
+/* printf */
+#include <stdio.h>
+
+/* open */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+/* read */
+#include <unistd.h>
+
+/* free */
+#include <stdlib.h>
+
+/* ioctl */
+#include <sys/ioctl.h>
+
+/* lseek64 */
+#ifndef _LARGEFILE64_SOURCE
+#define _LARGEFILE64_SOURCE
+#endif
+#include <sys/types.h>
+#include <unistd.h>
+
+/* bzero */
+#include <strings.h>
+
+/* strlen, memset, strncpy, strtok... */
+#include <string.h>
+
+/* errno */
+#include <errno.h>
+
+/* BLKGETSIZE64 */
+#include <linux/fs.h>
+
+/* mrdump related */
+#include "mrdump_log.h"
+#include "mrdump_common.h"
+#include "mrdump_status.h"
+#include "mrdump_status_private.h"
+
+#ifdef __YOCTO_OS__
+#define strlcpy strncpy
+#endif
+
+static int file_read_string(const char* path, char *content, int len)
+{
+ if (len <= 0) {
+ return -2;
+ }
+
+ int fd = open(path, O_RDONLY);
+ if (fd < 0) {
+ return -1;
+ }
+
+ /* Preserved NULL byte */
+ len--;
+ int size = 0;
+ do {
+ int ret = read(fd, content + size, len - size);
+ if (ret <= 0)
+ break;
+ size = size + ret;
+ } while (size < len);
+ content[size] = 0;
+
+ close(fd);
+ return size;
+}
+
+static int expdb_open(struct partinfo *partinfo)
+{
+ uint64_t part_size;
+ uint32_t part_blksize;
+
+ memset(partinfo, 0, sizeof(struct partinfo));
+
+ char *pp = mrdump_get_device_node(MRDUMP_EXPDB_NAME);
+ if (pp == NULL) {
+ MD_LOGE("%s: No expdb partition found", __func__);
+ return -1;
+ }
+
+ int fd = open(pp, O_RDWR);
+ if (fd < 0) {
+ MD_LOGE("%s: open expdb failed(%d)", __func__, errno);
+ free(pp);
+ return -1;
+ }
+ free(pp);
+
+ if (ioctl(fd, BLKGETSIZE64, &part_size) < 0) {
+ MD_LOGE("%s, get expdb partition size fail(%d)", __func__, errno);
+ close(fd);
+ return -1;
+ }
+
+ if (ioctl(fd, BLKSSZGET, &part_blksize) < 0) {
+ MD_LOGE("%s, get sector size fail(%d)", __func__, errno);
+ close(fd);
+ return -1;
+ }
+
+ partinfo->fd = fd;
+ partinfo->size = part_size;
+ partinfo->blksize = part_blksize;
+
+ return 0;
+}
+
+int mrdump_is_supported(void)
+{
+ char kversion[16], lversion[16];
+ int klen, llen;
+
+ bzero(kversion, sizeof(kversion));
+ bzero(lversion, sizeof(lversion));
+
+ if (file_read_string(MRDUMP_KVER, kversion, sizeof(kversion)) < 0) {
+ MD_LOGE("%s: cannot get kernel version\n", __func__);
+ return 0;
+ }
+
+ klen = strlen(kversion);
+ if (klen == 0) {
+ MD_LOGE("%s: null kernel version\n", __func__);
+ return 0;
+ }
+
+ if (file_read_string(MRDUMP_LVER, lversion, sizeof(lversion)) < 0) {
+ MD_LOGE("%s: cannot get lk version\n", __func__);
+ return 0;
+ }
+
+ llen = strlen(lversion);
+ if (llen == 0) {
+ MD_LOGE("%s: null lk version\n", __func__);
+ return 0;
+ }
+
+ if ((klen != llen) || (strncmp(kversion, lversion, klen) != 0)) {
+ MD_LOGE("%s: kernel and lk version mismatched.\n", __func__);
+ return 0;
+ }
+
+ MD_LOGI("%s: true\n", __func__);
+ return 1;
+}
+
+bool mrdump_status_clear(void)
+{
+ struct partinfo partinfo;
+
+ if (expdb_open(&partinfo) >= 0) {
+ if (lseek64(partinfo.fd, partinfo.size - MRDUMP_OFFSET, SEEK_SET) < 0) {
+ MD_LOGE("%s: Can't seek part fd %d\n", __func__, partinfo.fd);
+ close(partinfo.fd);
+ return false;
+ }
+
+ struct mrdump_cblock_result cblock_result;
+ if (read(partinfo.fd, &cblock_result, sizeof(struct mrdump_cblock_result)) != sizeof(struct mrdump_cblock_result)) {
+ MD_LOGE("%s: Can't read part fd %d\n", __func__, partinfo.fd);
+ close(partinfo.fd);
+ return false;
+ }
+ memset(cblock_result.status, 0, sizeof(cblock_result.status));
+ strncpy(cblock_result.status, "CLEAR", 5);
+
+ if (lseek64(partinfo.fd, partinfo.size - MRDUMP_OFFSET, SEEK_SET) < 0) {
+ MD_LOGE("%s: Can't seek part fd %d\n", __func__, partinfo.fd);
+ close(partinfo.fd);
+ return false;
+ }
+ if (write(partinfo.fd, &cblock_result, sizeof(struct mrdump_cblock_result)) != sizeof(struct mrdump_cblock_result)) {
+ MD_LOGE("%s: Can't write part fd %d\n", __func__, partinfo.fd);
+ close(partinfo.fd);
+ return false;
+ }
+ close(partinfo.fd);
+ return true;
+ }
+ return false;
+}
+
+bool mrdump_status_get(struct mrdump_status_result *result)
+{
+ memset(result, 0, sizeof(struct mrdump_status_result));
+ result->struct_size = sizeof(struct mrdump_status_result);
+
+ struct partinfo partinfo;
+ if (expdb_open(&partinfo) >= 0) {
+ if (lseek64(partinfo.fd, partinfo.size - MRDUMP_OFFSET, SEEK_SET) < 0) {
+ MD_LOGE("%s: Can't seek part fd %d\n", __func__, partinfo.fd);
+ close(partinfo.fd);
+ return false;
+ }
+
+ struct mrdump_cblock_result cblock_result;
+ if (read(partinfo.fd, &cblock_result, sizeof(struct mrdump_cblock_result)) != sizeof(struct mrdump_cblock_result)) {
+ MD_LOGE("%s: Can't read part fd %d\n", __func__, partinfo.fd);
+ close(partinfo.fd);
+ return false;
+ }
+ close(partinfo.fd);
+
+ if (strcmp(cblock_result.sig, MRDUMP_SIG) != 0) {
+ MD_LOGE("%s: Signature mismatched (result: %s)\n", __func__, cblock_result.sig);
+ return false;
+ }
+ /* Copy/parsing status line */
+ strncpy(result->status_line, cblock_result.status, sizeof(cblock_result.status));
+ result->status_line[sizeof(result->status_line) - 1] = 0;
+
+ char *saveptr;
+ cblock_result.status[sizeof(cblock_result.status) - 1] = 0;
+ char *strval = strtok_r(cblock_result.status, "\n", &saveptr);
+ if (strval != NULL) {
+ if (strcmp(strval, "OK") == 0) {
+ result->status = MRDUMP_STATUS_OK;
+ result->output = MRDUMP_OUTPUT_NULL;
+
+ do {
+ strval = strtok_r(NULL, "\n", &saveptr);
+ if (strval != NULL) {
+ if (strncmp(strval, "OUTPUT:", 7) == 0) {
+ if (strcmp(strval + 7, "EXT4_DATA") == 0) {
+ result->output = MRDUMP_OUTPUT_DATA_FS;
+ }
+ else if (strcmp(strval + 7, "PARTITION_DATA") == 0) {
+ result->output = MRDUMP_OUTPUT_PARTITION;
+ }
+ else {
+ return false;
+ }
+ }
+ else if (strncmp(strval, "MODE:", 5) == 0) {
+ strlcpy(result->mode, strval + 5, sizeof(result->mode));
+ }
+ }
+ } while (strval != NULL);
+ }
+ else if (strcmp(strval, "NONE") == 0) {
+ result->status = MRDUMP_STATUS_NONE;
+ }
+ else if (strcmp(strval, "CLEAR") == 0) {
+ result->status = MRDUMP_STATUS_NONE;
+ }
+ else {
+ result->status = MRDUMP_STATUS_FAILED;
+ }
+ }
+ else {
+ MD_LOGE("%s: status parsing error \"%s\"\n", __func__, cblock_result.status);
+ return false;
+ }
+
+ strncpy(result->log_buf, cblock_result.log_buf, sizeof(cblock_result.log_buf));
+ result->log_buf[sizeof(result->log_buf) - 1] = 0;
+ return true;
+ }
+ return false;
+}
diff --git a/src/devtools/mrdump/mrdump_tool_source/mrdump_status.h b/src/devtools/mrdump/mrdump_tool_source/mrdump_status.h
new file mode 100644
index 0000000..8212626
--- /dev/null
+++ b/src/devtools/mrdump/mrdump_tool_source/mrdump_status.h
@@ -0,0 +1,40 @@
+#if !defined(__MRDUMP_H__)
+#define __MRDUMP_H__
+
+#include <stdbool.h>
+#include <stdint.h>
+
+typedef enum {
+ MRDUMP_STATUS_NONE,
+ MRDUMP_STATUS_FAILED,
+ MRDUMP_STATUS_OK,
+} MRDUMP_STATUS;
+
+typedef enum {
+ MRDUMP_OUTPUT_NULL,
+ MRDUMP_OUTPUT_USB,
+ MRDUMP_OUTPUT_DATA_FS,
+ MRDUMP_OUTPUT_UNUSED, /* VFAT */
+ MRDUMP_OUTPUT_PARTITION,
+} MRDUMP_OUTPUT;
+
+#define MRDUMP_OUTPUT_EXT4_DATA MRDUMP_OUTPUT_DATA_FS
+#define MRDUMP_OUTPUT_PARTITION_DATA MRDUMP_OUTPUT_PARTITION
+
+struct mrdump_status_result {
+ uint32_t struct_size;
+
+ MRDUMP_STATUS status;
+ MRDUMP_OUTPUT output;
+ char mode[32];
+
+ char status_line[128];
+ char log_buf[2048];
+};
+
+/* public api */
+int mrdump_is_supported(void);
+bool mrdump_status_clear(void);
+bool mrdump_status_get(struct mrdump_status_result *result);
+
+#endif
diff --git a/src/devtools/mrdump/mrdump_tool_source/mrdump_status_private.h b/src/devtools/mrdump/mrdump_tool_source/mrdump_status_private.h
new file mode 100644
index 0000000..00651cd
--- /dev/null
+++ b/src/devtools/mrdump/mrdump_tool_source/mrdump_status_private.h
@@ -0,0 +1,26 @@
+#if !defined(__MRDUMP_USER_PRIVATE_H__)
+#define __MRDUMP_USER_PRIVATE_H__
+
+#include <stdbool.h>
+#include <stdint.h>
+
+/* DRAM KLOG at MRDUMP area of expdb, offset from bottom = 3145728 - 16384 = 3129344 */
+#define MRDUMP_OFFSET 3145728
+#define MRDUMP_EXPDB_NAME "/expdb"
+#define MRDUMP_KVER "/sys/module/mrdump/version"
+#define MRDUMP_LVER "/sys/module/mrdump/parameters/lk"
+#define MRDUMP_SIG "MRDUMP08"
+
+struct __attribute__((__packed__)) mrdump_cblock_result {
+ char sig[9];
+ char status[128];
+ char log_buf[2048];
+};
+
+struct partinfo {
+ int fd;
+ uint64_t size;
+ uint32_t blksize;
+};
+
+#endif
diff --git a/src/devtools/mrdump/mrdump_tool_source/mrdump_support_ext4.c b/src/devtools/mrdump/mrdump_tool_source/mrdump_support_ext4.c
new file mode 100644
index 0000000..1d00e94
--- /dev/null
+++ b/src/devtools/mrdump/mrdump_tool_source/mrdump_support_ext4.c
@@ -0,0 +1,1399 @@
+/* print */
+#include <stdio.h>
+
+/* uint64_t ...*/
+#include <inttypes.h>
+#include <stdbool.h>
+
+/* __u32 */
+#include <linux/types.h>
+
+/* struct stat, open */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+/* malloc */
+#include <stdlib.h>
+
+/* strerror */
+#include <string.h>
+/* errno */
+#include <errno.h>
+
+/* figetbsz */
+#include <linux/fs.h>
+#include <sys/ioctl.h>
+
+/* statfs() and statvfs() */
+#include <sys/statfs.h>
+#include <sys/statvfs.h>
+#include <sys/vfs.h>
+
+/* crc32, Z_NULL */
+#include <zlib.h>
+
+/* syscall, __NR_fallocate */
+#include <sys/syscall.h>
+
+/* time */
+#include <time.h>
+
+/* sysenv */
+#include "mrdump_defaults.h"
+
+/* mrdump related */
+#include "mrdump_log.h"
+#include "mrdump_common.h"
+#include "mrdump_status.h"
+#include "mrdump_support_fiemap.h"
+#include "mrdump_support_ext4.h"
+#include "mrdump_support_f2fs.h"
+#include "mrdump_support_mpart.h"
+
+/* add for block verification */
+static uint64_t lba_marker_time;
+static struct marked_block_data bdata;
+
+struct palloc_file {
+ int fd;
+ int blksize;
+ int lbaooo;
+};
+
+static struct palloc_file *palloc_file_open(const char *allocfile)
+{
+ struct stat statinfo;
+
+ struct palloc_file *pfile = malloc(sizeof(struct palloc_file));
+ pfile->fd = -1;
+ pfile->blksize = 0;
+ pfile->lbaooo = 0;
+
+ /////////////////////////////////////////////////////
+ // open file handle
+ pfile->fd = open(allocfile, O_RDONLY);
+ if(0 > pfile->fd) {
+ MD_LOGE("%s: file(%s) marker open failed(%d), %s\n", __func__, allocfile, errno, strerror(errno));
+ return NULL;
+ }
+ // Get file statinfo
+ if(0 > fstat(pfile->fd, &statinfo)) {
+ MD_LOGE("%s: marker stat failed(%d), %s\n", __func__, errno, strerror(errno));
+ goto cleanup;
+ }
+
+ if(0 > ioctl(pfile->fd, FIGETBSZ, &pfile->blksize)) {
+ MD_LOGE("%s: FIGETGSZ failed(%d), %s", __func__, errno, strerror(errno));
+ goto cleanup;
+ }
+
+ pfile->lbaooo = mrdump_fiemap_get_entry_lba(pfile->fd, pfile->blksize, 0);
+ if (pfile->lbaooo < 0) {
+ MD_LOGE("%s: get lba failed", __func__);
+ goto cleanup;
+ }
+ return pfile;
+
+ cleanup:
+ mrdump_close(pfile->fd);
+ pfile->fd = -1;
+ pfile->blksize = 0;
+ pfile->lbaooo = 0;
+ return NULL;
+}
+
+void palloc_file_close(struct palloc_file *pfile)
+{
+ mrdump_close(pfile->fd);
+ free(pfile);
+}
+
+static int fop_file_write_string(const char *path, const char *content, ...)
+{
+ int ret_val = 0;
+
+ int fd = open(path, O_WRONLY);
+ if (fd >= 0) {
+ char content_buf[1024];
+ va_list ap;
+
+ va_start(ap, content);
+ int n = vsnprintf(content_buf, sizeof(content_buf), content, ap);
+ va_end(ap);
+ int val = write(fd, content_buf, n);
+ if (val != n) {
+ if (val < 0) {
+ ret_val = -errno;
+ }
+ else {
+ ret_val = -EIO;
+ }
+ }
+ mrdump_close(fd);
+ if (ret_val == 0) {
+ ret_val = n;
+ }
+ }
+ else {
+ ret_val = -errno;
+ }
+ return ret_val;
+}
+
+////////////////////////////////////////////
+// common function (static in this file) //
+////////////////////////////////////////////
+static bool ext4_setup_attr(char const *allocfile, bool enabled)
+{
+ int fd;
+ unsigned int myflags;
+
+ if(allocfile == NULL) {
+ allocfile = MRDUMP_EXT4_ALLOCATE_FILE;
+ }
+
+ fd = open(allocfile, O_RDONLY);
+ if(0 > fd) {
+ MD_LOGE("%s: open allocfile failed(%d), %s\n", __func__, errno, strerror(errno));
+ return false;
+ }
+
+ if(0 > ioctl(fd, FS_IOC_GETFLAGS, &myflags)) {
+ MD_LOGE("%s: FS_IOC_GETFLAGS failed(%d), %s\n", __func__, errno, strerror(errno));
+ return false;
+ }
+
+ if (enabled) {
+ myflags |= (FS_SECRM_FL | FS_IMMUTABLE_FL);
+ }
+ else {
+ myflags &= ~(FS_SECRM_FL | FS_IMMUTABLE_FL);
+ }
+ if(0 > ioctl(fd, FS_IOC_SETFLAGS, &myflags)) {
+ MD_LOGE("%s: FS_IOC_SETFLAGS failed(%d), %s\n", __func__, errno, strerror(errno));
+ return false;
+ }
+
+ mrdump_close(fd);
+ return true;
+}
+
+static off64_t ext4_block_lseek(int fd, unsigned lba, int blksize)
+{
+ unsigned long long location = (unsigned long long) lba * (unsigned long long) blksize;
+ return lseek64(fd, location, SEEK_SET);
+}
+
+static int ext4_open_device_node(const char *mountp)
+{
+ char *devicenode = mrdump_get_device_node(mountp);
+ if(devicenode == NULL) {
+ MD_LOGE("%s: Get devicenode return null\n", __func__);
+ return -1;
+ }
+ int fd = open(devicenode, O_RDWR);
+ if(0 > fd) {
+ MD_LOGE("%s: open devicenode failed(%d), %s\n", __func__, errno, strerror(errno));
+ free(devicenode);
+ return -1;
+ }
+ free(devicenode);
+ return fd;
+}
+
+bool mount_as_ext4(const char *mountp)
+{
+ struct statfs fs;
+ if(statfs(mountp, &fs) == 0) {
+ /*
+ * bionic header didn't define EXT4_SUPER_MAGIC
+ * use EXT3_SUPER_MAGIC instead
+ */
+ if(fs.f_type == EXT3_SUPER_MAGIC)
+ return true;
+ return false;
+ }
+ MD_LOGE("%s: %s statfs error.\n", __func__, mountp);
+ return false;
+}
+
+static int check_a_data_block(int myfds, int mybs, uint32_t lba)
+{
+ unsigned long long offset = (unsigned long long)lba * (unsigned long long)mybs;
+ struct marked_block_data output_data;
+ unsigned int mycrc = crc32(0, Z_NULL, 0);
+ mycrc = crc32(mycrc, (void *)&bdata, (mybs-4));
+ bdata.crc = mycrc;
+ bdata.lba = lba;
+
+ if(0 > pread64(myfds, (void *)&output_data, mybs, offset)) {
+ MD_LOGE("%s: write block error!(%d), %s", __func__, errno, strerror(errno));
+ return -1;
+ };
+
+ // check lba
+ if (bdata.lba != output_data.lba) {
+ MD_LOGE("Read BlockData LBA failed (c:%u, v:%u)\n", bdata.lba, output_data.lba);
+ return -1;
+ }
+ // check timestamp
+ if (bdata.timestamp != output_data.timestamp) {
+ MD_LOGE("Read BlockData timestamp failed (c:%u, v:%u)\n", bdata.timestamp, output_data.timestamp);
+ return -1;
+ }
+ // check crc
+ if (bdata.crc != output_data.crc) {
+ MD_LOGE("Read BlockData crc32 failed (c:%u, v:%u)\n", bdata.crc, output_data.crc);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int format_a_data_block(int myfds, int mybs, uint32_t lba)
+{
+ unsigned long long offset = (unsigned long long)lba * (unsigned long long)mybs;
+
+ bdata.lba = lba;
+ // (no change) bdata.timestamp = lba_marker_time;
+ unsigned int mycrc = crc32(0, Z_NULL, 0);
+ mycrc = crc32(mycrc, (void *)&bdata, (mybs-4));
+ bdata.crc = mycrc;
+
+ if(0 > pwrite64(myfds, (void *)&bdata, mybs, offset)) {
+ MD_LOGE("%s: write block error!(%d), %s", __func__, errno, strerror(errno));
+ return -1;
+ };
+
+ return 0;
+}
+
+static int ext4_get_next_bidx(int myfd, unsigned int *pBlock, unsigned int bbidx, unsigned int bs, unsigned int moves)
+{
+ unsigned int rlba, mycrc;
+
+ if(bbidx > MRDUMP_EXT4_LBA_PER_BLOCK)
+ return -1;
+
+ if(bbidx == MRDUMP_EXT4_LBA_PER_BLOCK) {
+ rlba = pBlock[bbidx];
+ // seek to location
+ if(-1 == ext4_block_lseek(myfd, rlba, bs)) {
+ MD_LOGE("%s: lseek64 location failed(%d), %s", __func__, errno, strerror(errno));
+ return -1;
+ }
+ // read to pBlock
+ if(0 > read(myfd, pBlock, bs)) {
+ MD_LOGE("%s: read lbaooo error!(%d), %s", __func__, errno, strerror(errno));
+ return -1;
+ }
+ // check crc32
+ mycrc = crc32(0, Z_NULL, 0);
+ mycrc = crc32(mycrc, (void *)pBlock, (bs-4));
+ if(mycrc != pBlock[1023]) {
+ MD_LOGE("%s: crc32 error!(%d), %s", __func__, errno, strerror(errno));
+ return -1;
+ }
+ bbidx = 0;
+ } else {
+ bbidx+=moves;
+ }
+ return bbidx;
+}
+
+static unsigned int ext4_num_to_join(unsigned int *pBlock, unsigned int bbidx)
+{
+ unsigned int i, j;
+ for(i=0, j=0; i<MRDUMP_EXT4_MAX_CONTINUE; i++) {
+ if((pBlock[bbidx+i] - pBlock[bbidx]) == i) {
+ j++;
+ continue;
+ }
+ break;
+ }
+ return j;
+}
+
+static int construct_a_block(int myfds, int mybs, int myloop, int myoffset, struct fiemap_info *mapinfo, unsigned int rows)
+{
+ unsigned int i, lba, num, mycrc;
+ unsigned int block[1024]; // assume max BLOCKSIZE=4096, int(4byte) for addressing
+
+ // Zero blocks
+ memset(block, 0, sizeof(block));
+
+ // number of address per block
+ // 1024 = Normal_LBA[1022] + Next_LBA + crc32
+ num = (mybs+sizeof(int)-1) / sizeof(int);
+
+ // Indexing by 0. --> (i-1)
+ // i = 1~MRDUMP_EXT4_LBA_PER_BLOCK(1022)
+ // index = 0~1021
+ i = 1;
+ while(i < (num - 1)) {
+ lba = myoffset + (i-1);
+ lba = mrdump_fiemap_get_lba_of_block(mapinfo, rows, lba);
+ if(0 > lba) {
+ MD_LOGE("%s: mrdump_fiemap_get_lba_of_block(1021) failed(%d), %s", __func__, errno, strerror(errno));
+ return -1;
+ }
+ block[(i-1)] = lba;
+ i++;
+ }
+
+ /* coverity: to avoid while(i < (num - 1)) taking false branch */
+ if (i < 2) {
+ MD_LOGE("%s: number of address per block should be more than 2\n", __func__);
+ return -1;
+ }
+
+ // i = 1023
+ // index = MRDUMP_EXT4_LBA_PER_BLOCK(1022)
+ if (block[(i-2)] == 0) {
+ // End of File
+ block[(i-1)] = 0;
+ } else {
+ // lba = (myloop+1); --> Need ++ For InfoLBA[EXT4_LBA_INFO_NUM];
+ // block starts from 2nd Block
+ lba = myloop + 2;
+ lba = mrdump_fiemap_get_lba_of_block(mapinfo, rows, lba);
+ if(0 > lba) {
+ MD_LOGE("%s: mrdump_fiemap_get_lba_of_block(1022) failed(%d), %s", __func__, errno, strerror(errno));
+ return -1;
+ }
+ block[(i-1)] = lba;
+ }
+
+ // i = 1023: crc32
+ // index = 1023: (NO block[i+1] now...)
+ // PS: index = 1023 now... i takes no changes.
+ mycrc = crc32(0, Z_NULL, 0);
+ mycrc = crc32(mycrc, (void *)block, (mybs-4));
+ block[i] = mycrc;
+
+ // Prepare to write onto the Blocks in the front ...
+ //
+ // the address (LBA) where to write on.
+ // lba = myloop; --> Need ++ For InfoLBA[EXT4_LBA_INFO_NUM];
+ lba = myloop+1;
+ lba = mrdump_fiemap_get_lba_of_block(mapinfo, rows, lba);
+ if(0 > lba) {
+ MD_LOGE("%s: mrdump_fiemap_get_lba_of_block(write) failed(%d), %s", __func__, errno, strerror(errno));
+ return -1;
+ }
+ // Write block onto location;
+ if (-1 == ext4_block_lseek(myfds, lba, mybs)) {
+ MD_LOGE("%s: lseek64 location failed(%d), %s", __func__, errno, strerror(errno));
+ return -1;
+ }
+ if(0 > write(myfds, (void *)block, sizeof(block))) {
+ MD_LOGE("%s: write block error!(%d), %s", __func__, errno, strerror(errno));
+ return -1;
+ }
+
+ // return the new offset
+ // i = 1023
+ if (block[(i-1)] == 0) {
+ myoffset = 0;
+ } else {
+ myoffset = myoffset + (i - 1);
+ }
+
+ return (int)myoffset;
+}
+
+static void mrdump_dump_pafile_info(const uint8_t lba[MRDUMP_PAF_TOTAL_SIZE])
+{
+ uint32_t version = *(uint32_t *)(lba);
+ uint32_t info_lba = *(uint32_t *)(lba + MRDUMP_PAF_INFO_LBA);
+ uint32_t addr_lba = *(uint32_t *)(lba + MRDUMP_PAF_ADDR_LBA);
+ uint64_t filesize = *(uint64_t *)(lba + MRDUMP_PAF_ALLOCSIZE);
+ uint64_t coredump_size = *(uint64_t *)(lba + MRDUMP_PAF_COREDUMPSIZE);
+ uint64_t timestamp = *(uint64_t *)(lba + MRDUMP_PAF_TIMESTAMP);
+ uint32_t crcval = *(uint64_t *)(lba + MRDUMP_PAF_CRC32);
+
+
+ MD_LOGD("PAFILE-INFO version %u info-lba %u addr-lba %u file-size %llu coredump-size %llu timestamp %llx crc %x\n",
+ version, info_lba, addr_lba, filesize, coredump_size, timestamp, crcval);
+}
+
+/* lba format
+ * 0: version (2 bytes)
+ * 2:reserved (2 bytes)
+ * 4:info lba (4 bytes)
+ * 8:addr lba (4 bytes)
+ * 12:allocate size (8 bytes)
+ * 20:coredump size (8 bytes)
+ * 28:timestamp (8 bytes)
+ * 36:CRC32 (4 bytes)
+ */
+static bool fs_lba_mark_header(const struct palloc_file *pfile)
+{
+ int num_blocks, rsv_blocks;
+ struct stat statinfo;
+ unsigned int mycrc, block;
+ uint8_t InfoLBA[MRDUMP_PAF_TOTAL_SIZE], *pinfo;
+
+ // Get file statinfo
+ if(0 > fstat(pfile->fd, &statinfo)) {
+ MD_LOGE("%s: marker stat failed(%d), %s\n", __func__, errno, strerror(errno));
+ return false;
+ }
+ // Get Blocksize and counting blocks
+ uint64_t blksize = pfile->blksize;
+
+ // Counting blocks
+ num_blocks = (statinfo.st_size + blksize - 1) / blksize;
+
+ /////////////////////////////////////////////////////
+ // Zero InfoLBA ...
+ memset(InfoLBA, 0, sizeof(InfoLBA));
+ pinfo = &InfoLBA[0];
+
+ /* Setup pafile info version */
+ *(uint16_t *)pinfo = MRDUMP_PAF_VERSION;
+
+ /* Flags */
+ *(uint16_t *)(pinfo + 2) = 0;
+
+ // Get info LBA
+ block = mrdump_fiemap_get_entry_lba(pfile->fd, blksize, 0);
+ *(uint32_t *)(pinfo + MRDUMP_PAF_INFO_LBA) = block;
+
+ // Get 2nd LBA
+ if(2 > mrdump_fiemap_get_entry_tot(pfile->fd, blksize, 0))
+ *(uint32_t *)(pinfo + MRDUMP_PAF_ADDR_LBA) = mrdump_fiemap_get_entry_lba(pfile->fd, blksize, 1);
+ else
+ *(uint32_t *)(pinfo + MRDUMP_PAF_ADDR_LBA) = block + 1;
+
+ // Reserved space for Header and Tailer
+ rsv_blocks = num_blocks/MRDUMP_EXT4_LBA_PER_BLOCK; // Header
+ rsv_blocks+= 2; // Tailer
+ *(uint64_t *)(pinfo + MRDUMP_PAF_ALLOCSIZE) = (num_blocks - rsv_blocks) * blksize;
+
+ // Set core dump size to zero
+ *(uint64_t *)(pinfo + MRDUMP_PAF_COREDUMPSIZE) = 0UL;
+
+ // Set timestamp to lba_marker_time
+ *(uint64_t *)(pinfo + MRDUMP_PAF_TIMESTAMP) = lba_marker_time;
+
+ // check crc32 of InfoLBA
+ mycrc = crc32(0, Z_NULL, 0);
+ mycrc = crc32(mycrc, (void *)InfoLBA, MRDUMP_LBA_DATAONLY);
+ *(uint32_t *)(pinfo + MRDUMP_PAF_CRC32) = mycrc;
+
+ int fd = ext4_open_device_node(MRDUMP_EXT4_MOUNT_POINT);
+ if (fd < 0) {
+ return false;
+ }
+ // Save InfoLBA First
+ if(-1 == ext4_block_lseek(fd, block, blksize)) {
+ MD_LOGE("%s: marker header lseek64 InfoLBA failed(%d), %s\n", __func__, errno, strerror(errno));
+ mrdump_close(fd);
+ return false;
+ }
+ if(0 > write(fd, (void *)InfoLBA, (sizeof(InfoLBA)))) {
+ MD_LOGE("%s: marker header write InfoLBA error!(%d), %s\n", __func__, errno, strerror(errno));
+ mrdump_close(fd);
+ return false;
+ }
+
+ mrdump_close(fd);
+ return true;
+}
+
+static bool fs_lba_mark_body(const struct palloc_file *pfile)
+{
+ int fds;
+ int i, blksize, num_blocks, loop, offset;
+ struct stat statinfo;
+
+ // Get file statinfo
+ if(0 > fstat(pfile->fd, &statinfo)) {
+ MD_LOGE("%s: marker stat failed(%d), %s\n", __func__, errno, strerror(errno));
+ return false;
+ }
+ // Get Blocksize and counting blocks
+ blksize = pfile->blksize;
+ num_blocks = (statinfo.st_size + blksize - 1) / blksize;
+
+ /////////////////////////////////////////////////////
+ // begin to record (2-layer block writing)
+ char *devicenode = mrdump_get_device_node(MRDUMP_EXT4_MOUNT_POINT);
+ if(devicenode == NULL) {
+ MD_LOGE("%s: get devicenode failed(%d), %s\n", __func__, errno, strerror(errno));
+ return false;
+ } else {
+ fds = open(devicenode, O_RDWR);
+ if(0 > fds) {
+ free(devicenode);
+ MD_LOGE("%s: open devicenode failed(%d), %s\n", __func__, errno, strerror(errno));
+ return false;
+ }
+ }
+ free(devicenode);
+
+ // for performance, we must finish fiemap here... but not in the loop
+ unsigned int my_num = mrdump_fiemap_total_entries(pfile->fd);
+ if(my_num == 0) {
+ MD_LOGE("%s: mrdump_fiemap_total_entries error!(%d), %s\n", __func__, errno, strerror(errno));
+ mrdump_close(fds);
+ return false;
+ }
+
+#ifdef MRDUMP_DEBUG
+ MD_LOGI("%s: my_num=(%06u)\n", __func__, my_num);
+#endif
+
+ struct fiemap_info *myinfo = malloc(my_num * sizeof(struct fiemap_info));
+ if(!mrdump_fiemap_get_entries(pfile->fd, blksize, myinfo, my_num)) {
+ MD_LOGE("%s: mrdump_fiemap_get_entries error!(%d), %s\n", __func__, errno, strerror(errno));
+ mrdump_close(fds);
+ return false;
+ }
+
+#ifdef MRDUMP_DEBUG
+ for(i=0; i<(int)my_num; i++) {
+ MD_LOGI("%s: i=%03d, LBA=%06u, TOT=%06u\n", __func__, i, myinfo[i].lba, myinfo[i].tot);
+ }
+#endif
+
+ // go
+ loop = (blksize / sizeof(unsigned int)) - 2;
+ loop = (num_blocks + loop - 1) / loop;
+#ifdef MRDUMP_DEBUG
+ MD_LOGI("%s: num_blocks=%d, my_num=%u\n", __func__, num_blocks, my_num);
+#endif
+ offset = loop + 1;
+ for(i=0; i<loop; i++) {
+ offset = construct_a_block(fds, blksize, i, offset, myinfo, my_num);
+ if (offset == -1) {
+ MD_LOGE("%s: marker construct block error!(%d), %s\n", __func__, errno, strerror(errno));
+ mrdump_close(fds);
+ free(myinfo);
+ return false;
+ }
+ }
+ mrdump_close(fds);
+ free(myinfo);
+ return true;
+}
+
+static bool ext4_fallocate(const char *allocfile, uint64_t allocsize)
+{
+ int fd;
+
+ if((allocfile == NULL) || (allocsize == 0)) {
+ MD_LOGE("%s: allocfile is NULL or allocsize = %" PRIu64 "\n", __func__, allocsize);
+ return false;
+ }
+
+ while(!mrdump_file_is_exist(AE_DUMPSYS_DATA_PATH)) {
+ MD_LOGI("%s: wait until %s ready.\n", __func__, AE_DUMPSYS_DATA_PATH);
+ sleep(1);
+ }
+
+ if(mount_as_f2fs(MRDUMP_EXT4_MOUNT_POINT)) {
+
+ allocsize = ((allocsize + F2FS_MAPSIZE - 1) / F2FS_MAPSIZE) * F2FS_MAPSIZE;
+ if(!f2fs_fallocate(allocfile, allocsize)) {
+ MD_LOGE("%s: f2fs_fallocate failed (allocfile=%s, allocsize=%" PRIu64 ")\n", __func__, allocfile, allocsize);
+ return false;
+ }
+
+ fd = open(allocfile, O_RDONLY);
+ if(0 > fd) {
+ MD_LOGE("%s: open fd failed.\n", __func__);
+ return false;
+ }
+
+ unsigned int val = 1234;
+ if(0 > ioctl(fd, F2FS_IOC_GET_PIN_FILE , &val)) {
+ MD_LOGE("%s: F2FS_IOC_GET_PIN_FILE(%u) failed(%d), %s\n", __func__, val, errno, strerror(errno));
+ }
+ MD_LOGI("%s: file(%s:%" PRIu64 ") Skip GC (%u times)\n", __func__, allocfile, allocsize, val);
+
+ mrdump_close(fd);
+
+ } else {
+
+ fd = open(allocfile, O_RDWR | O_CREAT, 0400);
+ if(0 > fd) {
+ MD_LOGE("%s: open allocfile failed(%d), %s\n", __func__, errno, strerror(errno));
+ return false;
+ }
+
+#if (!__LP64__)
+ uint32_t low = allocsize & 0xffffffff;
+ uint32_t high = allocsize >> 32;
+
+ if(0 > syscall(__NR_fallocate, fd, 0, 0, 0, low, high)) {
+ MD_LOGE("%s: fallocate32 failed(allocfile=%s, allocsize=%" PRIu64 ")\n", __func__, allocfile, allocsize);
+ mrdump_close(fd);
+ unlink(allocfile);
+ return false;
+ }
+#else
+ if(0 > syscall(__NR_fallocate, fd, 0, 0, allocsize)) {
+ MD_LOGE("%s: fallocate64 failed(allocfile=%s, allocsize=%" PRIu64 ")\n", __func__, allocfile, allocsize);
+ mrdump_close(fd);
+ unlink(allocfile);
+ return false;
+ }
+#endif
+ mrdump_close(fd);
+ }
+
+ return true;
+}
+
+static bool palloc_file_remove(const char *allocfile)
+{
+ /* Ignore attribute setting failed */
+ fop_file_write_string(MRDUMP_EXT4_PARA_LBAOOO, "0");
+
+ if (mrdump_file_is_exist(allocfile)) {
+ ext4_setup_attr(allocfile, false);
+ if (unlink(allocfile) != 0) {
+ MD_LOGE("%s: Cannot unlink %s(%d), %s\n", __func__, allocfile, errno, strerror(errno));
+ return false;
+ }
+ }
+ return true;
+}
+
+static bool mrdump_read_pafile_info(const struct palloc_file *pfile, int device_fd,
+ struct mrdump_pafile_info *info)
+{
+ memset(info, 0, sizeof(struct mrdump_pafile_info));
+
+ uint8_t block0[MRDUMP_PAF_TOTAL_SIZE];
+ memset(block0, 0, sizeof(block0));
+
+ if (-1 == ext4_block_lseek(device_fd, pfile->lbaooo, pfile->blksize)) {
+ MD_LOGE("%s: lseek64 InfoLBA failed(%d), %s\n", __func__, errno, strerror(errno));
+ return false;
+ }
+
+ if (0 > read(device_fd, block0, sizeof(block0))) {
+ MD_LOGE("%s: read InfoLBA error (%d), %s\n", __func__, errno, strerror(errno));
+ return false;
+ }
+
+ uint8_t *bufp = &block0[0];
+ unsigned int crcval = crc32(0, Z_NULL, 0);
+ crcval = crc32(crcval, (void *)block0, MRDUMP_LBA_DATAONLY);
+ if (crcval != *(uint32_t *)&block0[MRDUMP_PAF_CRC32]) {
+ MD_LOGE("%s: LBA info CRC error (c:%08x, v:%08x)\n", __func__, crcval,
+ *(uint32_t *)&block0[MRDUMP_PAF_CRC32]);
+ return false;
+ }
+
+ uint16_t version = *(uint16_t *)&block0[0];
+ if (version != MRDUMP_PAF_VERSION) {
+ MD_LOGE("%s: LBA version mismatch (c:%d, v:%d)\n", __func__, MRDUMP_PAF_VERSION, version);
+ mrdump_dump_pafile_info(block0);
+ return false;
+ }
+ info->info_lba = *(uint32_t *)(bufp + MRDUMP_PAF_INFO_LBA);
+ info->addr_lba = *(uint32_t *)(bufp + MRDUMP_PAF_ADDR_LBA);
+ info->filesize = *(uint64_t *)(bufp + MRDUMP_PAF_ALLOCSIZE);
+ info->coredump_size = *(uint64_t *)(bufp + MRDUMP_PAF_COREDUMPSIZE);
+ info->timestamp = *(uint64_t *)(bufp + MRDUMP_PAF_TIMESTAMP);
+ return true;
+}
+
+static bool mark_data_block(const struct palloc_file *pfile)
+{
+ int fds, fdd; /* fd of src and dst */
+ int i, j, blksize, num_blocks, loop;
+ struct stat statinfo;
+ unsigned int lba, BlockLBA[1024];
+
+ // Get file statinfo
+ if(0 > fstat(pfile->fd, &statinfo)) {
+ MD_LOGE("%s: marker stat failed(%d), %s\n", __func__, errno, strerror(errno));
+ return false;
+ }
+ // Get Blocksize and counting blocks
+ blksize = pfile->blksize;
+ num_blocks = (statinfo.st_size + blksize - 1) / blksize;
+
+ /////////////////////////////////////////////////////
+ // begin to record (2-layer block writing)
+ char *devicenode = mrdump_get_device_node(MRDUMP_EXT4_MOUNT_POINT);
+ if(devicenode == NULL) {
+ MD_LOGE("%s: get devicenode failed(%d), %s\n", __func__, errno, strerror(errno));
+ return false;
+ } else {
+ fds = open(devicenode, O_RDONLY);
+ if(0 > fds) {
+ free(devicenode);
+ MD_LOGE("%s: open devicenode failed(%d), %s\n", __func__, errno, strerror(errno));
+ return false;
+ }
+ fdd = open(devicenode, O_WRONLY);
+ if(0 > fdd) {
+ mrdump_close(fds);
+ free(devicenode);
+ MD_LOGE("%s: open devicenode failed(%d), %s\n", __func__, errno, strerror(errno));
+ return false;
+ }
+ }
+ free(devicenode);
+
+ // Check each Block (Now: InfoLBA + Address Block)
+ // 1. InfoLBA blocks
+ struct mrdump_pafile_info info;
+ if (!mrdump_read_pafile_info(pfile, fds, &info)) {
+ mrdump_close(fds);
+ mrdump_close(fdd);
+ return false;
+ }
+
+ // go for Address Area
+ bool stop_here = false;
+ lba = (unsigned int)info.addr_lba;
+ bdata.timestamp = info.timestamp;
+ loop = (blksize / sizeof(unsigned int)) - 2; // 1022
+ loop = (num_blocks + loop - 1) / loop; // num of blocks which Address Area really occupied
+
+ for(i=0; i<loop; i++) {
+#ifdef MRDUMMP_DEBUG
+ MD_LOGE("%s: i(%03d) loop(%03d)\n", __func__, i, loop);
+#endif
+ if(-1 == ext4_block_lseek(fds, lba, blksize)) {
+ MD_LOGE("%s: bdata lseek64 BlockLBA failed(%d), %s\n", __func__, errno, strerror(errno));
+ mrdump_close(fds);
+ mrdump_close(fdd);
+ return false;
+ }
+ if(0 > read(fds, (void *)BlockLBA, blksize)) {
+ MD_LOGE("%s: bdata read BlockLBA error!(%d), %s\n", __func__, errno, strerror(errno));
+ mrdump_close(fds);
+ mrdump_close(fdd);
+ return false;
+ }
+
+ for(j=0; j<MRDUMP_EXT4_LBA_PER_BLOCK; j++) {
+ lba = BlockLBA[j];
+
+ if(lba == 0)
+ stop_here = true;
+
+ if(format_a_data_block(fdd, blksize, lba) < 0) {
+ MD_LOGE("%s: format_data_block error! j=%d (%d), %s\n", __func__, j, errno, strerror(errno));
+ mrdump_close(fds);
+ mrdump_close(fdd);
+ return false;
+ }
+ }
+ lba = BlockLBA[j];
+
+ if(stop_here)
+ break;
+ }
+ mrdump_close(fds);
+ mrdump_close(fdd);
+ return true;
+}
+
+static bool fs_lba_maker(const struct palloc_file *pfile, bool need_to_reinit)
+{
+#ifdef MRDUMP_DEBUG
+ MD_LOGI("%s start... need_to_reinit=(%d)\n", __func__, need_to_reinit);
+#endif
+
+ if (pfile == NULL)
+ MD_LOGE("%s pfile is null.\n", __func__);
+ else
+ MD_LOGE("%s pfile is not null.\n", __func__);
+
+ if (need_to_reinit) {
+ lba_marker_time = (uint64_t)time(NULL);
+ MD_LOGI("%s: lba_marker_time(%llx)\n", __func__, lba_marker_time);
+
+ if (!fs_lba_mark_header(pfile)) {
+ MD_LOGE("%s: mark header failed(%d), %s\n", __func__, errno, strerror(errno));
+ return false;
+ }
+
+ if (!fs_lba_mark_body(pfile)) {
+ MD_LOGE("%s: mark body failed(%d), %s\n", __func__, errno, strerror(errno));
+ return false;
+ }
+ }
+
+ if (MRDUMP_DATA_FS_F2FS == mrdump_get_data_os()) {
+ if(!mark_data_block(pfile)) {
+ MD_LOGE("%s: mark data block failed(%d), %s\n", __func__, errno, strerror(errno));
+ return false;
+ }
+ }
+
+ sync();
+#ifdef MRDUMP_DEBUG
+ MD_LOGI("%s end...\n", __func__);
+#endif
+ return true;
+}
+
+static struct palloc_file *ext4_new_fallocfile(const char *allocfile, uint64_t allocsize)
+{
+ uint64_t psize = mrdump_get_partition_free_size(MRDUMP_EXT4_MOUNT_POINT);
+ if (psize < (allocsize + MRDUMP_REST_SPACE)) {
+ MD_LOGE("Error: Partition %s has no enough free space(%" PRIu64 "MB), allocate size %" PRIu64 "MB\n",
+ MRDUMP_EXT4_MOUNT_POINT, psize / (1024 * 1024), allocsize / (1024 * 1024));
+ return NULL;
+ }
+
+ if (!ext4_fallocate(allocfile, allocsize)) {
+ MD_LOGE("%s: new fallocate failed(%d), %s\n", __func__, errno, strerror(errno));
+ return NULL;
+ }
+
+ if (!ext4_setup_attr(allocfile, true)) {
+ MD_LOGE("%s: ext4_setup_attr failed(%d), %s\n", __func__, errno, strerror(errno));
+ return NULL;
+ }
+
+ struct palloc_file *pfile = palloc_file_open(allocfile);
+ if (pfile == NULL) {
+ MD_LOGE("%s: palloc_file_open failed(%d), %s\n", __func__, errno, strerror(errno));
+ return NULL;
+ }
+
+ if (!fs_lba_maker(pfile, true)) {
+ palloc_file_close(pfile);
+ MD_LOGE("%s: lba marker failed(%d), %s\n", __func__, errno, strerror(errno));
+ return NULL;
+ }
+
+ // sync when finish lba_marker in new_fallocate.
+ sync();
+
+ return pfile;
+}
+
+static int ext4_bdata_is_ok(const struct palloc_file *pfile)
+{
+ int fds, num_blocks, j;
+ struct stat statinfo;
+ unsigned int mycrc, BlockLBA[1024];
+ unsigned int i;
+ bool stop_here = false;
+
+ // Get file statinfo
+ if(0 > fstat(pfile->fd, &statinfo)) {
+ MD_LOGE("%s: bdata stat failed(%d), %s\n", __func__, errno, strerror(errno));
+ return BDATA_STATE_FILE_ACCESS_ERROR;
+ }
+
+ // Counting blocks
+ num_blocks = (statinfo.st_size + statinfo.st_blksize - 1) / statinfo.st_blksize;
+ num_blocks = (num_blocks + MRDUMP_EXT4_LBA_PER_BLOCK - 1) / MRDUMP_EXT4_LBA_PER_BLOCK;
+
+ // open
+ char *devicenode = mrdump_get_device_node(MRDUMP_EXT4_MOUNT_POINT);
+ if(devicenode == NULL) {
+ MD_LOGE("%s: get devicenode failed(%d), %s\n", __func__, errno, strerror(errno));
+ return BDATA_STATE_FILE_ACCESS_ERROR;
+ } else {
+ fds = open(devicenode, O_RDWR);
+ if(0 > fds) {
+ free(devicenode);
+ MD_LOGE("%s: open devicenode failed(%d), %s\n", __func__, errno, strerror(errno));
+ return BDATA_STATE_FILE_ACCESS_ERROR;
+ }
+ }
+ free(devicenode);
+
+ // Check each Block (Now: InfoLBA + Address Block)
+ // 1. InfoLBA blocks
+ struct mrdump_pafile_info info;
+ if (!mrdump_read_pafile_info(pfile, fds, &info)) {
+ mrdump_close(fds);
+ return BDATA_STATE_BLOCK_HEADER_ERROR;
+ }
+
+ //get timestamp
+ bdata.timestamp = info.timestamp;
+
+ // for performance, we must finish fiemap here... but not in the loop
+ unsigned int my_num = mrdump_fiemap_total_entries(pfile->fd);
+ if(my_num == 0) {
+ MD_LOGE("%s: mrdump_fiemap_total_entries error!(%d), %s\n", __func__, errno, strerror(errno));
+ mrdump_close(fds);
+ return BDATA_STATE_BLOCK_HEADER_ERROR;
+ }
+ struct fiemap_info *myinfo = malloc(my_num * sizeof(struct fiemap_info));
+ if(!mrdump_fiemap_get_entries(pfile->fd, pfile->blksize, myinfo, my_num)) {
+ MD_LOGE("%s: mrdump_fiemap_get_entries error!(%d), %s\n", __func__, errno, strerror(errno));
+ mrdump_close(fds);
+ return BDATA_STATE_BLOCK_HEADER_ERROR;
+ }
+
+ // 2. Address Block sector wait until patch in lk
+
+ if (mount_as_ext4(MRDUMP_EXT4_MOUNT_POINT) && info.coredump_size == ULLONG_MAX) {
+ MD_LOGE("coredump size is incorrect\n");
+ return BDATA_STATE_BLOCK_DATA_ERROR;
+ }
+ for (i=1; i<(unsigned int)num_blocks; i++) {
+ unsigned int lba = (unsigned int)mrdump_fiemap_get_lba_of_block(myinfo, my_num, i);
+ if(-1 == ext4_block_lseek(fds, lba, pfile->blksize)) {
+ MD_LOGE("%s: bdata lseek64 BlockLBA failed(%d), %s\n", __func__, errno, strerror(errno));
+ free(myinfo);
+ mrdump_close(fds);
+ return BDATA_STATE_BLOCK_HEADER_ERROR;
+ }
+ if(0 > read(fds, (void *)BlockLBA, pfile->blksize)) {
+ MD_LOGE("%s: bdata read BlockLBA error!(%d), %s\n", __func__, errno, strerror(errno));
+ free(myinfo);
+ mrdump_close(fds);
+ return BDATA_STATE_BLOCK_HEADER_ERROR;
+ }
+ mycrc = crc32(0, Z_NULL, 0);
+ mycrc = crc32(mycrc, (void *)BlockLBA, (pfile->blksize-4));
+ if (mycrc != BlockLBA[1023]) {
+ MD_LOGE("%s: bdata BlockLBA %d CRC error(%08x, %08x)\n", __func__, i, mycrc, BlockLBA[1023]);
+ free(myinfo);
+ mrdump_close(fds);
+ return BDATA_STATE_BLOCK_HEADER_ERROR;
+ }
+ }
+ // data block vaildation for F2FS
+ if (mount_as_f2fs(MRDUMP_EXT4_MOUNT_POINT) && info.coredump_size == ULLONG_MAX) {
+ for(i=1; i<(unsigned int)num_blocks; i++) {
+ unsigned int lba = (unsigned int)mrdump_fiemap_get_lba_of_block(myinfo, my_num, i);
+ if(-1 == ext4_block_lseek(fds, lba, pfile->blksize)) {
+ MD_LOGE("%s: bdata lseek64 BlockLBA failed(%d), %s\n", __func__, errno, strerror(errno));
+ mrdump_close(fds);
+ return BDATA_STATE_BLOCK_DATA_ERROR;
+ }
+ if(0 > read(fds, (void *)BlockLBA, pfile->blksize)) {
+ MD_LOGE("%s: bdata read BlockLBA error!(%d), %s\n", __func__, errno, strerror(errno));
+ mrdump_close(fds);
+ return BDATA_STATE_BLOCK_DATA_ERROR;
+ }
+
+ for(j=0; j<MRDUMP_EXT4_LBA_PER_BLOCK; j++) {
+ lba = BlockLBA[j];
+
+ if(lba == 0)
+ stop_here = true;
+
+ if(check_a_data_block(fds, pfile->blksize, lba) < 0) {
+ MD_LOGE("%s: format_data_block error! j=%d \n", __func__, j);
+ mrdump_close(fds);
+ return BDATA_STATE_BLOCK_DATA_ERROR;
+ }
+ }
+ lba = BlockLBA[j];
+
+ if(stop_here)
+ break;
+ }
+ }
+
+ mrdump_close(fds);
+ free(myinfo);
+ return BDATA_STATE_CHECK_PASS;
+}
+
+////////////////////////////////////////////
+// export function (extern of other files)//
+////////////////////////////////////////////
+
+bool mrdump_file_get_info(const char *allocfile, struct mrdump_pafile_info *info)
+{
+ struct palloc_file *pfile = palloc_file_open(allocfile);
+ if (pfile == NULL) {
+ return false;
+ }
+ int device_fd = ext4_open_device_node(MRDUMP_EXT4_MOUNT_POINT);
+ if (device_fd < 0) {
+ palloc_file_close(pfile);
+ return false;
+ }
+ bool retval = mrdump_read_pafile_info(pfile, device_fd, info);
+ palloc_file_close(pfile);
+ mrdump_close(device_fd);
+ return retval;
+}
+
+static uint64_t ext4_default_filesize(int memsize)
+{
+ int ret = 0;
+ FILE *fp;
+ char c, myline[1024];
+ char *delim="\x09\x20";
+ uint64_t MySize;
+
+ fp = fopen("/proc/meminfo", "r");
+ if(fp == NULL)
+ return ret;
+
+ while(!feof(fp)) {
+
+ // getline
+ ret = fscanf(fp, "%[^\n]", myline);
+
+ // strtok strings
+ MySize = 0;
+ if(ret > 0) {
+ char *mystr = strtok(myline, delim);
+ if(mystr != NULL) {
+ if(!strcmp(mystr, "MemTotal:")) {
+ mystr = strtok(NULL, delim);
+ if(mystr != NULL) {
+ MySize = atol(mystr);
+ }
+ break;
+ }
+ }
+ }
+
+ /* clear newline character */
+ ret = fscanf(fp, "%c", &c);
+ if (ret != 1) {
+ MD_LOGE("%s: not EOL.", __func__);
+ fclose(fp);
+ break;
+ }
+ }
+ fclose(fp);
+
+ // Count proper MySize about half size of MemTotal;
+ ret = ((MySize*1000) + (1000*1000) - 1)/(1000000);
+ if(memsize == DEFAULT_HALFMEM)
+ ret/= 2;
+ MySize = (uint64_t)ret*1024*1024;
+
+ return (MySize);
+}
+
+uint64_t mrdump_file_default_filesize(void)
+{
+ uint64_t fsize = 0;
+ int f_mem = USERDEFINED_MEM;
+ const char *mrdump_allocate_size = sysenv_get("mrdump_allocate_size");
+
+printf("mrdump_allocate_size = %s\n", mrdump_allocate_size);
+ if ((mrdump_allocate_size == NULL) || !strncmp(mrdump_allocate_size, "fullmem", 7)) {
+ fsize = ext4_default_filesize(DEFAULT_FULLMEM);
+ f_mem = DEFAULT_FULLMEM;
+ }
+ else if ((!strncmp(mrdump_allocate_size, "0", 1))) {
+ fsize = 0;
+ f_mem = DEFAULT_DISABLE;
+ }
+ else if (!strncmp(mrdump_allocate_size, "halfmem", 7)) {
+ fsize = ext4_default_filesize(DEFAULT_HALFMEM);
+ f_mem = DEFAULT_HALFMEM;
+ }
+ // nnn or others
+ else if(f_mem == USERDEFINED_MEM) {
+ int value = atoi(mrdump_allocate_size);
+ if(value > 0) {
+ fsize = (uint64_t)value*1024*1024;
+ }
+ else {
+ fsize = 0;
+ }
+ }
+
+ return fsize;
+}
+
+////////////////////////////////////////////
+// User API //
+////////////////////////////////////////////
+static bool mrdump_ext4_reinit_allocfile(const char *allocfile, uint64_t realsize, bool reset)
+{
+ int check_state = 0;
+
+ /* pre-allocate only in internal-storage:ext4 */
+ const char *output_dev = sysenv_get("mrdump_output");
+ MD_LOGI("%s: output-dev(%s)\n", __func__, output_dev);
+ if ((output_dev != NULL) && (strcmp(output_dev, "internal-storage") != 0)) {
+ palloc_file_remove(allocfile);
+ return false;
+ }
+
+ if (realsize > 0) {
+ struct palloc_file *pfile = NULL;
+ if (!mrdump_file_is_exist(allocfile)) {
+ pfile = ext4_new_fallocfile(allocfile, realsize);
+ if (pfile == NULL) {
+ MD_LOGE("%s: fallocate failed at new creation.\n", __func__);
+ return false;
+ }
+ } else {
+ pfile = palloc_file_open(allocfile);
+ if (pfile == NULL) {
+ MD_LOGE("%s: palloc_file_open failed.\n", __func__);
+ goto cleanup;
+ }
+
+ // existed allocate
+ // Check Block Data validity
+ check_state = ext4_bdata_is_ok(pfile);
+ if ((check_state == BDATA_STATE_FILE_ACCESS_ERROR) || (check_state == BDATA_STATE_BLOCK_HEADER_ERROR)) {
+ MD_LOGI("%s: Address Blocks checked: incorrect.\n", __func__);
+ palloc_file_close(pfile);
+ palloc_file_remove(allocfile);
+ pfile = ext4_new_fallocfile(allocfile, realsize);
+ if (pfile == NULL) {
+ MD_LOGE("%s: Address Blocks not correct, re-fallocate.\n", __func__);
+ return false;
+ }
+ } else if (check_state == BDATA_STATE_BLOCK_DATA_ERROR) {
+ MD_LOGE("BlockData Verification failed\n");
+ if (!fs_lba_maker(pfile, true)) {
+ MD_LOGE("%s: lba marker failed, removing pre-allocate-file.\n", __func__);
+ palloc_file_close(pfile);
+ goto cleanup;
+ }
+ } else {
+ MD_LOGI("%s: Address Blocks checked: correct.\n", __func__);
+ if (reset) {
+ if (!fs_lba_maker(pfile, true)) {
+ MD_LOGE("%s: lba marker failed, removing pre-allocate-file.\n", __func__);
+ palloc_file_close(pfile);
+ goto cleanup;
+ }
+ }
+ }
+ }
+
+ int retval = fop_file_write_string(MRDUMP_EXT4_PARA_LBAOOO, "%u\n", (unsigned int) pfile->lbaooo);
+ if (retval < 0) {
+ MD_LOGE("%s: write %s failed(%d), %s\n", __func__, MRDUMP_EXT4_PARA_LBAOOO,
+ -retval, strerror(-retval));
+ palloc_file_close(pfile);
+ goto cleanup;
+ }
+ palloc_file_close(pfile);
+ MD_LOGI("%s: LBAOOO ready\n", __func__);
+ return true;
+ }
+ MD_LOGI("Allocate size %llx set to zero, remove preallocate file\n", realsize);
+ cleanup:
+ palloc_file_remove(allocfile);
+ return false;
+}
+
+bool mrdump_file_fetch_zip_coredump(const char *outfile)
+{
+ struct mrdump_pafile_info lbainfo;
+ unsigned int blknum;
+ unsigned int rlba, bidx, BlockLBA[1024];
+ unsigned int len, mylen;
+ unsigned char MyData[MRDUMP_EXT4_EXSPACE];
+ int fpRead, fpWrite, ret;
+
+ // outfile
+ if(outfile == NULL) {
+ MD_LOGE("%s: outfile is NULL! (%d), %s\n", __func__, errno, strerror(errno));
+ return false;
+ }
+
+ struct palloc_file *pfile = palloc_file_open(MRDUMP_EXT4_ALLOCATE_FILE);
+ if (pfile == 0) {
+ return false;
+ }
+
+ fpRead = ext4_open_device_node(MRDUMP_EXT4_MOUNT_POINT);
+ if (fpRead < -1) {
+ goto cleanup0;
+ }
+
+ if (!mrdump_read_pafile_info(pfile, fpRead, &lbainfo)) {
+ mrdump_close(fpRead);
+ goto cleanup0;
+ }
+ if (lbainfo.coredump_size == 0) {
+ MD_LOGI("Ramdump size is 0, no data to dump\n");
+ mrdump_close(fpRead);
+ goto cleanup0;
+ }
+
+ // Write handle
+ fpWrite = open(outfile, O_RDWR | O_CREAT | O_TRUNC, 0600);
+ if(0 > fpWrite) {
+ MD_LOGE("%s: open Write handle open failed(%d), %s\n", __func__, errno, strerror(errno));
+ mrdump_close(fpRead);
+ goto cleanup0;
+ }
+
+ // Init BlockLBA
+ rlba = lbainfo.addr_lba;
+ if(-1 == ext4_block_lseek(fpRead, rlba, pfile->blksize)) {
+ MD_LOGE("%s: lseek64 Init BlockLBA failed(%d), %s\n", __func__, errno, strerror(errno));
+ mrdump_close(fpRead);
+ mrdump_close(fpWrite);
+ unlink(outfile);
+ goto cleanup0;
+ }
+ if(0 > read(fpRead, BlockLBA, sizeof(BlockLBA))) {
+ MD_LOGE("%s: fetch read BlockLBA error!(%d), %s\n", __func__, errno, strerror(errno));
+ mrdump_close(fpRead);
+ mrdump_close(fpWrite);
+ unlink(outfile);
+ goto cleanup0;
+ }
+
+ // Fetching data
+ bidx = 0;
+ rlba = BlockLBA[bidx];
+
+ uint64_t delaylen = 0;
+ uint64_t coresize = lbainfo.coredump_size;
+ while(coresize > 0) {
+
+ // counting coutinue datas...
+ blknum = ext4_num_to_join((unsigned int *)BlockLBA, bidx);
+ len = blknum * pfile->blksize;
+ if(coresize < len) {
+ mylen = coresize;
+ } else {
+ mylen = len;
+ }
+
+ // Reading data to MyData
+ if(-1 == ext4_block_lseek(fpRead, rlba, pfile->blksize)) {
+ MD_LOGE("%s: lseek64 Read MyData failed(%d), %s", __func__, errno, strerror(errno));
+ mrdump_close(fpRead);
+ mrdump_close(fpWrite);
+ unlink(outfile);
+ goto cleanup0;
+ }
+ if(0 > read(fpRead, MyData, mylen)) {
+ MD_LOGE("%s: fetch MyData error!(%d), %s", __func__, errno, strerror(errno));
+ mrdump_close(fpRead);
+ mrdump_close(fpWrite);
+ unlink(outfile);
+ goto cleanup0;
+ }
+ if(0 > write(fpWrite, MyData, mylen)) {
+ MD_LOGE("%s: fetch MyData error!(%d), %s", __func__, errno, strerror(errno));
+ mrdump_close(fpRead);
+ mrdump_close(fpWrite);
+ unlink(outfile);
+ goto cleanup0;
+ }
+
+ ret = ext4_get_next_bidx(fpRead, (unsigned int *)BlockLBA, bidx, pfile->blksize, blknum);
+ if(ret < 0){
+ MD_LOGE("%s: fpRead failed to get next block idx(%d), %s", __func__, errno, strerror(errno));
+ mrdump_close(fpRead);
+ mrdump_close(fpWrite);
+ unlink(outfile);
+ goto cleanup0;
+ }
+ bidx = (unsigned int)ret;
+
+ if(bidx > MRDUMP_EXT4_LBA_PER_BLOCK) {
+ mrdump_close(fpRead);
+ mrdump_close(fpWrite);
+ unlink(outfile);
+ goto cleanup0;
+ }
+ if(bidx == MRDUMP_EXT4_LBA_PER_BLOCK) {
+ ret = ext4_get_next_bidx(fpRead, (unsigned int *)BlockLBA, bidx, pfile->blksize, blknum);
+ if(ret < 0) {
+ MD_LOGE("%s: bidx(1022) failed to get next block idx(%d), %s", __func__, errno, strerror(errno));
+ mrdump_close(fpRead);
+ mrdump_close(fpWrite);
+ unlink(outfile);
+ goto cleanup0;
+ }
+ bidx = (unsigned int)ret;
+ }
+ rlba = BlockLBA[bidx];
+ coresize -= mylen;
+
+ /* flow control */
+ delaylen += mylen;
+ if (delaylen >= MRDUMP_MAX_BANDWIDTH) {
+ delaylen = 0;
+ fdatasync(fpWrite);
+ sleep(1);
+ }
+ }
+
+ mrdump_close(fpRead);
+ mrdump_close(fpWrite);
+
+ MD_LOGI("Ramdump write to %s size %" PRId64 "\n", outfile, lbainfo.coredump_size);
+ return true;
+
+ cleanup0:
+ palloc_file_close(pfile);
+ return false;
+}
+
+void mrdump_file_set_maxsize(int mrdump_size)
+{
+ palloc_file_remove(MRDUMP_EXT4_ALLOCATE_FILE);
+
+ char s[64];
+ uint64_t fsize = 0;
+
+ if(mrdump_size < 0)
+ mrdump_size = 0;
+
+ switch(mrdump_size) {
+ case DEFAULT_DISABLE:
+ sysenv_set("mrdump_allocate_size", "0");
+ fsize = 0;
+ break;
+ case DEFAULT_HALFMEM:
+ sysenv_set("mrdump_allocate_size", "halfmem");
+ fsize = mrdump_file_default_filesize();
+ break;
+ case DEFAULT_FULLMEM:
+ sysenv_set("mrdump_allocate_size", "fullmem");
+ fsize = mrdump_file_default_filesize();
+ break;
+ default:
+ snprintf(s, sizeof(s), "%d", mrdump_size);
+ sysenv_set("mrdump_allocate_size", s);
+ fsize = (uint64_t)mrdump_size*1024*1024;
+ break;
+ }
+
+ if (mrdump_ext4_reinit_allocfile(MRDUMP_EXT4_ALLOCATE_FILE, fsize, true)) {
+ printf("set MT-RAMDUMP allocated file size => %" PRIu64 " MB].\n", (fsize/1024/1024));
+ }
+}
+
+/* System startup setup
+ * Sanity check
+ * 1. Check if /data partition filesystem is supported
+ * 2. Check if lk/kernel MT-RAMDUMP support is enabled
+ * 3. Check if mrdump file size is set to non-zero
+ * If above condition is failed, remove pre-allocated file and disable MRDUMP.
+ * Try to pre-allocated file
+ * 1. If file doesn't exist, create a new file
+ * 2. If file exist and header/body corrupted, re-create a new file
+ */
+void mrdump_file_setup(bool reset)
+{
+ /* check if mount as ext4 partition or f2fs */
+ if(MRDUMP_DATA_FS_NONE == mrdump_get_data_os()) {
+ MD_LOGE("Unsupport file system type.");
+ return;
+ }
+
+ if (!mrdump_is_supported()) {
+ MD_LOGE("MRDUMP is not supported\n");
+ palloc_file_remove(MRDUMP_EXT4_ALLOCATE_FILE);
+ return;
+ }
+
+ mrdump_ext4_reinit_allocfile(MRDUMP_EXT4_ALLOCATE_FILE, mrdump_file_default_filesize(), reset);
+}
diff --git a/src/devtools/mrdump/mrdump_tool_source/mrdump_support_ext4.h b/src/devtools/mrdump/mrdump_tool_source/mrdump_support_ext4.h
new file mode 100644
index 0000000..eb05c11
--- /dev/null
+++ b/src/devtools/mrdump/mrdump_tool_source/mrdump_support_ext4.h
@@ -0,0 +1,80 @@
+#pragma once
+
+/* debug on/off */
+#define MRDUMP_DEBUG
+
+/* for statfs */
+#define EXT3_SUPER_MAGIC 0xEF53
+
+/* Variables defined */
+#define AE_DUMPSYS_DATA_PATH "/log/mtklog"
+#define MRDUMP_EXT4_NEW_FILE true
+#define MRDUMP_EXT4_OLD_FILE false
+#define MRDUMP_EXT4_PARA_LBAOOO "/sys/module/mrdump/parameters/lbaooo"
+#define MRDUMP_EXT4_PROC_MOUNTS "/proc/self/mounts"
+//#define MRDUMP_EXT4_MOUNT_POINT "/data"
+#define MRDUMP_EXT4_MOUNT_POINT "/log"
+#define MRDUMP_EXT4_ALLOCATE_FILE AE_DUMPSYS_DATA_PATH"/mrdump_preallocated"
+#define MRDUMP_EXT4_MIN_ALLOCATE 256
+#define MRDUMP_EXT4_BLKSIZE 4096
+#define MRDUMP_EXT4_MAX_CONTINUE 64
+#define MRDUMP_EXT4_EXSPACE (MRDUMP_EXT4_BLKSIZE*MRDUMP_EXT4_MAX_CONTINUE)
+#define MRDUMP_EXT4_LBA_PER_BLOCK 1022
+
+/*
+ * v1: support allocate size > 4G
+ * v2: support timestamp
+ */
+#define MRDUMP_PAF_VERSION 0x0002
+
+#define MRDUMP_PAF_INFO_LBA 4
+#define MRDUMP_PAF_ADDR_LBA 8
+#define MRDUMP_PAF_ALLOCSIZE 12
+#define MRDUMP_PAF_COREDUMPSIZE 20
+#define MRDUMP_PAF_TIMESTAMP 28
+#define MRDUMP_PAF_CRC32 36
+#define MRDUMP_LBA_DATAONLY MRDUMP_PAF_CRC32
+#define MRDUMP_PAF_TOTAL_SIZE 40
+
+typedef enum {
+ DEFAULT_DISABLE,
+ DEFAULT_HALFMEM,
+ DEFAULT_FULLMEM,
+ USERDEFINED_MEM
+} MRDUMP_DEFAULT_SIZE;
+
+typedef enum {
+ BDATA_STATE_CHECK_PASS,
+ BDATA_STATE_FILE_ACCESS_ERROR,
+ BDATA_STATE_BLOCK_HEADER_ERROR,
+ BDATA_STATE_BLOCK_DATA_ERROR,
+} MRDUMP_BDATA_STATE;
+
+/* for chattr */
+#define FS_IOC_GETFLAGS _IOR('f', 1, long)
+#define FS_IOC_SETFLAGS _IOW('f', 2, long)
+#define FS_SECRM_FL 0x00000001 /* Secure deletion */
+#define FS_IMMUTABLE_FL 0x00000010 /* Immutable file */
+
+struct mrdump_pafile_info {
+ uint32_t info_lba;
+ uint32_t addr_lba;
+ uint64_t filesize;
+ uint64_t coredump_size;
+ uint64_t timestamp;
+};
+
+struct __attribute__((__packed__)) marked_block_data {
+ uint32_t lba;
+ uint64_t zero_padding[510];
+ uint64_t timestamp;
+ uint32_t crc;
+};
+
+/* Function Prototypes */
+void mrdump_file_set_maxsize(int mrdump_size);
+void mrdump_file_setup(bool reset);
+bool mrdump_file_get_info(const char *allocfile, struct mrdump_pafile_info *info);
+uint64_t mrdump_file_default_filesize(void);
+bool mrdump_file_fetch_zip_coredump(const char *outfile);
+bool mount_as_ext4(const char *mountp);
diff --git a/src/devtools/mrdump/mrdump_tool_source/mrdump_support_f2fs.c b/src/devtools/mrdump/mrdump_tool_source/mrdump_support_f2fs.c
new file mode 100644
index 0000000..dbeb418
--- /dev/null
+++ b/src/devtools/mrdump/mrdump_tool_source/mrdump_support_f2fs.c
@@ -0,0 +1,94 @@
+/* uint64_t ...*/
+#include <inttypes.h>
+#include <stdbool.h>
+
+/* statfs() */
+#include <sys/statfs.h>
+
+/* mmap, munmap */
+#include <sys/mman.h>
+
+/* fsync(), close(), write(), unlink() */
+#include <unistd.h>
+
+/* __u32 */
+#include <linux/types.h>
+
+/* ioctl */
+//#include <linux/fs.h>
+#include <sys/ioctl.h>
+
+/* struct stat, open */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+/* strerror */
+#include <string.h>
+/* errno */
+#include <errno.h>
+
+/* mrdump related */
+#include "mrdump_log.h"
+#include "mrdump_common.h"
+#include "mrdump_support_f2fs.h"
+
+bool mount_as_f2fs(const char *mountp)
+{
+ struct statfs fs;
+ if(statfs(mountp, &fs) == 0) {
+ if(fs.f_type == F2FS_SUPER_MAGIC)
+ return true;
+
+ return false;
+ }
+ MD_LOGE("%s: %s statfs error.\n", __func__, mountp);
+ return false;
+}
+
+bool f2fs_fallocate(const char *allocfile, uint64_t allocsize)
+{
+ int i;
+ int zQ = (allocsize + F2FS_MAPSIZE - 1) / F2FS_MAPSIZE;
+ unsigned int val;
+
+ if((allocfile == NULL) || (allocsize == 0)) {
+ MD_LOGE("%s: allocfile is NULL or allocsize = %" PRIu64 "\n", __func__, allocsize);
+ return false;
+ }
+
+ void *ZeroPage = mmap(NULL, F2FS_MAPSIZE, PROT_READ, MAP_ANONYMOUS | MAP_SHARED, -1, 0);
+ if(ZeroPage == NULL) {
+ MD_LOGE("%s: ZeroPage map failed.\n", __func__);
+ return false;
+ }
+
+ int fd = open(allocfile, O_RDWR | O_CREAT, 0400);
+ if(0 > fd) {
+ MD_LOGE("%s: open fd failed.\n", __func__);
+ munmap(ZeroPage, F2FS_MAPSIZE);
+ return false;
+ }
+
+ for(i=0; i<zQ; i++) {
+ if(0 >= write(fd,ZeroPage, F2FS_MAPSIZE)) {
+ MD_LOGE("%s: ZeroPage write failed\n", __func__);
+ close(fd);
+ unlink(allocfile);
+ munmap(ZeroPage, F2FS_MAPSIZE);
+ return false;
+ }
+ }
+
+ fsync(fd);
+
+ val = 31337;
+ if(0 > ioctl(fd, F2FS_IOC_SET_PIN_FILE, &val)) {
+ MD_LOGE("%s: F2FS_IOC_SET_PIN_FILE(%u) failed(%d), %s\n", __func__, val, errno, strerror(errno));
+ }
+
+ close(fd);
+ munmap(ZeroPage, F2FS_MAPSIZE);
+
+ return true;
+}
diff --git a/src/devtools/mrdump/mrdump_tool_source/mrdump_support_f2fs.h b/src/devtools/mrdump/mrdump_tool_source/mrdump_support_f2fs.h
new file mode 100644
index 0000000..8408201
--- /dev/null
+++ b/src/devtools/mrdump/mrdump_tool_source/mrdump_support_f2fs.h
@@ -0,0 +1,14 @@
+#pragma once
+
+/* Map size for ZeroPage */
+#define F2FS_SUPER_MAGIC 0xF2F52010
+#define F2FS_MAPSIZE (1024*1024*8)
+
+/* for IOCTL */
+#define F2FS_IOCTL_MAGIC 0xf5
+#define F2FS_IOC_SET_PIN_FILE _IOW(F2FS_IOCTL_MAGIC, 13, __u32)
+#define F2FS_IOC_GET_PIN_FILE _IOR(F2FS_IOCTL_MAGIC, 14, __u32)
+
+/* Function Prototypes */
+bool mount_as_f2fs(const char *mountp);
+bool f2fs_fallocate(const char *allocfile, uint64_t allocsize);
diff --git a/src/devtools/mrdump/mrdump_tool_source/mrdump_support_fiemap.c b/src/devtools/mrdump/mrdump_tool_source/mrdump_support_fiemap.c
new file mode 100644
index 0000000..9481947
--- /dev/null
+++ b/src/devtools/mrdump/mrdump_tool_source/mrdump_support_fiemap.c
@@ -0,0 +1,194 @@
+/* printf */
+#include <stdio.h>
+
+/* uint64_t ...*/
+#include <inttypes.h>
+#include <stdbool.h>
+
+/* malloc */
+#include <stdlib.h>
+
+/* ioctl, fibmap, fiemap */
+#include <linux/fs.h>
+#include <sys/ioctl.h>
+#include <linux/fiemap.h>
+
+/* strerror */
+#include <string.h>
+/* errno */
+#include <errno.h>
+
+/* mrdump related */
+#include "mrdump_log.h"
+#include "mrdump_common.h"
+#include "mrdump_support_fiemap.h"
+
+static unsigned int fiemap_total_entries(int fd)
+{
+ int is_last, rows = 0;
+
+ // Preparing for fiemap work
+ struct fiemap *fiemap = (struct fiemap *)malloc(sizeof(struct fiemap) + sizeof(struct fiemap_extent));
+ unsigned long long lstart = 0; // logical input mapping star
+#if (__LP64__)
+ unsigned long long llength = ~0ULL; // logical input mapping length
+#else
+ unsigned long long llength = 0xFFFFFFFF;
+#endif
+
+ fiemap->fm_start = lstart;
+ fiemap->fm_length = llength;
+ fiemap->fm_flags = 0;
+ fiemap->fm_extent_count = 1;
+ fiemap->fm_mapped_extents = 0; // output only
+
+ do {
+ if(0 > ioctl(fd, FS_IOC_FIEMAP, (unsigned long)fiemap)) {
+ MD_LOGE("%s: FIEMAP ioctl failed!(%d), %s\n", __func__, errno, strerror(errno));
+ return 0;
+ }
+
+ if(fiemap->fm_mapped_extents == 0) {
+ MD_LOGE("%s: FIEMAP: fm_mapped_extents = 0(%d), %s\n", __func__, errno, strerror(errno));
+ return 0;
+ }
+
+ // check if the last extent
+ is_last = fiemap->fm_extents[0].fe_flags & FIEMAP_EXTENT_LAST;
+
+ // Set up the next call arguments
+ if(!is_last) {
+ unsigned long long foo = fiemap->fm_extents[0].fe_logical + fiemap->fm_extents[0].fe_length;
+ fiemap->fm_start = foo;
+ fiemap->fm_length = lstart + llength - foo;
+ fiemap->fm_flags = 0;
+ fiemap->fm_extent_count = 1;
+ }
+
+ rows++;
+
+ } while(!is_last);
+
+ free(fiemap);
+ return rows;
+
+}
+
+static bool fiemap_get_entries(int fd, unsigned int blksize, struct fiemap_info *mapinfo, unsigned int rows)
+{
+ struct fiemap_info *myinfo = mapinfo;
+
+ // Preparing for fiemap work
+ struct fiemap *fiemap = (struct fiemap *)malloc(sizeof(struct fiemap) + sizeof(struct fiemap_extent));
+ unsigned long long lstart = 0; // logical input mapping star
+#if (__LP64__)
+ unsigned long long llength = ~0ULL; // logical input mapping length
+#else
+ unsigned long long llength = 0xFFFFFFFF;
+#endif
+
+ fiemap->fm_start = lstart;
+ fiemap->fm_length = llength;
+ fiemap->fm_flags = 0;
+ fiemap->fm_extent_count = 1;
+ fiemap->fm_mapped_extents = 0; // output only
+
+ unsigned int i, is_last;
+ for(i=0; i<rows; i++)
+ {
+ if(0 > ioctl(fd, FS_IOC_FIEMAP, (unsigned long)fiemap)) {
+ printf("%s: FIEMAP ioctl failed!(%d), %s\n", __func__, errno, strerror(errno));
+ return false;
+ }
+
+ // check if the last extent
+ is_last = fiemap->fm_extents[0].fe_flags & FIEMAP_EXTENT_LAST;
+
+ // basic parameters
+ myinfo->lba = (unsigned int)(fiemap->fm_extents[0].fe_physical/blksize);
+ myinfo->tot = (unsigned int)(fiemap->fm_extents[0].fe_length / blksize);
+
+ // Set up the next call arguments
+ if(!is_last) {
+
+ unsigned long long foo = fiemap->fm_extents[0].fe_logical + fiemap->fm_extents[0].fe_length;
+ fiemap->fm_start = foo;
+ fiemap->fm_length = lstart + llength - foo;
+ fiemap->fm_flags = 0;
+ fiemap->fm_extent_count = 1;
+ }
+ myinfo++;
+ }
+ free(fiemap);
+ return true;
+}
+
+static int fiemap_get_entry_lba(int fd, unsigned int blksize, unsigned int rows)
+{
+ unsigned int lba = 0, num = (unsigned int)fiemap_total_entries(fd);
+ if(num > 0) {
+ struct fiemap_info *myinfo = malloc(num * sizeof(struct fiemap_info));
+ if(fiemap_get_entries(fd, blksize, myinfo, num)) {
+ lba = myinfo[rows].lba;
+ free(myinfo);
+ return (int)lba;
+ }
+ free(myinfo);
+ }
+ return -1;
+}
+
+static int fiemap_get_entry_tot(int fd, unsigned int blksize, unsigned int rows)
+{
+ unsigned int tot = 0, num = (unsigned int)fiemap_total_entries(fd);
+ if(num > 0) {
+ struct fiemap_info *myinfo = malloc(num * sizeof(struct fiemap_info));
+ if(fiemap_get_entries(fd, blksize, myinfo, num)) {
+ tot = myinfo[rows].tot;
+ free(myinfo);
+ return (int)tot;
+ }
+ free(myinfo);
+ }
+ return -1;
+}
+
+static unsigned int fiemap_get_lba_of_block(struct fiemap_info *myinfo, unsigned int rows, unsigned int block)
+{
+ unsigned int i, lba = 0, tot = 0;
+ for(i=0; i<rows; i++) {
+ tot = myinfo[i].tot;
+ if(block < tot) {
+ lba = myinfo[i].lba + block;
+ break;
+ } else {
+ block = block - tot;
+ }
+ }
+ return lba;
+}
+
+unsigned int mrdump_fiemap_total_entries(int fd)
+{
+ return fiemap_total_entries(fd);
+}
+
+bool mrdump_fiemap_get_entries(int fd, unsigned int blksize, struct fiemap_info *mapinfo, unsigned int rows)
+{
+ return fiemap_get_entries(fd, blksize, mapinfo, rows);
+}
+
+unsigned int mrdump_fiemap_get_lba_of_block(struct fiemap_info *myinfo, unsigned int num, unsigned int block)
+{
+ return fiemap_get_lba_of_block(myinfo, num, block);
+}
+
+int mrdump_fiemap_get_entry_tot(int fd, unsigned int blksize, unsigned int rows)
+{
+ return fiemap_get_entry_tot(fd, blksize, rows);
+}
+
+int mrdump_fiemap_get_entry_lba(int fd, unsigned int blksize, unsigned int rows)
+{
+ return fiemap_get_entry_lba(fd, blksize, rows);
+}
diff --git a/src/devtools/mrdump/mrdump_tool_source/mrdump_support_fiemap.h b/src/devtools/mrdump/mrdump_tool_source/mrdump_support_fiemap.h
new file mode 100644
index 0000000..f703a13
--- /dev/null
+++ b/src/devtools/mrdump/mrdump_tool_source/mrdump_support_fiemap.h
@@ -0,0 +1,13 @@
+#pragma once
+
+struct fiemap_info {
+ __u32 lba;
+ __u32 tot;
+};
+
+/* Function Prototypes */
+unsigned int mrdump_fiemap_total_entries(int fd);
+bool mrdump_fiemap_get_entries(int fd, unsigned int blksize, struct fiemap_info *mapinfo, unsigned int rows);
+unsigned int mrdump_fiemap_get_lba_of_block(struct fiemap_info *myinfo, unsigned int num, unsigned int block);
+int mrdump_fiemap_get_entry_tot(int fd, unsigned int blksize, unsigned int rows);
+int mrdump_fiemap_get_entry_lba(int fd, unsigned int blksize, unsigned int rows);
diff --git a/src/devtools/mrdump/mrdump_tool_source/mrdump_support_mpart.c b/src/devtools/mrdump/mrdump_tool_source/mrdump_support_mpart.c
new file mode 100644
index 0000000..924e00c
--- /dev/null
+++ b/src/devtools/mrdump/mrdump_tool_source/mrdump_support_mpart.c
@@ -0,0 +1,281 @@
+/* strlcpy */
+#include <stdio.h>
+
+/* uint64_t ...*/
+#include <inttypes.h>
+#include <stdbool.h>
+
+/* struct stat, lstat, open, execl */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+/* malloc */
+#include <stdlib.h>
+
+/* strlen */
+#include <string.h>
+
+/* strerror */
+#include <string.h>
+/* errno */
+#include <errno.h>
+
+/* bzero */
+#include <strings.h>
+
+/* ctime */
+#include <time.h>
+
+/* crc32, Z_NULL */
+#include <zlib.h>
+
+/* mrdump related */
+#include "mrdump_log.h"
+#include "mrdump_common.h"
+#include "mrdump_support_mpart.h"
+#include "mrdump_support_ext4.h"
+
+/* remember to free the fullpath when it is no longer required. */
+static char *get_partition_fullpath(char *linkfile)
+{
+ struct stat sa;
+ if (lstat(linkfile, &sa) == -1) {
+ MD_LOGE("%s: no mrdump partition.\n", __func__);
+ return NULL;
+ }
+
+ char *fullpath = malloc(sa.st_size + 1);
+ if (fullpath == NULL) {
+ MD_LOGE("%s: insufficient memory\n");
+ return NULL;
+ }
+
+ ssize_t r = readlink(linkfile, fullpath, sa.st_size + 1);
+ if (r == -1) {
+ MD_LOGE("%s: lstat\n");
+ return NULL;
+ }
+ if (r > sa.st_size) {
+ MD_LOGE("%s: symlink increased in size "
+ "between lstat() and readlink()\n");
+ return NULL;
+ }
+ fullpath[r] = '\0';
+
+ return fullpath;
+}
+
+/* remember to free the pname when it is no longer required. */
+static char *get_partition_name(char *fullpath)
+{
+ char *pfile = fullpath;
+ if (!pfile) {
+ MD_LOGE("%s: no such full path\n", __func__);
+ return NULL;
+ }
+ int len = strlen(pfile);
+
+ char *pname = malloc(len);
+ if (pname == NULL) {
+ MD_LOGE("%s: malloc failed\n", __func__);
+ return NULL;
+ }
+
+ char *delim="\x2f";
+ char *p = strtok(pfile, delim);
+ while (p) {
+ p = strtok(NULL, delim);
+ if (p) {
+ bzero(pname, len);
+ strlcpy(pname, p, len);
+ }
+ }
+
+ return pname;
+}
+
+int mrdump_check_partition(void)
+{
+ /* get real path from symbolic file */
+ char *fullpath = get_partition_fullpath(MRDUMP_MPART_PARTITION);
+ if (!fullpath) {
+ MD_LOGE("%s: no such fullpath\n", __func__);
+ return 0;
+ }
+
+ /* get device node name */
+ char *realpath= strdup(fullpath);
+ char *pname = get_partition_name(realpath);
+ if (!pname) {
+ MD_LOGE("%s: cannot get the partition name\n", __func__);
+ return 0;
+ }
+ free(realpath);
+
+ /* get partition size */
+ uint64_t psize = mrdump_get_partition_size(fullpath);
+
+ /* get stat */
+ struct stat sb;
+ if (stat(fullpath, &sb) == -1) {
+ MD_LOGE("%s: no mrdump partition.\n", __func__);
+ return 0;
+ }
+
+ /* parition informations, reference to EXAMPLE of manpage STAT(2) */
+ MD_LOGI("PARTNAME: mrdump\n");
+ MD_LOGI("LINK: %s\n", MRDUMP_MPART_PARTITION);
+ MD_LOGI("Partition size: %llu bytes\n", psize);
+ MD_LOGI("DEVNAME: %s\n", pname);
+ MD_LOGI("FILE: %s\n", fullpath);
+ MD_LOGI("File type: ");
+ switch (sb.st_mode & S_IFMT) {
+ case S_IFBLK: MD_LOGI("block device\n"); break;
+ case S_IFCHR: MD_LOGI("character device\n"); break;
+ case S_IFDIR: MD_LOGI("directory\n"); break;
+ case S_IFIFO: MD_LOGI("FIFO/pipe\n"); break;
+ case S_IFLNK: MD_LOGI("symlink\n"); break;
+ case S_IFREG: MD_LOGI("regular file\n"); break;
+ case S_IFSOCK: MD_LOGI("socket\n"); break;
+ default: MD_LOGI("unknown?\n"); break;
+ }
+ MD_LOGI("Ownership: UID=%ld GID=%ld\n",
+ (long) sb.st_uid, (long) sb.st_gid);
+ MD_LOGI("I-node number: %ld\n", (long) sb.st_ino);
+ MD_LOGI("Mode: %lo (octal)\n", (unsigned long) sb.st_mode);
+ MD_LOGI("Link count: %ld\n", (long) sb.st_nlink);
+ MD_LOGI("Last status change: %s\n", ctime(&sb.st_ctime));
+ MD_LOGI("Last file access: %s\n", ctime(&sb.st_atime));
+ MD_LOGI("Last file modification: %s\n", ctime(&sb.st_mtime));
+
+ /* remember to free fullpath and pname */
+ free(fullpath);
+ free(pname);
+
+ return 1;
+}
+
+static bool mrdump_read_pafile_info(int device_fd,
+ struct mrdump_pafile_info *info)
+{
+ memset(info, 0, sizeof(struct mrdump_pafile_info));
+
+ uint8_t block0[MRDUMP_PAF_TOTAL_SIZE];
+ memset(block0, 0, sizeof(block0));
+
+ if (0 > read(device_fd, block0, sizeof(block0))) {
+ MD_LOGE("%s: read InfoLBA error (%d), %s\n", __func__, errno, strerror(errno));
+ return false;
+ }
+
+ uint8_t *bufp = &block0[0];
+ unsigned int crcval = crc32(0, Z_NULL, 0);
+ crcval = crc32(crcval, (void *)block0, MRDUMP_LBA_DATAONLY);
+ if (crcval != *(uint32_t *)&block0[MRDUMP_PAF_CRC32]) {
+ MD_LOGE("%s: LBA info CRC error (c:%08x, v:%08x)\n", __func__, crcval,
+ *(uint32_t *)&block0[MRDUMP_PAF_CRC32]);
+ return false;
+ }
+
+ info->coredump_size = *(uint64_t *)(bufp + MRDUMP_PAF_COREDUMPSIZE);
+ return true;
+}
+
+bool mrdump_file_fetch_zip_coredump_partition(const char *outfile)
+{
+ struct mrdump_pafile_info lbainfo;
+ unsigned int read_len, mylen;
+ unsigned char MyData[MRDUMP_PARTITION_EXSPACE];
+ int fpRead, fpWrite;
+
+ // outfile
+ if(outfile == NULL) {
+ MD_LOGE("%s: outfile is NULL! (%d), %s\n", __func__, errno, strerror(errno));
+ return false;
+ }
+
+ fpRead = open(MRDUMP_MPART_PARTITION, O_RDWR);
+ if (fpRead < 0) {
+ MD_LOGE("mrdump partition %s open failed (%d), %s\n",
+ MRDUMP_MPART_PARTITION, errno, strerror(errno));
+ return false;
+ }
+
+ if (!mrdump_read_pafile_info(fpRead, &lbainfo)) {
+ mrdump_close(fpRead);
+ return false;
+ }
+
+ if (lbainfo.coredump_size == 0) {
+ MD_LOGI("mrdump partition have 0 size dump, no data to dump\n");
+ mrdump_close(fpRead);
+ return false;
+ }
+
+ // Write handle
+ fpWrite = open(outfile, O_RDWR | O_CREAT | O_TRUNC, 0600);
+ if(0 > fpWrite) {
+ MD_LOGE("%s: open Write handle open failed(%d), %s\n", __func__, errno, strerror(errno));
+ mrdump_close(fpRead);
+ goto cleanup0;
+ }
+
+ uint64_t delaylen = 0;
+ uint64_t coresize = lbainfo.coredump_size;
+
+ if (lseek64(fpRead, BLK_SIZE, SEEK_SET) == (off64_t) -1) {
+ MD_LOGE("%s: lseek64 Read MyData failed(%d), %s", __func__, errno, strerror(errno));
+ mrdump_close(fpRead);
+ mrdump_close(fpWrite);
+ unlink(outfile);
+ goto cleanup0;
+ }
+
+ while(coresize > 0) {
+
+ // counting coutinue datas...
+ read_len = MAX_READ_BLK * BLK_SIZE;
+
+ if(coresize < read_len) {
+ mylen = coresize;
+ } else {
+ mylen = read_len;
+ }
+
+ if(0 > read(fpRead, MyData, mylen)) {
+ MD_LOGE("%s: fetch MyData error!(%d), %s", __func__, errno, strerror(errno));
+ mrdump_close(fpRead);
+ mrdump_close(fpWrite);
+ unlink(outfile);
+ goto cleanup0;
+ }
+ if(0 > write(fpWrite, MyData, mylen)) {
+ MD_LOGE("%s: fetch MyData error!(%d), %s", __func__, errno, strerror(errno));
+ mrdump_close(fpRead);
+ mrdump_close(fpWrite);
+ unlink(outfile);
+ goto cleanup0;
+ }
+
+ coresize -= mylen;
+
+ /* flow control */
+ delaylen += mylen;
+ if (delaylen >= MRDUMP_MAX_BANDWIDTH) {
+ delaylen = 0;
+ fdatasync(fpWrite);
+ sleep(1);
+ }
+ }
+
+ mrdump_close(fpRead);
+ mrdump_close(fpWrite);
+
+ MD_LOGI("Ramdump write to %s size %" PRId64 "\n", outfile, lbainfo.coredump_size);
+ return true;
+
+ cleanup0:
+ return false;
+}
diff --git a/src/devtools/mrdump/mrdump_tool_source/mrdump_support_mpart.h b/src/devtools/mrdump/mrdump_tool_source/mrdump_support_mpart.h
new file mode 100644
index 0000000..fb791f0
--- /dev/null
+++ b/src/devtools/mrdump/mrdump_tool_source/mrdump_support_mpart.h
@@ -0,0 +1,12 @@
+#pragma once
+
+/* for DPART(Dedicated Partition) solution */
+#define MRDUMP_MPART_PARTITION "/dev/block/platform/bootdevice/by-name/mrdump"
+#define MRDUMP_MPART_START_OFFSET 4096
+#define MAX_READ_BLK 64
+#define BLK_SIZE 4096
+#define MRDUMP_PARTITION_EXSPACE MAX_READ_BLK*BLK_SIZE
+
+/* functions */
+int mrdump_check_partition(void);
+bool mrdump_file_fetch_zip_coredump_partition(const char *outfile);
diff --git a/src/devtools/mrdump/mrdump_tool_source/mrdump_tool.c b/src/devtools/mrdump/mrdump_tool_source/mrdump_tool.c
new file mode 100644
index 0000000..085aabe
--- /dev/null
+++ b/src/devtools/mrdump/mrdump_tool_source/mrdump_tool.c
@@ -0,0 +1,405 @@
+/* uint64_t ...*/
+#include <inttypes.h>
+#include <stdbool.h>
+
+/* vprintf, vsnprintf */
+#include <stdio.h>
+
+/* exit(), atoi() */
+#include <stdlib.h>
+
+/* getopt, optind */
+#include <unistd.h>
+
+/* sysenv */
+#include "mrdump_defaults.h"
+
+/* strcmp */
+#include <string.h>
+
+#include <getopt.h>
+/* mrdump related */
+#include "mrdump_log.h"
+#include "mrdump_common.h"
+#include "mrdump_status.h"
+#include "mrdump_support_ext4.h"
+#include "mrdump_support_mpart.h"
+
+static void usage(const char *prog) __attribute__((noreturn));
+static void usage(const char *prog)
+{
+ printf("Usage\n"
+ "\t%1$s is-supported\n\n"
+ "\t%1$s status-get\n"
+ "\t%1$s status-log\n"
+ "\t%1$s status-clear\n\n"
+ "\t%1$s file-setup\n"
+ "\t%1$s file-allocate n\n"
+ "\t\tn is 0(disable file output) 1(halfmem) 2(fullmem) >256\n"
+ "\t%1$s file-extract-core [-r] filename\n"
+ "\t\t-r\tre-init pre-allocated file\n"
+ "\t%1$s file-info\n\n"
+ "\t%1$s mem-size-set n\n"
+ "\t\tn is between 64 ~ 16384(m), 0 is output total-mem-size\n\n"
+ "\t%1$s output-set output\n"
+ "\t\tsetting mrdump output device\n"
+ "\t\t none\n"
+ "\t\t null\n"
+ "\t\t usb\n"
+ "\t\t partition: mrdump partition\n"
+ "\t\t internal-storage: ext4, f2fs\n"
+ "\t%1$s output-get\n"
+ "\t\tgetting mrdump output device\n",
+ prog);
+ exit(1);
+}
+
+static void dump_status_ok(const struct mrdump_status_result *result)
+{
+ printf("Ok\n");
+ printf("\tMode: %s\n\tOutput: ", result->mode);
+
+ switch (result->output) {
+ case MRDUMP_OUTPUT_NULL:
+ printf("null\n");
+ break;
+ case MRDUMP_OUTPUT_USB:
+ printf("usb\n");
+ break;
+ case MRDUMP_OUTPUT_DATA_FS:
+ printf("ext4/data partition\n");
+ break;
+ case MRDUMP_OUTPUT_PARTITION:
+ printf("dynamic mrdump partition\n");
+ break;
+ default:
+ printf("not supported\n");
+ break;
+ }
+}
+
+static int file_setup_command(int argc, char * __attribute__((unused)) argv[])
+{
+ if (!mrdump_is_supported()) {
+ error("file-setup not allowed in this mode.\n");
+ }
+ if (argc != 1) {
+ error("Invalid file-setup command argument\n");
+ }
+ mrdump_file_setup(false);
+ return 0;
+}
+
+static void file_allocate_command(int argc, char *argv[])
+{
+ if (!mrdump_is_supported()) {
+ error("file-allocate not allowed in this mode.\n");
+ }
+ if (argc != 2) {
+ error("Invaid file-allocate command argument\n");
+ }
+ int size_m = atoi(argv[1]);
+
+ if (size_m < 0)
+ size_m = 0;
+
+ if ((size_m <= 2) || (size_m >= MRDUMP_EXT4_MIN_ALLOCATE)) {
+ // enable condition: only 0, 1, 2, >256
+ mrdump_file_set_maxsize(size_m);
+ }
+ else {
+ error("Invalid dump size %d\n", size_m);
+ }
+}
+
+static int file_extract_core_command(int argc, char *argv[])
+{
+ int opt;
+ bool reinit = false;
+
+ while ((opt = getopt(argc, argv, "r")) != -1) {
+ switch (opt) {
+ case 'r':
+ reinit = true;
+ break;
+ default:
+ error("Invalid file-extract-core parameter\n");
+ }
+ }
+ if (optind >= argc) {
+ error("Expected filename after options\n");
+ }
+
+ const char *fn = argv[optind];
+ const char *output_dev = sysenv_get("mrdump_output");
+
+ MD_LOGI("%s: mrdump_output= %s\n",__func__, output_dev);
+
+ if (output_dev) {
+ if (!strncmp(output_dev, "partition", 9)) {
+ MD_LOGI("%s: partition solution\n",__func__);
+ if (mrdump_file_fetch_zip_coredump_partition(fn)) {
+ return 0;
+ }
+ }
+ else if (!strncmp(output_dev, "internal-storage", 21)) {
+ MD_LOGI("%s: ext4 solution\n",__func__);
+ if (mrdump_file_fetch_zip_coredump(fn)) {
+ mrdump_file_setup(reinit);
+ return 0;
+ }
+ }
+ }
+
+ error("Fetching Coredump data failed\n");
+}
+
+static int file_info_command(int argc, char * __attribute__((unused)) argv[])
+{
+ if (argc != 1) {
+ error("Invalid file-info command argument\n");
+ }
+
+ struct mrdump_pafile_info info;
+ if (mrdump_file_get_info(MRDUMP_EXT4_ALLOCATE_FILE, &info)) {
+ printf("\tInfo LBA : %" PRIu32 "\n"
+ "\tAddress LBA : %" PRIu32 "\n"
+ "\tFile Size : %" PRIu64 "\n"
+ "\tCoredump Size : %" PRIu64 "\n"
+ "\tTimestamp : %" PRIx64 "\n",
+ info.info_lba, info.addr_lba,
+ info.filesize, info.coredump_size,
+ info.timestamp
+ );
+ return 0;
+ }
+ else {
+ error("Cannot get pre-allocate file info\n");
+ }
+}
+
+static void mem_size_set_command(int argc, char *argv[])
+{
+ char msize[5];
+
+ if (argc != 2) {
+ error("Invaid mem-size-set command argument\n");
+ }
+
+ int size_m = atoi(argv[1]);
+ if ((size_m == 0) || ((size_m >= 64) && (size_m <= 16 * 1024))) {
+ if (size_m != 0) {
+ snprintf(msize, sizeof(msize), "%d", size_m);
+ if (sysenv_set("mrdump_mem_size", msize) == 0) {
+ MD_LOGI("mem-size-set done.\n");
+ }
+ }
+ else {
+ if (sysenv_set("mrdump_mem_size", "") == 0) {
+ MD_LOGI("total-mem-size done.\n");
+ }
+ else {
+ error("failed to set memory dump size, plz try again later.\n");
+ }
+ }
+ }
+ else {
+ error("Invalid memory dump size\n");
+ }
+}
+
+static void output_set_command(int argc, char *argv[])
+{
+ if(argc < 2) {
+ error("Invalid output device, valid input [none, null, usb, partition, internal-storage]\n");
+ }
+ else {
+ const char *output_dev = argv[1];
+ int need_reboot = 0;
+ const char *prev_output_dev = sysenv_get("mrdump_output");
+
+ if (strcmp(prev_output_dev, "partition") == 0) {
+ if (mrdump_check_partition()) {
+ need_reboot = 1;
+ }
+ }
+ if (strcmp(output_dev, "partition") == 0) {
+ if (!mrdump_check_partition()) {
+ error("mrdump partition doesn't exist, cannot dump to partition.\n");
+ }
+ need_reboot = 1;
+ }
+ else if (strcmp(output_dev, "none") &&
+ strcmp(output_dev, "null") &&
+ strcmp(output_dev, "usb") &&
+ strcmp(output_dev, "internal-storage")) {
+ error("Unknown output %s\n", output_dev);
+ }
+
+ if (sysenv_set("mrdump_output", output_dev) == 0) {
+ MD_LOGI("mrdump_output = %s\n", output_dev);
+ }
+ else {
+ error("output-set failed.(%s)\n", output_dev);
+ }
+
+ if (strcmp(output_dev, "internal-storage") == 0) {
+ mrdump_file_set_maxsize(DEFAULT_FULLMEM);
+ }
+ else {
+ mrdump_file_set_maxsize(DEFAULT_DISABLE);
+ }
+
+ if (need_reboot) {
+ if (0 > execl("/system/bin/reboot", "reboot", NULL, NULL))
+ error("%s: failed to reboot into LK for partition resize.\n", __func__);
+ }
+ }
+}
+
+static void status_get_command(int __attribute((unused)) argc,
+ char * __attribute ((unused)) argv[])
+{
+ struct mrdump_status_result result;
+ if (mrdump_status_get(&result)) {
+ printf("MT-RAMDUMP\n\tStatus:");
+ switch (result.status) {
+ case MRDUMP_STATUS_NONE:
+ printf("None\n");
+ break;
+ case MRDUMP_STATUS_FAILED:
+ printf("Failed\n");
+ break;
+ case MRDUMP_STATUS_OK:
+ dump_status_ok(&result);
+ break;
+ }
+ }
+ else {
+ error("MT-RAMDUMP get status failed\n");
+ }
+}
+
+static int parse_log_level(const char *log_level)
+{
+ if (strcmp(log_level, "debug") == 0)
+ return LOG_DEBUG;
+ else if (strcmp(log_level, "info") == 0)
+ return LOG_INFO;
+ else if (strcmp(log_level, "warn") == 0)
+ return LOG_WARNING;
+ else if (strcmp(log_level, "error") == 0)
+ return LOG_ERR;
+ return LOG_WARNING;
+}
+
+int main(int argc, char *argv[])
+{
+ int log_level = LOG_WARNING;
+ int log_syslog = 0;
+
+ static struct option long_options[]= {
+ {"help", no_argument, 0, 0},
+ {"log-level", required_argument, 0, 0},
+ {"log-syslog", no_argument, 0, 0},
+ {0, 0, 0, 0},
+ };
+
+ while (1) {
+ int option_index, c;
+ c = getopt_long(argc, argv, "+", long_options, &option_index);
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 0:
+ if (strcmp(long_options[option_index].name, "log-level") == 0) {
+ log_level = parse_log_level(optarg);
+ }
+ else if (strcmp(long_options[option_index].name, "log-syslog") == 0) {
+ log_syslog = 1;
+ }
+ else if (strcmp(long_options[option_index].name, "help") == 0) {
+ usage(argv[0]);
+ }
+ break;
+
+ default:
+ usage(argv[0]);
+ }
+ }
+
+ mdlog_init(log_level, log_syslog);
+
+ const int command_argc = argc - optind;
+ if (command_argc < 1) {
+ error("No command given\n");
+ }
+ const char *command = argv[optind];
+ char **command_argv = &argv[optind];
+
+ if (strcmp(command, "is-supported") == 0) {
+ if (mrdump_is_supported()) {
+ printf("MT-RAMDUMP support ok\n");
+ }
+ else {
+ printf("MT-RAMDUMP not support\n");
+ }
+ }
+ else if (strcmp(command, "status-get") == 0) {
+ status_get_command(command_argc, command_argv);
+ }
+ else if (strcmp(command, "status-log") == 0) {
+ struct mrdump_status_result result;
+ bool res = mrdump_status_get(&result);
+
+ printf("=>status line:\n%s\n=>log:\n%s\n", result.status_line, result.log_buf);
+ if (!res) {
+ error("MT-RAMDUMP get status failed\n");
+ }
+ }
+ else if (strcmp(command, "status-clear") == 0) {
+ if (!mrdump_is_supported()) {
+ error("MT-RAMDUMP not support\n");
+ }
+ if (!mrdump_status_clear()) {
+ error("MT-RAMDUMP Status clear failed\n");
+ }
+ }
+ else if (strcmp(command, "file-setup") == 0) {
+ file_setup_command(command_argc, command_argv);
+ }
+ else if (strcmp(command, "file-allocate") == 0) {
+ file_allocate_command(command_argc, command_argv);
+ }
+ else if (strcmp(command, "file-extract-core") == 0) {
+ file_extract_core_command(command_argc, command_argv);
+ }
+ else if (strcmp(command, "file-info") == 0) {
+ file_info_command(command_argc, command_argv);
+ }
+ else if (strcmp(command, "mem-size-set") == 0) {
+ mem_size_set_command(command_argc, command_argv);
+ }
+ else if (strcmp(command, "output-set") == 0) {
+ output_set_command(command_argc, command_argv);
+ }
+ else if (strcmp(command, "partition") == 0) {
+ /* ignored "-Wunused-result" */
+ if (1 == mrdump_check_partition()) {;}
+ }
+ else if (strcmp(command, "output-get") == 0) {
+ const char *output_dev = sysenv_get("mrdump_output");
+ if (!output_dev) {
+ printf("default\n");
+ }
+ else {
+ printf("%s\n", output_dev);
+ }
+ }
+ else {
+ error("Unknown command %s\n", command);
+ }
+
+ return 0;
+}