From c16ef7b59b8327332b4252a9c7e70616c363b868 Mon Sep 17 00:00:00 2001
From: Jakub Filak <jfilak@redhat.com>
Date: Wed, 21 Jan 2015 09:37:30 +0100
Subject: [PATCH] rewrite dump_fd_info()
Now, the function is same as from systemd coredump's function compose_open_fds()
Closes #320
Signed-off-by: Jakub Filak <jfilak@redhat.com>
---
src/include/internal_libreport.h | 4 +-
src/lib/get_cmdline.c | 105 ++++++++++++++++++++++++++++++---------
src/lib/read_write.c | 7 ++-
3 files changed, 90 insertions(+), 26 deletions(-)
diff --git a/src/include/internal_libreport.h b/src/include/internal_libreport.h
index 7cda793..00ff7a1 100644
--- a/src/include/internal_libreport.h
+++ b/src/include/internal_libreport.h
@@ -185,6 +185,8 @@ void* xmalloc_open_read_close(const char *filename, size_t *maxsz_p);
void* xmalloc_xopen_read_close(const char *filename, size_t *maxsz_p);
#define malloc_readlink libreport_malloc_readlink
char* malloc_readlink(const char *linkname);
+#define malloc_readlinkat libreport_malloc_readlinkat
+char* malloc_readlinkat(int dir_fd, const char *linkname);
/* Returns malloc'ed block */
@@ -641,7 +643,7 @@ char* get_rootdir(pid_t pid);
#define get_fsuid libreport_get_fsuid
int get_fsuid(const char *proc_pid_status);
#define dump_fd_info libreport_dump_fd_info
-int dump_fd_info(const char *dest_filename, char *source_filename, int source_base_ofs);
+int dump_fd_info(const char *dest_filename, const char *proc_pid_fd_path);
/* Takes ptr to time_t, or NULL if you want to use current time.
* Returns "YYYY-MM-DD-hh:mm:ss" string.
diff --git a/src/lib/get_cmdline.c b/src/lib/get_cmdline.c
index 7ceba2f..2e362c5 100644
--- a/src/lib/get_cmdline.c
+++ b/src/lib/get_cmdline.c
@@ -213,39 +213,96 @@ int get_fsuid(const char *proc_pid_status)
return fs_uid;
}
-int dump_fd_info(const char *dest_filename, char *source_filename, int source_base_ofs)
+int dump_fd_info(const char *dest_filename, const char *proc_pid_fd_path)
{
- FILE *fp = fopen(dest_filename, "w");
- if (!fp)
- return 0;
+ DIR *proc_fd_dir = NULL;
+ int proc_fdinfo_fd = -1;
+ char *buffer = NULL;
+ FILE *stream = NULL;
+ const char *fddelim = "";
+ struct dirent *dent = NULL;
+ int r = 0;
- /*TODO: BUG: there might be holes as programs can close any fd at any time*/
- unsigned fd = 0;
- while (fd <= 99999) /* paranoia check */
+ proc_fd_dir = opendir(proc_pid_fd_path);
+ if (!proc_fd_dir)
{
- sprintf(source_filename + source_base_ofs, "fd/%u", fd);
- char *name = malloc_readlink(source_filename);
- if (!name)
- break;
- fprintf(fp, "%u:%s\n", fd, name);
- free(name);
+ r = -errno;
+ goto dumpfd_cleanup;
+ }
- sprintf(source_filename + source_base_ofs, "fdinfo/%u", fd);
- fd++;
- FILE *in = fopen(source_filename, "r");
- if (!in)
+ proc_fdinfo_fd = openat(dirfd(proc_fd_dir), "../fdinfo", O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC|O_PATH);
+ if (proc_fdinfo_fd < 0)
+ {
+ r = -errno;
+ goto dumpfd_cleanup;
+ }
+
+ stream = fopen(dest_filename, "w");
+ if (!stream)
+ {
+ r = -ENOMEM;
+ goto dumpfd_cleanup;
+ }
+
+ while (1)
+ {
+ errno = 0;
+ dent = readdir(proc_fd_dir);
+ if (dent == NULL)
+ {
+ if (errno > 0)
+ {
+ r = -errno;
+ goto dumpfd_cleanup;
+ }
+ break;
+ }
+ else if (dot_or_dotdot(dent->d_name))
continue;
- char buf[128];
- while (fgets(buf, sizeof(buf)-1, in))
+
+ FILE *fdinfo = NULL;
+ char *fdname = NULL;
+ char line[LINE_MAX];
+ int fd;
+
+ fdname = malloc_readlinkat(dirfd(proc_fd_dir), dent->d_name);
+
+ fprintf(stream, "%s%s:%s\n", fddelim, dent->d_name, fdname);
+ fddelim = "\n";
+
+ /* Use the directory entry from /proc/[pid]/fd with /proc/[pid]/fdinfo */
+ fd = openat(proc_fdinfo_fd, dent->d_name, O_NOFOLLOW|O_CLOEXEC|O_RDONLY);
+ if (fd < 0)
+ goto dumpfd_next_fd;
+
+ fdinfo = fdopen(fd, "re");
+ if (fdinfo == NULL)
+ goto dumpfd_next_fd;
+
+ while (fgets(line, sizeof(line)-1, fdinfo))
{
/* in case the line is not terminated, terminate it */
- char *eol = strchrnul(buf, '\n');
+ char *eol = strchrnul(line, '\n');
eol[0] = '\n';
eol[1] = '\0';
- fputs(buf, fp);
+ fputs(line, stream);
}
- fclose(in);
+
+dumpfd_next_fd:
+ fclose(fdinfo);
+ free(fdname);
}
- fclose(fp);
- return 1;
+
+dumpfd_cleanup:
+ errno = 0;
+ fclose(stream);
+
+ if (r == 0 && errno != 0)
+ r = -errno;
+
+ closedir(proc_fd_dir);
+ close(proc_fdinfo_fd);
+ free(buffer);
+
+ return r;
}
diff --git a/src/lib/read_write.c b/src/lib/read_write.c
index 3f3bd1e..657adb0 100644
--- a/src/lib/read_write.c
+++ b/src/lib/read_write.c
@@ -194,10 +194,15 @@ void* xmalloc_xopen_read_close(const char *filename, size_t *maxsz_p)
char* malloc_readlink(const char *linkname)
{
+ return malloc_readlinkat(AT_FDCWD, linkname);
+}
+
+char* malloc_readlinkat(int dir_fd, const char *linkname)
+{
char buf[PATH_MAX + 1];
int len;
- len = readlink(linkname, buf, sizeof(buf)-1);
+ len = readlinkat(dir_fd, linkname, buf, sizeof(buf)-1);
if (len >= 0)
{
buf[len] = '\0';
--
2.1.0