diff --git a/lib/libc/stdio/lib_lowoutstream.c b/lib/libc/stdio/lib_lowoutstream.c index 4e8aca79ba..a70ba81824 100644 --- a/lib/libc/stdio/lib_lowoutstream.c +++ b/lib/libc/stdio/lib_lowoutstream.c @@ -65,6 +65,9 @@ #include "lib_internal.h" +#ifdef CONFIG_LOWLOG_DUMP +#include +#endif /**************************************************************************** * Private Functions ****************************************************************************/ @@ -76,6 +79,9 @@ static void lowoutstream_putc(FAR struct lib_outstream_s *this, int ch) { DEBUGASSERT(this); +#if defined(__KERNEL__) && defined(CONFIG_LOWLOG_DUMP) + lowlog_dump_save_ch(ch); +#endif #if defined(CONFIG_BUILD_FLAT) || (defined(CONFIG_BUILD_PROTECTED) && defined(__KERNEL__)) if (up_putc(ch) != EOF) { this->nput++; diff --git a/os/Kconfig b/os/Kconfig index 1bc144cf00..be562afab4 100644 --- a/os/Kconfig +++ b/os/Kconfig @@ -625,6 +625,10 @@ menu "Binary manager" source kernel/binary_manager/Kconfig endmenu +menu "Lowlog dump" +source kernel/log_dump/Kconfig +endmenu + menu "Task Monitor" source kernel/task_monitor/Kconfig endmenu diff --git a/os/include/tinyara/log_dump/lowlog_dump.h b/os/include/tinyara/log_dump/lowlog_dump.h new file mode 100644 index 0000000000..d7f5c7971d --- /dev/null +++ b/os/include/tinyara/log_dump/lowlog_dump.h @@ -0,0 +1,66 @@ +/**************************************************************************** + * + * Copyright 2025 Samsung Electronics All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the License. + * + ****************************************************************************/ + +#ifndef __LOWLOG_DUMP_H__ +#define __LOWLOG_DUMP_H__ + +/**************************************************************************** + * Included Files + ****************************************************************************/ +/************************************************************************************* +* Description: +* resume saving lldbg to buf. +* +*************************************************************************************/ +void lowlog_dump_resume(void); + +/************************************************************************************* +* Description: +* pause saving lldbg to buf. +* +*************************************************************************************/ +void lowlog_dump_pause(void); + +/**************************************************************************** + * Description: + * This is used to store logs that are output via lldbg() during a user crash situation into a buffer. + * + ****************************************************************************/ +void lowlog_dump_save_ch(char ch); + +/**************************************************************************** + * Description: + * Saves the crash log to a file. + * + ****************************************************************************/ +int lowlog_dump_save(); + +/************************************************************************************* +* Description: +* Reads a log from a file and stores it in a buffer. If the log is compresed, it is +* decompressed before being stored. +*************************************************************************************/ +int lowlog_dump_read(char *filename, char *buf, int buf_size); + +/************************************************************************************* +* Description: +* Reads the most recent log from a file and stores it in a buffer. If the log is compresed, it is +* decompressed before being stored. +*************************************************************************************/ +int lowlog_dump_read_recent(char *buf, int buf_size); +#endif diff --git a/os/kernel/binary_manager/binary_manager_recovery.c b/os/kernel/binary_manager/binary_manager_recovery.c index 7c8f969e90..8aabfc7fd3 100644 --- a/os/kernel/binary_manager/binary_manager_recovery.c +++ b/os/kernel/binary_manager/binary_manager_recovery.c @@ -42,6 +42,10 @@ #include "semaphore/semaphore.h" #include "binary_manager_internal.h" +#ifdef CONFIG_LOWLOG_DUMP +#include +#endif + /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ @@ -345,6 +349,12 @@ void binary_manager_recovery(int bin_idx) bmlldbg("Failed to deactivate binary, bin idx %d\n", bin_idx); goto reboot_board; } +#endif +#ifdef CONFIG_LOWLOG_DUMP + lowlog_dump_save(); +#ifdef CONFIG_LOWLOG_DUMP_REBOOT + binary_manager_reset_board(REBOOT_SYSTEM_BINARY_RECOVERYFAIL); +#endif #endif /* Create loader to reload binary */ ret = binary_manager_execute_loader(LOADCMD_RELOAD, bin_idx); diff --git a/os/kernel/log_dump/Kconfig b/os/kernel/log_dump/Kconfig new file mode 100644 index 0000000000..82c4f68f09 --- /dev/null +++ b/os/kernel/log_dump/Kconfig @@ -0,0 +1,50 @@ +# +# For a description of the syntax of this configuration file, +# see kconfig-language at https://www.kernel.org/doc/Documentation/kbuild/kconfig-language.txt +# + + +config LOWLOG_DUMP + bool "enable lowlog dump" + default n + depends on BINMGR_RECOVERY + ---help--- + This saves the lowlog. + +if LOWLOG_DUMP + +config LOWLOG_DUMP_COMPRESS + bool "LOWLOG_DUMP_COMPRESS" + default y + ---help--- + Controls whether compression is applied. + if the value is n compression is not performed. + + +config LOWLOG_DUMP_BUF_SIZE + int "LOWLOG_DUMP_BUF_SIZE" + default 8192 + ---help--- + Determines the size of the buffer where crash logs will be stored. + The low log is stored in the data section. + +config LOWLOG_DUMP_REBOOT + bool "REBOOT_AFTER_SAVING_LOG" + default y + ---help--- + Determines whether to reboot after saving the low log. + +config LOWLOG_DUMP_MAX_FILES + int "LOWLOG_DUMP_MAX_FILES" + default 5 + ---help--- + Determine the maximum number of low log files to be stored. + +config LOWLOG_DUMP_RECORD_TIME + bool "LOWLOG_DUMP_RECORD_TIME" + default n + ---help--- + Measure and record the time it takes to save the crash log to a file. + +endif # LOWLOG_DUMP + diff --git a/os/kernel/log_dump/Make.defs b/os/kernel/log_dump/Make.defs index dd8a4c1e82..bb517bc81a 100644 --- a/os/kernel/log_dump/Make.defs +++ b/os/kernel/log_dump/Make.defs @@ -24,3 +24,10 @@ DEPPATH += --dep-path log_dump VPATH += :log_dump endif + +ifeq ($(CONFIG_LOWLOG_DUMP),y) + +CSRCS += lowlog_dump_read.c lowlog_dump_ch.c lowlog_dump_save.c +CSRCS += lowlog_dump_resume.c lowlog_dump_pause.c + +endif # CONFIG_LOWLOG_DUMP diff --git a/os/kernel/log_dump/lowlog_dump.h b/os/kernel/log_dump/lowlog_dump.h new file mode 100644 index 0000000000..bd1ed48972 --- /dev/null +++ b/os/kernel/log_dump/lowlog_dump.h @@ -0,0 +1,71 @@ +/**************************************************************************** + * + * Copyright 2025 Samsung Electronics All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the License. + * + ****************************************************************************/ + +#ifndef __SCHED_LOWLOG_DUMP_H +#define __SCHED_LOWLOG_DUMP_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#ifdef CONFIG_LOWLOG_DUMP + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ +#define DIR_PATH "/mnt/lowlog_dump" +#define MAX_FILENAME_LEN 64 +#define PRE_FILENAME_UNCOMP "lowlog_dump" +#define PRE_FILENAME_COMP "lowlog_dump_comp" +#define REQUIRED_HEAP_FOR_COMPRESS 400000 +/**************************************************************************** + * Private Type Declarations + ****************************************************************************/ +typedef struct { + int number; + char name[MAX_FILENAME_LEN]; +} FileEntry; + +/**************************************************************************** + * Function Prototypes + ****************************************************************************/ +void lowlog_dump_init(void); +void lowlog_dump_init_flag(void); +void lowlog_dump_init_buf(void); +char *lowlog_dump_get_buf(void); +int lowlog_dump_is_valid_filename(const char *name, int *out_number); +int lowlog_dump_get_size(void); +int lowlog_dump_set_store_flag(int flag); + +#endif /* CONFIG_LOWLOG_DUMP */ +#endif /* __SCHED_LOWLOG_DUMP_H */ diff --git a/os/kernel/log_dump/lowlog_dump_ch.c b/os/kernel/log_dump/lowlog_dump_ch.c new file mode 100644 index 0000000000..4389198d15 --- /dev/null +++ b/os/kernel/log_dump/lowlog_dump_ch.c @@ -0,0 +1,104 @@ +/**************************************************************************** + * + * Copyright 2025 Samsung Electronics All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include "lowlog_dump.h" + +/**************************************************************************** + * Public Variables + ****************************************************************************/ + +/**************************************************************************** + * Private Variables + ****************************************************************************/ +static char g_lowlog[CONFIG_LOWLOG_DUMP_BUF_SIZE]; +int g_lowlog_index = 0; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ +/************************************************************************************* +* Name: lowlog_dump_get_size +* +* Description: +* Gets the size (in bytes) of the log currently stored in the buffer. +* +*************************************************************************************/ +int lowlog_dump_get_size() +{ + return g_lowlog_index; +} + +/************************************************************************************* +* Name: lowlog_dump_init_buf +* +* Description: +* init global buf +* +*************************************************************************************/ +//TODO : It may be necessary to remove this function. +void lowlog_dump_init_buf() +{ + for (int i = 0; i < CONFIG_LOWLOG_DUMP_BUF_SIZE; i++) { + g_lowlog[i] = '\0'; + } + g_lowlog_index = 0; +} + +/************************************************************************************* +* Name: lowlog_dump_get_buf +* +* Description: +* return lowlog buf +* +*************************************************************************************/ +char *lowlog_dump_get_buf() +{ + return g_lowlog; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ +/************************************************************************************* +* Name: crashlog_writer_crashlog_to_buffer +* +* Description: +* Stores the crash log into the buffer. +* This is used to store logs that are output via lldbg() during a user crash situation into a buffer. +*************************************************************************************/ +void lowlog_dump_save_ch(char ch) +{ + if (lowlog_dump_get_store_flag() && g_lowlog_index < CONFIG_LOWLOG_DUMP_BUF_SIZE) { + g_lowlog[g_lowlog_index++] = ch; + } +} + diff --git a/os/kernel/log_dump/lowlog_dump_pause.c b/os/kernel/log_dump/lowlog_dump_pause.c new file mode 100644 index 0000000000..df689ad766 --- /dev/null +++ b/os/kernel/log_dump/lowlog_dump_pause.c @@ -0,0 +1,110 @@ +/**************************************************************************** + * + * Copyright 2025 Samsung Electronics All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include "lowlog_dump.h" +#include +#include +#include + +/**************************************************************************** + * Public Variables + ****************************************************************************/ + +/**************************************************************************** + * Private Variables + ****************************************************************************/ +static int g_start_to_save = 1; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ +/************************************************************************************* +* Name: lowlog_dump_init +* +* Description: +* init global variables. +* +*************************************************************************************/ +void lowlog_dump_init() +{ + lowlog_dump_init_buf(); + lowlog_dump_init_flag(); +} + +/************************************************************************************* +* Name: lowlog_dump_init_flag +* +* Description: +* init global variables. +* +*************************************************************************************/ +void lowlog_dump_init_flag() +{ + g_start_to_save = 1; +} + +/************************************************************************************* +* Name: lowlog_dump_get_store_flag +* +* Description: +* return store flag +*************************************************************************************/ +int lowlog_dump_get_store_flag(void) +{ + return g_start_to_save; +} + +/************************************************************************************* +* Name: lowlog_dump_set_store_flag +* +* Description: +* set store flag. +*************************************************************************************/ +int lowlog_dump_set_store_flag(int flag) +{ + g_start_to_save = flag; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/************************************************************************************* +* Name: lowlog_dump_pause +* +* Description: +* pause saving lldbg to buf. +*************************************************************************************/ +void lowlog_dump_pause(void) +{ + lowlog_dump_set_store_flag(0); +} diff --git a/os/kernel/log_dump/lowlog_dump_read.c b/os/kernel/log_dump/lowlog_dump_read.c new file mode 100644 index 0000000000..7a7377f996 --- /dev/null +++ b/os/kernel/log_dump/lowlog_dump_read.c @@ -0,0 +1,142 @@ +/**************************************************************************** + * + * Copyright 2025 Samsung Electronics All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include "lowlog_dump.h" + +/**************************************************************************** + * Public Variables + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ +/************************************************************************************* +* Name: lowlog_dump_read +* +* Description: +* Reads a log from a file and stores it in a buffer. If the log is compresed, it is +* decompressed before being stored. +*************************************************************************************/ +int lowlog_dump_read(char *filename, char *buf, int buf_size) +{ + int fd = open(filename, O_RDONLY); + int ret; + if (fd < 0) { + ldpllvdbg("file open failed\n"); + return ERROR; + } + /* After reading the logs from the file, all files in DIRPATH should + be deleted. Using lowlog_dump_is_valid_filename() will make this easier*/ + int dir_len = strlen(DIR_PATH); + if (strlen(filename) - dir_len - 1 > strlen(PRE_FILENAME_COMP) && !strncmp(filename + dir_len + 1, PRE_FILENAME_COMP, strlen(PRE_FILENAME_COMP))) { //simple check + unsigned int malloc_size = CONFIG_LOWLOG_DUMP_BUF_SIZE; + unsigned char *compressed_buf = (unsigned char *)kmm_malloc(malloc_size); + if (compressed_buf == NULL) { + ldpllvdbg("kmm_malloc() failed\n"); + close(fd); + return ERROR; + } + unsigned int compressed_buf_size = malloc_size; + ret = read(fd, compressed_buf, compressed_buf_size); + if (ret < 0) { + ldpllvdbg("read failed\n"); + free(compressed_buf); + close(fd); + return ERROR; + } + int tmp_buf_size = buf_size; + decompress_block(buf, &tmp_buf_size, compressed_buf, &compressed_buf_size); + free(compressed_buf); + close(fd); + return tmp_buf_size; + } + else if (strlen(filename) - dir_len - 1 > strlen(PRE_FILENAME_UNCOMP) && !strncmp(filename + dir_len + 1, PRE_FILENAME_UNCOMP, strlen(PRE_FILENAME_UNCOMP))) { //simple check + ldpllvdbg("uncompressed file read start\n"); + ret = read(fd, buf, buf_size); //no add null + if (ret < 0) { + ldpllvdbg("read failed\n"); + close(fd); + return ERROR; + } + close(fd); + return ret; + } + return ERROR; +} + +/************************************************************************************* +* Name: lowlog_dump_read_recent +* +* Description: +* Reads the most recent log from a file and stores it in a buffer. If the log is compresed, it is +* decompressed before being stored. +*************************************************************************************/ +int lowlog_dump_read_recent(char *buf, int buf_size) +{ + char most_recent_file_name[MAX_FILENAME_LEN]; + DIR *dir = opendir(DIR_PATH); + if (!dir) { + ldpllvdbg("opendir failed\n"); + return ERROR; + } + char temp_name[MAX_FILENAME_LEN]; + int count = 0; + int max_number = -1; + struct dirent *entry; + while ((entry = readdir(dir)) != NULL) { + int num; + if (lowlog_dump_is_valid_filename(entry->d_name, &num) == OK) { + count++; + if (num > max_number) { + max_number = num; + strncpy(temp_name, entry->d_name, sizeof(temp_name)); + } + if (count >= CONFIG_LOWLOG_DUMP_MAX_FILES) { + break; + } + } + } + + closedir(dir); + + snprintf(most_recent_file_name, MAX_FILENAME_LEN, "%s/%s", DIR_PATH, temp_name); + ldpllvdbg("most_recent_file_name is %s\n",most_recent_file_name); + lowlog_dump_read(most_recent_file_name, buf, buf_size); + return OK; +} \ No newline at end of file diff --git a/os/kernel/log_dump/lowlog_dump_resume.c b/os/kernel/log_dump/lowlog_dump_resume.c new file mode 100644 index 0000000000..6064260832 --- /dev/null +++ b/os/kernel/log_dump/lowlog_dump_resume.c @@ -0,0 +1,51 @@ +/**************************************************************************** + * + * Copyright 2025 Samsung Electronics All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include "lowlog_dump.h" +#include +#include +#include + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/************************************************************************************* +* Name: lowlog_dump_resume +* +* Description: +* restart saving lldbg to buf. +*************************************************************************************/ +void lowlog_dump_resume(void) +{ + lowlog_dump_set_store_flag(1); +} diff --git a/os/kernel/log_dump/lowlog_dump_save.c b/os/kernel/log_dump/lowlog_dump_save.c new file mode 100644 index 0000000000..f7f34802ae --- /dev/null +++ b/os/kernel/log_dump/lowlog_dump_save.c @@ -0,0 +1,315 @@ +/**************************************************************************** + * + * Copyright 2025 Samsung Electronics All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include "lowlog_dump.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Variables + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ +/************************************************************************************* + +/************************************************************************************* +* Name: lowlog_dump_is_valid_filename +* +* Description: +* This function checks whether a file in mnt/crashlog/ is a log save file based on its filename. +* +*************************************************************************************/ +int lowlog_dump_is_valid_filename(const char *name, int *out_number) +{ + int pre_filename_comp_len = strlen(PRE_FILENAME_COMP); + int pre_filename_uncomp_len = strlen(PRE_FILENAME_UNCOMP); + int name_len = strlen(name); + if (name_len > pre_filename_comp_len && !strncmp(name, PRE_FILENAME_COMP, pre_filename_comp_len)) { + for (int i = pre_filename_comp_len; i < name_len; i++) { + if (!isdigit(name[i])) { + return ERROR; + } + } + *out_number = atoi(name + pre_filename_comp_len); + return OK; + } + else if (name_len > pre_filename_uncomp_len && !strncmp(name, PRE_FILENAME_UNCOMP, pre_filename_uncomp_len)) { + for (int i = pre_filename_uncomp_len; i < name_len; i++) { + if (!isdigit(name[i])) { + return ERROR; + } + } + *out_number = atoi(name + pre_filename_uncomp_len); + return OK; + } + return ERROR; +} + +/************************************************************************************* +* Name: lowlog_dump_get_next_filename +* +* Description: +* This function generates the filename for a lowlog file +* ex) +* if compression is enabled -> lowlog_dumpXXX +* if compression is disabled -> lowlog_dump_compXXX +*************************************************************************************/ +static int lowlog_dump_get_next_filename(char *new_filename) +{ + //TODO : Directory is not being created when it does not exist. + DIR *dir = opendir(DIR_PATH); + if (!dir) { + if (errno == ENOENT) { + if (mkdir(DIR_PATH, 0755) != 0) { + ldpllvdbg("mkdir failed\n"); + return ERROR; + } + else { + dir = opendir(DIR_PATH); + if (!dir) { + ldpllvdbg("opendir failed\n"); + return ERROR; + } + } + } + ldpllvdbg("opendir failed\n"); + return ERROR; + } + FileEntry entries[CONFIG_LOWLOG_DUMP_MAX_FILES]; + int count = 0; + int max_number = -1; + int min_number = 999999999; + struct dirent *entry; + while ((entry = readdir(dir)) != NULL) { + int num; + if (lowlog_dump_is_valid_filename(entry->d_name, &num) == 0K) { + strncpy(entries[count].name, entry->d_name, sizeof(entries[count].name)); + entries[count].number = num; + count++; + if (num > max_number) { + max_number = num; + } + if (num < min_number) { + min_number = num; + } + if (count >= CONFIG_LOWLOG_DUMP_MAX_FILES) { + break; + } + } + } + closedir(dir); + // If there are more than CONFIG_LOWLOG_DUMP_MAX_FILES files, not add a new file. + if (max_number + 1 >= CONFIG_LOWLOG_DUMP_MAX_FILES) { + return ERROR; + } + char tmp[64]; + snprintf(new_filename, MAX_FILENAME_LEN, "%s/", DIR_PATH); + + int path_len = strlen(new_filename); +#ifdef CONFIG_LOWLOG_DUMP_COMPRESS + snprintf(tmp, MAX_FILENAME_LEN - path_len - 1, "%s%d", PRE_FILENAME_COMP, max_number + 1); +#else + snprintf(tmp, MAX_FILENAME_LEN - path_len - 1, "%s%d", PRE_FILENAME_UNCOMP, max_number + 1); +#endif + strncat(new_filename, tmp, MAX_FILENAME_LEN - path_len - 1); + return OK; +} + +/************************************************************************************* +* Name: lowlog_dump_save_uncomp +* +* Description: +* Saves the log stored in the buffer to a file. +*************************************************************************************/ +static int lowlog_dump_save_uncomp(char *filenm) +{ + ldpllvdbg("\n\n\n===================================crash log file saving start==========================================\n\n\n"); + char new_filename[MAX_FILENAME_LEN]; + int ret = lowlog_dump_get_next_filename(new_filename); + if (ret < 0) { + ldpllvdbg("get_next_filename() failed\n"); + return ERROR; + } + int fd = open(new_filename, O_WRONLY | O_CREAT | O_TRUNC); + if (fd < 0) { + ldpllvdbg("file open failed\n"); + return ERROR; + } + int log_size = write(fd, lowlog_dump_get_buf(), lowlog_dump_get_size()); + close(fd); + if (log_size < 0) { + ldpllvdbg("file write failed\n"); + return ERROR; + } + snprintf(filenm, MAX_FILENAME_LEN, "%s", new_filename); + ldpllvdbg("file write success, count:%d\n", log_size); + ldpllvdbg("\n\n\n===========================================crash log file saving end=====================================================\n\n\n"); + return log_size; +} + +/************************************************************************************* +* Name: lowlog_dump_save_comp +* +* Description: +* Saves the compressed log from the buffer to a file. +*************************************************************************************/ +static int lowlog_dump_save_comp(char *filenm, unsigned char *compressed_buf, unsigned int compressed_buf_size) +{ + ldpllvdbg("\n\n================================================================compress file write start===========================================================\n\n"); + char new_filename[MAX_FILENAME_LEN]; + if (compressed_buf == NULL) { + return ERROR; + } + int ret = lowlog_dump_get_next_filename(new_filename); + ldpllvdbg("filename is %s\n", new_filename); + if (ret < 0) { + ldpllvdbg("get_next_filename() failed\n"); + return ERROR; + } + int fd = open(new_filename, O_WRONLY | O_CREAT | O_TRUNC); + if (fd < 0) { + ldpllvdbg("file open failed\n"); + return ERROR; + } + ret = write(fd, compressed_buf, compressed_buf_size); + if (ret < 0) { + ldpllvdbg("file write failed\n"); + close(fd); + return ERROR; + } + close(fd); + snprintf(filenm, MAX_FILENAME_LEN, "%s", new_filename); + ldpllvdbg("write count: %d\n", ret); + ldpllvdbg("\n\n==========================================================compress file write end===========================================================\n\n"); + return ret; +} + +/************************************************************************************* +* Name: lowlog_dump_compress_and_save +* +* Description: +* Compresses the log stored in the buffer and save to file. +*************************************************************************************/ +static int lowlog_dump_compress_and_save(char *filenm) +{ + ldpllvdbg("\n\n=====================================================compress start=====================================================\n\n"); + int malloc_size = lowlog_dump_get_size() / 3; + if (kmm_get_largest_freenode_size() < malloc_size) { + return ERROR; + } + unsigned char *compressed_buf = (unsigned char *)kmm_malloc(malloc_size); + if (compressed_buf == NULL) { + ldpllvdbg("kmm_malloc() failed\n"); + return ERROR; + } + if (kmm_get_largest_freenode_size() < REQUIRED_HEAP_FOR_COMPRESS) { + return ERROR; + /*TODO : A configuration option should be added, and when this option is enabled, + the system should save logs without compression + if there is insufficient heap memory available for compression */ + } + unsigned int compressed_buf_size = malloc_size; + compress_block(compressed_buf, &compressed_buf_size, lowlog_dump_get_buf(), lowlog_dump_get_size()); + ldpllvdbg("compressed buf size: %d\n", compressed_buf_size); + + ldpllvdbg("\n==============================================================compress end===============================================================\n"); + + lowlog_dump_save_comp(filenm, compressed_buf, compressed_buf_size); + free(compressed_buf); + return compressed_buf_size; + +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/************************************************************************************* +* Name: lowlog_dump_save +* +* Description: +* Saves the crash log to a file. +*************************************************************************************/ +int lowlog_dump_save(void) +{ + lowlog_dump_pause(); + char filenm[MAX_FILENAME_LEN]; + int log_size = lowlog_dump_get_size(); + if (log_size == 0) { + return ERROR; + } +#ifdef CONFIG_LOWLOG_DUMP_RECORD_TIME + clock_t start = clock(); +#endif + int ret; +#ifdef CONFIG_LOWLOG_DUMP_COMPRESS + ret = lowlog_dump_compress_and_save(filenm); +#else + ret = lowlog_dump_save_uncomp(filenm); +#endif + if (ret < 0) { + return ERROR; + } +#ifdef CONFIG_LOWLOG_DUMP_RECORD_TIME + clock_t end = clock(); + double elapsed_time = (double)(end - start) / CLOCKS_PER_SEC; + ldpllvdbg("\n\nElapsed time: %.6f seconds\n\n", elapsed_time); + int fd = open("/mnt/lowlog_dump/result", O_CREAT | O_WRONLY | O_APPEND); + if (fd < 0) { + return ERROR; + } + char buf[100]; +//TODO : The number of snprintf and write calls should be reduced. +//TODO : add result checking and error handling about snprintf and write. +#ifdef CONFIG_LOWLOG_DUMP_COMPRESS + snprintf(buf, sizeof(buf), "C: %d -> %d ", log_size, ret); + write(fd, buf, strlen(buf)); +#else + snprintf(buf, sizeof(buf), "U: %d ", ret); + write(fd, buf, strlen(buf)); +#endif + ldpllvdbg("filenm is %s\n", filenm); + snprintf(buf, sizeof(buf), "in %.6fs", elapsed_time); + write(fd, buf, strlen(buf)); + snprintf(buf, sizeof(buf), " (%s)\n", filenm); + write(fd, buf, strlen(buf)); + close(fd); +#endif + return OK; +}