blob: edc4a2e29900165fdaa106a6421a6d48f870b228 [file] [log] [blame]
/* 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;
}