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:
committed by
waddlesplash
parent
ba28b6f5f7
commit
904fd2abf0
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -38,6 +38,8 @@ static const FlagsTypeHandler::FlagInfo kOpenFlagInfos[] = {
|
||||
|
||||
FLAG_INFO_ENTRY(O_DIRECTORY),
|
||||
|
||||
FLAG_INFO_ENTRY(O_CLOFORK),
|
||||
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
|
||||
@@ -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 }
|
||||
};
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user