On 04/14/2016 03:59 AM, Richard W.M. Jones wrote:
The current implementation of getumask involves writing a file with mode 0777 and then testing what mode was created by the kernel. This doesn't work properly if the user set a per-mount umask (or fmask/ dmask).
This alternative method was suggested by Josh Stone. By forking, we can use the thread-unsafe method (calling umask) and pass the result back over a pipe.
This change also fixes another problem: mode_t is unsigned, so cannot be used to return an error indication (ie. -1). Return a plain int instead.
Thanks: Josh Stone, Jiri Jaburek, Eric Blake. ---
+guestfs_int_getumask (guestfs_h *g) +{
+ if (pid == 0) { + /* The child process must ONLY call async-safe functions. */ + close (fd[0]); + + /* umask can't fail. */ + mask = umask (0); + + if (write (fd[1], &mask, sizeof mask) != sizeof mask) + _exit (EXIT_FAILURE); + if (close (fd[1]) == -1) + _exit (EXIT_FAILURE); + + _exit (EXIT_SUCCESS);
Yay - the child looks good now.
+ } + + /* Parent. */ + close (fd[1]); + + /* Read the umask. */ + if (read (fd[0], &mask, sizeof mask) != sizeof mask) { + perrorf (g, "read"); + close (fd[0]); + return -1;
Oops - this strands a child process. You have to reap the child, even if the read() failed.
+ } + close (fd[0]); + + again: + if (waitpid (pid, &status, 0) == -1) { + if (errno == EINTR) goto again; + perrorf (g, "waitpid"); + return -1; + } + else if (!WIFEXITED (status) || WEXITSTATUS (status) != 0) { + guestfs_int_external_command_failed (g, status, "umask", NULL); + return -1; + }
Getting closer. -- Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org