[libvirt] [PATCH v4 2/5] util: Create virFileAccessibleAs function

Michal Privoznik mprivozn at redhat.com
Thu Oct 20 14:52:49 UTC 2011


This function checks if a given path is accessible under
given uid and gid.
---
 src/util/util.c |   78 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/util/util.h |    3 ++
 2 files changed, 81 insertions(+), 0 deletions(-)

diff --git a/src/util/util.c b/src/util/util.c
index 01146f5..2020415 100644
--- a/src/util/util.c
+++ b/src/util/util.c
@@ -671,6 +671,72 @@ virFileIsExecutable(const char *file)
 }
 
 #ifndef WIN32
+/* Check that a file is accessible under certain
+ * user & gid.
+ * @mode can be R_OK, W_OK, X_OK or F_OK.
+ * see 'man accesss' for more details.
+ * Returns 0 on success, -errno on fail,
+ * >0 on signaled child.
+ */
+int
+virFileAccessibleAs(const char *path, int mode,
+                    uid_t uid, gid_t gid)
+{
+    pid_t pid;
+    int waitret, status, ret = 0;
+    int forkRet;
+
+    forkRet = virFork(&pid);
+
+    if (pid < 0) {
+        return -1;
+    }
+
+    if (pid) { /* parent */
+        do {
+            if ((waitret = waitpid(pid, &status, 0)) < 0) {
+                ret = -errno;
+                virKillProcess(pid, SIGKILL);
+                return ret;
+            }
+        } while (!WIFEXITED(status) && !WIFSIGNALED(status));
+
+        /* child actually returns positive value
+         * anded by 0xFF (see man waitpid @ WEXITSTATUS)
+         */
+
+        if (WIFSIGNALED(status))
+            return WTERMSIG(status);
+
+        return -WEXITSTATUS(status);
+    }
+
+    /* child.
+     * Return positive value here. Parent
+     * will change it to negative one. */
+
+    if (forkRet < 0) {
+        ret = 1;
+        goto childerror;
+    }
+
+    if (virSetUIDGID(uid, gid) < 0) {
+        ret = errno;
+        goto childerror;
+    }
+
+    if (access(path, mode) < 0)
+        ret = errno;
+
+childerror:
+    if ((ret & 0xFF) != ret) {
+        VIR_WARN("unable to pass desired return value %d", ret);
+        ret = 0xFF;
+    }
+
+    _exit(ret);
+}
+
 /* return -errno on failure, or 0 on success */
 static int
 virFileOpenAsNoFork(const char *path, int openflags, mode_t mode,
@@ -993,6 +1059,18 @@ childerror:
 
 #else /* WIN32 */
 
+int
+virFileAccessibleAs(const char *path ATTRIBUTE_UNUSED,
+                    int mode ATTRIBUTE_UNUSED,
+                    uid_t uid ATTRIBUTE_UNUSED,
+                    git_t gid ATTRIBUTE_UNUSED)
+{
+    virUtilError(VIR_ERR_INTERNAL_ERROR,
+                 "%s", _("virFileAccessibleAs is not implemented for WIN32"));
+
+    return -ENOSYS;
+}
+
 /* return -errno on failure, or 0 on success */
 int virFileOpenAs(const char *path ATTRIBUTE_UNUSED,
                   int openflags ATTRIBUTE_UNUSED,
diff --git a/src/util/util.h b/src/util/util.h
index c55e852..e869f1b 100644
--- a/src/util/util.h
+++ b/src/util/util.h
@@ -93,6 +93,9 @@ enum {
     VIR_FILE_OPEN_AS_UID      = (1 << 0),
     VIR_FILE_OPEN_FORCE_PERMS = (1 << 1),
 };
+int virFileAccessibleAs(const char *path, int mode,
+                        uid_t uid, gid_t gid)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
 int virFileOpenAs(const char *path, int openflags, mode_t mode,
                   uid_t uid, gid_t gid,
                   unsigned int flags)
-- 
1.7.3.4




More information about the libvir-list mailing list