X-Git-Url: https://git.lttng.org/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fbin%2Flttng-crash%2Flttng-crash.c;h=7f1f52803f9f5c5102ebcdbc5b8f5cd1281fa3d0;hp=0a8f072e721bee295e6560c6cf525a1ec1ddb0b9;hb=4ff128af76f44cc4e0aff55f00be3e57abf6ac00;hpb=93c4b58325c074281b332afb451356685641f33a diff --git a/src/bin/lttng-crash/lttng-crash.c b/src/bin/lttng-crash/lttng-crash.c index 0a8f072e7..7f1f52803 100644 --- a/src/bin/lttng-crash/lttng-crash.c +++ b/src/bin/lttng-crash/lttng-crash.c @@ -2,21 +2,10 @@ * Copyright (C) 2011 David Goulet * Copyright (C) 2014 Mathieu Desnoyers * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, version 2 only, - * as published by the Free Software Foundation. + * SPDX-License-Identifier: GPL-2.0-only * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#define _GNU_SOURCE #include #include #include @@ -29,18 +18,17 @@ #include #include #include -#include #include #include -#include +#include #include #include #include #include #include - -#define DEFAULT_VIEWER "babeltrace" +#include +#include #define COPY_BUFLEN 4096 #define RB_CRASH_DUMP_ABI_LEN 32 @@ -62,6 +50,14 @@ 0xF1 ^ 0xFF, 0x77 ^ 0xFF, 0xBF ^ 0xFF, 0x17 ^ 0xFF, \ } +static const char *help_msg = +#ifdef LTTNG_EMBED_HELP +#include +#else +NULL +#endif +; + /* * Non-static to ensure the compiler does not optimize away the xor. */ @@ -183,9 +179,9 @@ struct lttng_crash_layout { }; /* Variables */ -static char *progname, - *opt_viewer_path = NULL, - *opt_output_path = NULL; +static const char *progname; +static char *opt_viewer_path = NULL; +static char *opt_output_path = NULL; static char *input_path; @@ -206,35 +202,24 @@ static struct option long_options[] = { { NULL, 0, NULL, 0 }, }; -static void usage(FILE *ofp) +static void usage(void) { - fprintf(ofp, "LTTng Crash Trace Viewer " VERSION " - " VERSION_NAME "%s\n\n", - GIT_VERSION[0] == '\0' ? "" : " - " GIT_VERSION); - fprintf(ofp, "usage: lttng-crash [OPTIONS] FILE\n"); - fprintf(ofp, "\n"); - fprintf(ofp, "Options:\n"); - fprintf(ofp, " -V, --version Show version.\n"); - fprintf(ofp, " -h, --help Show this help.\n"); - fprintf(ofp, " --list-options Simple listing of lttng-crash options.\n"); - fprintf(ofp, " -v, --verbose Increase verbosity.\n"); - fprintf(ofp, " -e, --viewer Specify viewer and/or options to use. This will\n" - " completely override the default viewers so please\n" - " make sure to specify the full command. The trace\n" - " directory paths appended at the end to the\n" - " arguments.\n"); - fprintf(ofp, " -x, --extract PATH Extract trace(s) to specified path. Don't view\n" - " trace.\n"); - fprintf(ofp, "\n"); - fprintf(ofp, "Please see the lttng-crash(1) man page for full documentation.\n"); - fprintf(ofp, "See http://lttng.org for updates, bug reports and news.\n"); + int ret = utils_show_help(1, "lttng-crash", help_msg); + + if (ret) { + ERR("Cannot show --help for `lttng-crash`"); + perror("exec"); + exit(EXIT_FAILURE); + } } static void version(FILE *ofp) { fprintf(ofp, "%s (LTTng Crash Trace Viewer) " VERSION " - " VERSION_NAME -"%s\n", + "%s%s\n", progname, - GIT_VERSION[0] == '\0' ? "" : " - " GIT_VERSION); + GIT_VERSION[0] == '\0' ? "" : " - " GIT_VERSION, + EXTRA_VERSION_NAME[0] == '\0' ? "" : " - " EXTRA_VERSION_NAME); } /* @@ -271,7 +256,7 @@ static int parse_args(int argc, char **argv) int opt, ret = 0; if (argc < 2) { - usage(stderr); + usage(); exit(EXIT_FAILURE); } @@ -282,7 +267,7 @@ static int parse_args(int argc, char **argv) ret = 1; goto end; case 'h': - usage(stdout); + usage(); ret = 1; goto end; case 'v': @@ -304,18 +289,14 @@ static int parse_args(int argc, char **argv) ret = 1; goto end; default: - usage(stderr); + ERR("Unknown command-line option"); goto error; } } - if (!opt_viewer_path) { - opt_viewer_path = DEFAULT_VIEWER; - } - /* No leftovers, or more than one input path, print usage and quit */ - if ((argc - optind) == 0 || (argc - optind) > 1) { - usage(stderr); + if (argc - optind != 1) { + ERR("Command-line error: Specify exactly one input path"); goto error; } @@ -392,19 +373,19 @@ uint64_t _crash_get_field(const struct lttng_crash_layout *layout, switch (size) { case 1: return *(uint8_t *) ptr; case 2: if (layout->reverse_byte_order) { - return __bswap_16(*(uint16_t *) ptr); + return bswap_16(*(uint16_t *) ptr); } else { return *(uint16_t *) ptr; } case 4: if (layout->reverse_byte_order) { - return __bswap_32(*(uint32_t *) ptr); + return bswap_32(*(uint32_t *) ptr); } else { return *(uint32_t *) ptr; } case 8: if (layout->reverse_byte_order) { - return __bswap_64(*(uint64_t *) ptr); + return bswap_64(*(uint64_t *) ptr); } else { return *(uint64_t *) ptr; } @@ -503,7 +484,8 @@ int check_magic(const uint8_t *magic) } static -int get_crash_layout(struct lttng_crash_layout *layout, int fd) +int get_crash_layout(struct lttng_crash_layout *layout, int fd, + const char *input_file) { char *map; int ret = 0, unmapret; @@ -514,7 +496,21 @@ int get_crash_layout(struct lttng_crash_layout *layout, int fd) const struct crash_abi_unknown *abi; uint16_t endian; enum lttng_crash_type layout_type; + struct stat stat; + ret = fstat(fd, &stat); + if (ret < 0) { + PERROR("Failed to fstat '%s'", input_file); + return -1; + } + if (stat.st_size < RB_CRASH_DUMP_ABI_LEN) { + ERR("File '%s' truncated: file length of %" PRIi64 + " bytes does not meet the minimal expected " + "length of %d bytes", + input_file, (int64_t) stat.st_size, + RB_CRASH_DUMP_ABI_LEN); + return -1; + } map = mmap(NULL, RB_CRASH_DUMP_ABI_LEN, PROT_READ, MAP_PRIVATE, fd, 0); if (map == MAP_FAILED) { @@ -668,7 +664,7 @@ int copy_crash_subbuf(const struct lttng_crash_layout *layout, return -EINVAL; } - DBG("Copy crash subbuffer at offset %lu", offset); + DBG("Copy crash subbuffer at offset %" PRIu64, offset); sbidx = subbuf_index(offset, buf_size, subbuf_size); /* @@ -724,7 +720,7 @@ int copy_crash_subbuf(const struct lttng_crash_layout *layout, subbuf_ptr + layout->offset.packet_size, layout->length.packet_size); if (layout->reverse_byte_order) { - packet_size = __bswap_64(packet_size); + packet_size = bswap_64(packet_size); } packet_size /= CHAR_BIT; } else { @@ -740,7 +736,7 @@ int copy_crash_subbuf(const struct lttng_crash_layout *layout, */ patch_size = committed * CHAR_BIT; if (layout->reverse_byte_order) { - patch_size = __bswap_64(patch_size); + patch_size = bswap_64(patch_size); } if (layout->length.content_size) { memcpy(subbuf_ptr + layout->offset.content_size, @@ -843,7 +839,7 @@ int extract_file(int output_dir_fd, const char *output_file, } /* Query the crash ABI layout */ - ret = get_crash_layout(&layout, fd_src); + ret = get_crash_layout(&layout, fd_src, input_file); if (ret) { goto close_src; } @@ -978,6 +974,7 @@ int extract_trace_recursive(const char *output_path, DIR *dir; int dir_fd, ret = 0, closeret; struct dirent *entry; + size_t path_len; int has_warning = 0; /* Open directory */ @@ -986,6 +983,9 @@ int extract_trace_recursive(const char *output_path, PERROR("Cannot open '%s' path", input_path); return -1; } + + path_len = strlen(input_path); + dir_fd = dirfd(dir); if (dir_fd < 0) { PERROR("dirfd"); @@ -993,13 +993,34 @@ int extract_trace_recursive(const char *output_path, } while ((entry = readdir(dir))) { + struct stat st; + size_t name_len; + char filename[PATH_MAX]; + if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) { continue; } - switch (entry->d_type) { - case DT_DIR: - { + + name_len = strlen(entry->d_name); + if (path_len + name_len + 2 > sizeof(filename)) { + ERR("Failed to remove file: path name too long (%s/%s)", + input_path, entry->d_name); + continue; + } + + if (snprintf(filename, sizeof(filename), "%s/%s", + input_path, entry->d_name) < 0) { + ERR("Failed to format path."); + continue; + } + + if (stat(filename, &st)) { + PERROR("stat"); + continue; + } + + if (S_ISDIR(st.st_mode)) { char output_subpath[PATH_MAX]; char input_subpath[PATH_MAX]; @@ -1031,10 +1052,7 @@ int extract_trace_recursive(const char *output_path, if (ret) { has_warning = 1; } - break; - } - case DT_REG: - case DT_LNK: + } else if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) { if (!strcmp(entry->d_name, "metadata")) { ret = extract_one_trace(output_path, input_path); @@ -1044,9 +1062,7 @@ int extract_trace_recursive(const char *output_path, has_warning = 1; } } - /* Ignore other files */ - break; - default: + } else { has_warning = 1; goto end; } @@ -1064,6 +1080,7 @@ int delete_dir_recursive(const char *path) { DIR *dir; int dir_fd, ret = 0, closeret; + size_t path_len; struct dirent *entry; /* Open trace directory */ @@ -1071,8 +1088,11 @@ int delete_dir_recursive(const char *path) if (!dir) { PERROR("Cannot open '%s' path", path); ret = -errno; - goto end; + goto end_no_closedir; } + + path_len = strlen(path); + dir_fd = dirfd(dir); if (dir_fd < 0) { PERROR("dirfd"); @@ -1081,13 +1101,34 @@ int delete_dir_recursive(const char *path) } while ((entry = readdir(dir))) { + struct stat st; + size_t name_len; + char filename[PATH_MAX]; + if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) { continue; } - switch (entry->d_type) { - case DT_DIR: - { + + name_len = strlen(entry->d_name); + if (path_len + name_len + 2 > sizeof(filename)) { + ERR("Failed to remove file: path name too long (%s/%s)", + path, entry->d_name); + continue; + } + + if (snprintf(filename, sizeof(filename), "%s/%s", + path, entry->d_name) < 0) { + ERR("Failed to format path."); + continue; + } + + if (stat(filename, &st)) { + PERROR("stat"); + continue; + } + + if (S_ISDIR(st.st_mode)) { char *subpath = zmalloc(PATH_MAX); if (!subpath) { @@ -1105,19 +1146,16 @@ int delete_dir_recursive(const char *path) ret = delete_dir_recursive(subpath); free(subpath); if (ret) { - /* Error occured, abort traversal. */ + /* Error occurred, abort traversal. */ goto end; } - break; - } - case DT_REG: + } else if (S_ISREG(st.st_mode)) { ret = unlinkat(dir_fd, entry->d_name, 0); if (ret) { PERROR("Unlinking '%s'", entry->d_name); goto end; } - break; - default: + } else { ret = -EINVAL; goto end; } @@ -1133,11 +1171,12 @@ end: if (closeret) { PERROR("closedir"); } +end_no_closedir: return ret; } static -int view_trace(const char *viewer_path, const char *trace_path) +int view_trace(const char *trace_path, char *viewer_path) { pid_t pid; @@ -1158,13 +1197,12 @@ int view_trace(const char *viewer_path, const char *trace_path) /* Child */ int ret; - ret = execlp(viewer_path, viewer_path, - trace_path, (char *) NULL); + ret = spawn_viewer(trace_path, viewer_path, false); if (ret) { - PERROR("execlp"); exit(EXIT_FAILURE); } - exit(EXIT_SUCCESS); /* Never reached */ + /* Never reached */ + exit(EXIT_SUCCESS); } return 0; } @@ -1216,7 +1254,7 @@ int main(int argc, char *argv[]) } if (!opt_output_path) { /* View trace */ - ret = view_trace(opt_viewer_path, output_path); + ret = view_trace(output_path, opt_viewer_path); if (ret) { has_warning = true; }