* Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
* Copyright (C) 2014 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
*
- * 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.
*/
#include <getopt.h>
#include <version.h>
#include <lttng/lttng.h>
#include <common/common.h>
+#include <common/spawn-viewer.h>
#include <common/utils.h>
-#define DEFAULT_VIEWER "babeltrace"
-
#define COPY_BUFLEN 4096
#define RB_CRASH_DUMP_ABI_LEN 32
0xF1 ^ 0xFF, 0x77 ^ 0xFF, 0xBF ^ 0xFF, 0x17 ^ 0xFF, \
}
+static const char *help_msg =
+#ifdef LTTNG_EMBED_HELP
+#include <lttng-crash.1.h>
+#else
+NULL
+#endif
+;
+
/*
* Non-static to ensure the compiler does not optimize away the xor.
*/
};
/* 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;
static void usage(void)
{
- int ret = utils_show_man_page(1, "lttng-crash");
+ int ret = utils_show_help(1, "lttng-crash", help_msg);
if (ret) {
- ERR("Cannot view man page lttng-crash(1)");
+ 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);
}
/*
}
}
- if (!opt_viewer_path) {
- opt_viewer_path = DEFAULT_VIEWER;
- }
-
/* No leftovers, or more than one input path, print usage and quit */
if (argc - optind != 1) {
ERR("Command-line error: Specify exactly one input path");
}
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;
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) {
}
/* 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;
}
DIR *dir;
int dir_fd, ret = 0, closeret;
struct dirent *entry;
+ size_t path_len;
int has_warning = 0;
/* Open directory */
PERROR("Cannot open '%s' path", input_path);
return -1;
}
+
+ path_len = strlen(input_path);
+
dir_fd = dirfd(dir);
if (dir_fd < 0) {
PERROR("dirfd");
}
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];
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);
has_warning = 1;
}
}
- /* Ignore other files */
- break;
- default:
+ } else {
has_warning = 1;
goto end;
}
{
DIR *dir;
int dir_fd, ret = 0, closeret;
+ size_t path_len;
struct dirent *entry;
/* Open trace directory */
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");
}
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) {
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;
}
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;
/* 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;
}
}
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;
}