Fix: lttng-crash: fd leak
[lttng-tools.git] / src / bin / lttng-crash / lttng-crash.c
index dda157be3cfe03c789f992dcf1bf2c10a11face4..c3a8b778925d1de9bed8d191b1eec1324f982d2b 100644 (file)
@@ -103,7 +103,7 @@ enum rb_modes {
 
 struct crash_abi_unknown {
        uint8_t magic[RB_CRASH_DUMP_ABI_MAGIC_LEN];
-       uint64_t mmap_length;   /* Overall lenght of crash record */
+       uint64_t mmap_length;   /* Overall length of crash record */
        uint16_t endian;        /*
                                 * { 0x12, 0x34 }: big endian
                                 * { 0x34, 0x12 }: little endian
@@ -186,8 +186,7 @@ static char *progname,
        *opt_viewer_path = DEFAULT_VIEWER,
        *opt_output_path;
 
-static int nr_input_paths;
-static char **input_paths;
+static char *input_path;
 
 int lttng_opt_quiet, lttng_opt_verbose, lttng_opt_mi;
 
@@ -210,7 +209,7 @@ static void usage(FILE *ofp)
 {
        fprintf(ofp, "LTTng Crash Trace Viewer " VERSION " - " VERSION_NAME "%s\n\n",
                GIT_VERSION[0] == '\0' ? "" : " - " GIT_VERSION);
-       fprintf(ofp, "usage: lttng [OPTIONS] FILE...\n");
+       fprintf(ofp, "usage: lttng-crash [OPTIONS] FILE\n");
        fprintf(ofp, "\n");
        fprintf(ofp, "Options:\n");
        fprintf(ofp, "  -V, --version              Show version.\n");
@@ -307,14 +306,13 @@ static int parse_args(int argc, char **argv)
                }
        }
 
-       /* No leftovers, print usage and quit */
-       if ((argc - optind) == 0) {
+       /* No leftovers, or more than one input path, print usage and quit */
+       if ((argc - optind) == 0 || (argc - optind) > 1) {
                usage(stderr);
                goto error;
        }
 
-       input_paths = &argv[optind];
-       nr_input_paths = argc - optind;
+       input_path = argv[optind];
 end:
        return ret;
 
@@ -325,29 +323,33 @@ error:
 static
 int copy_file(const char *file_dest, const char *file_src)
 {
-       int fd_src, fd_dest;
+       int fd_src = -1, fd_dest = -1;
        ssize_t readlen, writelen;
        char buf[COPY_BUFLEN];
+       int ret;
 
        DBG("Copy metadata file '%s' into '%s'", file_src, file_dest);
 
        fd_src = open(file_src, O_RDONLY);
        if (fd_src < 0) {
                PERROR("Error opening %s for reading", file_src);
-               return fd_src;
+               ret = -errno;
+               goto error;
        }
        fd_dest = open(file_dest, O_RDWR | O_CREAT | O_EXCL,
                        S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
        if (fd_dest < 0) {
                PERROR("Error opening %s for writing", file_dest);
-               return fd_dest;
+               ret = -errno;
+               goto error;
        }
 
        for (;;) {
                readlen = lttng_read(fd_src, buf, COPY_BUFLEN);
                if (readlen < 0) {
                        PERROR("Error reading input file");
-                       return -1;
+                       ret = -1;
+                       goto error;
                }
                if (!readlen) {
                        break;
@@ -355,10 +357,25 @@ int copy_file(const char *file_dest, const char *file_src)
                writelen = lttng_write(fd_dest, buf, readlen);
                if (writelen < readlen) {
                        PERROR("Error writing to output file");
-                       return -1;
+                       ret = -1;
+                       goto error;
                }
        }
-       return 0;
+
+       ret = 0;
+error:
+       if (fd_src >= 0) {
+               if (close(fd_src) < 0) {
+                       PERROR("Error closing %s", file_src);
+               }
+       }
+
+       if (fd_dest >= 0) {
+               if (close(fd_dest) < 0) {
+                       PERROR("Error closing %s", file_dest);
+               }
+       }
+       return ret;
 }
 
 static
@@ -768,7 +785,8 @@ int copy_crash_data(const struct lttng_crash_layout *layout, int fd_dest,
        readlen = lttng_read(fd_src, buf, src_file_len);
        if (readlen < 0) {
                PERROR("Error reading input file");
-               return -1;
+               ret = -1;
+               goto end;
        }
 
        prod_offset = crash_get_field(layout, buf, prod_offset);
@@ -947,28 +965,89 @@ int extract_one_trace(const char *output_path,
 }
 
 static
-int extract_all_traces(const char *output_path,
-               char **input_paths,
-               int nr_input_paths)
+int extract_trace_recursive(const char *output_path,
+               const char *input_path)
 {
-       int ret, i;
+       DIR *dir;
+       int dir_fd, ret = 0, closeret;
+       struct dirent *entry;
        int has_warning = 0;
 
-       /* Only one input path is currently supported */
-       if (nr_input_paths != 1) {
-               ERR("Only a single input path is currently supported.\n");
+       /* Open directory */
+       dir = opendir(input_path);
+       if (!dir) {
+               PERROR("Cannot open '%s' path", input_path);
+               return -1;
+       }
+       dir_fd = dirfd(dir);
+       if (dir_fd < 0) {
+               PERROR("dirfd");
                return -1;
        }
 
-       for (i = 0; i < nr_input_paths; i++) {
-               ret = extract_one_trace(output_path,
-                       input_paths[i]);
-               if (ret) {
-                       WARN("Error extracting trace '%s', continuing anyway.",
-                               input_paths[i]);
+       while ((entry = readdir(dir))) {
+               if (!strcmp(entry->d_name, ".")
+                               || !strcmp(entry->d_name, "..")) {
+                       continue;
+               }
+               switch (entry->d_type) {
+               case DT_DIR:
+               {
+                       char output_subpath[PATH_MAX];
+                       char input_subpath[PATH_MAX];
+
+                       strncpy(output_subpath, output_path,
+                               sizeof(output_subpath));
+                       output_subpath[sizeof(output_subpath) - 1] = '\0';
+                       strncat(output_subpath, "/",
+                               sizeof(output_subpath) - strlen(output_subpath) - 1);
+                       strncat(output_subpath, entry->d_name,
+                               sizeof(output_subpath) - strlen(output_subpath) - 1);
+
+                       ret = mkdir(output_subpath, S_IRWXU | S_IRWXG);
+                       if (ret) {
+                               PERROR("mkdir");
+                               has_warning = 1;
+                               goto end;
+                       }
+
+                       strncpy(input_subpath, input_path,
+                               sizeof(input_subpath));
+                       input_subpath[sizeof(input_subpath) - 1] = '\0';
+                       strncat(input_subpath, "/",
+                               sizeof(input_subpath) - strlen(input_subpath) - 1);
+                       strncat(input_subpath, entry->d_name,
+                               sizeof(input_subpath) - strlen(input_subpath) - 1);
+
+                       ret = extract_trace_recursive(output_subpath,
+                               input_subpath);
+                       if (ret) {
+                               has_warning = 1;
+                       }
+                       break;
+               }
+               case DT_REG:
+                       if (!strcmp(entry->d_name, "metadata")) {
+                               ret = extract_one_trace(output_path,
+                                       input_path);
+                               if (ret) {
+                                       WARN("Error extracting trace '%s', continuing anyway.",
+                                               input_path);
+                                       has_warning = 1;
+                               }
+                       }
+                       /* Ignore other files */
+                       break;
+               default:
                        has_warning = 1;
+                       goto end;
                }
        }
+end:
+       closeret = closedir(dir);
+       if (closeret) {
+               PERROR("closedir");
+       }
        return has_warning;
 }
 
@@ -993,8 +1072,9 @@ int delete_trace(const char *trace_path)
 
        while ((entry = readdir(trace_dir))) {
                if (!strcmp(entry->d_name, ".")
-                               || !strcmp(entry->d_name, ".."))
+                               || !strcmp(entry->d_name, "..")) {
                        continue;
+               }
                switch (entry->d_type) {
                case DT_DIR:
                        unlinkat(trace_dir_fd, entry->d_name, AT_REMOVEDIR);
@@ -1018,7 +1098,6 @@ end:
        return ret;
 }
 
-
 static
 int view_trace(const char *viewer_path, const char *trace_path)
 {
@@ -1085,8 +1164,7 @@ int main(int argc, char *argv[])
                }
        }
 
-       ret = extract_all_traces(output_path, input_paths,
-               nr_input_paths);
+       ret = extract_trace_recursive(output_path, input_path);
        if (ret < 0) {
                exit(EXIT_FAILURE);
        } else if (ret > 0) {
This page took 0.026162 seconds and 4 git commands to generate.