From 1334306585f66534a3f16a9ba99f63bd69bf03b3 Mon Sep 17 00:00:00 2001 From: anjiahao Date: Thu, 9 Nov 2023 12:08:11 +0800 Subject: [PATCH] coredump:support coredump command restore coredump form block device Signed-off-by: anjiahao --- system/coredump/coredump.c | 386 +++++++++++++++++++++++++++++++------ 1 file changed, 330 insertions(+), 56 deletions(-) diff --git a/system/coredump/coredump.c b/system/coredump/coredump.c index a29ffc96b..2dfc61f5a 100644 --- a/system/coredump/coredump.c +++ b/system/coredump/coredump.c @@ -23,68 +23,246 @@ ****************************************************************************/ #include -#include -#include - #include - -#include +#include +#include #include #include +#include +#include +#include +#include +#include -#include +#include +#include /**************************************************************************** - * Public Functions + * Private Types + ****************************************************************************/ + +typedef CODE void (*dumpfile_cb_t)(FAR char *path, FAR const char *filename, + FAR void *arg); + +/**************************************************************************** + * Private Functions ****************************************************************************/ /**************************************************************************** - * coredump_main + * dumpfile_iterate ****************************************************************************/ -int main(int argc, FAR char *argv[]) +#ifdef CONFIG_BOARD_COREDUMP_BLKDEV +static int dumpfile_iterate(FAR char *path, dumpfile_cb_t cb, FAR void *arg) +{ + FAR struct dirent *entry; + FAR DIR *dir; + int ret; + + dir = opendir(path); + if (dir == NULL) + { + ret = mkdir(path, 0777); + if (ret < 0) + { + return ret; + } + } + + while ((entry = readdir(dir)) != NULL) + { + if (entry->d_type == DT_REG && !strncmp(entry->d_name, "core-", 5)) + { + cb(path, entry->d_name, arg); + } + } + + closedir(dir); + return 0; +} + +/**************************************************************************** + * dumpfile_count + ****************************************************************************/ + +static void dumpfile_count(FAR char *path, FAR const char *filename, + FAR void *arg) +{ + FAR size_t *max = (FAR size_t *)arg; + + *max += 1; +} + +/**************************************************************************** + * dumpfile_delete + ****************************************************************************/ + +static void dumpfile_delete(FAR char *path, FAR const char *filename, + FAR void *arg) +{ + FAR char *dumppath = arg; + + sprintf(dumppath, "%s/%s", path, filename); + printf("Remove %s\n", dumppath); + remove(dumppath); +} + +/**************************************************************************** + * coredump_restore + ****************************************************************************/ + +static void coredump_restore(FAR char *savepath, size_t maxfile) +{ + FAR struct coredump_info_s *info; + unsigned char *swap; + char dumppath[PATH_MAX]; + struct geometry geo; + ssize_t writesize; + ssize_t readsize; + struct tm *dtime; + size_t offset = 0; + size_t max = 0; + int dumpfd; + int blkfd; + int ret; + + blkfd = open(CONFIG_BOARD_COREDUMP_BLKDEV_PATH, O_RDWR); + if (blkfd < 0) + { + return; + } + + ret = ioctl(blkfd, BIOC_GEOMETRY, (unsigned long)((uintptr_t)&geo)); + if (ret < 0) + { + goto blkfd_err; + } + + info = malloc(geo.geo_sectorsize); + if (info == NULL) + { + goto blkfd_err; + } + + lseek(blkfd, (geo.geo_nsectors - 1) * geo.geo_sectorsize, SEEK_SET); + read(blkfd, info, geo.geo_sectorsize); + if (info->magic != COREDUMP_MAGIC) + { + printf("%s coredump not found!\n", CONFIG_BOARD_COREDUMP_BLKDEV_PATH); + goto info_err; + } + + ret = dumpfile_iterate(savepath, dumpfile_count, &max); + if (ret < 0) + { + goto info_err; + } + + if (max >= maxfile) + { + ret = dumpfile_iterate(savepath, dumpfile_delete, dumppath); + if (ret < 0) + { + goto info_err; + } + } + + ret = snprintf(dumppath, sizeof(dumppath), + "%s/core-%s", savepath, + info->name.version); + dtime = localtime(&info->time); + if (dtime) + { + ret += snprintf(dumppath + ret, sizeof(dumppath) - ret, + "-%d-%d-%d-%d-%d", dtime->tm_mon + 1, + dtime->tm_mday, dtime->tm_hour, + dtime->tm_min, dtime->tm_sec); + } + +#ifdef CONFIG_BOARD_COREDUMP_COMPRESSION + ret += snprintf(dumppath + ret, sizeof(dumppath) - ret, ".lzf"); +#else + ret += snprintf(dumppath + ret, sizeof(dumppath) - ret, ".core"); +#endif + + while (ret--) + { + if (dumppath[ret] == ' ' || dumppath[ret] == ':') + { + dumppath[ret] = '-'; + } + } + + dumpfd = open(dumppath, O_CREAT | O_WRONLY | O_TRUNC, 0777); + if (dumpfd < 0) + { + printf("Open %s fail\n", dumppath); + goto info_err; + } + + swap = malloc(geo.geo_sectorsize); + if (swap == NULL) + { + printf("Malloc fail\n"); + goto fd_err; + } + + lseek(blkfd, 0, SEEK_SET); + while (offset < info->size) + { + readsize = read(blkfd, swap, geo.geo_sectorsize); + if (readsize < 0) + { + printf("Read %s fail\n", CONFIG_BOARD_COREDUMP_BLKDEV_PATH); + break; + } + + writesize = write(dumpfd, swap, readsize); + if (writesize != readsize) + { + printf("Write %s fail\n", dumppath); + break; + } + + offset += writesize; + } + + printf("Coredump finish [%s][%zu]\n", dumppath, info->size); + info->magic = 0; + lseek(blkfd, (geo.geo_nsectors - 1) * geo.geo_sectorsize, SEEK_SET); + write(blkfd, info, geo.geo_sectorsize); + free(swap); +fd_err: + close(dumpfd); +info_err: + free(info); +blkfd_err: + close(blkfd); +} + +#endif + +/**************************************************************************** + * coredump_now + ****************************************************************************/ + +static int coredump_now(int pid, FAR char *filename) { FAR struct lib_stdoutstream_s *outstream; FAR struct lib_hexdumpstream_s *hstream; +#ifdef CONFIG_BOARD_COREDUMP_COMPRESSION FAR struct lib_lzfoutstream_s *lstream; - char *name = NULL; +#endif FAR void *stream; + FAR FILE *file; int logmask; - int pid = 0; - FILE *file; - if (argc >= 2) + if (filename != NULL) { - pid = atoi(argv[1]); - if (pid == 0) - { - name = argv[1]; - } - - if (argc >= 3) - { - if (name == NULL) - { - name = argv[2]; - } - else - { - pid = atoi(argv[2]); - } - } - } - - if (pid == 0) - { - pid = INVALID_PROCESS_ID; - } - - if (name != NULL) - { - file = fopen(name, "w"); + file = fopen(filename, "w"); if (file == NULL) { - return 1; + return -errno; } } else @@ -92,29 +270,37 @@ int main(int argc, FAR char *argv[]) file = stdout; } - hstream = malloc(sizeof(*hstream) + sizeof(*lstream) + sizeof(*outstream)); +#ifdef CONFIG_BOARD_COREDUMP_COMPRESSION + hstream = malloc(sizeof(*hstream) + sizeof(*lstream) + + sizeof(*outstream)); +#else + hstream = malloc(sizeof(*hstream) + sizeof(*outstream)); +#endif + if (hstream == NULL) { - if (name != NULL) + if (filename != NULL) { fclose(file); } - return 1; + return -ENOMEM; } +#ifdef CONFIG_BOARD_COREDUMP_COMPRESSION lstream = (FAR void *)(hstream + 1); outstream = (FAR void *)(lstream + 1); - - logmask = setlogmask(LOG_ALERT); +#else + outstream = (FAR void *)(hstream + 1); +#endif printf("Start coredump:\n"); + logmask = setlogmask(LOG_ALERT); /* Initialize hex output stream */ lib_stdoutstream(outstream, file); lib_hexdumpstream(hstream, (FAR void *)outstream); - stream = hstream; #ifdef CONFIG_BOARD_COREDUMP_COMPRESSION @@ -129,21 +315,109 @@ int main(int argc, FAR char *argv[]) /* Do core dump */ core_dump(NULL, stream, pid); - -#ifdef CONFIG_BOARD_COREDUMP_COMPRESSION - printf("Finish coredump (Compression Enabled).\n"); -#else - printf("Finish coredump.\n"); -#endif - setlogmask(logmask); +# ifdef CONFIG_BOARD_COREDUMP_COMPRESSION + printf("Finish coredump (Compression Enabled).\n"); +# else + printf("Finish coredump.\n"); +# endif free(hstream); - - if (name != NULL) + if (filename != NULL) { fclose(file); } return 0; } + +/**************************************************************************** + * usage + ****************************************************************************/ + +static void usage(FAR const char *progname, int exitcode) +{ + fprintf(stderr, "%s [option]:\n", progname); + fprintf(stderr, "Default usage, will coredump directly\n"); + fprintf(stderr, "\t -p, --pid , Default, all thread\n"); + fprintf(stderr, "\t -f, --filename , Default stdout\n"); + +#ifdef CONFIG_BOARD_COREDUMP_BLKDEV + fprintf(stderr, "Second usage, will restore coredump" + "from %s to savepath\n", + CONFIG_BOARD_COREDUMP_BLKDEV_PATH); + fprintf(stderr, "\t -s, --savepath \n"); + fprintf(stderr, "\t -m, --maxfile ," + "Maximum number of coredump files, Default 1\n"); +#endif + exit(exitcode); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * coredump_main + ****************************************************************************/ + +int main(int argc, FAR char *argv[]) +{ +#ifdef CONFIG_BOARD_COREDUMP_BLKDEV + FAR char *savepath = NULL; + size_t maxfile = 1; +#endif + char *name = NULL; + int pid = INVALID_PROCESS_ID; + int ret; + + struct option options[] = + { + {"pid", 1, NULL, 'p'}, + {"filename", 1, NULL, 'f'}, +#ifdef CONFIG_BOARD_COREDUMP_BLKDEV + {"savepath", 1, NULL, 's'}, + {"maxfile", 1, NULL, 'm'}, +#endif + {"help", 0, NULL, 'h'} + }; + + while ((ret = getopt_long(argc, argv, "p:f:s:m:h", options, NULL)) + != ERROR) + { + switch (ret) + { + case 'p': + pid = atoi(optarg); + break; + case 'f': + name = optarg; + break; +#ifdef CONFIG_BOARD_COREDUMP_BLKDEV + case 's': + savepath = optarg; + break; + case 'm': + maxfile = atoi(optarg); + break; +#endif + case 'h': + default: + usage(argv[0], EXIT_SUCCESS); + break; + } + } + +#ifdef CONFIG_BOARD_COREDUMP_BLKDEV + if (savepath != NULL) + { + coredump_restore(savepath, maxfile); + } + else +#endif + { + coredump_now(pid, name); + } + + return 0; +}