From: Stuart Henderson Subject: posix_spawn_file_actions_addchdir/addfchdir To: tech Date: Thu, 6 Aug 2026 13:24:15 +0100 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 ;) 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 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);