Blob Blame History Raw
From 23fcd4616606eca71ffe5f862828163d23490cc0 Mon Sep 17 00:00:00 2001
From: Jakub Filak <jfilak@redhat.com>
Date: Mon, 8 Dec 2014 15:26:56 +0100
Subject: [PATCH] lib: add /proc/[pid]/utils

Related to abrt/abrt#548

Signed-off-by: Jakub Filak <jfilak@redhat.com>
---
 src/include/internal_libreport.h |  12 +++++
 src/lib/get_cmdline.c            | 101 +++++++++++++++++++++++++++++++++++++++
 src/lib/read_write.c             |  14 ++++++
 3 files changed, 127 insertions(+)

diff --git a/src/include/internal_libreport.h b/src/include/internal_libreport.h
index d664fa4..fca8138 100644
--- a/src/include/internal_libreport.h
+++ b/src/include/internal_libreport.h
@@ -178,6 +178,8 @@ void* xmalloc_read(int fd, size_t *maxsz_p);
 void* xmalloc_open_read_close(const char *filename, size_t *maxsz_p);
 #define xmalloc_xopen_read_close libreport_xmalloc_xopen_read_close
 void* xmalloc_xopen_read_close(const char *filename, size_t *maxsz_p);
+#define malloc_readlink libreport_malloc_readlink
+char* malloc_readlink(const char *linkname);
 
 
 /* Returns malloc'ed block */
@@ -625,6 +627,16 @@ struct strbuf *strbuf_prepend_strfv(struct strbuf *strbuf,
 char* get_cmdline(pid_t pid);
 #define get_environ libreport_get_environ
 char* get_environ(pid_t pid);
+#define get_executable libreport_get_executable
+char *get_executable(pid_t pid);
+#define get_cwd libreport_get_cwd
+char* get_cwd(pid_t pid);
+#define get_rootdir libreport_get_rootdir
+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);
 
 /* 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 55c49ea..7ceba2f 100644
--- a/src/lib/get_cmdline.c
+++ b/src/lib/get_cmdline.c
@@ -148,3 +148,104 @@ char* get_environ(pid_t pid)
     snprintf(path, sizeof(path), "/proc/%lu/environ", (long)pid);
     return get_escaped(path, '\n');
 }
+
+char* get_executable(pid_t pid)
+{
+    char buf[sizeof("/proc/%lu/exe") + sizeof(long)*3];
+
+    sprintf(buf, "/proc/%lu/exe", (long)pid);
+    char *executable = malloc_readlink(buf);
+    if (!executable)
+        return NULL;
+    /* find and cut off " (deleted)" from the path */
+    char *deleted = executable + strlen(executable) - strlen(" (deleted)");
+    if (deleted > executable && strcmp(deleted, " (deleted)") == 0)
+    {
+        *deleted = '\0';
+        log_info("File '%s' seems to be deleted", executable);
+    }
+    /* find and cut off prelink suffixes from the path */
+    char *prelink = executable + strlen(executable) - strlen(".#prelink#.XXXXXX");
+    if (prelink > executable && strncmp(prelink, ".#prelink#.", strlen(".#prelink#.")) == 0)
+    {
+        log_info("File '%s' seems to be a prelink temporary file", executable);
+        *prelink = '\0';
+    }
+    return executable;
+}
+
+char* get_cwd(pid_t pid)
+{
+    char buf[sizeof("/proc/%lu/cwd") + sizeof(long)*3];
+    sprintf(buf, "/proc/%lu/cwd", (long)pid);
+    return malloc_readlink(buf);
+}
+
+char* get_rootdir(pid_t pid)
+{
+    char buf[sizeof("/proc/%lu/root") + sizeof(long)*3];
+    sprintf(buf, "/proc/%lu/root", (long)pid);
+    return malloc_readlink(buf);
+}
+
+int get_fsuid(const char *proc_pid_status)
+{
+    int real, euid, saved;
+    /* if we fail to parse the uid, then make it root only readable to be safe */
+    int fs_uid = 0;
+
+    const char *line = proc_pid_status; /* never NULL */
+    for (;;)
+    {
+        if (strncmp(line, "Uid", 3) == 0)
+        {
+            int n = sscanf(line, "Uid:\t%d\t%d\t%d\t%d\n", &real, &euid, &saved, &fs_uid);
+            if (n != 4)
+                return -1;
+            break;
+        }
+        line = strchr(line, '\n');
+        if (!line)
+            break;
+        line++;
+    }
+
+    return fs_uid;
+}
+
+int dump_fd_info(const char *dest_filename, char *source_filename, int source_base_ofs)
+{
+    FILE *fp = fopen(dest_filename, "w");
+    if (!fp)
+        return 0;
+
+    /*TODO: BUG: there might be holes as programs can close any fd at any time*/
+    unsigned fd = 0;
+    while (fd <= 99999) /* paranoia check */
+    {
+        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);
+
+        sprintf(source_filename + source_base_ofs, "fdinfo/%u", fd);
+        fd++;
+        FILE *in = fopen(source_filename, "r");
+        if (!in)
+            continue;
+        char buf[128];
+        while (fgets(buf, sizeof(buf)-1, in))
+        {
+            /* in case the line is not terminated, terminate it */
+            char *eol = strchrnul(buf, '\n');
+            eol[0] = '\n';
+            eol[1] = '\0';
+            fputs(buf, fp);
+        }
+        fclose(in);
+    }
+    fclose(fp);
+    return 1;
+}
diff --git a/src/lib/read_write.c b/src/lib/read_write.c
index 7ce2097..3f3bd1e 100644
--- a/src/lib/read_write.c
+++ b/src/lib/read_write.c
@@ -191,3 +191,17 @@ void* xmalloc_xopen_read_close(const char *filename, size_t *maxsz_p)
         perror_msg_and_die("Can't read '%s'", filename);
     return buf;
 }
+
+char* malloc_readlink(const char *linkname)
+{
+    char buf[PATH_MAX + 1];
+    int len;
+
+    len = readlink(linkname, buf, sizeof(buf)-1);
+    if (len >= 0)
+    {
+        buf[len] = '\0';
+        return xstrdup(buf);
+    }
+    return NULL;
+}
-- 
2.1.0