POSIX-2024: support for O_CLOFORK, SO_CLOFORK

Change-Id: I4f3a961947eefdeafd5a249499899cc92d67c2d1
Reviewed-on: https://review.haiku-os.org/c/haiku/+/9330
Tested-by: Commit checker robot <[email protected]>
Reviewed-by: waddlesplash <[email protected]>
This commit is contained in:
Jérôme Duval
2025-06-09 16:26:13 +00:00
committed by waddlesplash
parent ba28b6f5f7
commit 904fd2abf0
10 changed files with 68 additions and 11 deletions
+3
View File
@@ -21,6 +21,7 @@
#define F_SETLK 0x0080 /* set locking information */
#define F_SETLKW 0x0100 /* as above, but waits if blocked */
#define F_DUPFD_CLOEXEC 0x0200 /* duplicate fd with close on exec set */
#define F_DUPFD_CLOFORK 0x0400 /* duplicate fd with close on fork set */
/* advisory locking types */
#define F_RDLCK 0x0040 /* read or shared lock */
@@ -29,6 +30,7 @@
/* file descriptor flags for fcntl() */
#define FD_CLOEXEC 1 /* close on exec */
#define FD_CLOFORK 2 /* close on fork */
/* file access modes for open() */
#define O_RDONLY 0x0000 /* read only */
@@ -57,6 +59,7 @@
/* possible */
#define O_NOCACHE O_DIRECT
#define O_DIRECTORY 0x00200000 /* fail if not a directory */
#define O_CLOFORK 0x00400000 /* close on fork */
/* flags for the *at() functions */
#define AT_FDCWD (-100) /* CWD FD for the *at() functions */
+1
View File
@@ -49,6 +49,7 @@ typedef uint8_t sa_family_t;
#define SOCK_NONBLOCK 0x00040000
#define SOCK_CLOEXEC 0x00080000
#define SOCK_CLOFORK 0x00100000
/* Socket options for SOL_SOCKET level */
#define SOL_SOCKET -1
+3
View File
@@ -94,6 +94,9 @@ extern bool fd_is_file(struct file_descriptor* descriptor);
extern bool fd_close_on_exec(const struct io_context *context, int fd);
extern void fd_set_close_on_exec(struct io_context *context, int fd,
bool closeFD);
extern bool fd_close_on_fork(const struct io_context *context, int fd);
extern void fd_set_close_on_fork(struct io_context *context, int fd,
bool closeFD);
static struct io_context *get_current_io_context(bool kernel);
+1
View File
@@ -56,6 +56,7 @@ typedef struct io_context {
struct file_descriptor **fds;
struct select_info **select_infos;
uint8 *fds_close_on_exec;
uint8 *fds_close_on_fork;
struct list node_monitors;
uint32 num_monitors;
uint32 max_monitors;
+2
View File
@@ -38,6 +38,8 @@ static const FlagsTypeHandler::FlagInfo kOpenFlagInfos[] = {
FLAG_INFO_ENTRY(O_DIRECTORY),
FLAG_INFO_ENTRY(O_CLOFORK),
{ 0, NULL }
};
+1
View File
@@ -82,6 +82,7 @@ static const enum_info kShutdownHow[] = {
static const FlagsTypeHandler::FlagInfo kSocketFlagInfos[] = {
FLAG_INFO_ENTRY(SOCK_NONBLOCK),
FLAG_INFO_ENTRY(SOCK_CLOEXEC),
FLAG_INFO_ENTRY(SOCK_CLOFORK),
{ 0, NULL }
};
+21 -1
View File
@@ -109,6 +109,23 @@ fd_set_close_on_exec(struct io_context* context, int fd, bool closeFD)
}
bool
fd_close_on_fork(const struct io_context* context, int fd)
{
return CHECK_BIT(context->fds_close_on_fork[fd / 8], fd & 7) ? true : false;
}
void
fd_set_close_on_fork(struct io_context* context, int fd, bool closeFD)
{
if (closeFD)
context->fds_close_on_fork[fd / 8] |= (1 << (fd & 7));
else
context->fds_close_on_fork[fd / 8] &= ~(1 << (fd & 7));
}
/*! Searches a free slot in the FD table of the provided I/O context, and
inserts the specified descriptor into it.
*/
@@ -315,6 +332,7 @@ remove_fd(struct io_context* context, int fd)
context->fds[fd] = NULL;
fd_set_close_on_exec(context, fd, false);
fd_set_close_on_fork(context, fd, false);
context->num_used_fds--;
selectInfos = context->select_infos[fd];
@@ -351,6 +369,7 @@ dup_fd(int fd, bool kernel)
} else {
WriteLocker locker(context->lock);
fd_set_close_on_exec(context, status, false);
fd_set_close_on_fork(context, status, false);
}
return status;
@@ -374,7 +393,7 @@ dup2_fd(int oldfd, int newfd, int flags, bool kernel)
// quick check
if (oldfd < 0 || newfd < 0)
return B_FILE_ERROR;
if ((flags & ~O_CLOEXEC) != 0)
if ((flags & ~(O_CLOEXEC | O_CLOFORK)) != 0)
return B_BAD_VALUE;
// Get current I/O context and lock it
@@ -411,6 +430,7 @@ dup2_fd(int oldfd, int newfd, int flags, bool kernel)
}
fd_set_close_on_exec(context, newfd, (flags & O_CLOEXEC) != 0);
fd_set_close_on_fork(context, newfd, (flags & O_CLOFORK) != 0);
locker.Unlock();
+8 -5
View File
@@ -371,6 +371,8 @@ create_socket_fd(net_socket* socket, int flags, bool kernel)
int oflags = 0;
if ((flags & SOCK_CLOEXEC) != 0)
oflags |= O_CLOEXEC;
if ((flags & SOCK_CLOFORK) != 0)
oflags |= O_CLOFORK;
if ((flags & SOCK_NONBLOCK) != 0 || nonBlock)
oflags |= O_NONBLOCK;
@@ -394,6 +396,7 @@ create_socket_fd(net_socket* socket, int flags, bool kernel)
rw_lock_write_lock(&context->lock);
fd_set_close_on_exec(context, fd, (oflags & O_CLOEXEC) != 0);
fd_set_close_on_fork(context, fd, (oflags & O_CLOFORK) != 0);
rw_lock_write_unlock(&context->lock);
return fd;
@@ -409,8 +412,8 @@ common_socket(int family, int type, int protocol, bool kernel)
if (!get_stack_interface_module())
return B_UNSUPPORTED;
int sflags = type & (SOCK_CLOEXEC | SOCK_NONBLOCK);
type &= ~(SOCK_CLOEXEC | SOCK_NONBLOCK);
int sflags = type & (SOCK_CLOEXEC | SOCK_NONBLOCK | SOCK_CLOFORK);
type &= ~(SOCK_CLOEXEC | SOCK_NONBLOCK | SOCK_CLOFORK);
// create the socket
net_socket* socket;
@@ -487,7 +490,7 @@ common_accept(int fd, struct sockaddr *address, socklen_t *_addressLength, int f
GET_SOCKET_FD_OR_RETURN(fd, kernel, descriptor);
FileDescriptorPutter _(descriptor);
if ((flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK)) != 0)
if ((flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK | SOCK_CLOFORK)) != 0)
RETURN_AND_SET_ERRNO(B_BAD_VALUE);
net_socket* acceptedSocket;
@@ -649,8 +652,8 @@ common_socketpair(int family, int type, int protocol, int fds[2], bool kernel)
if (!get_stack_interface_module())
return B_UNSUPPORTED;
int sflags = type & (SOCK_CLOEXEC | SOCK_NONBLOCK);
type &= ~(SOCK_CLOEXEC | SOCK_NONBLOCK);
int sflags = type & (SOCK_CLOEXEC | SOCK_NONBLOCK | SOCK_CLOFORK);
type &= ~(SOCK_CLOEXEC | SOCK_NONBLOCK | SOCK_CLOFORK);
net_socket* sockets[2];
status_t error = sStackInterface->socketpair(family, type, protocol,
+26 -5
View File
@@ -2883,6 +2883,7 @@ get_new_fd(struct fd_ops* ops, struct fs_mount* mount, struct vnode* vnode,
rw_lock_write_lock(&context->lock);
fd_set_close_on_exec(context, fd, (openMode & O_CLOEXEC) != 0);
fd_set_close_on_fork(context, fd, (openMode & O_CLOFORK) != 0);
rw_lock_write_unlock(&context->lock);
return fd;
@@ -3659,6 +3660,7 @@ free_io_context(io_context* context)
remove_node_monitors(context);
free(context->fds_close_on_exec);
free(context->fds_close_on_fork);
free(context->select_infos);
free(context->fds);
free(context);
@@ -4974,7 +4976,8 @@ vfs_new_io_context(const io_context* parentContext, bool purgeCloseOnExec)
}
const bool closeOnExec = fd_close_on_exec(parentContext, i);
if (closeOnExec && purgeCloseOnExec)
const bool closeOnFork = fd_close_on_fork(parentContext, i);
if ((closeOnExec && purgeCloseOnExec) || (closeOnFork && !purgeCloseOnExec))
continue;
TFD(InheritFD(context, i, descriptor, parentContext));
@@ -4986,6 +4989,8 @@ vfs_new_io_context(const io_context* parentContext, bool purgeCloseOnExec)
if (closeOnExec)
fd_set_close_on_exec(context, i, true);
if (closeOnFork)
fd_set_close_on_fork(context, i, true);
}
parentLocker.Unlock();
@@ -5048,6 +5053,7 @@ vfs_resize_fd_table(struct io_context* context, uint32 newSize)
file_descriptor** oldFDs = context->fds;
select_info** oldSelectInfos = context->select_infos;
uint8* oldCloseOnExecTable = context->fds_close_on_exec;
uint8* oldCloseOnForkTable = context->fds_close_on_fork;
// allocate new tables (separately to reduce the chances of needing a raw allocation)
file_descriptor** newFDs = (file_descriptor**)malloc(
@@ -5055,16 +5061,20 @@ vfs_resize_fd_table(struct io_context* context, uint32 newSize)
select_info** newSelectInfos = (select_info**)malloc(
+ sizeof(select_info**) * newSize);
uint8* newCloseOnExecTable = (uint8*)malloc(newCloseOnExitBitmapSize);
if (newFDs == NULL || newSelectInfos == NULL || newCloseOnExecTable == NULL) {
uint8* newCloseOnForkTable = (uint8*)malloc(newCloseOnExitBitmapSize);
if (newFDs == NULL || newSelectInfos == NULL || newCloseOnExecTable == NULL
|| newCloseOnForkTable == NULL) {
free(newFDs);
free(newSelectInfos);
free(newCloseOnExecTable);
free(newCloseOnForkTable);
return B_NO_MEMORY;
}
context->fds = newFDs;
context->select_infos = newSelectInfos;
context->fds_close_on_exec = newCloseOnExecTable;
context->fds_close_on_fork = newCloseOnForkTable;
context->table_size = newSize;
if (oldSize != 0) {
@@ -5075,6 +5085,8 @@ vfs_resize_fd_table(struct io_context* context, uint32 newSize)
memcpy(context->select_infos, oldSelectInfos, sizeof(void*) * toCopy);
memcpy(context->fds_close_on_exec, oldCloseOnExecTable,
min_c(oldCloseOnExitBitmapSize, newCloseOnExitBitmapSize));
memcpy(context->fds_close_on_fork, oldCloseOnForkTable,
min_c(oldCloseOnExitBitmapSize, newCloseOnExitBitmapSize));
}
// clear additional entries, if the tables grow
@@ -5084,11 +5096,14 @@ vfs_resize_fd_table(struct io_context* context, uint32 newSize)
sizeof(void*) * (newSize - oldSize));
memset(context->fds_close_on_exec + oldCloseOnExitBitmapSize, 0,
newCloseOnExitBitmapSize - oldCloseOnExitBitmapSize);
memset(context->fds_close_on_fork + oldCloseOnExitBitmapSize, 0,
newCloseOnExitBitmapSize - oldCloseOnExitBitmapSize);
}
free(oldFDs);
free(oldSelectInfos);
free(oldCloseOnExecTable);
free(oldCloseOnForkTable);
return B_OK;
}
@@ -6238,9 +6253,10 @@ common_fcntl(int fd, int op, size_t argument, bool kernel)
{
// Set file descriptor flags
// O_CLOEXEC is the only flag available at this time
// O_CLOEXEC and O_CLOFORK are the only flags available at this time
rw_lock_write_lock(&context->lock);
fd_set_close_on_exec(context, fd, (argument & FD_CLOEXEC) != 0);
fd_set_close_on_fork(context, fd, (argument & FD_CLOFORK) != 0);
rw_lock_write_unlock(&context->lock);
status = B_OK;
@@ -6252,6 +6268,7 @@ common_fcntl(int fd, int op, size_t argument, bool kernel)
// Get file descriptor flags
rw_lock_read_lock(&context->lock);
status = fd_close_on_exec(context, fd) ? FD_CLOEXEC : 0;
status |= fd_close_on_fork(context, fd) ? FD_CLOFORK : 0;
rw_lock_read_unlock(&context->lock);
break;
}
@@ -6288,11 +6305,15 @@ common_fcntl(int fd, int op, size_t argument, bool kernel)
case F_DUPFD:
case F_DUPFD_CLOEXEC:
case F_DUPFD_CLOFORK:
{
status = new_fd_etc(context, descriptor.Get(), (int)argument);
if (status >= 0) {
rw_lock_write_lock(&context->lock);
fd_set_close_on_exec(context, status, op == F_DUPFD_CLOEXEC);
if (op == F_DUPFD_CLOEXEC)
fd_set_close_on_exec(context, status, true);
else if (op == F_DUPFD_CLOFORK)
fd_set_close_on_fork(context, status, true);
rw_lock_write_unlock(&context->lock);
atomic_add(&descriptor->ref_count, 1);
@@ -9575,7 +9596,7 @@ status_t
_user_create_pipe(int* userFDs, int flags)
{
// check acceptable flags
if ((flags & ~(O_NONBLOCK | O_CLOEXEC)) != 0)
if ((flags & ~(O_NONBLOCK | O_CLOEXEC | O_CLOFORK)) != 0)
return B_BAD_VALUE;
// rootfs should support creating FIFOs, but let's be sure
+2
View File
@@ -31,5 +31,7 @@ dup3(int oldFD, int newFD, int flags)
{
if (oldFD == newFD)
RETURN_AND_SET_ERRNO(EINVAL);
if ((flags & ~(O_CLOEXEC | O_CLOFORK)) != 0)
RETURN_AND_SET_ERRNO(EINVAL);
RETURN_AND_SET_ERRNO(_kern_dup2(oldFD, newFD, flags));
}