Compare commits
5 Commits
ba6229b92d
...
c304133224
| Author | SHA1 | Date |
|---|---|---|
|
|
c304133224 | |
|
|
7843d3de62 | |
|
|
aef536fff3 | |
|
|
d472e1ac0e | |
|
|
120c08fb75 |
|
|
@ -396,6 +396,7 @@ namespace Kernel
|
|||
BAN::UniqPtr<PageTable> m_page_table;
|
||||
BAN::RefPtr<TTY> m_controlling_terminal;
|
||||
|
||||
friend class OpenFileDescriptorSet;
|
||||
friend class Thread;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ namespace Kernel
|
|||
|
||||
BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> SharedMemoryObject::clone(PageTable& new_page_table)
|
||||
{
|
||||
auto region = TRY(SharedMemoryObjectManager::get().map_object(m_object->key, new_page_table, { .start = vaddr(), .end = vaddr() + size() }));
|
||||
auto region = TRY(SharedMemoryObject::create(m_object, new_page_table, { .start = vaddr(), .end = vaddr() + size() }));
|
||||
return BAN::UniqPtr<MemoryRegion>(BAN::move(region));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,20 @@
|
|||
namespace Kernel
|
||||
{
|
||||
|
||||
struct InodeRefPtrHash
|
||||
{
|
||||
BAN::hash_t operator()(const BAN::RefPtr<Inode>& inode)
|
||||
{
|
||||
return BAN::hash<const Inode*>()(inode.ptr());
|
||||
}
|
||||
};
|
||||
|
||||
static Mutex s_fcntl_lock_mutex;
|
||||
static ThreadBlocker s_fcntl_lock_thread_blocker;
|
||||
static BAN::HashMap<BAN::RefPtr<Inode>, BAN::Vector<struct flock>, InodeRefPtrHash> s_fcntl_locks;
|
||||
|
||||
static BAN::ErrorOr<void> fcntl_lock(BAN::RefPtr<Inode> inode, int cmd, struct flock& flock);
|
||||
|
||||
OpenFileDescriptorSet::OpenFileDescriptorSet(const Credentials& credentials)
|
||||
: m_credentials(credentials)
|
||||
{
|
||||
|
|
@ -219,6 +233,68 @@ namespace Kernel
|
|||
|
||||
BAN::ErrorOr<int> OpenFileDescriptorSet::fcntl(int fd, int cmd, uintptr_t extra)
|
||||
{
|
||||
if (cmd == F_SETLK || cmd == F_SETLKW || cmd == F_GETLK)
|
||||
{
|
||||
struct flock flock;
|
||||
TRY(Process::current().read_from_user(reinterpret_cast<void*>(extra), &flock, sizeof(struct flock)));
|
||||
flock.l_pid = Process::current().pid();
|
||||
|
||||
BAN::RefPtr<Inode> inode;
|
||||
|
||||
{
|
||||
LockGuard _(m_mutex);
|
||||
|
||||
TRY(validate_fd(fd));
|
||||
|
||||
const auto& open_file = m_open_files[fd];
|
||||
|
||||
inode = open_file.inode();
|
||||
|
||||
switch (flock.l_whence)
|
||||
{
|
||||
case SEEK_SET:
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
if (BAN::Math::will_addition_overflow(flock.l_start, open_file.offset()))
|
||||
return BAN::Error::from_errno(EOVERFLOW);
|
||||
flock.l_start += m_open_files[fd].offset();
|
||||
break;
|
||||
case SEEK_END:
|
||||
if (BAN::Math::will_addition_overflow(flock.l_start, inode->size()))
|
||||
return BAN::Error::from_errno(EOVERFLOW);
|
||||
flock.l_start += inode->size();
|
||||
break;
|
||||
default:
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
}
|
||||
|
||||
if (BAN::Math::will_addition_overflow(flock.l_start, flock.l_len))
|
||||
return BAN::Error::from_errno(EOVERFLOW);
|
||||
|
||||
if (flock.l_len < 0)
|
||||
{
|
||||
flock.l_start += flock.l_len;
|
||||
if (flock.l_len == BAN::numeric_limits<decltype(flock.l_len)>::min())
|
||||
return BAN::Error::from_errno(EOVERFLOW);
|
||||
flock.l_len = -flock.l_len;
|
||||
}
|
||||
|
||||
flock.l_whence = SEEK_SET;
|
||||
}
|
||||
|
||||
auto lock_ret = fcntl_lock(inode, cmd, flock);
|
||||
if (lock_ret.is_error())
|
||||
{
|
||||
if (lock_ret.error().get_error_code() == ENOMEM)
|
||||
return BAN::Error::from_errno(ENOLCK);
|
||||
return lock_ret.release_error();
|
||||
}
|
||||
|
||||
if (cmd == F_GETLK)
|
||||
TRY(Process::current().write_to_user(reinterpret_cast<void*>(extra), &flock, sizeof(struct flock)));
|
||||
return 0;
|
||||
}
|
||||
|
||||
LockGuard _(m_mutex);
|
||||
|
||||
TRY(validate_fd(fd));
|
||||
|
|
@ -252,46 +328,6 @@ namespace Kernel
|
|||
m_open_files[fd].status_flags() &= O_ACCMODE;
|
||||
m_open_files[fd].status_flags() |= extra;
|
||||
return 0;
|
||||
case F_GETLK:
|
||||
{
|
||||
dwarnln("TODO: proper fcntl F_GETLK");
|
||||
|
||||
auto* param = reinterpret_cast<struct flock*>(extra);
|
||||
const auto& flock = m_open_files[fd].description->flock;
|
||||
|
||||
if (flock.lockers.empty())
|
||||
param->l_type = F_UNLCK;
|
||||
else
|
||||
{
|
||||
*param = {
|
||||
.l_type = static_cast<short>(flock.shared ? F_RDLCK : F_WRLCK),
|
||||
.l_whence = SEEK_SET,
|
||||
.l_start = 0,
|
||||
.l_len = 1,
|
||||
.l_pid = *flock.lockers.begin(),
|
||||
};
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
case F_SETLK:
|
||||
case F_SETLKW:
|
||||
{
|
||||
dwarnln("TODO: proper fcntl F_SETLK(W)");
|
||||
|
||||
int op = cmd == F_SETLKW ? LOCK_NB : 0;
|
||||
switch (reinterpret_cast<const struct flock*>(extra)->l_type)
|
||||
{
|
||||
case F_UNLCK: op |= LOCK_UN; break;
|
||||
case F_RDLCK: op |= LOCK_SH; break;
|
||||
case F_WRLCK: op |= LOCK_EX; break;
|
||||
default:
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
}
|
||||
TRY(flock(fd, op));
|
||||
|
||||
return 0;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -363,6 +399,18 @@ namespace Kernel
|
|||
}
|
||||
}
|
||||
|
||||
{
|
||||
LockGuard _(s_fcntl_lock_mutex);
|
||||
if (auto it = s_fcntl_locks.find(open_file.inode()); it != s_fcntl_locks.end())
|
||||
{
|
||||
auto& flocks = it->value;
|
||||
for (size_t i = 0; i < flocks.size(); i++)
|
||||
if (flocks[i].l_pid == Process::current().pid())
|
||||
flocks.remove(i--);
|
||||
s_fcntl_lock_thread_blocker.unblock();
|
||||
}
|
||||
}
|
||||
|
||||
open_file.inode()->on_close(open_file.status_flags());
|
||||
open_file.description.clear();
|
||||
open_file.descriptor_flags = 0;
|
||||
|
|
@ -389,6 +437,147 @@ namespace Kernel
|
|||
}
|
||||
}
|
||||
|
||||
static BAN::ErrorOr<void> fcntl_lock(BAN::RefPtr<Inode> inode, int cmd, struct flock& flock)
|
||||
{
|
||||
if (!inode->mode().ifreg())
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
|
||||
LockGuard _(s_fcntl_lock_mutex);
|
||||
|
||||
static constexpr auto locks_overlap =
|
||||
[](struct flock a, struct flock b) -> bool
|
||||
{
|
||||
if (a.l_len == 0 && b.l_len == 0)
|
||||
return true;
|
||||
if (a.l_len == 0 && a.l_start < b.l_start + b.l_len)
|
||||
return true;
|
||||
if (b.l_len == 0 && b.l_start < a.l_start + a.l_len)
|
||||
return true;
|
||||
if (a.l_start + a.l_len <= b.l_start)
|
||||
return false;
|
||||
if (b.l_start + b.l_len <= a.l_start)
|
||||
return false;
|
||||
return true;
|
||||
};
|
||||
|
||||
const auto lock_preventer =
|
||||
[flock](BAN::Span<struct flock> locks) -> struct flock*
|
||||
{
|
||||
for (auto& lock : locks)
|
||||
{
|
||||
if (lock.l_pid == flock.l_pid)
|
||||
continue;
|
||||
if (!locks_overlap(lock, flock))
|
||||
continue;
|
||||
if (lock.l_type == F_RDLCK && flock.l_type == F_RDLCK)
|
||||
continue;
|
||||
return &lock;
|
||||
}
|
||||
return nullptr;
|
||||
};
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case F_GETLK:
|
||||
{
|
||||
auto it = s_fcntl_locks.find(inode);
|
||||
if (it == s_fcntl_locks.end())
|
||||
flock.l_type = F_UNLCK;
|
||||
else if (auto* preventer = lock_preventer(it->value.span()))
|
||||
flock = *preventer;
|
||||
else
|
||||
flock.l_type = F_UNLCK;
|
||||
return {};
|
||||
}
|
||||
case F_SETLK:
|
||||
case F_SETLKW:
|
||||
{
|
||||
if (flock.l_type == F_UNLCK)
|
||||
{
|
||||
auto it = s_fcntl_locks.find(inode);
|
||||
if (it == s_fcntl_locks.end())
|
||||
return {};
|
||||
auto& flocks = it->value;
|
||||
|
||||
for (size_t i = 0; i < flocks.size(); i++)
|
||||
{
|
||||
if (flocks[i].l_pid != flock.l_pid)
|
||||
continue;
|
||||
if (!locks_overlap(flocks[i], flock))
|
||||
continue;
|
||||
|
||||
struct flock new_flocks[2];
|
||||
size_t new_flock_count { 0 };
|
||||
|
||||
if (flocks[i].l_start < flock.l_start)
|
||||
{
|
||||
const off_t flock_len = flocks[i].l_len ? flocks[i].l_len : inode->size();
|
||||
new_flocks[new_flock_count] = flock;
|
||||
new_flocks[new_flock_count].l_len = flocks[i].l_start + flock_len - flock.l_start;
|
||||
new_flock_count++;
|
||||
}
|
||||
|
||||
if (flock.l_len == 0)
|
||||
;
|
||||
else if (flocks[i].l_len == 0)
|
||||
{
|
||||
new_flocks[new_flock_count] = flock;
|
||||
new_flocks[new_flock_count].l_start = flock.l_start + flock.l_len;
|
||||
new_flocks[new_flock_count].l_len = 0;
|
||||
new_flock_count++;
|
||||
}
|
||||
else if (flocks[i].l_start + flocks[i].l_len > flock.l_start + flock.l_len)
|
||||
{
|
||||
new_flocks[new_flock_count] = flock;
|
||||
new_flocks[new_flock_count].l_start = flock.l_start + flock.l_len;
|
||||
new_flocks[new_flock_count].l_len = (flocks[i].l_start + flocks[i].l_len) - (flock.l_start + flock.l_len);
|
||||
new_flock_count++;
|
||||
}
|
||||
|
||||
switch (new_flock_count)
|
||||
{
|
||||
case 0:
|
||||
flocks.remove(i--);
|
||||
break;
|
||||
case 1:
|
||||
flocks[i] = new_flocks[0];
|
||||
break;
|
||||
case 2:
|
||||
TRY(flocks.insert(i + 1, new_flocks[1]));
|
||||
flocks[i++] = new_flocks[0];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (flocks.empty())
|
||||
s_fcntl_locks.remove(it);
|
||||
|
||||
s_fcntl_lock_thread_blocker.unblock();
|
||||
|
||||
return {};
|
||||
}
|
||||
else for (;;)
|
||||
{
|
||||
auto it = s_fcntl_locks.find(inode);
|
||||
if (it == s_fcntl_locks.end())
|
||||
it = TRY(s_fcntl_locks.emplace(inode));
|
||||
|
||||
if (lock_preventer(it->value.span()) == nullptr)
|
||||
{
|
||||
TRY(it->value.push_back(flock));
|
||||
return {};
|
||||
}
|
||||
|
||||
if (cmd == F_SETLK)
|
||||
return BAN::Error::from_errno(EAGAIN);
|
||||
TRY(Thread::current().block_or_eintr_indefinite(s_fcntl_lock_thread_blocker, &s_fcntl_lock_mutex));
|
||||
}
|
||||
}
|
||||
default:
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> OpenFileDescriptorSet::flock(int fd, int op)
|
||||
{
|
||||
const auto pid = Process::current().pid();
|
||||
|
|
|
|||
|
|
@ -1271,9 +1271,8 @@ namespace Kernel
|
|||
return 0;
|
||||
}
|
||||
|
||||
// FIXME: buffer_region can be null as stack is not MemoryRegion
|
||||
auto* buffer_region = TRY(validate_and_pin_pointer_access(buffer, count, true));
|
||||
BAN::ScopeGuard _([buffer_region] { if (buffer_region) buffer_region->unpin(); });
|
||||
BAN::ScopeGuard _([buffer_region] { buffer_region->unpin(); });
|
||||
return TRY(m_open_file_descriptors.read(fd, BAN::ByteSpan(static_cast<uint8_t*>(buffer), count)));
|
||||
}
|
||||
|
||||
|
|
@ -1285,9 +1284,8 @@ namespace Kernel
|
|||
return 0;
|
||||
}
|
||||
|
||||
// FIXME: buffer_region can be null as stack is not MemoryRegion
|
||||
auto* buffer_region = TRY(validate_and_pin_pointer_access(buffer, count, false));
|
||||
BAN::ScopeGuard _([buffer_region] { if (buffer_region) buffer_region->unpin(); });
|
||||
BAN::ScopeGuard _([buffer_region] { buffer_region->unpin(); });
|
||||
return TRY(m_open_file_descriptors.write(fd, BAN::ConstByteSpan(static_cast<const uint8_t*>(buffer), count)));
|
||||
}
|
||||
|
||||
|
|
@ -1465,7 +1463,7 @@ namespace Kernel
|
|||
auto inode = TRY(m_open_file_descriptors.inode_of(fd));
|
||||
|
||||
auto* buffer_region = TRY(validate_and_pin_pointer_access(buffer, count, true));
|
||||
BAN::ScopeGuard _([buffer_region] { if (buffer_region) buffer_region->unpin(); });
|
||||
BAN::ScopeGuard _([buffer_region] { buffer_region->unpin(); });
|
||||
|
||||
return TRY(inode->read(offset, { reinterpret_cast<uint8_t*>(buffer), count }));
|
||||
}
|
||||
|
|
@ -1475,7 +1473,7 @@ namespace Kernel
|
|||
auto inode = TRY(m_open_file_descriptors.inode_of(fd));
|
||||
|
||||
auto* buffer_region = TRY(validate_and_pin_pointer_access(buffer, count, false));
|
||||
BAN::ScopeGuard _([buffer_region] { if (buffer_region) buffer_region->unpin(); });
|
||||
BAN::ScopeGuard _([buffer_region] { buffer_region->unpin(); });
|
||||
|
||||
return TRY(inode->write(offset, { reinterpret_cast<const uint8_t*>(buffer), count })); }
|
||||
|
||||
|
|
@ -1802,10 +1800,10 @@ namespace Kernel
|
|||
BAN::Vector<MemoryRegion*> regions;
|
||||
BAN::ScopeGuard _([®ions] {
|
||||
for (auto* region : regions)
|
||||
if (region != nullptr)
|
||||
region->unpin();
|
||||
region->unpin();
|
||||
});
|
||||
|
||||
// FIXME: this can leak memory if push to regions fails but pinning succeeded
|
||||
if (message.msg_name)
|
||||
TRY(regions.push_back(TRY(validate_and_pin_pointer_access(message.msg_name, message.msg_namelen, true))));
|
||||
if (message.msg_control)
|
||||
|
|
@ -1832,8 +1830,7 @@ namespace Kernel
|
|||
BAN::Vector<MemoryRegion*> regions;
|
||||
BAN::ScopeGuard _([®ions] {
|
||||
for (auto* region : regions)
|
||||
if (region != nullptr)
|
||||
region->unpin();
|
||||
region->unpin();
|
||||
});
|
||||
|
||||
if (message.msg_name)
|
||||
|
|
@ -1985,7 +1982,7 @@ namespace Kernel
|
|||
BAN::ErrorOr<long> Process::sys_ppoll(pollfd* fds, nfds_t nfds, const timespec* user_timeout, const sigset_t* user_sigmask)
|
||||
{
|
||||
auto* fds_region = TRY(validate_and_pin_pointer_access(fds, nfds * sizeof(pollfd), true));
|
||||
BAN::ScopeGuard _([fds_region] { if (fds_region) fds_region->unpin(); });
|
||||
BAN::ScopeGuard _([fds_region] { fds_region->unpin(); });
|
||||
|
||||
const auto old_sigmask = Thread::current().m_signal_block_mask;
|
||||
if (user_sigmask != nullptr)
|
||||
|
|
@ -2168,10 +2165,7 @@ namespace Kernel
|
|||
}
|
||||
|
||||
auto* events_region = TRY(validate_and_pin_pointer_access(events, maxevents * sizeof(epoll_event), true));
|
||||
BAN::ScopeGuard _([events_region] {
|
||||
if (events_region)
|
||||
events_region->unpin();
|
||||
});
|
||||
BAN::ScopeGuard _([events_region] { events_region->unpin(); });
|
||||
|
||||
const auto old_sigmask = Thread::current().m_signal_block_mask;
|
||||
if (user_sigmask)
|
||||
|
|
@ -2364,7 +2358,7 @@ namespace Kernel
|
|||
return BAN::Error::from_errno(EOVERFLOW);
|
||||
|
||||
auto* list_region = TRY(validate_and_pin_pointer_access(list, list_len * sizeof(struct dirent), true));
|
||||
BAN::ScopeGuard _([list_region] { if (list_region) list_region->unpin(); });
|
||||
BAN::ScopeGuard _([list_region] { list_region->unpin(); });
|
||||
return TRY(m_open_file_descriptors.read_dir_entries(fd, list, list_len));
|
||||
}
|
||||
|
||||
|
|
@ -3188,7 +3182,7 @@ namespace Kernel
|
|||
op &= ~(FUTEX_PRIVATE | FUTEX_REALTIME);
|
||||
|
||||
auto* buffer_region = TRY(validate_and_pin_pointer_access(addr, sizeof(uint32_t), false));
|
||||
BAN::ScopeGuard pin_guard([&] { if (buffer_region) buffer_region->unpin(); });
|
||||
BAN::ScopeGuard pin_guard([buffer_region] { buffer_region->unpin(); });
|
||||
|
||||
const paddr_t paddr = m_page_table->physical_address_of(vaddr & PAGE_ADDR_MASK) | (vaddr & ~PAGE_ADDR_MASK);
|
||||
ASSERT(paddr != 0);
|
||||
|
|
@ -3819,7 +3813,7 @@ namespace Kernel
|
|||
return BAN::Error::from_errno(EPERM);
|
||||
|
||||
auto* region = TRY(validate_and_pin_pointer_access(groups, count * sizeof(gid_t), false));
|
||||
BAN::ScopeGuard pin_guard([region] { if (region) region->unpin(); });
|
||||
BAN::ScopeGuard pin_guard([region] { region->unpin(); });
|
||||
|
||||
TRY(m_credentials.set_groups({ groups, count }));
|
||||
|
||||
|
|
|
|||
|
|
@ -14,8 +14,58 @@ __BEGIN_DECLS
|
|||
#define __need_pid_t
|
||||
#include <sys/types.h>
|
||||
|
||||
typedef int posix_spawnattr_t;
|
||||
typedef int posix_spawn_file_actions_t;
|
||||
typedef struct
|
||||
{
|
||||
short flags;
|
||||
pid_t pgroup;
|
||||
sched_param schedparam;
|
||||
int schedpolicy;
|
||||
sigset_t sigdefault;
|
||||
sigset_t sigmask;
|
||||
} posix_spawnattr_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int fildes;
|
||||
} _posix_spawn_file_actions_close_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int fildes;
|
||||
int newfildes;
|
||||
} _posix_spawn_file_actions_dup2_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int fildes;
|
||||
char* path;
|
||||
int oflag;
|
||||
mode_t mode;
|
||||
} _posix_spawn_file_actions_open_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
_POSIX_SPAWN_FILE_ACTION_CLOSE,
|
||||
_POSIX_SPAWN_FILE_ACTION_DUP2,
|
||||
_POSIX_SPAWN_FILE_ACTION_OPEN,
|
||||
} _posix_spawn_file_action_type_e;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
_posix_spawn_file_action_type_e type;
|
||||
union
|
||||
{
|
||||
_posix_spawn_file_actions_close_t close;
|
||||
_posix_spawn_file_actions_dup2_t dup2;
|
||||
_posix_spawn_file_actions_open_t open;
|
||||
};
|
||||
} _posix_spawn_file_action_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
_posix_spawn_file_action_t* actions;
|
||||
size_t action_count;
|
||||
} posix_spawn_file_actions_t;
|
||||
|
||||
#define POSIX_SPAWN_RESETIDS 0x01
|
||||
#define POSIX_SPAWN_SETPGROUP 0x02
|
||||
|
|
|
|||
|
|
@ -36,12 +36,12 @@ __BEGIN_DECLS
|
|||
#define _POSIX_RAW_SOCKETS 0 /* raw sockets :D */
|
||||
#define _POSIX_READER_WRITER_LOCKS 200809L
|
||||
#define _POSIX_REALTIME_SIGNALS -1 /* siq{queue,timedwait,waitinfo} */
|
||||
#define _POSIX_REGEXP -1 /* reg{comp,error,exec,free} */
|
||||
#define _POSIX_REGEXP 200809L
|
||||
#define _POSIX_SAVED_IDS 200809L
|
||||
#define _POSIX_SEMAPHORES -1 /* sem_{close,destroy,getvalue,init,open,post,trywait,unlink,wait} */
|
||||
#define _POSIX_SHARED_MEMORY_OBJECTS -1 /* shm_{open,unlink} */
|
||||
#define _POSIX_SHELL 200809L
|
||||
#define _POSIX_SPAWN -1 /* posix_spawn* */
|
||||
#define _POSIX_SPAWN 200809L
|
||||
#define _POSIX_SPIN_LOCKS 200809L
|
||||
#define _POSIX_SPORADIC_SERVER -1 /* sched_{setparam,setscheduler} with SCHED_SPORADIC */
|
||||
#define _POSIX_SYNCHRONIZED_IO 200809L
|
||||
|
|
|
|||
|
|
@ -1,34 +1,316 @@
|
|||
#include <BAN/Debug.h>
|
||||
#include <BAN/Atomic.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <spawn.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/banan-os.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define TODO_FUNC(name, ...) int name(__VA_ARGS__) { dwarnln("TODO: " #name); errno = ENOTSUP; return -1; }
|
||||
|
||||
static int do_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[], char* const envp[], bool do_path_resolution)
|
||||
int posix_spawnattr_init(posix_spawnattr_t* attr)
|
||||
{
|
||||
if (file_actions != nullptr)
|
||||
attr->flags = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int posix_spawnattr_destroy(posix_spawnattr_t* attr)
|
||||
{
|
||||
(void)attr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int posix_spawnattr_getflags(const posix_spawnattr_t* __restrict attr, short* __restrict flags)
|
||||
{
|
||||
*flags = attr->flags;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int posix_spawnattr_setflags(posix_spawnattr_t* attr, short flags)
|
||||
{
|
||||
if (flags & ~(POSIX_SPAWN_RESETIDS | POSIX_SPAWN_SETPGROUP | POSIX_SPAWN_SETSCHEDPARAM | POSIX_SPAWN_SETSCHEDULER | POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK))
|
||||
return EINVAL;
|
||||
attr->flags = flags;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int posix_spawnattr_getpgroup(const posix_spawnattr_t* __restrict attr, pid_t* __restrict pgroup)
|
||||
{
|
||||
*pgroup = attr->pgroup;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int posix_spawnattr_setpgroup(posix_spawnattr_t* attr, pid_t pgroup)
|
||||
{
|
||||
attr->pgroup = pgroup;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int posix_spawnattr_getschedparam(const posix_spawnattr_t* __restrict attr, struct sched_param* __restrict schedparam)
|
||||
{
|
||||
*schedparam = attr->schedparam;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int posix_spawnattr_setschedparam(posix_spawnattr_t* __restrict attr, const struct sched_param* __restrict schedparam)
|
||||
{
|
||||
attr->schedparam = *schedparam;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int posix_spawnattr_getschedpolicy(const posix_spawnattr_t* __restrict attr, int* __restrict schedpolicy)
|
||||
{
|
||||
*schedpolicy = attr->schedpolicy;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int posix_spawnattr_setschedpolicy(posix_spawnattr_t* attr, int schedpolicy)
|
||||
{
|
||||
switch (schedpolicy)
|
||||
{
|
||||
dwarnln("TODO: posix_spawn with file actions");
|
||||
errno = ENOTSUP;
|
||||
return -1;
|
||||
case SCHED_FIFO:
|
||||
case SCHED_RR:
|
||||
case SCHED_SPORADIC:
|
||||
case SCHED_OTHER:
|
||||
break;
|
||||
default:
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
if (attrp != nullptr)
|
||||
attr->schedpolicy = schedpolicy;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int posix_spawnattr_getsigdefault(const posix_spawnattr_t* __restrict attr, sigset_t* __restrict sigdefault)
|
||||
{
|
||||
*sigdefault = attr->sigdefault;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int posix_spawnattr_setsigdefault(posix_spawnattr_t* __restrict attr, const sigset_t* __restrict sigdefault)
|
||||
{
|
||||
attr->sigdefault = *sigdefault;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int posix_spawnattr_getsigmask(const posix_spawnattr_t* __restrict attr, sigset_t* __restrict sigmask)
|
||||
{
|
||||
*sigmask = attr->sigmask;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int posix_spawnattr_setsigmask(posix_spawnattr_t* __restrict attr, const sigset_t* __restrict sigmask)
|
||||
{
|
||||
attr->sigmask = *sigmask;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int posix_spawn_file_actions_init(posix_spawn_file_actions_t* file_actions)
|
||||
{
|
||||
*file_actions = {
|
||||
.actions = nullptr,
|
||||
.action_count = 0,
|
||||
};
|
||||
return 0;
|
||||
}
|
||||
|
||||
int posix_spawn_file_actions_destroy(posix_spawn_file_actions_t* file_actions)
|
||||
{
|
||||
for (size_t i = 0; i < file_actions->action_count; i++)
|
||||
{
|
||||
dwarnln("TODO: posix_spawn with attributes");
|
||||
errno = ENOTSUP;
|
||||
return -1;
|
||||
switch (file_actions->actions[i].type)
|
||||
{
|
||||
case _POSIX_SPAWN_FILE_ACTION_CLOSE:
|
||||
case _POSIX_SPAWN_FILE_ACTION_DUP2:
|
||||
break;
|
||||
case _POSIX_SPAWN_FILE_ACTION_OPEN:
|
||||
free(file_actions->actions[i].open.path);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (file_actions->actions != nullptr)
|
||||
free(file_actions->actions);
|
||||
|
||||
file_actions->actions = nullptr;
|
||||
file_actions->action_count = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int add_file_action(posix_spawn_file_actions_t* file_actions, _posix_spawn_file_action_t action)
|
||||
{
|
||||
void* new_actions = realloc(file_actions->actions, sizeof(_posix_spawn_file_action_t) * (file_actions->action_count + 1));
|
||||
if (new_actions == nullptr)
|
||||
return ENOMEM;
|
||||
file_actions->actions = static_cast<_posix_spawn_file_action_t*>(new_actions);
|
||||
file_actions->actions[file_actions->action_count++] = action;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int posix_spawn_file_actions_addclose(posix_spawn_file_actions_t* file_actions, int fildes)
|
||||
{
|
||||
if (fildes < 0 || fildes >= OPEN_MAX)
|
||||
return EBADF;
|
||||
|
||||
return add_file_action(file_actions, {
|
||||
.type = _POSIX_SPAWN_FILE_ACTION_CLOSE,
|
||||
.close = {
|
||||
.fildes = fildes,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
int posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t* file_actions, int fildes, int newfildes)
|
||||
{
|
||||
if (fildes < 0 || fildes >= OPEN_MAX || newfildes < 0 || newfildes >= OPEN_MAX)
|
||||
return EBADF;
|
||||
|
||||
return add_file_action(file_actions, {
|
||||
.type = _POSIX_SPAWN_FILE_ACTION_DUP2,
|
||||
.dup2 = {
|
||||
.fildes = fildes,
|
||||
.newfildes = newfildes,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
int posix_spawn_file_actions_addopen(posix_spawn_file_actions_t* __restrict file_actions, int fildes, const char* __restrict path, int oflag, mode_t mode)
|
||||
{
|
||||
if (fildes < 0 || fildes >= OPEN_MAX)
|
||||
return EBADF;
|
||||
|
||||
char* path_copy = strdup(path);
|
||||
if (path_copy == nullptr)
|
||||
return ENOMEM;
|
||||
|
||||
const auto ret = add_file_action(file_actions, {
|
||||
.type = _POSIX_SPAWN_FILE_ACTION_OPEN,
|
||||
.open = {
|
||||
.fildes = fildes,
|
||||
.path = path_copy,
|
||||
.oflag = oflag,
|
||||
.mode = mode,
|
||||
}
|
||||
});
|
||||
|
||||
if (ret != 0)
|
||||
free(path_copy);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int do_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[], char* const envp[], bool do_path_resolution)
|
||||
{
|
||||
// MAP_SHARED | MAP_ANONYMOUS is not supported :D
|
||||
|
||||
const auto smo_key = smo_create(sizeof(int), PROT_READ | PROT_WRITE);
|
||||
if (smo_key == -1)
|
||||
return errno;
|
||||
|
||||
void* addr = smo_map(smo_key);
|
||||
smo_delete(smo_key);
|
||||
if (addr == MAP_FAILED)
|
||||
return errno;
|
||||
|
||||
auto& child_status = *static_cast<BAN::Atomic<int>*>(addr);
|
||||
child_status = INT_MAX;
|
||||
|
||||
const pid_t child_pid = fork();
|
||||
if (child_pid == 0)
|
||||
{
|
||||
#define DIE_ON_ERROR(err, ...) \
|
||||
do { \
|
||||
auto ret = __VA_ARGS__; \
|
||||
if (ret != (err)) \
|
||||
break; \
|
||||
child_status = errno; \
|
||||
exit(127); \
|
||||
} while (false)
|
||||
|
||||
if (attrp != nullptr)
|
||||
{
|
||||
if (attrp->flags & POSIX_SPAWN_RESETIDS)
|
||||
DIE_ON_ERROR(-1, seteuid(getuid()));
|
||||
|
||||
if (attrp->flags & POSIX_SPAWN_SETPGROUP)
|
||||
DIE_ON_ERROR(-1, setpgid(0, attrp->pgroup));
|
||||
|
||||
if (attrp->flags & POSIX_SPAWN_SETSCHEDULER)
|
||||
DIE_ON_ERROR(-1, (errno = ENOTSUP, -1));
|
||||
// DIE_ON_ERROR(-1, sched_setscheduler(0, attrp->schedpolicy, &attrp->schedparam));
|
||||
else if (attrp->flags & POSIX_SPAWN_SETSCHEDPARAM)
|
||||
DIE_ON_ERROR(-1, (errno = ENOTSUP, -1));
|
||||
// DIE_ON_ERROR(-1, sched_setparam(0, &attrp->schedparam));
|
||||
|
||||
if (attrp->flags & POSIX_SPAWN_SETSIGDEF)
|
||||
for (int sig = _SIGMIN; sig <= _SIGMAX; sig++)
|
||||
if (attrp->sigdefault & (1ull << sig))
|
||||
DIE_ON_ERROR(NULL, signal(sig, SIG_DFL));
|
||||
|
||||
if (attrp->flags & POSIX_SPAWN_SETSIGMASK)
|
||||
DIE_ON_ERROR(-1, sigprocmask(SIG_SETMASK, &attrp->sigmask, nullptr));
|
||||
}
|
||||
|
||||
if (file_actions != nullptr)
|
||||
{
|
||||
for (size_t i = 0; i < file_actions->action_count; i++)
|
||||
{
|
||||
const auto& action = file_actions->actions[i];
|
||||
switch (action.type)
|
||||
{
|
||||
case _POSIX_SPAWN_FILE_ACTION_CLOSE:
|
||||
// EBADF is not considered an error with addclose
|
||||
close(action.close.fildes);
|
||||
break;
|
||||
case _POSIX_SPAWN_FILE_ACTION_DUP2:
|
||||
if (action.dup2.fildes != action.dup2.newfildes)
|
||||
DIE_ON_ERROR(-1, dup2(action.dup2.fildes, action.dup2.newfildes));
|
||||
else
|
||||
DIE_ON_ERROR(-1, fcntl(action.dup2.fildes, F_SETFD, fcntl(action.dup2.fildes, F_GETFD) & ~O_CLOEXEC));
|
||||
break;
|
||||
case _POSIX_SPAWN_FILE_ACTION_OPEN:
|
||||
const int fd = open(action.open.path, action.open.oflag, action.open.mode);
|
||||
DIE_ON_ERROR(-1, fd);
|
||||
if (fd != action.open.fildes)
|
||||
{
|
||||
DIE_ON_ERROR(-1, dup2(fd, action.open.fildes));
|
||||
close(fd);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#undef DIE_ON_ERROR
|
||||
|
||||
child_status = 0;
|
||||
|
||||
auto* func = do_path_resolution ? execvpe : execve;
|
||||
func(path, argv, envp);
|
||||
exit(128 + errno);
|
||||
exit(127);
|
||||
}
|
||||
|
||||
if (child_pid == -1)
|
||||
{
|
||||
munmap(addr, sizeof(int));
|
||||
return errno;
|
||||
}
|
||||
|
||||
while (child_status == INT_MAX)
|
||||
sched_yield();
|
||||
|
||||
const int child_status_copy = child_status;
|
||||
munmap(addr, sizeof(int));
|
||||
|
||||
if (child_status_copy != 0)
|
||||
{
|
||||
while (waitpid(child_pid, nullptr, 0) == -1 && errno == EINTR)
|
||||
continue;
|
||||
return child_status_copy;
|
||||
}
|
||||
|
||||
if (pid != nullptr)
|
||||
|
|
@ -46,23 +328,3 @@ int posix_spawnp(pid_t* __restrict pid, const char* __restrict path, const posix
|
|||
{
|
||||
return do_posix_spawn(pid, path,file_actions, attrp, argv, envp, true);
|
||||
}
|
||||
|
||||
TODO_FUNC(posix_spawn_file_actions_addclose, posix_spawn_file_actions_t*, int)
|
||||
TODO_FUNC(posix_spawn_file_actions_adddup2, posix_spawn_file_actions_t*, int, int)
|
||||
TODO_FUNC(posix_spawn_file_actions_addopen, posix_spawn_file_actions_t* __restrict, int, const char* __restrict, int, mode_t)
|
||||
TODO_FUNC(posix_spawn_file_actions_destroy, posix_spawn_file_actions_t*)
|
||||
TODO_FUNC(posix_spawn_file_actions_init, posix_spawn_file_actions_t*)
|
||||
TODO_FUNC(posix_spawnattr_destroy, posix_spawnattr_t*)
|
||||
TODO_FUNC(posix_spawnattr_getflags, const posix_spawnattr_t* __restrict, short* __restrict)
|
||||
TODO_FUNC(posix_spawnattr_getpgroup, const posix_spawnattr_t* __restrict, pid_t* __restrict)
|
||||
TODO_FUNC(posix_spawnattr_getschedparam, const posix_spawnattr_t* __restrict, struct sched_param* __restrict)
|
||||
TODO_FUNC(posix_spawnattr_getschedpolicy, const posix_spawnattr_t* __restrict, int* __restrict)
|
||||
TODO_FUNC(posix_spawnattr_getsigdefault, const posix_spawnattr_t* __restrict, sigset_t* __restrict)
|
||||
TODO_FUNC(posix_spawnattr_getsigmask, const posix_spawnattr_t* __restrict, sigset_t* __restrict)
|
||||
TODO_FUNC(posix_spawnattr_init, posix_spawnattr_t*)
|
||||
TODO_FUNC(posix_spawnattr_setflags, posix_spawnattr_t*, short)
|
||||
TODO_FUNC(posix_spawnattr_setpgroup, posix_spawnattr_t*, pid_t)
|
||||
TODO_FUNC(posix_spawnattr_setschedparam, posix_spawnattr_t* __restrict, const struct sched_param* __restrict)
|
||||
TODO_FUNC(posix_spawnattr_setschedpolicy, posix_spawnattr_t*, int)
|
||||
TODO_FUNC(posix_spawnattr_setsigdefault, posix_spawnattr_t* __restrict, const sigset_t* __restrict)
|
||||
TODO_FUNC(posix_spawnattr_setsigmask, posix_spawnattr_t* __restrict, const sigset_t* __restrict)
|
||||
|
|
|
|||
Loading…
Reference in New Issue