| /* 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; |
| } |