Hi Paul, > I'm addressing https://savannah.gnu.org/bugs/?56834 > > I want to invoke a child process, and I need the program I'm going to > invoke to be searched for in a PATH which is (potentially) different > than the PATH which is active in the parent. > > When you use execlp(), you can just assign the child's environment > before you invoke the exec. Since you've already forked you're not > modifying the parent's environment. > > However, with posix_spawnp() that doesn't work Thanks for explaining. > the path search is done > on the _parent's_ PATH environment value not the one passed in to > posix_spawnp(). I don't want that, I need the search done in the > child's environment. I can't decide if this behavior by posix_spawnp() > is correct or not, and the POSIX spec isn't clear, but it's how it > works (at least on GNU/Linux). For me, the POSIX spec [1] is clear: envp "constitute[s] the environment for the new process image". It does not say that the search for the program is done through envp. All implementations agree on this: In the attached test, I get the output Callee found in parent's $PATH. in all tested platforms (glibc/Linux, glibc/kFreeBSD, glibc/Hurd, Mac OS X, FreeBSD 11, NetBSD 7, AIX, Solaris 10, Solaris 11, Solaris OpenIndiana, Haiku) and with gnulib's replacement (tested on Solaris 9). So, there is no portability issue here. > At the same time, I don't want to be running putenv() to set then > reset the PATH environment variable in the parent every time I invoke > a command. > > So what I want to do is run find_in_path_str() passing in the PATH from > the child's environment then pass the result to posix_spawn. Makes sense. > I suppose an even simpler interface, for me, would be something like: > > find_in_path_envp (const char *prog, const char **envp); > > where it would look up PATH in the environment passed in, so I don't > have to do the lookup of PATH, and use that instead of getenv(). But I > don't know if that's as generally useful an interface. If there were many libc functions that take a '[const] char**' environment as argument, I would agree that this was the way to go. But there are no getenv, setenv, putenv variants that take a 'char **' arguments; so it appears that POSIX and libc APIs don't recognize 'char **' as a valuable data type. I therefore find it better to define the function with just the PATH value as argument. > Because that's not my use-case :). I already have a PATH string, it's > just not in my current environment. OK. > prog = find_in_path_str ("myprog", lookup_path ()); > > and if lookup_path() returns NULL it defaults to the environment PATH, I don't think NULL should be interpreted as "look in the default PATH". Rather, the convention is that an empty or null PATH means the current directory. Try $ (cd /tmp; PATH=; cat --version) $ (cd /bin; PATH=; cat --version) $ (cd /tmp; unset PATH; cat --version) $ (cd /bin; unset PATH; cat --version) > rather than having to do something like: > > const char *path = lookup_path (); > if (path) > prog = find_in_path_str ("myprog", path); > else > prog = find_in_path ("myprog"); If the caller needs this logic, it should better be coded explicitly like this. Note also that what you need is not merely an *attempt* to determine the filename of the executable, but you need it always - since you _don't_ want the program to be looked up in the parent's PATH. Thus you need also a return value that indicates that the program was not found in PATH. Otherwise, assume parent PATH = "/bin:/usr/bin" child PATH = "/tmp" program = "cat" the find_in_path_str search would do a lookup in the child PATH, not find it, return "cat", and the posix_spawnp would then find "cat" in the parent PATH and invoke /bin/cat. This, in turn, means that we need to provide also an implementation for Windows, Cygwin, EMX, DOS. And this means that it can't really share much with the existing findprog.c. So the implementation should go into a different .c file. Bruno [1] https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_spawn.html