This commit extends the chutil library by providing a set of helpers
which operate on files already opened by the process.

The implementation provided only works with linux systems, but any
system which provides a system call mechanism to do this (such as
FreeBSD), could be used.  The linux implementation also resolves some
unix domain sockets to their filenames.

Signed-off-by: Aaron Conole <acon...@redhat.com>
---
 lib/chutil-unix.c   | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/chutil.h        |   4 ++
 tests/test-chutil.c |   6 +++
 3 files changed, 118 insertions(+)

diff --git a/lib/chutil-unix.c b/lib/chutil-unix.c
index e2ae8e9..3e9eb88 100644
--- a/lib/chutil-unix.c
+++ b/lib/chutil-unix.c
@@ -18,6 +18,7 @@
 
 #include "chutil.h"
 
+#include <dirent.h>
 #include <errno.h>
 #include <grp.h>
 #include <inttypes.h>
@@ -31,6 +32,12 @@
 #include "util.h"
 #include "openvswitch/vlog.h"
 
+#ifdef __linux__
+#define LINUX 1
+#else
+#define LINUX 0
+#endif
+
 VLOG_DEFINE_THIS_MODULE(chutil_unix);
 
 #ifndef S_ISLNK
@@ -345,3 +352,104 @@ ovs_fchown(int fd, const char *owner)
 
     return 0;
 }
+
+struct unix_socket_map {
+    char name[PATH_MAX];
+    char path[PATH_MAX];
+};
+
+static int
+opened_unix_sockets(struct unix_socket_map *map_data, int map_size) {
+    char data[PATH_MAX * 2] = {0};
+    FILE *netfile = NULL;
+    int total = 0;
+
+    netfile = fopen("/proc/self/net/unix", "r");
+    if (!netfile) {
+        return -1;
+    }
+
+    for (char *line = fgets(data, sizeof(data), netfile); line;
+         line = fgets(data, sizeof(data), netfile)) {
+        char *path = strrchr(data, ' ');
+        if (path && *(path + 1) == '/') {
+            *path++ = 0;
+            path[strcspn(path, "\n")] = 0;
+            if (total < map_size) {
+                snprintf(map_data[total].name, PATH_MAX, "socket:[%s]",
+                         strrchr(data, ' ')+1);
+                snprintf(map_data[total].path, PATH_MAX, "%s", path);
+            }
+            total++;
+        }
+    }
+    return total;
+}
+
+static int
+name_to_fd(const char *name)
+{
+    int result = -1;
+    if (LINUX) {
+        DIR *d = opendir("/proc/self/fd");
+        struct unix_socket_map mp[256];
+
+        opened_unix_sockets(mp, ARRAY_SIZE(mp));
+
+        if (!d) {
+            return -1;
+        }
+
+        for (struct dirent *ent = readdir(d); ent; ent = readdir(d)) {
+            char check_path[PATH_MAX];
+            char resolved_path[PATH_MAX] = {0};
+            snprintf(check_path, PATH_MAX, "/proc/self/fd/%s", ent->d_name);
+            if (readlink(check_path, resolved_path, PATH_MAX) < 0) {
+                continue;
+            }
+
+            if (!strcmp(resolved_path, name)) {
+                result = strtol(ent->d_name, NULL, 10);
+                break;
+            } else if (!strncmp(resolved_path, "socket:", 7)) {
+                for (size_t i = 0; i < ARRAY_SIZE(mp) && mp[i].name[0]; ++i) {
+                    if (!strcmp(resolved_path, mp[i].name)) {
+                        result = strtol(ent->d_name, NULL, 10);
+                        break;
+                    }
+                }
+            }
+        }
+        closedir(d);
+        if (result < 0) {
+            errno = ENOENT;
+        }
+    } else {
+        errno = ENOTSUP;
+    }
+    return result;
+}
+
+int
+ovs_chown_open_file(const char *name, const char *owner)
+{
+    int fd = name_to_fd(name);
+    if (fd < 0) {
+        VLOG_ERR("ovs_chown_open_file: name_to_fd: %s\n", ovs_strerror(errno));
+        return errno;
+    }
+
+    return ovs_fchown(fd, owner);
+}
+
+int
+ovs_chmod_open_file(const char *name, const char *mode)
+{
+    int fd = name_to_fd(name);
+    if (fd < 0) {
+        VLOG_ERR("ovs_chmod_open_file: name_to_fd: %s\n", ovs_strerror(errno));
+        return errno;
+    }
+
+    return ovs_fchmod(fd, mode);
+}
diff --git a/lib/chutil.h b/lib/chutil.h
index cdd4d52..ea6bfc9 100644
--- a/lib/chutil.h
+++ b/lib/chutil.h
@@ -27,6 +27,10 @@ int ovs_fchmod(int fd, const char *mode) 
OVS_WARN_UNUSED_RESULT;
 int ovs_fchown(int fd, const char *usrstr) OVS_WARN_UNUSED_RESULT;
 int ovs_strtousr(const char *user_spec, uid_t *uid, char **user,
                  gid_t *gid, bool validate_user_group) OVS_WARN_UNUSED_RESULT;
+int ovs_chown_open_file(const char *name, const char *owner)
+    OVS_WARN_UNUSED_RESULT;
+int ovs_chmod_open_file(const char *name, const char *mode)
+    OVS_WARN_UNUSED_RESULT;
 #endif
 
 #endif
diff --git a/tests/test-chutil.c b/tests/test-chutil.c
index dce07b4..878e33e 100644
--- a/tests/test-chutil.c
+++ b/tests/test-chutil.c
@@ -154,6 +154,12 @@ run_chmod_str_successes(const char *pathname, int fd)
         printf("run_chmod_successes:assignF\n");
         return -1;
     }
+
+    if (ovs_chmod_open_file(pathname, "ugo-rwx") ||
+        get_mode(pathname, &pmode) || pmode != 0) {
+        printf("run_chmod_successes:byOpenNameF\n");
+        return -1;
+    }
     return 0;
 }
 
-- 
2.5.5

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to