Download raw body.
posix_spawn_file_actions_addchdir/addfchdir
On Thu, Aug 06, 2026 at 06:56:23PM +0200, Kirill A. Korinsky wrote:
> On Thu, 06 Aug 2026 14:24:15 +0200,
> Stuart Henderson <stu@spacehopper.org> wrote:
> >
> > posix_spawn_file_actions_addchdir and posix_spawn_file_actions_addfchdir
> > have been implemented as _np in some OS for a while, but have made it
> > into posix now.
> >
> > https://pubs.opengroup.org/onlinepubs/9799919799.2024edition/functions/posix_spawn_file_actions_addchdir.html
> >
> > a number of things in ports print information about testing for them
> > during configure (mostly via gnulib which provides replacements).
> > also the subprocess mode in llama.cpp is forcibly disabled via a
> > patch because we don't have ..._addchdir().
> >
> > https://exopi.bsdfrog.org/cgi-bin/omega?P=posix_spawn_file_actions_addchdir&DEFAULTOP=and&DB=default&FMT=query&xDB=default&xFILTERS=5
> >
> > do we want them (yet)? is this diff vaguely along the right lines?
> > (obviously needs shlib bump and testing in ports bulk).
> >
> > I wrote an initial diff, then discovered FreeBSD had them already
> > (then added the missing free which I spotted after comparing ;)
> >
>
> NetBSD also has them:
> https://man.netbsd.org/posix_spawn_file_actions_addchdir.3
>
> And yes, we need them for ports, I had encountered at least one case when it
> required: llama.cpp via https://github.com/sheredom/subprocess.h
>
I ran into the same thing with llama.cpp, so the change below would be welcome.
-ml
> Your diff reads sane enough, but I not sure that can review it the right way.
>
> > Index: include/spawn.h
> > ===================================================================
> > RCS file: /cvs/src/include/spawn.h,v
> > diff -u -p -r1.3 spawn.h
> > --- include/spawn.h 20 May 2015 22:50:07 -0000 1.3
> > +++ include/spawn.h 6 Aug 2026 12:18:31 -0000
> > @@ -69,6 +69,9 @@ int posix_spawn_file_actions_addopen(pos
> > int, const char *__restrict, int, mode_t);
> > int posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t *, int, int);
> > int posix_spawn_file_actions_addclose(posix_spawn_file_actions_t *, int);
> > +int posix_spawn_file_actions_addchdir(posix_spawn_file_actions_t *__restrict,
> > + const char *__restrict);
> > +int posix_spawn_file_actions_addfchdir(posix_spawn_file_actions_t *, int);
> >
> > /*
> > * Spawn attributes
> > Index: lib/libc/Symbols.list
> > ===================================================================
> > RCS file: /cvs/src/lib/libc/Symbols.list,v
> > diff -u -p -r1.95 Symbols.list
> > --- lib/libc/Symbols.list 24 Oct 2025 11:30:06 -0000 1.95
> > +++ lib/libc/Symbols.list 6 Aug 2026 12:18:31 -0000
> > @@ -725,8 +725,10 @@ pause
> > pclose
> > popen
> > posix_spawn
> > +posix_spawn_file_actions_addchdir
> > posix_spawn_file_actions_addclose
> > posix_spawn_file_actions_adddup2
> > +posix_spawn_file_actions_addfchdir
> > posix_spawn_file_actions_addopen
> > posix_spawn_file_actions_destroy
> > posix_spawn_file_actions_init
> > Index: lib/libc/gen/posix_spawn.3
> > ===================================================================
> > RCS file: /cvs/src/lib/libc/gen/posix_spawn.3,v
> > diff -u -p -r1.11 posix_spawn.3
> > --- lib/libc/gen/posix_spawn.3 26 Jun 2023 15:28:52 -0000 1.11
> > +++ lib/libc/gen/posix_spawn.3 6 Aug 2026 12:18:31 -0000
> > @@ -73,8 +73,10 @@ with
> > Otherwise, file descriptors in the child process
> > are altered according to
> > .Xr posix_spawn_file_actions_init 3 ,
> > +.Xr posix_spawn_file_actions_addchdir 3 ,
> > .Xr posix_spawn_file_actions_addclose 3 ,
> > .Xr posix_spawn_file_actions_adddup2 3 ,
> > +.Xr posix_spawn_file_actions_addfchdir 3 ,
> > and
> > .Xr posix_spawn_file_actions_addopen 3 .
> > .Pp
> > Index: lib/libc/gen/posix_spawn.c
> > ===================================================================
> > RCS file: /cvs/src/lib/libc/gen/posix_spawn.c,v
> > diff -u -p -r1.10 posix_spawn.c
> > --- lib/libc/gen/posix_spawn.c 28 Jun 2019 13:32:41 -0000 1.10
> > +++ lib/libc/gen/posix_spawn.c 6 Aug 2026 12:18:31 -0000
> > @@ -51,7 +51,7 @@ struct __posix_spawn_file_actions {
> >
> > typedef struct __posix_spawn_file_actions_entry {
> > SIMPLEQ_ENTRY(__posix_spawn_file_actions_entry) fae_list;
> > - enum { FAE_OPEN, FAE_DUP2, FAE_CLOSE } fae_action;
> > + enum { FAE_OPEN, FAE_DUP2, FAE_CLOSE, FAE_CHDIR, FAE_FCHDIR } fae_action;
> >
> > int fae_fildes;
> > union {
> > @@ -171,6 +171,14 @@ process_file_actions_entry(posix_spawn_f
> > /* Perform a close(), do not fail if already closed */
> > (void)close(fae->fae_fildes);
> > break;
> > + case FAE_CHDIR:
> > + if (chdir(fae->fae_path) == -1)
> > + return (errno);
> > + break;
> > + case FAE_FCHDIR:
> > + if (fchdir(fae->fae_fildes) == -1)
> > + return (errno);
> > + break;
> > }
> > return (0);
> > }
> > @@ -273,7 +281,8 @@ posix_spawn_file_actions_destroy(posix_s
> > SIMPLEQ_REMOVE_HEAD(&(*fa)->fa_list, fae_list);
> >
> > /* Deallocate file action entry */
> > - if (fae->fae_action == FAE_OPEN)
> > + if (fae->fae_action == FAE_OPEN ||
> > + fae->fae_action == FAE_CHDIR)
> > free(fae->fae_path);
> > free(fae);
> > }
> > @@ -352,6 +361,54 @@ posix_spawn_file_actions_addclose(posix_
> >
> > /* Set values and store in queue */
> > fae->fae_action = FAE_CLOSE;
> > + fae->fae_fildes = fildes;
> > +
> > + SIMPLEQ_INSERT_TAIL(&(*fa)->fa_list, fae, fae_list);
> > + return (0);
> > +}
> > +
> > +int
> > +posix_spawn_file_actions_addchdir(posix_spawn_file_actions_t *__restrict fa,
> > + const char *__restrict path)
> > +{
> > + posix_spawn_file_actions_entry_t *fae;
> > + int error;
> > +
> > + /* Allocate object */
> > + fae = malloc(sizeof(posix_spawn_file_actions_entry_t));
> > + if (fae == NULL)
> > + return (errno);
> > +
> > + /* Set values and store in queue */
> > + fae->fae_action = FAE_CHDIR;
> > + fae->fae_path = strdup(path);
> > + if (fae->fae_path == NULL) {
> > + error = errno;
> > + free(fae);
> > + return (error);
> > + }
> > +
> > + SIMPLEQ_INSERT_TAIL(&(*fa)->fa_list, fae, fae_list);
> > + return (0);
> > +}
> > +
> > +int
> > +posix_spawn_file_actions_addfchdir(posix_spawn_file_actions_t *__restrict fa,
> > + int fildes)
> > +{
> > + posix_spawn_file_actions_entry_t *fae;
> > + int error;
> > +
> > + if (fildes < 0)
> > + return (EBADF);
> > +
> > + /* Allocate object */
> > + fae = malloc(sizeof(posix_spawn_file_actions_entry_t));
> > + if (fae == NULL)
> > + return (errno);
> > +
> > + /* Set values and store in queue */
> > + fae->fae_action = FAE_FCHDIR;
> > fae->fae_fildes = fildes;
> >
> > SIMPLEQ_INSERT_TAIL(&(*fa)->fa_list, fae, fae_list);
> > Index: lib/libc/gen/posix_spawn_file_actions_addopen.3
> > ===================================================================
> > RCS file: /cvs/src/lib/libc/gen/posix_spawn_file_actions_addopen.3,v
> > diff -u -p -r1.9 posix_spawn_file_actions_addopen.3
> > --- lib/libc/gen/posix_spawn_file_actions_addopen.3 29 Mar 2022 18:15:52 -0000 1.9
> > +++ lib/libc/gen/posix_spawn_file_actions_addopen.3 6 Aug 2026 12:18:31 -0000
> > @@ -18,17 +18,23 @@
> > .Dt POSIX_SPAWN_FILE_ACTIONS_ADDOPEN 3
> > .Os
> > .Sh NAME
> > +.Nm posix_spawn_file_actions_addchdir ,
> > .Nm posix_spawn_file_actions_addclose ,
> > .Nm posix_spawn_file_actions_adddup2 ,
> > +.Nm posix_spawn_file_actions_addfchdir ,
> > .Nm posix_spawn_file_actions_addopen
> > .Nd add action to close, dup2 or open file descriptor to file actions object
> > .Sh SYNOPSIS
> > .In spawn.h
> > .Ft int
> > +.Fn posix_spawn_file_actions_addchdir "posix_spawn_file_actions_t *file_actions" "const char *restrict path"
> > +.Ft int
> > .Fn posix_spawn_file_actions_addclose "posix_spawn_file_actions_t *file_actions" "int fildes"
> > .Ft int
> > .Fn posix_spawn_file_actions_adddup2 "posix_spawn_file_actions_t *file_actions" "int fildes" "int newfildes"
> > .Ft int
> > +.Fn posix_spawn_file_actions_addfchdir "posix_spawn_file_actions_t *file_actions" "int fildes"
> > +.Ft int
> > .Fn posix_spawn_file_actions_addopen "posix_spawn_file_actions_t *file_actions" "int fildes" "const char *restrict path" "int oflag" "mode_t mode"
> > .Sh DESCRIPTION
> > These function add an action to
> > @@ -45,6 +51,15 @@ Actions are executed in order in the chi
> > .Bl -dash
> > .It
> > The
> > +.Fn posix_spawn_file_actions_addchdir
> > +function adds an action that causes
> > +.Bd -literal -offset indent
> > +chdir(path);
> > +.Ed
> > +.Pp
> > +to be called.
> > +.It
> > +The
> > .Fn posix_spawn_file_actions_addclose
> > function adds an action that causes
> > .Bd -literal -offset indent
> > @@ -69,6 +84,15 @@ equals
> > .Fa fildes .
> > .It
> > The
> > +.Fn posix_spawn_file_actions_addfchdir
> > +function adds an action that causes
> > +.Bd -literal -offset indent
> > +fchdir(fildes);
> > +.Ed
> > +.Pp
> > +to be called.
> > +.It
> > +The
> > .Fn posix_spawn_file_actions_addopen
> > function adds an action that causes
> > .Bd -literal -offset indent
> > @@ -100,7 +124,12 @@ if they run out of memory.
> > .Xr posix_spawn_file_actions_init 3 ,
> > .Xr posix_spawnp 3
> > .Sh STANDARDS
> > -These functions conform to
> > +.Fn posix_spawn_file_actions_addchdir
> > +and
> > +.Fn posix_spawn_file_actions_addfchdir
> > +conform to
> > +.St -p1003.1-2024 .
> > +Other functions conform to
> > .St -p1003.1-2001 .
> > .Sh AUTHORS
> > .An \&Ed Schouten Aq Mt ed@FreeBSD.org
> > Index: lib/libc/hidden/spawn.h
> > ===================================================================
> > RCS file: /cvs/src/lib/libc/hidden/spawn.h,v
> > diff -u -p -r1.1 spawn.h
> > --- lib/libc/hidden/spawn.h 4 Oct 2015 07:57:21 -0000 1.1
> > +++ lib/libc/hidden/spawn.h 6 Aug 2026 12:18:31 -0000
> > @@ -21,8 +21,10 @@
> > #include_next <spawn.h>
> >
> > PROTO_DEPRECATED(posix_spawn);
> > +PROTO_DEPRECATED(posix_spawn_file_actions_addchdir);
> > PROTO_DEPRECATED(posix_spawn_file_actions_addclose);
> > PROTO_DEPRECATED(posix_spawn_file_actions_adddup2);
> > +PROTO_DEPRECATED(posix_spawn_file_actions_addfchdir);
> > PROTO_DEPRECATED(posix_spawn_file_actions_addopen);
> > PROTO_DEPRECATED(posix_spawn_file_actions_destroy);
> > PROTO_DEPRECATED(posix_spawn_file_actions_init);
> >
>
> --
> wbr, Kirill
>
posix_spawn_file_actions_addchdir/addfchdir