diff --git a/tools/acrn-crashlog/acrnprobe/android_events.c b/tools/acrn-crashlog/acrnprobe/android_events.c index 47c13db96..471dffd38 100644 --- a/tools/acrn-crashlog/acrnprobe/android_events.c +++ b/tools/acrn-crashlog/acrnprobe/android_events.c @@ -32,38 +32,6 @@ static const char *android_img = "/data/android/android.img"; static const char *android_histpath = "logs/history_event"; char *loop_dev; -static char *get_line(const char *str, size_t str_size, - const char *area, size_t area_size, - const char *search_from, size_t *len) -{ - char *p; - char *match; - char *tail; - ssize_t search_size = area + area_size - search_from; - - if (search_size < 0 || (size_t)search_size < str_size) - return NULL; - - match = memmem(search_from, search_size, str, str_size); - if (!match) - return NULL; - tail = memchr(match + str_size, '\n', - area + area_size - match - str_size); - if (!tail) - return NULL; - - for (p = match; p >= area; p--) { - if (*p == '\n') { - *len = tail - p - 1; - return (char *)(p + 1); - } - } - - *len = tail - area; - return (char *)area; -} - - /* Find the next event that needs to be synced. * There is a history_event file in UOS side, it records UOS's events in * real-time. Generally, the cursor point to the first unsynchronized line. @@ -117,8 +85,10 @@ static char *next_vm_event(const char *cursor, const char *data, * 'type'. */ if (!new || memcmp(new, type + 1, tlen - 1) || - *(new + tlen - 1) != ' ') + *(new + tlen - 1) != ' ') { + free(type); continue; + } } else { new = get_line(type, (size_t)tlen, data, dlen, cursor, &len); @@ -136,10 +106,11 @@ static char *next_vm_event(const char *cursor, const char *data, return line_to_sync; } -#define VMRECORD_HEAD_LINES 6 +#define VMRECORD_HEAD_LINES 7 #define VMRECORD_TAG_LEN 9 #define VMRECORD_TAG_WAITING_SYNC " <==" #define VMRECORD_TAG_NOT_FOUND "NOT_FOUND" +#define VMRECORD_TAG_MISS_LOG "MISS_LOGS" #define VMRECORD_TAG_SUCCESS " " static int generate_log_vmrecord(const char *path) { @@ -148,6 +119,7 @@ static int generate_log_vmrecord(const char *path) " * This file records VM id synced or about to be synched,\n" " * the tag \"<==\" indicates event waiting to sync.\n" " * the tag \"NOT_FOUND\" indicates event not found in UOS.\n" + " * the tag \"MISS_LOGS\" indicates event miss logs in UOS.\n" " */\n\n"; LOGD("Generate (%s)\n", path); @@ -204,7 +176,12 @@ static int refresh_key_synced_stage1(const struct sender_t *sender, return -1; } - append_file(log_vmrecordid, log_new); + if (append_file(log_vmrecordid, log_new, + strnlen(log_new, 64)) < 0) { + LOGE("failed to add new record (%s) to (%s)\n", + log_new, log_vmrecordid); + return -1; + } return 0; } @@ -215,7 +192,8 @@ static int refresh_key_synced_stage1(const struct sender_t *sender, enum stage2_refresh_type_t { SUCCESS, - NOT_FOUND + NOT_FOUND, + MISS_LOG }; static int refresh_key_synced_stage2(char *line, size_t len, @@ -228,6 +206,8 @@ static int refresh_key_synced_stage2(char *line, size_t len, memcpy(tag, VMRECORD_TAG_SUCCESS, VMRECORD_TAG_LEN); else if (type == NOT_FOUND) memcpy(tag, VMRECORD_TAG_NOT_FOUND, VMRECORD_TAG_LEN); + else if (type == MISS_LOG) + memcpy(tag, VMRECORD_TAG_MISS_LOG, VMRECORD_TAG_LEN); else return -1; @@ -390,7 +370,7 @@ static void sync_lines_stage2(const struct sender_t *sender, } for (record = next_record(recos, recos->begin, &recolen); record; - record = next_record(recos, record, &recolen)) { + record = next_record(recos, record + recolen, &recolen)) { const char * const record_fmt = VM_NAME_FMT ANDROID_KEY_FMT IGN_RESTS; char *hist_line; @@ -398,6 +378,7 @@ static void sync_lines_stage2(const struct sender_t *sender, char vm_name[32]; char vmkey[ANDROID_WORD_LEN]; struct vm_t *vm; + int res; /* VMNAME xxxxxxxxxxxxxxxxxxxx <== */ if (str_split_ere(record, recolen, @@ -421,8 +402,11 @@ static void sync_lines_stage2(const struct sender_t *sender, continue; } - if (fn(hist_line, len + 1, vm) == VMEVT_HANDLED) + res = fn(hist_line, len + 1, vm); + if (res == VMEVT_HANDLED) refresh_key_synced_stage2(record, recolen, SUCCESS); + else if (res == VMEVT_MISSLOG) + refresh_key_synced_stage2(record, recolen, MISS_LOG); } out: @@ -454,8 +438,9 @@ static void get_last_line_synced(const struct sender_t *sender) continue; snprintf(vm_name, sizeof(vm_name), "%s ", vm->name); - ret = file_read_key_value_r(sender->log_vmrecordid, vm_name, - sizeof(vmkey), vmkey); + ret = file_read_key_value_r(vmkey, sizeof(vmkey), + sender->log_vmrecordid, + vm_name, strnlen(vm_name, 32)); if (ret == -ENOENT) { LOGD("no (%s), will generate\n", sender->log_vmrecordid); @@ -536,8 +521,8 @@ static char *setup_loop_dev(void) /* This function searches all android vms' new events and call the fn for * each event. * - * Note that: fn should return 0 to indicate event has been handled, - * or fn will be called in a time loop until it returns 0. + * Note that: fn should return VMEVT_HANDLED to indicate event has been handled. + * fn will be called in a time loop if it returns VMEVT_DEFER. */ void refresh_vm_history(const struct sender_t *sender, int (*fn)(const char*, size_t, const struct vm_t *)) diff --git a/tools/acrn-crashlog/acrnprobe/history.c b/tools/acrn-crashlog/acrnprobe/history.c index 831b9e8a6..e40ee9418 100644 --- a/tools/acrn-crashlog/acrnprobe/history.c +++ b/tools/acrn-crashlog/acrnprobe/history.c @@ -122,7 +122,6 @@ void hist_raise_event(const char *event, const char *type, const char *log, char eventtime[LONG_TIME_SIZE]; struct sender_t *crashlog; int maxlines; - int ret; struct history_entry entry = { .event = event, .type = type, @@ -143,16 +142,13 @@ void hist_raise_event(const char *event, const char *type, const char *log, backup_history(); } - ret = get_current_time_long(eventtime); - if (ret <= 0) + if (get_current_time_long(eventtime) <= 0) return; entry.eventtime = eventtime; entry_to_history_line(&entry, line); - ret = append_file(history_file, line); - if (ret < 0) { - LOGE("append (%s) failed, error (%s)\n", history_file, - strerror(errno)); + if (append_file(history_file, line, strnlen(line, MAXLINESIZE)) <= 0) { + LOGE("failed to append (%s) to (%s)\n", line, history_file); return; } } @@ -235,7 +231,8 @@ static int get_time_from_firstline(char *buffer, size_t size) const char *prefix = "#V1.0 CURRENTUPTIME "; int len; - len = file_read_key_value(history_file, prefix, MAXLINESIZE, lasttime); + len = file_read_key_value(lasttime, MAXLINESIZE, history_file, prefix, + strlen(prefix)); if (len <= 0) { LOGW("failed to read value from %s, error %s\n", history_file, strerror(-len)); @@ -289,11 +286,12 @@ int prepare_history(void) strerror(errno)); return ret; } - ret = append_file(history_file, HISTORY_BLANK_LINE2); + ret = append_file(history_file, HISTORY_BLANK_LINE2, + sizeof(HISTORY_BLANK_LINE2) - 1); if (ret < 0) { LOGE("Write (%s, %s) failed, error (%s)\n", history_file, HISTORY_BLANK_LINE2, - strerror(errno)); + strerror(-ret)); return ret; } current_lines = count_lines_in_file(history_file); diff --git a/tools/acrn-crashlog/acrnprobe/include/android_events.h b/tools/acrn-crashlog/acrnprobe/include/android_events.h index 5dc3e80c8..7dc9d0ba9 100644 --- a/tools/acrn-crashlog/acrnprobe/include/android_events.h +++ b/tools/acrn-crashlog/acrnprobe/include/android_events.h @@ -11,7 +11,9 @@ extern char *loop_dev; #define VMEVT_HANDLED 0 #define VMEVT_DEFER -1 +#define VMEVT_MISSLOG -2 +#define ANDROID_LOGS_DIR "/logs/" #define IGN_SPACES "%*[[[:space:]]*]" #define IGN_RESTS "%*[[.]*]" #define IGN_ONEWORD "%*[[^[:space:]]*]" IGN_SPACES diff --git a/tools/acrn-crashlog/acrnprobe/property.c b/tools/acrn-crashlog/acrnprobe/property.c index b1b4d5891..05af6ffe5 100644 --- a/tools/acrn-crashlog/acrnprobe/property.c +++ b/tools/acrn-crashlog/acrnprobe/property.c @@ -71,8 +71,9 @@ static int get_buildversion(struct sender_t *sender) char *logbuildid; char *currentbuild = gbuildversion; - ret = file_read_key_value(OS_VERSION, OS_VERSION_KEY, - sizeof(gbuildversion), gbuildversion); + ret = file_read_key_value(gbuildversion, sizeof(gbuildversion), + OS_VERSION, OS_VERSION_KEY, + strlen(OS_VERSION_KEY)); if (ret <= 0) { LOGE("failed to get version from %s, error (%s)\n", OS_VERSION, strerror(-ret)); diff --git a/tools/acrn-crashlog/acrnprobe/sender.c b/tools/acrn-crashlog/acrnprobe/sender.c index f782e06d6..e43ed1061 100644 --- a/tools/acrn-crashlog/acrnprobe/sender.c +++ b/tools/acrn-crashlog/acrnprobe/sender.c @@ -216,13 +216,14 @@ static void telemd_get_log(struct log_t *log, void *data) int res; int i; struct dirent **filelist; + struct ac_filter_data acfd = {log->name, log->name_len}; if (d->srcdir == NULL) goto send_nologs; /* search file which use log->name as substring */ count = ac_scandir(d->srcdir, &filelist, filter_filename_substr, - log->name, NULL); + &acfd, NULL); if (count < 0) { LOGE("search (%s) in dir (%s) failed\n", log->name, d->srcdir); return; @@ -544,8 +545,7 @@ static void telemd_send_reboot(void) } static int telemd_new_vmevent(const char *line_to_sync, - size_t len __attribute__((unused)), - const struct vm_t *vm) + size_t len, const struct vm_t *vm) { char event[ANDROID_WORD_LEN]; char longtime[ANDROID_WORD_LEN]; @@ -589,21 +589,26 @@ static int telemd_new_vmevent(const char *line_to_sync, severity = INFO_SEVERITY; /* if line contains log, fill vmlogpath */ - log = strstr(rest, "/logs/"); + log = strstr(rest, ANDROID_LOGS_DIR); if (log) { - struct sender_t *crashlog; + struct sender_t *crashlog = get_sender_by_name("crashlog"); + const char *logf; + size_t logflen; + int res; - crashlog = get_sender_by_name("crashlog"); if (!crashlog) return VMEVT_HANDLED; - res = find_file(crashlog->outdir, log + strlen("/logs/"), - 2, &vmlogpath, 1); - if (res < 0) { - LOGE("find (%s) in (%s) failed\n", - log + strlen("/logs/"), crashlog->outdir); + logf = log + sizeof(ANDROID_LOGS_DIR) - 1; + logflen = &rest[0] + strnlen(rest, PATH_MAX) - logf; + res = find_file(crashlog->outdir, logf, logflen, 1, + &vmlogpath, 1); + if (res == -1) { + LOGE("failed to find (%s) in (%s)\n", + logf, crashlog->outdir); + return VMEVT_DEFER; + } else if (res == 0) return VMEVT_DEFER; - } } res = asprintf(&class, "%s/%s/%s", vm->name, event, type); @@ -898,8 +903,7 @@ static void crashlog_send_reboot(void) } static int crashlog_new_vmevent(const char *line_to_sync, - size_t len __attribute__((unused)), - const struct vm_t *vm) + size_t len, const struct vm_t *vm) { struct sender_t *crashlog; char event[ANDROID_WORD_LEN]; @@ -980,12 +984,18 @@ static int crashlog_new_vmevent(const char *line_to_sync, ret = VMEVT_DEFER; } else { LOGW("(%s) is missing\n", vmlogpath); - ret = VMEVT_HANDLED; /* missing logdir */ + ret = VMEVT_MISSLOG; /* missing logdir */ } - res = remove(dir); - if (res == -1 && errno != ENOENT) + if (remove_r(dir) == -1) + LOGE("failed to remove %s (%d)\n", dir, -errno); + goto free_dir; + } + if (cnt == 1) { + LOGW("(%s) is empty, will sync it in the next loop\n", + vmlogpath); + ret = VMEVT_DEFER; + if (remove_r(dir) == -1) LOGE("failed to remove %s (%d)\n", dir, -errno); - goto free_dir; } } diff --git a/tools/acrn-crashlog/common/cmdutils.c b/tools/acrn-crashlog/common/cmdutils.c index 29539c443..e05682587 100644 --- a/tools/acrn-crashlog/common/cmdutils.c +++ b/tools/acrn-crashlog/common/cmdutils.c @@ -136,7 +136,7 @@ int exec_out2file(const char *outfile, const char *fmt, ...) if (ret < 0) return ret; - strtrim(cmd); + strtrim(cmd, ret); argc = strcnt(cmd, ' ') + 1; argv = (char **)calloc(argc + 1, sizeof(char *)); @@ -171,11 +171,12 @@ int exec_out2file(const char *outfile, const char *fmt, ...) * to memory. The memory is allocated by this function and needs to be freed * after return. * + * @param[out] outmem The pointer to command's output. * @param fmt Format string of command. * - * @return a pointer to command's output if successful, or NULL if not. + * @return the length of command's output if successful, or -1 if not. */ -char *exec_out2mem(const char *fmt, ...) +ssize_t exec_out2mem(char **outmem, const char *fmt, ...) { va_list args; char *cmd; @@ -183,23 +184,25 @@ char *exec_out2mem(const char *fmt, ...) char *out = NULL; char *new; char tmp[1024]; - int memsize = 0; - int newlen = 0; - int len = 0; + size_t memsize = 0; + size_t newlen = 0; + ssize_t len = 0; int ret; va_start(args, fmt); ret = vasprintf(&cmd, fmt, args); va_end(args); if (ret < 0) - return NULL; + return -1; pp = popen(cmd, "r"); - if (!pp) - goto free_cmd; + if (!pp) { + free(cmd); + return -1; + } while (fgets(tmp, 1024, pp) != NULL) { - newlen += strlen(tmp); + newlen += strnlen(tmp, 1024); if (newlen + 1 > memsize) { memsize += 1024; new = realloc(out, memsize); @@ -208,20 +211,22 @@ char *exec_out2mem(const char *fmt, ...) free(out); out = NULL; } + len = -1; goto end; } else { out = new; } } - memcpy(out + len, tmp, strlen(tmp) + 1); + /* fgets read at most 1023 bytes and plus '\0' */ + memcpy(out + len, tmp, strnlen(tmp, 1024) + 1); len = newlen; } end: + *outmem = out; pclose(pp); -free_cmd: free(cmd); - return out; + return len; } diff --git a/tools/acrn-crashlog/common/fsutils.c b/tools/acrn-crashlog/common/fsutils.c index 863027fe2..629d3a876 100644 --- a/tools/acrn-crashlog/common/fsutils.c +++ b/tools/acrn-crashlog/common/fsutils.c @@ -32,13 +32,12 @@ #include #include #include +#include #include "fsutils.h" #include "cmdutils.h" #include "strutils.h" #include "log_sys.h" -#define MAX_SEARCH_DIRS 4096 - /** * Help function to do fclose. In some cases (full partition), * file closure could fail, so get error message here. @@ -81,6 +80,30 @@ int mkdir_p(const char *path) return exec_out2file(NULL, "mkdir -p %s", path); } +static int rmfile(const char *path, + const struct stat *sbuf __attribute__((unused)), + int type __attribute__((unused)), + struct FTW *ftwb __attribute__((unused))) +{ + if (remove(path) == -1) { + LOGE("failed to remove (%s), error (%s)\n", path, + strerror(errno)); + return -1; + } + return 0; +} + +int remove_r(const char *dir) +{ + if (!dir) + return -1; + + if (nftw(dir, rmfile, 10, FTW_DEPTH | FTW_MOUNT | FTW_PHYS) == -1) + return -1; + + return 0; +} + /** * Count file lines. * This function defaults to all text files ending with \n. @@ -141,7 +164,6 @@ char *mm_get_line(struct mm_file_t *mfile, int line) struct mm_file_t *mmap_file(const char *path) { struct mm_file_t *mfile; - int size; mfile = malloc(sizeof(struct mm_file_t)); if (!mfile) { @@ -167,8 +189,7 @@ struct mm_file_t *mmap_file(const char *path) path, strerror(errno)); goto close_fd; } - size = mfile->size > 0 ? mfile->size : PAGE_SIZE; - mfile->begin = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, + mfile->begin = mmap(NULL, mfile->size, PROT_READ|PROT_WRITE, MAP_SHARED, mfile->fd, 0); if (mfile->begin == MAP_FAILED) { LOGE("mmap (%s) failed, error (%s)\n", path, strerror(errno)); @@ -293,22 +314,18 @@ int do_mv(char *src, char *dest) * * @return 0 if successful, or a negative errno-style value if not. */ -int append_file(char *filename, char *text) +ssize_t append_file(const char *filename, const char *text, size_t tlen) { - int fd, res, len; + int fd, res; - if (!filename || !text) + if (!filename || !text || !tlen) return -EINVAL; - len = strlen(text); - if (!len) - return -EINVAL; - - fd = open(filename, O_RDWR | O_APPEND); + fd = open(filename, O_WRONLY | O_APPEND); if (fd < 0) return -errno; - res = write(fd, text, len); + res = write(fd, text, tlen); close(fd); return (res == -1 ? -errno : res); @@ -344,7 +361,7 @@ int replace_file_head(char *filename, char *text) * The file is created if it does not exist, otherwise it is truncated. * * @param filename Path of file. - * @param text String need to be appended. + * @param text String need to be written. * * @return 0 if successful, or a negative errno-style value if not. */ @@ -368,42 +385,6 @@ int overwrite_file(const char *filename, const char *value) return ret; } -/** - * Read line from file descriptor. - * - * @param fd File descriptor. - * @param[out] buffer Content of line. - * - * @return length of line if successful, or a negative errno-style value if not. - */ -int readline(int fd, char buffer[MAXLINESIZE]) -{ - int size = 0, res; - char *pbuffer = &buffer[0]; - - /* Read the file until end of line or file */ - while ((res = read(fd, pbuffer, 1)) == 1 && size < MAXLINESIZE-1) { - if (pbuffer[0] == '\n') { - buffer[++size] = 0; - return size; - } - pbuffer++; - size++; - } - - /* Check the last read result */ - if (res < 0) { - /* ernno is checked in the upper layer as we could - * print the filename here - */ - return res; - } - /* last line */ - buffer[size] = 0; - - return size; -} - /** * Read the first line from file. * @@ -414,7 +395,7 @@ int readline(int fd, char buffer[MAXLINESIZE]) * @return length of string if successful, or a negative errno-style value * if not. */ -int file_read_string(const char *file, char *string, int size) +ssize_t file_read_string(const char *file, char *string, const int size) { FILE *fp; char *res; @@ -440,7 +421,7 @@ int file_read_string(const char *file, char *string, int size) end = strchr(string, '\n'); if (end) *end = 0; - return strlen(string); + return strnlen(string, size); } /** @@ -678,89 +659,17 @@ int count_lines_in_file(const char *filename) return ret; } -/** - * Read binary file. - * - * @param path File path to read. - * @param[out] File size being read. - * @param[out] data File content. - * - * @return 0 if successful, or -1 if not. - */ -int read_full_binary_file(const char *path, unsigned long *size, void **data) +static ssize_t _file_read_key_value(char *value, const size_t limit, + const char *path, const char *key, + size_t klen, const char op) { - FILE *f; - long _size; - void *buf; - int err; - - if (!path || !data || !size) { - errno = EINVAL; - return -1; - } - - f = fopen(path, "rb"); - if (!f) - return -1; - - if (fseek(f, 0, SEEK_END) == -1) { - err = errno; - goto close; - } - - _size = ftell(f); - if (_size == -1) { - err = errno; - goto close; - } else if (!_size) { - err = ERANGE; - goto close; - } - - if (fseek(f, 0, SEEK_SET) == -1) { - err = errno; - goto close; - } - - buf = malloc(_size + 10); - if (!buf) { - err = ENOMEM; - goto close; - } - - memset(buf, 0, _size + 10); - if (fread(buf, 1, _size, f) != (unsigned int)_size) { - err = EBADF; - goto free; - } - - close_file(path, f); - - *data = buf; - *size = (unsigned long)_size; - - return 0; - -free: - free(buf); -close: - close_file(path, f); - errno = err; - return -1; -} - -static int _file_read_key_value(const char *path, const char op, - const char *key, const size_t limit, - char *value) -{ - int fd; - int size; size_t len; - char *data; char *msg = NULL; - char *end, *start; + struct mm_file_t *f = mmap_file(path); - if (!key || !path) { + if (!f) + return -errno; + if (!key) { errno = EINVAL; return -errno; } @@ -770,63 +679,47 @@ static int _file_read_key_value(const char *path, const char op, return -errno; } - size = get_file_size(path); - if (size < 0) - return size; - if (!size) { - errno = ENOMSG; - return -errno; - } - - fd = open(path, O_RDONLY); - if (fd < 0) - return -errno; - - data = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); - if (data == MAP_FAILED) - goto close; - if (op == 'l') - msg = strstr(data, key); - else if (op == 'r') - msg = strrstr(data, key); + msg = get_line(key, klen, f->begin, f->size, f->begin, &len); + else if (op == 'r') { + char *msg_tmp; + + msg = f->begin; + len = 0; + while ((msg_tmp = get_line(key, klen, f->begin, f->size, + msg, &len))) + msg = msg_tmp + len; + if (msg != f->begin) + msg -= len; + else + msg = NULL; + } if (!msg) { errno = ENOMSG; goto unmap; } - start = msg + strlen(key); - end = strchr(start, '\n'); - if (end == NULL) - end = data + size; - - len = end - start; - len = MIN(len, limit - 1); - memcpy(value, start, len); - *(value + len) = 0; - - munmap(data, size); - close(fd); + len = MIN(len - klen, limit - 1); + *(char *)mempcpy(value, msg + klen, len) = '\0'; + unmap_file(f); return len; unmap: - munmap(data, size); -close: - close(fd); + unmap_file(f); return -errno; } -int file_read_key_value(const char *path, const char *key, - const size_t limit, char *value) +ssize_t file_read_key_value(char *value, const size_t limit, const char *path, + const char *key, size_t klen) { - return _file_read_key_value(path, 'l', key, limit, value); + return _file_read_key_value(value, limit, path, key, klen, 'l'); } -int file_read_key_value_r(const char *path, const char *key, - const size_t limit, char *value) +ssize_t file_read_key_value_r(char *value, const size_t limit, const char *path, + const char *key, size_t klen) { - return _file_read_key_value(path, 'r', key, limit, value); + return _file_read_key_value(value, limit, path, key, klen, 'r'); } /** @@ -914,41 +807,46 @@ e_free: /* filters return zero if the match is successful */ int filter_filename_substr(const struct dirent *entry, const void *arg) { - const char *substr = (const char *)arg; + struct ac_filter_data *d = (struct ac_filter_data *)arg; - return !strstr(entry->d_name, substr); + return !memmem(entry->d_name, _D_EXACT_NAMLEN(entry), d->str, d->len); } int filter_filename_exactly(const struct dirent *entry, const void *arg) { - const char *fname = (const char *)arg; + struct ac_filter_data *d = (struct ac_filter_data *)arg; - return strcmp(entry->d_name, fname); + return strcmp(entry->d_name, d->str); } int filter_filename_startswith(const struct dirent *entry, const void *arg) { - const char *str = (const char *)arg; + struct ac_filter_data *d = (struct ac_filter_data *)arg; - return memcmp(entry->d_name, str, strlen(str)); + if (_D_EXACT_NAMLEN(entry) < d->len) + return -1; + + return memcmp(entry->d_name, d->str, d->len); } -int dir_contains(const char *dir, const char *filename, const int exact) +int dir_contains(const char *dir, const char *filename, size_t flen, + const int exact) { int ret; int i; struct dirent **filelist; + struct ac_filter_data acfd = {filename, flen}; - if (!dir || !filename) + if (!dir || !filename || !flen) return -1; if (exact) ret = ac_scandir(dir, &filelist, filter_filename_exactly, - (const void *)filename, 0); + (const void *)&acfd, 0); else ret = ac_scandir(dir, &filelist, filter_filename_substr, - (const void *)filename, 0); + (const void *)&acfd, 0); if (ret <= 0) return ret; @@ -1008,121 +906,108 @@ free_list: return count; } -static int is_subdir(const struct dirent *entry) -{ - return (entry->d_type == DT_DIR) && - strcmp(entry->d_name, ".") && - strcmp(entry->d_name, ".."); -} - -static void expand_dir(char *_dirs[], int *count, int depth, int max_depth) -{ - int files; - int i; - int res; - struct dirent **filelist; - char *subdir; - char *name; - char *current_dir = _dirs[*count - 1]; - - if (depth > max_depth) - return; - - - files = scandir(current_dir, &filelist, is_subdir, 0); - if (files < 0) { - LOGE("lsdir failed, error (%s)\n", strerror(-files)); - return; - } - - for (i = 0; i < files; i++) { - if (*count >= MAX_SEARCH_DIRS) { - LOGE("too many dirs(%d) under %s\n", - *count, _dirs[0]); - goto free; - } - - name = filelist[i]->d_name; - res = asprintf(&subdir, "%s/%s", current_dir, name); - if (res < 0) { - LOGE("compute string failed, out of memory\n"); - goto free; - } - - _dirs[*count] = subdir; - (*count)++; - expand_dir(_dirs, count, depth++, max_depth); - } -free: - for (i = 0; i < files; i++) - free(filelist[i]); - free(filelist); -} - /** * Find target file in specified dir. * * @param dir Where to start search. * @param target_file Target file to search. - * @param depth File's depth in the directory tree. + * @param tflen The length of target_file. + * @param depth Descend at most depth of directories below the starting dir. * @param path[out] Searched file path in given dir. * @param limit The number of files uplayer want to get. * * @return the count of searched files on success, or -1 on error. */ -int find_file(const char *dir, char *target_file, int depth, char *path[], - int limit) +int find_file(const char *dir, const char *target_file, size_t tflen, + int depth, char *path[], int limit) { - int i, ret; - int count = 0; - char *_dirs[MAX_SEARCH_DIRS]; - int dirs; + int wdepth = 0; + int found = 0; + char wdir[PATH_MAX]; + DIR **dp; - if (depth < 1 || !dir || !target_file || !path || limit <= 0) + if (!dir || !target_file || !tflen || !path || limit <= 0) return -1; - - ret = asprintf(&_dirs[0], "%s", dir); - if (ret < 0) { - LOGE("compute string failed, out of memory\n"); + if (!memccpy(wdir, dir, 0, PATH_MAX)) + return -1; + dp = calloc(depth + 1, sizeof(DIR *)); + if (!dp) { + LOGE("out of memory\n"); return -1; } - dirs = 1; - /* expand all dirs */ - expand_dir(_dirs, &dirs, 1, depth); - for (i = 0; i < dirs; i++) { - if (count >= limit) - goto free; + while (wdepth >= 0) { + struct dirent *dirp; - ret = dir_contains(_dirs[i], target_file, 1); - if (ret == 1) { - ret = asprintf(&path[count++], "%s/%s", - _dirs[i], target_file); - if (ret < 0) { - LOGE("compute string failed, out of memory\n"); - ret = -1; - goto fail; + if (!dp[wdepth]) { + /* new stream */ + dp[wdepth] = opendir(wdir); + if (!dp[wdepth]) { + LOGE("failed to opendir (%s), error (%s)\n", + wdir, strerror(errno)); + goto fail_open; + } + } + + while (!(errno = 0) && (dirp = readdir(dp[wdepth]))) { + if (!strcmp(dirp->d_name, ".") || + !strcmp(dirp->d_name, "..")) + continue; + + if (!strcmp(dirp->d_name, target_file)) { + if (asprintf(&path[found], "%s/%s", wdir, + dirp->d_name) == -1) { + LOGE("out of memory\n"); + goto fail_read; + } + if (++found == limit) + goto end; + } + + if (dirp->d_type == DT_DIR && wdepth < depth) { + /* search in subdir */ + *(char *) + mempcpy(mempcpy(wdir + strnlen(wdir, PATH_MAX), + "/", 1), + dirp->d_name, + strnlen(dirp->d_name, NAME_MAX)) = '\0'; + wdepth++; + break; + } + } + if (!dirp) { + if (!errno) { + /* meet the end of stream, back to the parent */ + char *p; + + closedir(dp[wdepth]); + dp[wdepth--] = NULL; + p = strrchr(wdir, '/'); + if (p) + *p = '\0'; + } else { + LOGE("failed to readdir, (%s)\n", + strerror(errno)); + goto fail_read; } - } else if (ret < 0) { - LOGE("dir_contains failed\n"); - ret = -1; - goto fail; } } +end: + while (wdepth >= 0) + closedir(dp[wdepth--]); + free(dp); + return found; -free: - for (i = 0; i < dirs; i++) - free(_dirs[i]); - - return count; -fail: - for (i = 0; i < dirs; i++) - free(_dirs[i]); - - for (i = 0; i < count; i++) - free(path[i]); - - return ret; +fail_read: + LOGE("failed to search in dir %s\n", wdir); + closedir(dp[wdepth]); +fail_open: + while (wdepth) + closedir(dp[--wdepth]); + while (found) + free(path[--found]); + free(dp); + return -1; } int read_file(const char *path, unsigned long *size, void **data) @@ -1214,6 +1099,7 @@ int config_fmt_to_files(const char *file_fmt, char ***out) int ret = 0; struct dirent **filelist; char **out_array; + struct ac_filter_data acfd; if (!file_fmt || !out) return -1; @@ -1247,14 +1133,15 @@ int config_fmt_to_files(const char *file_fmt, char ***out) *p = '\0'; file_prefix = p + 1; p = strrchr(file_prefix, '['); - if (p) { - *p = '\0'; - } else { + if (!p) { ret = -1; LOGE("unsupported formats (%s)\n", dir); goto free_dir; } + *p = '\0'; + acfd.str = file_prefix; + acfd.len = p - file_prefix; if (!directory_exists(dir)) { ret = 0; @@ -1276,7 +1163,7 @@ int config_fmt_to_files(const char *file_fmt, char ***out) /* get all files which start with prefix */ count = ac_scandir(dir, &filelist, filter_filename_startswith, - file_prefix, alphasort); + &acfd, alphasort); if (count < 0) { ret = -1; LOGE("failed to ac_scandir\n"); diff --git a/tools/acrn-crashlog/common/include/cmdutils.h b/tools/acrn-crashlog/common/include/cmdutils.h index fe1898916..8248e7fa5 100644 --- a/tools/acrn-crashlog/common/include/cmdutils.h +++ b/tools/acrn-crashlog/common/include/cmdutils.h @@ -5,4 +5,4 @@ int execv_out2file(char * const argv[], const char *outfile); int exec_out2file(const char *outfile, const char *fmt, ...); -char *exec_out2mem(const char *fmt, ...); +ssize_t exec_out2mem(char **outmem, const char *fmt, ...); diff --git a/tools/acrn-crashlog/common/include/fsutils.h b/tools/acrn-crashlog/common/include/fsutils.h index d0f676a2f..ef0148531 100644 --- a/tools/acrn-crashlog/common/include/fsutils.h +++ b/tools/acrn-crashlog/common/include/fsutils.h @@ -43,6 +43,11 @@ struct mm_file_t { int size; }; +struct ac_filter_data { + const char *str; + size_t len; +}; + static inline int file_exists(const char *filename) { struct stat info; @@ -72,18 +77,17 @@ static inline int get_file_size(const char *filepath) char *mm_get_line(struct mm_file_t *mfile, int line); int mkdir_p(const char *path); +int remove_r(const char *dir); int mm_count_lines(struct mm_file_t *mfile); struct mm_file_t *mmap_file(const char *path); void unmap_file(struct mm_file_t *mfile); int do_copy_tail(const char *src, const char *dest, int limit); int do_mv(char *src, char *dest); -int append_file(char *filename, char *text); -int mm_replace_str_line(struct mm_file_t *mfile, char *replace, - int line); +ssize_t append_file(const char *filename, const char *text, size_t tlen); int replace_file_head(char *filename, char *text); int overwrite_file(const char *filename, const char *value); int readline(int fd, char buffer[MAXLINESIZE]); -int file_read_string(const char *file, char *string, int size); +ssize_t file_read_string(const char *file, char *string, const int size); void file_reset_init(const char *filename); int file_read_int(const char *filename, unsigned int *pcurrent); int file_update_int(const char *filename, unsigned int current, @@ -93,10 +97,10 @@ int space_available(const char *path, int quota); int count_lines_in_file(const char *filename); int read_full_binary_file(const char *path, unsigned long *size, void **data); -int file_read_key_value(const char *path, const char *key, - const size_t limit, char *value); -int file_read_key_value_r(const char *path, const char *key, - const size_t limit, char *value); +ssize_t file_read_key_value(char *value, const size_t limit, const char *path, + const char *key, size_t klen); +ssize_t file_read_key_value_r(char *value, const size_t limit, const char *path, + const char *key, size_t klen); int ac_scandir(const char *dirp, struct dirent ***namelist, int (*filter)(const struct dirent *, const void *), const void *farg, @@ -106,10 +110,10 @@ int filter_filename_substr(const struct dirent *entry, const void *arg); int filter_filename_exactly(const struct dirent *entry, const void *arg); int filter_filename_startswith(const struct dirent *entry, const void *arg); -int dir_contains(const char *dir, const char *filename, int exact); +int dir_contains(const char *dir, const char *filename, size_t flen, int exact); int lsdir(const char *dir, char *fullname[], int limit); -int find_file(const char *dir, char *target_file, int depth, char *path[], - int limit); +int find_file(const char *dir, const char *target_file, size_t tflen, + int depth, char *path[], int limit); int read_file(const char *path, unsigned long *size, void **data); int is_ac_filefmt(const char *file_fmt); int config_fmt_to_files(const char *file_fmt, char ***out); diff --git a/tools/acrn-crashlog/common/include/log_sys.h b/tools/acrn-crashlog/common/include/log_sys.h index 7fa4b8171..c03abe982 100644 --- a/tools/acrn-crashlog/common/include/log_sys.h +++ b/tools/acrn-crashlog/common/include/log_sys.h @@ -6,42 +6,43 @@ #ifndef __LOG_SYS_H__ #define __LOG_SYS_H__ -#include #include +#include -void do_log(int level, -#ifdef DEBUG_ACRN_CRASHLOG - const char *func, int line, -#endif - ...); +void debug_log(int level, const char *func, int line, ...); -#define MAX_LOG_LEN 1024 #define LOG_LEVEL LOG_WARNING #ifdef DEBUG_ACRN_CRASHLOG #define LOGE(...) \ - do_log(LOG_ERR, __func__, __LINE__, __VA_ARGS__) + debug_log(LOG_ERR, __func__, __LINE__, __VA_ARGS__) #define LOGW(...) \ - do_log(LOG_WARNING, __func__, __LINE__, __VA_ARGS__) + debug_log(LOG_WARNING, __func__, __LINE__, __VA_ARGS__) #define LOGI(...) \ - do_log(LOG_INFO, __func__, __LINE__, __VA_ARGS__) + debug_log(LOG_INFO, __func__, __LINE__, __VA_ARGS__) #define LOGD(...) \ - do_log(LOG_DEBUG, __func__, __LINE__, __VA_ARGS__) + debug_log(LOG_DEBUG, __func__, __LINE__, __VA_ARGS__) #else +#define ac_log(level, ...) \ + do { \ + if (level <= LOG_LEVEL) \ + sd_journal_print(level, __VA_ARGS__); \ + } while (0) + #define LOGE(...) \ - do_log(LOG_ERR, __VA_ARGS__) + ac_log(LOG_ERR, __VA_ARGS__) #define LOGW(...) \ - do_log(LOG_WARNING, __VA_ARGS__) + ac_log(LOG_WARNING, __VA_ARGS__) #define LOGI(...) \ - do_log(LOG_INFO, __VA_ARGS__) + ac_log(LOG_INFO, __VA_ARGS__) #define LOGD(...) \ - do_log(LOG_DEBUG, __VA_ARGS__) + ac_log(LOG_DEBUG, __VA_ARGS__) #endif #endif diff --git a/tools/acrn-crashlog/common/include/strutils.h b/tools/acrn-crashlog/common/include/strutils.h index faf3da101..d5ac2cb55 100644 --- a/tools/acrn-crashlog/common/include/strutils.h +++ b/tools/acrn-crashlog/common/include/strutils.h @@ -9,10 +9,12 @@ #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) #define s_not_expect(res, size) (res < 0 || (size_t)res >= size) +char *get_line(const char *str, size_t str_size, + const char *area, size_t area_size, + const char *search_from, size_t *len); ssize_t strlinelen(const char *str, size_t size); char *strrstr(const char *s, const char *str); -char *next_line(char *buf); -char *strtrim(char *str); +char *strtrim(char *str, size_t len); int strcnt(char *str, char c); int str_split_ere(const char *str, size_t slen, const char *fmt, size_t flen, ...); diff --git a/tools/acrn-crashlog/common/log_sys.c b/tools/acrn-crashlog/common/log_sys.c index 98f0d7f0a..44006d9e7 100644 --- a/tools/acrn-crashlog/common/log_sys.c +++ b/tools/acrn-crashlog/common/log_sys.c @@ -4,46 +4,35 @@ */ #include +#include #include -#include +#include #include "log_sys.h" -void do_log(const int level, -#ifdef DEBUG_ACRN_CRASHLOG - const char *func, const int line, -#endif - ...) +void debug_log(const int level, const char *func, const int line, ...) { va_list args; char *fmt; - char log[MAX_LOG_LEN]; - int n = 0; -#ifdef DEBUG_ACRN_CRASHLOG - const char header_fmt[] = "<%-20s%5d>: "; -#endif + char *head; + char *msg; if (level > LOG_LEVEL) return; -#ifdef DEBUG_ACRN_CRASHLOG va_start(args, line); -#else - va_start(args, level); -#endif fmt = va_arg(args, char *); if (!fmt) return; - -#ifdef DEBUG_ACRN_CRASHLOG - /* header */ - n = snprintf(log, sizeof(log), header_fmt, func, line); - if (n < 0 || (size_t)n >= sizeof(log)) - n = 0; -#endif - /* msg */ - vsnprintf(log + n, sizeof(log) - (size_t)n, fmt, args); - log[sizeof(log) - 1] = 0; + if (vasprintf(&msg, fmt, args) == -1) + return; va_end(args); - sd_journal_print(level, "%s", log); + if (asprintf(&head, "<%-20s%5d>: ", func, line) == -1) { + free(msg); + return; + } + + sd_journal_print(level, "%s%s", head, msg); + free(msg); + free(head); } diff --git a/tools/acrn-crashlog/common/strutils.c b/tools/acrn-crashlog/common/strutils.c index eb68377fb..9b6bbffb4 100644 --- a/tools/acrn-crashlog/common/strutils.c +++ b/tools/acrn-crashlog/common/strutils.c @@ -11,6 +11,62 @@ #include "log_sys.h" #include "fsutils.h" +/** + * Find the first line containing specified string in given area. + * + * @param str A pointer to the string contained by target line. + * @param str_size String length of str. + * @param area A pointer to the area where target line may be located. + * This pointer will be returned if the specified string is in + * the first line of area (There is not '\n' located between area + * and the head of searched string). + * @param area_size String length of area. + * @param search_from A pointer where searching starts. It should be greater + * than or equal to area, and less than area + area_size. + * @param[out] len The length of target line (excludes \n), it only be modified + * when function returns successfully. + * + * @return a pointer to the head of target line within area (it may be greater + * than search_from). + * NULL will be returned if the specified string is not found in + * any lines (lines must end with '\n'. It means the real searching + * scope is from search_from to the last '\n' in area). + */ +char *get_line(const char *str, size_t str_size, + const char *area, size_t area_size, + const char *search_from, size_t *len) +{ + char *p; + char *match; + char *tail; + ssize_t search_size = area + area_size - search_from; + + if (!str || !str_size || !area || !area_size || !search_from || !len) + return NULL; + + if (search_from < area || search_from >= area + area_size || + (size_t)search_size < str_size) + return NULL; + + match = memmem(search_from, search_size, str, str_size); + if (!match) + return NULL; + tail = memchr(match + str_size, '\n', + area + area_size - match - str_size); + if (!tail) + return NULL; + + for (p = match; p >= area; p--) { + if (*p == '\n') { + *len = tail - p - 1; + return (char *)(p + 1); + } + } + + *len = tail - area; + return (char *)area; +} + /** * Get the length of line. * @@ -57,54 +113,32 @@ char *strrstr(const char *s, const char *substr) return NULL; } -char *next_line(char *buf) +char *strtrim(char *str, size_t len) { + size_t h_del = 0; + size_t reserve; char *p; - p = strchr(buf, '\n'); - /* if meet end of buf, the return value is also NULL */ - if (p) - return p + 1; + if (!len) + return str; - return NULL; -} + for (p = str; p < str + len && *p == ' '; p++) + h_del++; -static char *strtriml(char *str) -{ - char *p = str; - - while (*p == ' ') - p++; - return memmove(str, p, strlen(p) + 1); -} - -static char *strtrimr(char *str) -{ - size_t len; - char *end; - - len = strlen(str); - if (len > 0) { - end = str + strlen(str) - 1; - while (*end == ' ' && end >= str) { - *end = 0; - end--; - } + reserve = len - h_del; + if (!reserve) { + *str = '\0'; + return str; } + for (p = str + len - 1; p >= str && *p == ' '; p--) + reserve--; + + memmove(str, str + h_del, reserve); + *(str + reserve) = '\0'; return str; } -char *strtrim(char *str) -{ - if (str) { - strtrimr(str); - return strtriml(str); - } - - return NULL; -} - int strcnt(char *str, char c) { int cnt = 0; diff --git a/tools/acrn-crashlog/usercrash/crash_dump.c b/tools/acrn-crashlog/usercrash/crash_dump.c index c5d948c64..a941c1047 100644 --- a/tools/acrn-crashlog/usercrash/crash_dump.c +++ b/tools/acrn-crashlog/usercrash/crash_dump.c @@ -129,12 +129,11 @@ static int get_backtrace(int pid, int fd, int sig, const char *comm) return -1; } } - membkt = exec_out2mem(GET_GDB_INFO, format); - if (!membkt) { + len = exec_out2mem(&membkt, GET_GDB_INFO, format); + if (len <= 0) { LOGE("get gdb info failed\n"); return -1; } - len = strlen(membkt); ret = write(fd, membkt, len); free(membkt); if (ret != len) {