diff --git a/cmds/dump.c b/cmds/dump.c index 0c3b3bbcd..04ed1947f 100644 --- a/cmds/dump.c +++ b/cmds/dump.c @@ -1013,9 +1013,12 @@ static void dump_chrome_footer(struct uftrace_dump_ops *ops, struct uftrace_chrome_dump *chrome = container_of(ops, typeof(*chrome), ops); /* read recorded date and time */ - snprintf(buf, sizeof(buf), "%s/info", opts->dirname); - if (stat(buf, &statbuf) < 0) - return; + snprintf(buf, sizeof(buf), "%s/info.txt", opts->dirname); + if (stat(buf, &statbuf) < 0) { + snprintf(buf, sizeof(buf), "%s/info", opts->dirname); + if (stat(buf, &statbuf) < 0) + return; + } ctime_r(&statbuf.st_mtime, buf); buf[strlen(buf) - 1] = '\0'; diff --git a/cmds/info.c b/cmds/info.c index a83ce6823..fdad1d97b 100644 --- a/cmds/info.c +++ b/cmds/info.c @@ -853,6 +853,85 @@ static int read_uftrace_version(void *arg) return 0; } +void write_header(int fd, struct uftrace_file_header *hdr) +{ + dprintf(fd, "magic:%s\n", hdr->magic); + dprintf(fd, "version:%u\n", hdr->version); + dprintf(fd, "header_size:%u\n", hdr->header_size); + dprintf(fd, "endian:%u\n", hdr->endian); + dprintf(fd, "elf_class:%u\n", hdr->elf_class); + dprintf(fd, "feat_mask:%"PRIu64"\n", hdr->feat_mask); + dprintf(fd, "info_mask:%"PRIu64"\n", hdr->info_mask); + dprintf(fd, "max_stack:%u\n", hdr->max_stack); +} + +static char *read_header_field(FILE *fp, struct uftrace_file_header *hdr, + const char *field, char *buf) +{ + int len = strlen(field); + + if (fgets(buf, PATH_MAX, fp) == NULL) + return NULL; + if (strncmp(buf, field, len)) + return NULL; + return &buf[len]; +} + +int read_header(struct uftrace_file_header *hdr, FILE *fp, bool is_info_txt) +{ + char buf[PATH_MAX]; + char *data; + + if (!is_info_txt) { + if (fread(hdr, sizeof(*hdr), 1, fp) != 1) + return -1; + return 0; + } + + data = read_header_field(fp, hdr, "magic:", buf); + if (!data) + return -1; + memcpy(hdr->magic, copy_info_str(data), UFTRACE_MAGIC_LEN - 1); + + data = read_header_field(fp, hdr, "version:", buf); + if (!data) + return -1; + sscanf(data, "%u", &hdr->version); + + data = read_header_field(fp, hdr, "header_size:", buf); + if (!data) + return -1; + sscanf(data, "%hu", &hdr->header_size); + + data = read_header_field(fp, hdr, "endian:", buf); + if (!data) + return -1; + sscanf(data, "%hhu", &hdr->endian); + + data = read_header_field(fp, hdr, "elf_class:", buf); + if (!data) + return -1; + sscanf(data, "%hhu", &hdr->elf_class); + + data = read_header_field(fp, hdr, "feat_mask:", buf); + if (!data) + return -1; + sscanf(data, "%"PRIu64, &hdr->feat_mask); + + data = read_header_field(fp, hdr, "info_mask:", buf); + if (!data) + return -1; + sscanf(data, "%"PRIu64, &hdr->info_mask); + + data = read_header_field(fp, hdr, "max_stack:", buf); + if (!data) + return -1; + sscanf(data, "%hu", &hdr->max_stack); + + return 0; +} + + struct uftrace_info_handler { enum uftrace_info_bits bit; int (*handler)(void *arg); @@ -987,10 +1066,12 @@ void process_uftrace_info(struct uftrace_data *handle, struct opts *opts, if (info_mask == 0) return; - snprintf(buf, sizeof(buf), "%s/info", opts->dirname); - - if (stat(buf, &statbuf) < 0) - return; + snprintf(buf, sizeof(buf), "%s/info.txt", opts->dirname); + if (stat(buf, &statbuf) < 0) { + snprintf(buf, sizeof(buf), "%s/info", opts->dirname); + if (stat(buf, &statbuf) < 0) + return; + } process(data, "# system information\n"); process(data, "# ==================\n"); diff --git a/cmds/record.c b/cmds/record.c index a51696df9..b144f1d21 100644 --- a/cmds/record.c +++ b/cmds/record.c @@ -421,11 +421,12 @@ static int fill_file_header(struct opts *opts, int status, struct rusage *rusage char *filename = NULL; struct uftrace_file_header hdr; char elf_ident[EI_NIDENT]; + char buf[PATH_MAX]; - xasprintf(&filename, "%s/info", opts->dirname); + xasprintf(&filename, "%s/info.txt", opts->dirname); pr_dbg3("fill header (metadata) info in %s\n", filename); - fd = open(filename, O_WRONLY | O_CREAT| O_TRUNC, 0644); + fd = open(filename, O_RDWR | O_CREAT| O_TRUNC, 0644); if (fd < 0) pr_err("cannot open info file"); @@ -447,26 +448,21 @@ static int fill_file_header(struct opts *opts, int status, struct rusage *rusage hdr.unused1 = 0; hdr.unused2 = 0; - if (write(fd, &hdr, sizeof(hdr)) != (int)sizeof(hdr)) - pr_err("writing header info failed"); - fill_uftrace_info(&hdr.info_mask, fd, opts, status, rusage, elapsed_time); -try_write: - ret = pwrite(fd, &hdr, sizeof(hdr), 0); - if (ret != (int)sizeof(hdr)) { - static int retry = 0; - - if (ret > 0 && retry++ < 3) - goto try_write; + memset(buf, 0, PATH_MAX); + lseek(fd, 0, SEEK_SET); + if (read(fd, buf, PATH_MAX) < 0) + goto close_efd; + lseek(fd, 0, SEEK_SET); + write_header(fd, &hdr); + if (write(fd, buf, strlen(buf)) < 0) { pr_dbg("writing header info failed.\n"); goto close_efd; } - ret = 0; - close_efd: close(efd); close_fd: @@ -1367,14 +1363,12 @@ static void send_dbg_files(int sock, const char *dirname) static void send_info_file(int sock, const char *dirname) { int fd; - char *filename = NULL; struct uftrace_file_header hdr; struct stat stbuf; void *info; int len; - xasprintf(&filename, "%s/info", dirname); - fd = open(filename, O_RDONLY); + fd = open_correct_info_file(dirname, O_RDONLY); if (fd < 0) pr_err("open info failed"); @@ -1394,7 +1388,6 @@ static void send_info_file(int sock, const char *dirname) close(fd); free(info); - free(filename); } static void send_kernel_metadata(int sock, const char *dirname) diff --git a/cmds/recv.c b/cmds/recv.c index 9c05d1b52..8e483c787 100644 --- a/cmds/recv.c +++ b/cmds/recv.c @@ -476,7 +476,7 @@ static void recv_trace_info(int sock, int len) if (read_all(sock, info, len) < 0) pr_err("recv info failed"); - write_client_file(client, "info", 2, &hdr, sizeof(hdr), info, len); + write_client_file(client, "info.txt", 2, &hdr, sizeof(hdr), info, len); free(info); } diff --git a/uftrace.h b/uftrace.h index 89b642343..23b7f5f33 100644 --- a/uftrace.h +++ b/uftrace.h @@ -309,6 +309,7 @@ int command_tui(int argc, char *argv[], struct opts *opts); extern volatile bool uftrace_done; int open_data_file(struct opts *opts, struct uftrace_data *handle); +int open_correct_info_file(const char *dirname, int flags, ...); int open_info_file(struct opts *opts, struct uftrace_data *handle); void __close_data_file(struct opts *opts, struct uftrace_data *handle, bool unload_modules); @@ -553,6 +554,9 @@ static inline bool has_event_data(struct uftrace_data *handle) struct rusage; + +void write_header(int fd, struct uftrace_file_header *hdr); +int read_header(struct uftrace_file_header *hdr, FILE *fp, bool is_info_txt); void fill_uftrace_info(uint64_t *info_mask, int fd, struct opts *opts, int status, struct rusage *rusage, char *elapsed_time); int read_uftrace_info(uint64_t info_mask, struct uftrace_data *handle); diff --git a/utils/data-file.c b/utils/data-file.c index e8a0f34d3..658a78415 100644 --- a/utils/data-file.c +++ b/utils/data-file.c @@ -410,21 +410,56 @@ bool data_is_lp64(struct uftrace_data *handle) return handle->hdr.elf_class == ELFCLASS64; } +int open_correct_info_file(const char *dirname, int flags, ...) +{ + char buf[PATH_MAX]; + struct stat statbuf; + + snprintf(buf, sizeof(buf), "%s/info.txt", dirname); + if (stat(buf, &statbuf) < 0) { + snprintf(buf, sizeof(buf), "%s/info", dirname); + if (stat(buf, &statbuf) < 0) + return -1; + } + + if (flags & O_CREAT) { + va_list ap; + mode_t mode; + + va_start(ap, flags); + mode = va_arg(ap, mode_t); + va_end(ap); + + return open(buf, flags, mode); + } + return open(buf, flags); +} + int open_info_file(struct opts *opts, struct uftrace_data *handle) { FILE *fp; - char buf[PATH_MAX]; + char info_txt[PATH_MAX]; + char info_bin[PATH_MAX]; + bool is_info_txt = true; int saved_errno = 0; struct stat stbuf; memset(handle, 0, sizeof(*handle)); - snprintf(buf, sizeof(buf), "%s/info", opts->dirname); + snprintf(info_txt, sizeof(info_txt), "%s/info.txt", opts->dirname); - fp = fopen(buf, "rb"); + fp = fopen(info_txt, "r"); if (fp != NULL) goto ok; + snprintf(info_bin, sizeof(info_bin), "%s/info", opts->dirname); + + fp = fopen(info_bin, "rb"); + if (fp != NULL) { + is_info_txt = false; + goto ok; + } + saved_errno = errno; /* provide a better error code for empty/invalid directories */ if (stat(opts->dirname, &stbuf) == 0) @@ -433,28 +468,44 @@ int open_info_file(struct opts *opts, struct uftrace_data *handle) /* if default dirname is failed */ if (!strcmp(opts->dirname, UFTRACE_DIR_NAME)) { /* try again inside the current directory */ + fp = fopen("./info.txt", "r"); + if (fp != NULL) { + opts->dirname = "./"; + goto ok; + } + fp = fopen("./info", "rb"); if (fp != NULL) { opts->dirname = "./"; + is_info_txt = false; goto ok; } /* retry with old default dirname */ - snprintf(buf, sizeof(buf), "%s/info", UFTRACE_DIR_OLD_NAME); - fp = fopen(buf, "rb"); + snprintf(info_txt, sizeof(info_txt), "%s/info.txt", UFTRACE_DIR_OLD_NAME); + fp = fopen(info_txt, "r"); + if (fp != NULL) { + opts->dirname = UFTRACE_DIR_OLD_NAME; + goto ok; + } + + snprintf(info_bin, sizeof(info_bin), "%s/info", UFTRACE_DIR_OLD_NAME); + fp = fopen(info_bin, "rb"); if (fp != NULL) { opts->dirname = UFTRACE_DIR_OLD_NAME; + is_info_txt = false; goto ok; } saved_errno = errno; /* restore original file name for error reporting */ - snprintf(buf, sizeof(buf), "%s/info", opts->dirname); + snprintf(info_txt, sizeof(info_txt), "%s/info.txt", opts->dirname); + snprintf(info_bin, sizeof(info_bin), "%s/info", opts->dirname); } /* data file loading is failed */ - pr_dbg("cannot open %s file\n", buf); + pr_dbg("cannot open %s or %s file\n", info_txt, info_bin); return -saved_errno; ok: @@ -469,7 +520,7 @@ int open_info_file(struct opts *opts, struct uftrace_data *handle) handle->last_perf_idx = -1; INIT_LIST_HEAD(&handle->events); - if (fread(&handle->hdr, sizeof(handle->hdr), 1, fp) != 1) + if (read_header(&handle->hdr, fp, is_info_txt) < 0) pr_err("cannot read header data"); if (memcmp(handle->hdr.magic, UFTRACE_MAGIC_STR, UFTRACE_MAGIC_LEN))