This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
Re: [RFC/PATCH glibc 0/2] setting working dir in posix_spawn()
- From: Eric Blake <eblake at redhat dot com>
- To: Florian Weimer <fweimer at redhat dot com>, Jonathan Nieder <jrnieder at gmail dot com>
- Cc: Austin Group <austin-group-l at opengroup dot org>, libc-alpha at sourceware dot org
- Date: Mon, 10 Sep 2018 11:30:56 -0500
- Subject: Re: [RFC/PATCH glibc 0/2] setting working dir in posix_spawn()
- References: <alpine.LFD.2.00.1008241029530.1046@i5.linux-foundation.org> <20100825013625.GC10423@burratino> <4C74BFA7.1090907@viscovery.net> <4C752739.3010808@redhat.com> <20100826061815.GH9708@burratino> <4C767682.7030700@redhat.com> <20100827063546.GB32454@burratino> <c31c9ac5-ee21-c418-1924-049207ef38fb@redhat.com> <ec1299eb-55d9-7d5f-8f7b-045223f998be@redhat.com>
On 9/9/18 3:34 PM, Florian Weimer wrote:
On 09/08/2018 12:54 AM, Eric Blake wrote:
Also, I've realized that we do NOT need
posix_spawn_file_actions_addopenat(). The main benefit of openat() is
that you can redirect relative file names according to an fd of your
choice, without affecting global state. But during posix_spawn(),
there are no other threads competing for global state (if you are
doing a library implementation where the chdir() is done between
fork() and exec()), so:
openat(mydir, "file", mode);
can be decomposed to:
posix_spawn_file_actions_addopen(&act, 5, ".", O_RDONLY|O_DIRECTORY, 0);
posix_spawn_file_actions_addfchdir(&act, mydir);
posix_spawn_file_actions_addopen(&act, 4, "file", mode, 0);
posix_spawn_file_actions_addfchdir(&act, 5);
posix_spawn_file_actions_addclose(&act, 5);
Is it possible to choose an appropriate value for the directory
descriptor automatically?
Not that I know of. But it's tougher than it looks - my initial thought
was "what about a magic negative number" that says to auto-allocate at
the next free fd (the way AT_FDCWD is a magic number) - but since the
allocation of fds is done at a later point (the posix_spawn() call) than
the addition to file_actions (the posix_spawn_file_actions_addopen()),
there is no way to predict WHAT that fd will actually resolve to, and
thus no way to reuse that fd in posix_spawn_file_actions_addfchdir(),
posix_spawn_file_actions_adddup2(), or
posix_spawn_file_actions_addclose() as needed. In other words, by the
time you're using posix_spawn(), you're already stuck with having to
micro-manage your fds - and if you want to avoid closing something
important by accident, you practically have to do:
scratch_fd = open("/dev/null", O_RDONLY|O_CLOEXEC);
posix_spawn_file_actions_addopen(&act, scratch_fd, ...);
posix_spawn(, &act, );
close(scratch_fd);
What about support for AT_EMPTY_PATH, for upgrading an O_PATH
descriptor? I think this operation still needs openat.
O_PATH and AT_EMPTY_PATH are Linux/glibc extensions not in POSIX. So
yes, they are worth thinking about in terms of what glibc should
provide, but I'm not sure if they are sufficient on their own to require
POSIX to worry about posix_spawn_file_actions_addopenat(), but rather
might argue that glibc should add posix_spawn_file_actions_addopenat_np().
Or looking at it another way - I'm trying to stick to the initial
philosophy documented in the posix_spawn() RATIONALE section (page 1457
in the 2017 edition):
The requirements for posix_spawn( ) and posix_spawnp( ) are:
• They must be implementable without an MMU or unusual hardware.
• They must be compatible with existing POSIX standards.
Additional goals are:
• They should be efficiently implementable.
• They should be able to replace at least 50% of typical executions of fork( ).
• A system with posix_spawn( ) and posix_spawnp( ) and without fork( ) should be useful, at least for realtime applications.
• A system with fork( ) and the exec family should be able to implement posix_spawn( ) and posix_spawnp( ) as library routines.
Adding just posix_spawn_file_actions_addfchdir() is lighter-weight than
adding posix_spawn_file_actions_addopenat(),
posix_spawn_file_actions_fchdirat(), and others. If you really have to
deal with things like O_PATH or AT_EMPTY_PATH, then pre-open the fd in
the parent and use posix_spawn_file_actions_adddup2(), rather than
making file_actions more complicated. And we're not trying to replace
100% of fork/exec, but merely try to add a common-enough chdir paradigm
to make it easier to replace the common 50%.
Also, note that http://austingroupbugs.net/view.php?id=411 is also
somewhat relevant, which states:
At line 46976 [XSH posix_spawn_file_actions_adddup2], add a sentence:
If fildes and newfildes are equal, then the action shall ensure that
the FD_CLOEXEC flag of fildes is cleared (even though dup2( ) would
leave it unchanged).
After line 46999 [XSH posix_spawn_file_actions_adddup2], add the
following:
>
Although dup2( ) is required to do nothing when fildes and newfildes
are equal and fildes is an open descriptor, the use of
posix_spawn_file_actions_adddup2( ) is required to clear the
FD_CLOEXEC flag of fildes. This is because there is no counterpart of
posix_spawn_file_actions_fcntl( ) that could be used for clearing the
flag; it would also be possible to achieve this effect by using two
calls to posix_spawn_file_actions_adddup2( ) and a temporary fildes
value known to not conflict with any other file descriptors, coupled
with a posix_spawn_file_actions_close( ) to avoid leaking the
temporary, but this approach is complex, and risks EMFILE or ENFILE
failure that can be avoided with the in-place removal of FD_CLOEXEC.
There is no need for posix_spawn_file_actions_adddup3( ), since it
makes no sense to create a file descriptor with FD_CLOEXEC set before
spawning the child process, where that file descriptor would
immediately be closed again.
--
Eric Blake, Principal Software Engineer
Red Hat, Inc. +1-919-301-3266
Virtualization: qemu.org | libvirt.org