Re: posix_spawn_file_actions_addchdir/addfchdir

Kirill A. Korinsky <[email protected]> Thu, 06 Aug 2026 18:56:23 +0200
Newsgroups gmane.os.openbsd.tech
Message-ID <[email protected]>
On Thu, 06 Aug 2026 14:24:15 +0200,
Stuart Henderson <[email protected]> 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

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 [email protected]
> 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