From d096e1f70a01a8651631a906de41771f2b416900 Mon Sep 17 00:00:00 2001
From: Jakub Filak <jfilak@redhat.com>
Date: Mon, 10 Nov 2014 08:30:31 -0500
Subject: [PATCH 4/4] coredump: collect all /proc data useful for bug reporting

/proc/[pid]:
- status
- maps
- limits
- cgroup
- cwd
- root
- environ
- fd/ & fdinfo/ joined in open_fds
---
 src/journal/coredump.c | 137 ++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 135 insertions(+), 2 deletions(-)

diff --git a/src/journal/coredump.c b/src/journal/coredump.c
index 26a2010..1b04105 100644
--- a/src/journal/coredump.c
+++ b/src/journal/coredump.c
@@ -461,18 +461,87 @@ static int allocate_journal_field(int fd, size_t size, char **ret, size_t *ret_s
         return 0;
 }
 
+/* Joins /proc/[pid]/fd/ and /proc/[pid]/fdinfo/ into the following lines:
+ *
+ * 0:/dev/pts/23
+ * pos:    0
+ * flags:  0100002
+ * 1:/dev/pts/23
+ * pos:    0
+ * flags:  0100002
+ * 2:/dev/pts/23
+ *
+ */
+static int compose_open_fds(pid_t pid, char **open_fds) {
+        const char *fd_name = NULL, *fdinfo_name = NULL;
+        char *outcome = NULL;
+        size_t len = 0, allocated = 0;
+        char line[LINE_MAX];
+        unsigned fd = 0;
+        int r = 0;
+
+        assert(pid >= 0);
+
+        fd_name = alloca(strlen("/proc//fd/") + DECIMAL_STR_MAX(pid_t) + DECIMAL_STR_MAX(unsigned) + 1);
+        fdinfo_name = alloca(strlen("/proc//fdinfo/") + DECIMAL_STR_MAX(pid_t) + DECIMAL_STR_MAX(unsigned) + 1);
+
+        while (fd <= 99999) {
+                _cleanup_free_ char *name = NULL;
+                _cleanup_fclose_ FILE *fdinfo = NULL;
+
+                sprintf((char *)fd_name, "/proc/"PID_FMT"/fd/%u", pid, fd);
+                r = readlink_malloc(fd_name, &name);
+                if (r < 0) {
+                        if (r == -ENOENT) {
+                            *open_fds = outcome;
+                            r = 0;
+                        }
+                        else
+                            free(outcome);
+
+                        break;
+                }
+
+                if (!GREEDY_REALLOC(outcome, allocated, len + strlen(name) + DECIMAL_STR_MAX(unsigned) + 3))
+                        return -ENOMEM;
+
+                len += sprintf(outcome + len, "%u:%s\n", fd, name);
+                ++fd;
+
+                sprintf((char *)fdinfo_name, "/proc/"PID_FMT"/fdinfo/%u", pid, fd);
+                fdinfo = fopen(fdinfo_name, "r");
+                if (fdinfo == NULL)
+                        continue;
+
+                while(fgets(line, sizeof(line), fdinfo) != NULL) {
+                        if (!GREEDY_REALLOC(outcome, allocated, len + strlen(line) + 2))
+                                return -ENOMEM;
+
+                        len += sprintf(outcome + len, "%s", line);
+                        if (strchr(line, '\n') == NULL) {
+                                outcome[len++] = '\n';
+                                outcome[len] = '\0';
+                        }
+                }
+        }
+
+        return r;
+}
+
 int main(int argc, char* argv[]) {
 
         _cleanup_free_ char *core_pid = NULL, *core_uid = NULL, *core_gid = NULL, *core_signal = NULL,
                 *core_timestamp = NULL, *core_comm = NULL, *core_exe = NULL, *core_unit = NULL,
                 *core_session = NULL, *core_message = NULL, *core_cmdline = NULL, *coredump_data = NULL,
-                *core_slice = NULL, *core_cgroup = NULL, *core_owner_uid = NULL,
+                *core_slice = NULL, *core_cgroup = NULL, *core_owner_uid = NULL, *core_open_fds = NULL,
+                *core_proc_status = NULL, *core_proc_maps = NULL, *core_proc_limits = NULL, *core_proc_cgroup = NULL,
+                *core_cwd = NULL, *core_root = NULL, *core_environ = NULL,
                 *exe = NULL, *comm = NULL, *filename = NULL;
         const char *info[_INFO_LEN];
 
         _cleanup_close_ int coredump_fd = -1;
 
-        struct iovec iovec[18];
+        struct iovec iovec[26];
         off_t coredump_size;
         int r, j = 0;
         uid_t uid, owner_uid;
@@ -638,6 +707,70 @@ int main(int argc, char* argv[]) {
                         IOVEC_SET_STRING(iovec[j++], core_cgroup);
         }
 
+        if (compose_open_fds(pid, &t) >= 0) {
+                core_open_fds = strappend("COREDUMP_OPEN_FDS=", t);
+                free(t);
+
+                if (core_open_fds)
+                        IOVEC_SET_STRING(iovec[j++], core_open_fds);
+        }
+
+        if (get_process_status(pid, &t) >= 0) {
+                core_proc_status = strappend("COREDUMP_PROC_STATUS=", t);
+                free(t);
+
+                if (core_proc_status)
+                        IOVEC_SET_STRING(iovec[j++], core_proc_status);
+        }
+
+        if (get_process_maps(pid, &t) >= 0) {
+                core_proc_maps = strappend("COREDUMP_PROC_MAPS=", t);
+                free(t);
+
+                if (core_proc_maps)
+                        IOVEC_SET_STRING(iovec[j++], core_proc_maps);
+        }
+
+        if (get_process_limits(pid, &t) >= 0) {
+                core_proc_limits = strappend("COREDUMP_PROC_LIMITS=", t);
+                free(t);
+
+                if (core_proc_limits)
+                        IOVEC_SET_STRING(iovec[j++], core_proc_limits);
+        }
+
+        if (get_process_cgroup(pid, &t) >=0) {
+                core_proc_cgroup = strappend("COREDUMP_PROC_CGROUP=", t);
+                free(t);
+
+                if (core_proc_cgroup)
+                        IOVEC_SET_STRING(iovec[j++], core_proc_cgroup);
+        }
+
+        if (get_process_cwd(pid, &t) >= 0) {
+                core_cwd = strappend("COREDUMP_CWD=", t);
+                free(t);
+
+                if (core_cwd)
+                        IOVEC_SET_STRING(iovec[j++], core_cwd);
+        }
+
+        if (get_process_root(pid, &t) >= 0) {
+                core_root = strappend("COREDUMP_ROOT=", t);
+                free(t);
+
+                if (core_root)
+                        IOVEC_SET_STRING(iovec[j++], core_root);
+        }
+
+        if (get_process_environ(pid, &t) >= 0) {
+                core_environ = strappend("COREDUMP_ENVIRON=", t);
+                free(t);
+
+                if (core_environ)
+                        IOVEC_SET_STRING(iovec[j++], core_environ);
+        }
+
         core_timestamp = strjoin("COREDUMP_TIMESTAMP=", info[INFO_TIMESTAMP], "000000", NULL);
         if (core_timestamp)
                 IOVEC_SET_STRING(iovec[j++], core_timestamp);
-- 
2.1.0

