[Libguestfs] [PATCH] umask: Use /proc/<PID>/status to read umask in Linux >= 4.7.

Richard W.M. Jones rjones at redhat.com
Sat May 21 12:14:40 UTC 2016


Since Linux 4.7, the process umask is available in /proc/<pid>/status.
See:
https://github.com/torvalds/linux/commit/3e42979e65dace1f9268dd5440e5ab096b8dee59

Use this value if available, else fall back to the existing codepath
for Linux <= 4.6 and other Unix.
---
 src/umask.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 78 insertions(+), 8 deletions(-)

diff --git a/src/umask.c b/src/umask.c
index b8748e8..3f32337 100644
--- a/src/umask.c
+++ b/src/umask.c
@@ -18,12 +18,22 @@
 
 /**
  * Return current umask in a thread-safe way.
+ *
+ * glibc documents, but does not actually implement, a "getumask(3)"
+ * call.
+ *
+ * We use C<Umask> from F</proc/I<PID>/status> for Linux E<ge> 4.7.
+ * For older Linux and other Unix, this file implements an expensive
+ * but thread-safe way to get the current process's umask.
+ *
+ * Thanks to: Josh Stone, Jiri Jaburek, Eric Blake.
  */
 
 #include <config.h>
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <stdbool.h>
 #include <unistd.h>
 #include <fcntl.h>
 #include <errno.h>
@@ -35,21 +45,81 @@
 #include "guestfs.h"
 #include "guestfs-internal.h"
 
+static int get_umask_from_proc (guestfs_h *g);
+static int get_umask_from_fork (guestfs_h *g);
+
 /**
- * glibc documents, but does not actually implement, a L<getumask(3)>
- * call.
- *
- * This function implements an expensive, but thread-safe way to get
- * the current process's umask.
- *
  * Returns the current process's umask.  On failure, returns C<-1> and
  * sets the error in the guestfs handle.
- *
- * Thanks to: Josh Stone, Jiri Jaburek, Eric Blake.
  */
 int
 guestfs_int_getumask (guestfs_h *g)
 {
+  int mask;
+
+  mask = get_umask_from_proc (g);
+  if (mask == -1)
+    return -1;
+  if (mask >= 0)
+    return mask;
+
+  return get_umask_from_fork (g);
+}
+
+/**
+ * For Linux E<ge> 4.7 get the umask from F</proc/I<PID>/status>.
+ *
+ * On failure this returns C<-1>.  However if we could not open the
+ * F</proc> file or find the C<Umask> entry in it, return C<-2> which
+ * causes the fallback path to run.
+ */
+static int
+get_umask_from_proc (guestfs_h *g)
+{
+  FILE *fp;
+  CLEANUP_FREE char *path = NULL, *line = NULL;
+  size_t allocsize;
+  ssize_t len;
+  unsigned int mask;
+  bool found = false;
+
+  path = safe_asprintf (g, "/proc/%d/status", getpid ());
+  fp = fopen (path, "r");
+  if (fp == NULL) {
+    if (errno == ENOENT || errno == ENOTDIR)
+      return -2;                /* fallback */
+    perrorf (g, "open: %s", path);
+    return -1;
+  }
+
+  while ((len = getline (&line, &allocsize, fp)) != -1) {
+    if (len > 0 && line[len-1] == '\n')
+      line[--len] = '\0';
+
+    /* Looking for: "Umask:  0022" */
+    if (sscanf (line, "Umask: %o", &mask) == 1) {
+      found = true;
+      break;
+    }
+  }
+
+  if (fclose (fp) == -1) {
+    perrorf (g, "close: %s", path);
+    return -1;
+  }
+
+  if (!found)
+    return -2;                  /* fallback */
+
+  return (int) mask;
+}
+
+/**
+ * Fallback method of getting the umask using fork.
+ */
+static int
+get_umask_from_fork (guestfs_h *g)
+{
   pid_t pid;
   int fd[2], r;
   int mask;
-- 
2.7.4




More information about the Libguestfs mailing list