diff --git a/contrib/netbsd-tests/lib/libc/gen/posix_spawn/t_fileactions.c b/contrib/netbsd-tests/lib/libc/gen/posix_spawn/t_fileactions.c --- a/contrib/netbsd-tests/lib/libc/gen/posix_spawn/t_fileactions.c +++ b/contrib/netbsd-tests/lib/libc/gen/posix_spawn/t_fileactions.c @@ -385,6 +385,77 @@ ATF_REQUIRE(insize == outsize); } +static void +t_spawn_chdir_impl(bool chdir) +{ + int status, err, tmpdir_fd; + pid_t pid; + char * const args[2] = { __UNCONST("pwd"), NULL }; + posix_spawn_file_actions_t fa; + FILE *f; + char read_pwd[128]; + size_t ss; + static const char tmp_path[] = "/tmp"; + + unlink(TESTFILE); + + posix_spawn_file_actions_init(&fa); + posix_spawn_file_actions_addopen(&fa, fileno(stdout), + TESTFILE, O_WRONLY | O_CREAT, 0600); + if (chdir) { + ATF_REQUIRE(posix_spawn_file_actions_addchdir_np(&fa, + tmp_path) == 0); + } else { + tmpdir_fd = open(tmp_path, O_DIRECTORY | O_RDONLY); + ATF_REQUIRE(tmpdir_fd > 0); + ATF_REQUIRE(posix_spawn_file_actions_addfchdir_np(&fa, + tmpdir_fd) == 0); + } + err = posix_spawn(&pid, "/bin/pwd", &fa, NULL, args, NULL); + posix_spawn_file_actions_destroy(&fa); + if (!chdir) + close(tmpdir_fd); + + ATF_REQUIRE(err == 0); + waitpid(pid, &status, 0); + ATF_REQUIRE(WIFEXITED(status) && WEXITSTATUS(status) == EXIT_SUCCESS); + + f = fopen(TESTFILE, "r"); + ATF_REQUIRE(f != NULL); + ss = fread(read_pwd, 1, sizeof(read_pwd), f); + fclose(f); + ATF_REQUIRE(ss == strlen(tmp_path) + 1); + ATF_REQUIRE(strncmp(read_pwd, tmp_path, strlen(tmp_path)) == 0); +} + +ATF_TC(t_spawn_chdir); + +ATF_TC_HEAD(t_spawn_chdir, tc) +{ + atf_tc_set_md_var(tc, "descr", + "posix_spawn changes directory for the spawned program"); + atf_tc_set_md_var(tc, "require.progs", "/bin/pwd"); +} + +ATF_TC_BODY(t_spawn_chdir, tc) +{ + t_spawn_chdir_impl(true); +} + +ATF_TC(t_spawn_fchdir); + +ATF_TC_HEAD(t_spawn_fchdir, tc) +{ + atf_tc_set_md_var(tc, "descr", + "posix_spawn changes directory for the spawned program"); + atf_tc_set_md_var(tc, "require.progs", "/bin/pwd"); +} + +ATF_TC_BODY(t_spawn_fchdir, tc) +{ + t_spawn_chdir_impl(false); +} + ATF_TP_ADD_TCS(tp) { ATF_TP_ADD_TC(tp, t_spawn_fileactions); @@ -395,6 +466,8 @@ ATF_TP_ADD_TC(tp, t_spawn_reopen); ATF_TP_ADD_TC(tp, t_spawn_openmode); ATF_TP_ADD_TC(tp, t_spawn_empty_fileactions); + ATF_TP_ADD_TC(tp, t_spawn_chdir); + ATF_TP_ADD_TC(tp, t_spawn_fchdir); return atf_no_error(); } diff --git a/include/spawn.h b/include/spawn.h --- a/include/spawn.h +++ b/include/spawn.h @@ -87,6 +87,15 @@ 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); +#if __BSD_VISIBLE +int posix_spawn_file_actions_addchdir_np(posix_spawn_file_actions_t * + __restrict, const char * __restrict); +int posix_spawn_file_actions_addfchdir_np(posix_spawn_file_actions_t *, + int); +int posix_spawn_file_actions_addclosefrom_np (posix_spawn_file_actions_t *, + int); +#endif + /* * Spawn attributes */ diff --git a/lib/libc/gen/Makefile.inc b/lib/libc/gen/Makefile.inc --- a/lib/libc/gen/Makefile.inc +++ b/lib/libc/gen/Makefile.inc @@ -463,7 +463,10 @@ MLINKS+=popen.3 pclose.3 MLINKS+=posix_spawn.3 posix_spawnp.3 \ posix_spawn_file_actions_addopen.3 posix_spawn_file_actions_addclose.3 \ + posix_spawn_file_actions_addopen.3 posix_spawn_file_actions_addclosefrom_np.3 \ posix_spawn_file_actions_addopen.3 posix_spawn_file_actions_adddup2.3 \ + posix_spawn_file_actions_addopen.3 posix_spawn_file_actions_addchdir_np.3 \ + posix_spawn_file_actions_addopen.3 posix_spawn_file_actions_addfchdir_np.3 \ posix_spawn_file_actions_init.3 posix_spawn_file_actions_destroy.3 \ posix_spawnattr_getflags.3 posix_spawnattr_setflags.3 \ posix_spawnattr_getpgroup.3 posix_spawnattr_setpgroup.3 \ diff --git a/lib/libc/gen/Symbol.map b/lib/libc/gen/Symbol.map --- a/lib/libc/gen/Symbol.map +++ b/lib/libc/gen/Symbol.map @@ -436,6 +436,9 @@ }; FBSD_1.7 { + posix_spawn_file_actions_addchdir_np; + posix_spawn_file_actions_addfchdir_np; + posix_spawn_file_actions_addclosefrom_np; sched_getaffinity; sched_setaffinity; sched_getcpu; diff --git a/lib/libc/gen/posix_spawn.3 b/lib/libc/gen/posix_spawn.3 --- a/lib/libc/gen/posix_spawn.3 +++ b/lib/libc/gen/posix_spawn.3 @@ -34,7 +34,7 @@ .\" .\" $FreeBSD$ .\" -.Dd January 5, 2016 +.Dd November 28, 2021 .Dt POSIX_SPAWN 3 .Os .Sh NAME @@ -46,9 +46,23 @@ .Sh SYNOPSIS .In spawn.h .Ft int -.Fn posix_spawn "pid_t *restrict pid" "const char *restrict path" "const posix_spawn_file_actions_t *file_actions" "const posix_spawnattr_t *restrict attrp" "char *const argv[restrict]" "char *const envp[restrict]" +.Fo posix_spawn +.Fa "pid_t *restrict pid" +.Fa "const char *restrict path" +.Fa "const posix_spawn_file_actions_t *file_actions" +.Fa "const posix_spawnattr_t *restrict attrp" +.Fa "char *const argv[restrict]" +.Fa "char *const envp[restrict]" +.Fc .Ft int -.Fn posix_spawnp "pid_t *restrict pid" "const char *restrict file" "const posix_spawn_file_actions_t *file_actions" "const posix_spawnattr_t *restrict attrp" "char *const argv[restrict]" "char *const envp[restrict]" +.Fo posix_spawnp +.Fa "pid_t *restrict pid" +.Fa "const char *restrict file" +.Fa "const posix_spawn_file_actions_t *file_actions" +.Fa "const posix_spawnattr_t *restrict attrp" +.Fa "char *const argv[restrict]" +.Fa "char *const envp[restrict]" +.Fc .Sh DESCRIPTION The .Fn posix_spawn @@ -408,6 +422,11 @@ This implementation ignores any errors from .Fn close , including trying to close a descriptor that is not open. +The ignore extends to any errors from individual file descriptors +.Fn close +executed as part of the +.Fn closefrom +action. .El .Sh SEE ALSO .Xr close 2 , @@ -420,8 +439,11 @@ .Xr setpgid 2 , .Xr vfork 2 , .Xr posix_spawn_file_actions_addclose 3 , +.Xr posix_spawn_file_actions_addclosefrom_np 3 , .Xr posix_spawn_file_actions_adddup2 3 , .Xr posix_spawn_file_actions_addopen 3 , +.Xr posix_spawn_file_actions_addchdir_np 3 , +.Xr posix_spawn_file_actions_addfchdir_np 3 , .Xr posix_spawn_file_actions_destroy 3 , .Xr posix_spawn_file_actions_init 3 , .Xr posix_spawnattr_destroy 3 , diff --git a/lib/libc/gen/posix_spawn.c b/lib/libc/gen/posix_spawn.c --- a/lib/libc/gen/posix_spawn.c +++ b/lib/libc/gen/posix_spawn.c @@ -62,7 +62,14 @@ typedef struct __posix_spawn_file_actions_entry { STAILQ_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_CLOSEFROM, + } fae_action; int fae_fildes; union { @@ -176,6 +183,17 @@ /* Perform a close(), do not fail if already closed */ (void)_close(fae->fae_fildes); break; + case FAE_CHDIR: + if (chdir(fae->fae_path) != 0) + return (errno); + break; + case FAE_FCHDIR: + if (fchdir(fae->fae_fildes) != 0) + return (errno); + break; + case FAE_CLOSEFROM: + closefrom(fae->fae_fildes); + break; } return (0); } @@ -349,7 +367,7 @@ const posix_spawnattr_t *sa, char * const argv[], char * const envp[]) { - return do_posix_spawn(pid, path, fa, sa, argv, envp, 0); + return (do_posix_spawn(pid, path, fa, sa, argv, envp, 0)); } int @@ -358,7 +376,7 @@ const posix_spawnattr_t *sa, char * const argv[], char * const envp[]) { - return do_posix_spawn(pid, path, fa, sa, argv, envp, 1); + return (do_posix_spawn(pid, path, fa, sa, argv, envp, 1)); } /* @@ -389,7 +407,8 @@ STAILQ_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); } @@ -474,6 +493,71 @@ return (0); } +int +posix_spawn_file_actions_addchdir_np(posix_spawn_file_actions_t * + __restrict fa, const char *__restrict path) +{ + posix_spawn_file_actions_entry_t *fae; + int error; + + fae = malloc(sizeof(posix_spawn_file_actions_entry_t)); + if (fae == NULL) + return (errno); + + fae->fae_action = FAE_CHDIR; + fae->fae_path = strdup(path); + if (fae->fae_path == NULL) { + error = errno; + free(fae); + return (error); + } + + STAILQ_INSERT_TAIL(&(*fa)->fa_list, fae, fae_list); + return (0); +} + +int +posix_spawn_file_actions_addfchdir_np(posix_spawn_file_actions_t *__restrict fa, + int fildes) +{ + posix_spawn_file_actions_entry_t *fae; + + if (fildes < 0) + return (EBADF); + + /* Allocate object */ + fae = malloc(sizeof(posix_spawn_file_actions_entry_t)); + if (fae == NULL) + return (errno); + + fae->fae_action = FAE_FCHDIR; + fae->fae_fildes = fildes; + + STAILQ_INSERT_TAIL(&(*fa)->fa_list, fae, fae_list); + return (0); +} + +int +posix_spawn_file_actions_addclosefrom_np (posix_spawn_file_actions_t * + __restrict fa, int from) +{ + posix_spawn_file_actions_entry_t *fae; + + if (from < 0) + return (EBADF); + + /* Allocate object */ + fae = malloc(sizeof(posix_spawn_file_actions_entry_t)); + if (fae == NULL) + return (errno); + + fae->fae_action = FAE_CLOSEFROM; + fae->fae_fildes = from; + + STAILQ_INSERT_TAIL(&(*fa)->fa_list, fae, fae_list); + return (0); +} + /* * Spawn attributes */ diff --git a/lib/libc/gen/posix_spawn_file_actions_addopen.3 b/lib/libc/gen/posix_spawn_file_actions_addopen.3 --- a/lib/libc/gen/posix_spawn_file_actions_addopen.3 +++ b/lib/libc/gen/posix_spawn_file_actions_addopen.3 @@ -40,18 +40,49 @@ .Sh NAME .Nm posix_spawn_file_actions_addopen , .Nm posix_spawn_file_actions_adddup2 , -.Nm posix_spawn_file_actions_addclose -.Nd "add open, dup2 or close action to spawn file actions object" +.Nm posix_spawn_file_actions_addclose , +.Nm posix_spawn_file_actions_addclosefrom_np , +.Nm posix_spawn_file_actions_addchdir_np , +.Nm posix_spawn_file_actions_addfchdir_np +.Nd "add open, dup2, close, closefrom, or chdir/fchdir actions to spawn file actions object" .Sh LIBRARY .Lb libc .Sh SYNOPSIS .In spawn.h .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" +.Fo posix_spawn_file_actions_addopen +.Fa "posix_spawn_file_actions_t * file_actions" +.Fa "int fildes" +.Fa "const char *restrict path" +.Fa "int oflag" +.Fa "mode_t mode" +.Fc .Ft int -.Fn posix_spawn_file_actions_adddup2 "posix_spawn_file_actions_t * file_actions" "int fildes" "int newfildes" +.Fo posix_spawn_file_actions_adddup2 +.Fa "posix_spawn_file_actions_t * file_actions" +.Fa "int fildes" +.Fa "int newfildes" +.Fc .Ft int -.Fn posix_spawn_file_actions_addclose "posix_spawn_file_actions_t * file_actions" "int fildes" +.Fo posix_spawn_file_actions_addclose +.Fa "posix_spawn_file_actions_t * file_actions" +.Fa "int fildes" +.Fc +.Ft int +.Fo posix_spawn_file_actions_addclosefrom_np +.Fa "posix_spawn_file_actions_t * file_actions" +.Fa "int from" +.Fc +.Ft int +.Fo posix_spawn_file_actions_addchdir_np +.Fa "posix_spawn_file_actions_t *restrict file_actions" +.Fa "const char *restrict path" +.Fc +.Ft int +.Fo posix_spawn_file_actions_addfchdir_np +.Fa "posix_spawn_file_actions_t * file_actions" +.Fa "int fildes" +.Fc .Sh DESCRIPTION These functions add an open, dup2 or close action to a spawn file actions object. @@ -150,6 +181,34 @@ .Pp had been called) when a new process is spawned using this file actions object. +.Pp +The +.Fn posix_spawn_file_actions_addclosefrom_np +function adds a close action to close all file descriptors numerically +equal or greater then the argument +.Fa from . +For each open file descriptor, logically the close action is performed, +and any possible errors encountered are ignored. +.Pp +The +.Fn posix_spawn_file_actions_addchdir_np +and +.Fn posix_spawn_file_actions_addfchdir_np +functions add a change current directory action to the object +referenced by +.Fa file_actions +that affects actions (opens with relative path) performed after the operation, +in the order of insertion into the +.Fa file_actions +object. +Also it sets working directory for the spawned program. +The +.Fn posix_spawn_file_actions_addchdir_np +takes the +.Fa path +to set as the working directory, while +.Fn posix_spawn_file_actions_addfchdir_np +takes the directory file descriptor. .Sh RETURN VALUES Upon successful completion, these functions return zero; otherwise, an error number is returned to indicate the error. @@ -191,6 +250,14 @@ (clearing .Dv FD_CLOEXEC ) . A future update of the Standard is expected to require this behavior. +.Pp +The +.Fn posix_spawn_file_actions_addchdir_np , +.Fn posix_spawn_file_actions_addfchdir_np , +and +.Fn posix_spawn_file_actions_addclosefrom_np +are non-standard functions implemented after the similar functionality +provided by glibc. .Sh HISTORY The .Fn posix_spawn_file_actions_addopen , @@ -199,5 +266,12 @@ .Fn posix_spawn_file_actions_addclose functions first appeared in .Fx 8.0 . +The +.Fn posix_spawn_file_actions_addchdir_np , +.Fn posix_spawn_file_actions_addfchdir_np , +and +.Fn posix_spawn_file_actions_addclosefrom_np +functions first appeared in +.Fx 14.0 . .Sh AUTHORS .An \&Ed Schouten Aq Mt ed@FreeBSD.org diff --git a/lib/libc/gen/posix_spawn_file_actions_init.3 b/lib/libc/gen/posix_spawn_file_actions_init.3 --- a/lib/libc/gen/posix_spawn_file_actions_init.3 +++ b/lib/libc/gen/posix_spawn_file_actions_init.3 @@ -34,7 +34,7 @@ .\" .\" $FreeBSD$ .\" -.Dd March 24, 2008 +.Dd November 28, 2021 .Dt POSIX_SPAWN_FILE_ACTIONS_INIT 3 .Os .Sh NAME @@ -83,6 +83,7 @@ .Sh SEE ALSO .Xr posix_spawn 3 , .Xr posix_spawn_file_actions_addclose 3 , +.Xr posix_spawn_file_actions_addclosefrom_np 3 , .Xr posix_spawn_file_actions_adddup2 3 , .Xr posix_spawn_file_actions_addopen 3 , .Xr posix_spawnp 3