Fix: passing null to closedir() on error
[lttng-tools.git] / src / bin / lttng-crash / lttng-crash.c
index 13d136da96e845e8c78e23870caa507b7e708f3e..298ed71a43c2b1b47053156f624aa50b39fd0519 100644 (file)
                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.
  */
@@ -207,10 +215,10 @@ static struct option long_options[] = {
 
 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);
        }
@@ -965,6 +973,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 */
@@ -973,6 +982,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");
@@ -980,13 +992,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];
 
@@ -1018,10 +1051,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);
@@ -1031,9 +1061,7 @@ int extract_trace_recursive(const char *output_path,
                                        has_warning = 1;
                                }
                        }
-                       /* Ignore other files */
-                       break;
-               default:
+               } else {
                        has_warning = 1;
                        goto end;
                }
@@ -1051,6 +1079,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 */
@@ -1058,8 +1087,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");
@@ -1068,13 +1100,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) {
@@ -1092,19 +1145,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;
                }
@@ -1120,6 +1170,7 @@ end:
        if (closeret) {
                PERROR("closedir");
        }
+end_no_closedir:
        return ret;
 }
 
This page took 0.025752 seconds and 4 git commands to generate.