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