Compare commits

...

24 Commits

Author SHA1 Message Date
Bananymous 7691b019e2 LibC: Fix printf %c modifier for null byte 2025-05-28 03:10:01 +03:00
Bananymous f55d6b11c5 LibC: Implement `mblen` 2025-05-28 03:10:01 +03:00
Bananymous f52877abb4 LibC: Implement `readv` and `writev` 2025-05-28 03:10:01 +03:00
Bananymous ee7c9b6731 LibC: Add simple `getnameinfo`
This doesn't actually do any name resolution but just formats input to
string.
2025-05-28 03:10:01 +03:00
Bananymous 4721344518 LibC: Don't fail `getaddrinfo` if node is null 2025-05-28 03:10:01 +03:00
Bananymous e0d986dcd7 LibC: Add missing u_char and u_short types 2025-05-28 03:10:01 +03:00
Bananymous c7be3dcd5b LibC: Add timer{add,sub,clear,isset,cmp}
These are not POSIX but used by used by some ports
2025-05-28 03:10:01 +03:00
Bananymous 89c9bfd052 Kernel/LibC: Implement `socketpair` for UNIX sockets 2025-05-28 03:10:01 +03:00
Bananymous 12b93567f7 Kernel/LibC: Implement `getpeername` 2025-05-28 03:10:01 +03:00
Bananymous 2f37776614 Kernel: Notify epoll on new TCP connections 2025-05-28 03:10:01 +03:00
Bananymous f778bca3f2 Kernel: Remove accidentally commited debug code :) 2025-05-28 03:10:01 +03:00
Bananymous a945d19750 Kernel: Partially fix PCI PIN interrupt routing
Don't fail early if the first device is not the one we are looking for
2025-05-28 03:10:01 +03:00
Bananymous 7f04b2c96c Kernel: Fix E1000 interrupt handling
E1000 does not support MSI-X and thus does not generate RxQ0 interrupts.
2025-05-28 03:10:01 +03:00
Bananymous 8aa4e4ff1e LibC: Implement `clearenv`
This is GNU extension but seems nice to have :D
2025-05-28 03:10:01 +03:00
Bananymous 7eade002a7 LibC: Fix `mktime`
yday calculation was off so results were always off for march-december
2025-05-28 03:10:01 +03:00
Bananymous a8f8d27f4e LibC: Implement basic tzset()
I still don't have timezone support so this just sets values to UTC
2025-05-28 03:10:01 +03:00
Bananymous 356935bd4f LibC: Fix strtou{,l,ll} for negative values
Also set endp if base is invalid
2025-05-28 03:10:01 +03:00
Bananymous bce3dd045f LibC: Fix strncat return value 2025-05-28 03:10:01 +03:00
Bananymous 79a2b84c81 Kernel: Fix process exit when there are multiple threads 2025-05-28 03:10:01 +03:00
Bananymous 44b762f916 Kernel/LibC: Implement pwrite and make pread non-locking 2025-05-28 03:10:01 +03:00
Bananymous 5d80c880c8 LibC: Fix `FILE` buffering once again :D 2025-05-28 03:10:01 +03:00
Bananymous b907263f35 LibC: Implement basic tmpfile 2025-05-28 03:10:01 +03:00
Bananymous 0f0accf82c LibC: Don't use `false` in pthread initializers 2025-05-28 03:10:01 +03:00
Bananymous ddcf414107 LibC: Fix netinet/in.h and arpa/inet.h definitions 2025-05-28 03:10:01 +03:00
38 changed files with 498 additions and 125 deletions

View File

@ -111,6 +111,7 @@ namespace Kernel
BAN::ErrorOr<size_t> sendto(BAN::ConstByteSpan message, const sockaddr* address, socklen_t address_len);
BAN::ErrorOr<size_t> recvfrom(BAN::ByteSpan buffer, sockaddr* address, socklen_t* address_len);
BAN::ErrorOr<void> getsockname(sockaddr* address, socklen_t* address_len);
BAN::ErrorOr<void> getpeername(sockaddr* address, socklen_t* address_len);
// General API
BAN::ErrorOr<size_t> read(off_t, BAN::ByteSpan buffer);
@ -153,6 +154,7 @@ namespace Kernel
virtual BAN::ErrorOr<size_t> sendto_impl(BAN::ConstByteSpan, const sockaddr*, socklen_t) { return BAN::Error::from_errno(ENOTSUP); }
virtual BAN::ErrorOr<size_t> recvfrom_impl(BAN::ByteSpan, sockaddr*, socklen_t*) { return BAN::Error::from_errno(ENOTSUP); }
virtual BAN::ErrorOr<void> getsockname_impl(sockaddr*, socklen_t*) { return BAN::Error::from_errno(ENOTSUP); }
virtual BAN::ErrorOr<void> getpeername_impl(sockaddr*, socklen_t*) { return BAN::Error::from_errno(ENOTSUP); }
// General API
virtual BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) { return BAN::Error::from_errno(ENOTSUP); }

View File

@ -25,6 +25,7 @@ namespace Kernel
BAN::Vector<BAN::RefPtr<NetworkInterface>>& interfaces() { return m_interfaces; }
BAN::ErrorOr<BAN::RefPtr<Socket>> create_socket(Socket::Domain, Socket::Type, mode_t, uid_t, gid_t);
BAN::ErrorOr<void> connect_sockets(Socket::Domain, BAN::RefPtr<Socket>, BAN::RefPtr<Socket>);
void on_receive(NetworkInterface&, BAN::ConstByteSpan);

View File

@ -42,6 +42,7 @@ namespace Kernel
virtual BAN::ErrorOr<long> ioctl_impl(int request, void* arg) override;
virtual BAN::ErrorOr<void> getsockname_impl(sockaddr*, socklen_t*) override;
virtual BAN::ErrorOr<void> getpeername_impl(sockaddr*, socklen_t*) override = 0;
protected:
NetworkLayer& m_network_layer;

View File

@ -61,6 +61,7 @@ namespace Kernel
virtual BAN::ErrorOr<void> bind_impl(const sockaddr*, socklen_t) override;
virtual BAN::ErrorOr<size_t> sendto_impl(BAN::ConstByteSpan, const sockaddr*, socklen_t) override;
virtual BAN::ErrorOr<size_t> recvfrom_impl(BAN::ByteSpan, sockaddr*, socklen_t*) override;
virtual BAN::ErrorOr<void> getpeername_impl(sockaddr*, socklen_t*) override;
virtual void receive_packet(BAN::ConstByteSpan, const sockaddr* sender, socklen_t sender_len) override;

View File

@ -36,6 +36,7 @@ namespace Kernel
virtual BAN::ErrorOr<void> bind_impl(const sockaddr* address, socklen_t address_len) override;
virtual BAN::ErrorOr<size_t> sendto_impl(BAN::ConstByteSpan message, const sockaddr* address, socklen_t address_len) override;
virtual BAN::ErrorOr<size_t> recvfrom_impl(BAN::ByteSpan buffer, sockaddr* address, socklen_t* address_len) override;
virtual BAN::ErrorOr<void> getpeername_impl(sockaddr*, socklen_t*) override { return BAN::Error::from_errno(ENOTCONN); }
virtual bool can_read_impl() const override { return !m_packets.empty(); }
virtual bool can_write_impl() const override { return true; }

View File

@ -17,6 +17,7 @@ namespace Kernel
public:
static BAN::ErrorOr<BAN::RefPtr<UnixDomainSocket>> create(Socket::Type, const Socket::Info&);
BAN::ErrorOr<void> make_socket_pair(UnixDomainSocket&);
protected:
virtual BAN::ErrorOr<long> accept_impl(sockaddr*, socklen_t*, int) override;
@ -25,6 +26,7 @@ namespace Kernel
virtual BAN::ErrorOr<void> bind_impl(const sockaddr*, socklen_t) override;
virtual BAN::ErrorOr<size_t> sendto_impl(BAN::ConstByteSpan, const sockaddr*, socklen_t) override;
virtual BAN::ErrorOr<size_t> recvfrom_impl(BAN::ByteSpan, sockaddr*, socklen_t*) override;
virtual BAN::ErrorOr<void> getpeername_impl(sockaddr*, socklen_t*) override;
virtual bool can_read_impl() const override;
virtual bool can_write_impl() const override;

View File

@ -26,6 +26,7 @@ namespace Kernel
BAN::ErrorOr<int> open(BAN::StringView absolute_path, int flags);
BAN::ErrorOr<int> socket(int domain, int type, int protocol);
BAN::ErrorOr<void> socketpair(int domain, int type, int protocol, int socket_vector[2]);
BAN::ErrorOr<void> pipe(int fds[2]);

View File

@ -112,12 +112,15 @@ namespace Kernel
BAN::ErrorOr<long> sys_symlinkat(const char* path1, int fd, const char* path2);
BAN::ErrorOr<long> sys_pread(int fd, void* buffer, size_t count, off_t offset);
BAN::ErrorOr<long> sys_pwrite(int fd, const void* buffer, size_t count, off_t offset);
BAN::ErrorOr<long> sys_fchmodat(int fd, const char* path, mode_t mode, int flag);
BAN::ErrorOr<long> sys_fchownat(int fd, const char* path, uid_t uid, gid_t gid, int flag);
BAN::ErrorOr<long> sys_socket(int domain, int type, int protocol);
BAN::ErrorOr<long> sys_socketpair(int domain, int type, int protocol, int socket_vector[2]);
BAN::ErrorOr<long> sys_getsockname(int socket, sockaddr* address, socklen_t* address_len);
BAN::ErrorOr<long> sys_getpeername(int socket, sockaddr* address, socklen_t* address_len);
BAN::ErrorOr<long> sys_getsockopt(int socket, int level, int option_name, void* option_value, socklen_t* option_len);
BAN::ErrorOr<long> sys_setsockopt(int socket, int level, int option_name, const void* option_value, socklen_t option_len);

View File

@ -186,6 +186,14 @@ namespace Kernel
return getsockname_impl(address, address_len);
}
BAN::ErrorOr<void> Inode::getpeername(sockaddr* address, socklen_t* address_len)
{
LockGuard _(m_mutex);
if (!mode().ifsock())
return BAN::Error::from_errno(ENOTSOCK);
return getpeername_impl(address, address_len);
}
BAN::ErrorOr<size_t> Inode::read(off_t offset, BAN::ByteSpan buffer)
{
LockGuard _(m_mutex);

View File

@ -237,21 +237,28 @@ namespace Kernel
BAN::ErrorOr<void> E1000::enable_interrupt()
{
TRY(m_pci_device.reserve_interrupts(1));
write32(REG_ITR, 0x1000);
write32(REG_IVAR, 1 << 3);
write32(REG_EITR, 0x1000);
if (m_pci_device.interrupt_mechanism() == PCI::Device::InterruptMechanism::MSIX)
{
write32(REG_IVAR, 1 << 3);
write32(REG_EITR, 0x1000);
write32(REG_IMS, IMC_RxQ0);
}
else
{
write32(REG_IMS, IMC_RXT0);
}
write32(REG_IMS, IMC_RxQ0);
read32(REG_ICR);
write32(REG_ICR, 0xFFFFFFFF);
TRY(m_pci_device.reserve_interrupts(1));
m_pci_device.enable_interrupt(0, *this);
return {};
}
BAN::ErrorOr<void> E1000::send_bytes(BAN::MACAddress destination, EtherType protocol, BAN::ConstByteSpan buffer)
{
ASSERT(buffer.size() + sizeof(EthernetHeader) <= E1000_TX_BUFFER_SIZE);
@ -285,7 +292,7 @@ namespace Kernel
void E1000::handle_irq()
{
if (!(read32(REG_ICR) & ICR_RxQ0))
if (!(read32(REG_ICR) & (ICR_RxQ0 | ICR_RXT0)))
return;
SpinLockGuard _(m_lock);

View File

@ -129,6 +129,25 @@ namespace Kernel
return socket;
}
BAN::ErrorOr<void> NetworkManager::connect_sockets(Socket::Domain domain, BAN::RefPtr<Socket> socket1, BAN::RefPtr<Socket> socket2)
{
switch (domain)
{
case Socket::Domain::UNIX:
{
auto* usocket1 = static_cast<UnixDomainSocket*>(socket1.ptr());
auto* usocket2 = static_cast<UnixDomainSocket*>(socket2.ptr());
TRY(usocket1->make_socket_pair(*usocket2));
break;
}
default:
dwarnln("TODO: connect {} domain sockets", static_cast<int>(domain));
return BAN::Error::from_errno(ENOTSUP);
}
return {};
}
void NetworkManager::on_receive(NetworkInterface& interface, BAN::ConstByteSpan packet)
{
if (packet.size() < sizeof(EthernetHeader))

View File

@ -256,6 +256,17 @@ namespace Kernel
return to_send;
}
BAN::ErrorOr<void> TCPSocket::getpeername_impl(sockaddr* address, socklen_t* address_len)
{
if (!m_has_connected && m_state != State::Established)
return BAN::Error::from_errno(ENOTCONN);
ASSERT(m_connection_info.has_value());
const size_t to_copy = BAN::Math::min(m_connection_info->address_len, *address_len);
memcpy(address, &m_connection_info->address, to_copy);
*address_len = to_copy;
return {};
}
bool TCPSocket::can_read_impl() const
{
if (m_has_connected && !m_has_sent_zero && m_state != State::Established && m_state != State::Listen)
@ -492,6 +503,8 @@ namespace Kernel
connection_info,
header.seq_number + 1
));
epoll_notify(EPOLLIN);
}
}
else

View File

@ -69,6 +69,20 @@ namespace Kernel
}
}
BAN::ErrorOr<void> UnixDomainSocket::make_socket_pair(UnixDomainSocket& other)
{
if (!m_info.has<ConnectionInfo>() || !other.m_info.has<ConnectionInfo>())
return BAN::Error::from_errno(EINVAL);
TRY(this->get_weak_ptr());
TRY(other.get_weak_ptr());
this->m_info.get<ConnectionInfo>().connection = MUST(other.get_weak_ptr());
other.m_info.get<ConnectionInfo>().connection = MUST(this->get_weak_ptr());
return {};
}
BAN::ErrorOr<long> UnixDomainSocket::accept_impl(sockaddr* address, socklen_t* address_len, int flags)
{
if (!m_info.has<ConnectionInfo>())
@ -412,4 +426,33 @@ namespace Kernel
return nread;
}
BAN::ErrorOr<void> UnixDomainSocket::getpeername_impl(sockaddr* address, socklen_t* address_len)
{
if (!m_info.has<ConnectionInfo>())
return BAN::Error::from_errno(ENOTCONN);
auto connection = m_info.get<ConnectionInfo>().connection.lock();
if (!connection)
return BAN::Error::from_errno(ENOTCONN);
sockaddr_un sa_un;
sa_un.sun_family = AF_UNIX;
sa_un.sun_path[0] = 0;
{
SpinLockGuard _(s_bound_socket_lock);
for (auto& [path, socket] : s_bound_sockets)
{
if (socket.lock() != connection)
continue;
strcpy(sa_un.sun_path, path.data());
break;
}
}
const size_t to_copy = BAN::Math::min<socklen_t>(sizeof(sockaddr_un), *address_len);
memcpy(address, &sa_un, to_copy);
*address_len = to_copy;
return {};
}
}

View File

@ -83,50 +83,57 @@ namespace Kernel
return open(TRY(VirtualFileSystem::get().file_from_absolute_path(m_credentials, absolute_path, flags)), flags);
}
BAN::ErrorOr<int> OpenFileDescriptorSet::socket(int domain, int type, int protocol)
struct SocketInfo
{
bool valid_protocol = true;
Socket::Domain domain;
Socket::Type type;
int status_flags;
int descriptor_flags;
};
Socket::Domain sock_domain;
static BAN::ErrorOr<SocketInfo> parse_socket_info(int domain, int type, int protocol)
{
SocketInfo info;
bool valid_protocol = true;
switch (domain)
{
case AF_INET:
sock_domain = Socket::Domain::INET;
info.domain = Socket::Domain::INET;
break;
case AF_INET6:
sock_domain = Socket::Domain::INET6;
info.domain = Socket::Domain::INET6;
break;
case AF_UNIX:
sock_domain = Socket::Domain::UNIX;
info.domain = Socket::Domain::UNIX;
valid_protocol = false;
break;
default:
return BAN::Error::from_errno(EPROTOTYPE);
}
int status_flags = 0;
int descriptor_flags = 0;
info.status_flags = 0;
info.descriptor_flags = 0;
if (type & SOCK_NONBLOCK)
status_flags |= O_NONBLOCK;
info.status_flags |= O_NONBLOCK;
if (type & SOCK_CLOEXEC)
descriptor_flags |= O_CLOEXEC;
info.descriptor_flags |= O_CLOEXEC;
type &= ~(SOCK_NONBLOCK | SOCK_CLOEXEC);
Socket::Type sock_type;
switch (type)
{
case SOCK_STREAM:
sock_type = Socket::Type::STREAM;
info.type = Socket::Type::STREAM;
if (protocol != IPPROTO_TCP)
valid_protocol = false;
break;
case SOCK_DGRAM:
sock_type = Socket::Type::DGRAM;
info.type = Socket::Type::DGRAM;
if (protocol != IPPROTO_UDP)
valid_protocol = false;
break;
case SOCK_SEQPACKET:
sock_type = Socket::Type::SEQPACKET;
info.type = Socket::Type::SEQPACKET;
valid_protocol = false;
break;
default:
@ -136,15 +143,39 @@ namespace Kernel
if (protocol && !valid_protocol)
return BAN::Error::from_errno(EPROTONOSUPPORT);
auto socket = TRY(NetworkManager::get().create_socket(sock_domain, sock_type, 0777, m_credentials.euid(), m_credentials.egid()));
return info;
}
BAN::ErrorOr<int> OpenFileDescriptorSet::socket(int domain, int type, int protocol)
{
auto sock_info = TRY(parse_socket_info(domain, type, protocol));
auto socket = TRY(NetworkManager::get().create_socket(sock_info.domain, sock_info.type, 0777, m_credentials.euid(), m_credentials.egid()));
LockGuard _(m_mutex);
int fd = TRY(get_free_fd());
m_open_files[fd].description = TRY(BAN::RefPtr<OpenFileDescription>::create(VirtualFileSystem::File(socket, "<socket>"_sv), 0, O_RDWR | status_flags));
m_open_files[fd].descriptor_flags = descriptor_flags;
m_open_files[fd].description = TRY(BAN::RefPtr<OpenFileDescription>::create(VirtualFileSystem::File(socket, "<socket>"_sv), 0, O_RDWR | sock_info.status_flags));
m_open_files[fd].descriptor_flags = sock_info.descriptor_flags;
return fd;
}
BAN::ErrorOr<void> OpenFileDescriptorSet::socketpair(int domain, int type, int protocol, int socket_vector[2])
{
auto sock_info = TRY(parse_socket_info(domain, type, protocol));
auto socket1 = TRY(NetworkManager::get().create_socket(sock_info.domain, sock_info.type, 0600, m_credentials.euid(), m_credentials.egid()));
auto socket2 = TRY(NetworkManager::get().create_socket(sock_info.domain, sock_info.type, 0600, m_credentials.euid(), m_credentials.egid()));
TRY(NetworkManager::get().connect_sockets(sock_info.domain, socket1, socket2));
LockGuard _(m_mutex);
TRY(get_free_fd_pair(socket_vector));
m_open_files[socket_vector[0]].description = TRY(BAN::RefPtr<OpenFileDescription>::create(VirtualFileSystem::File(socket1, "<socketpair>"_sv), 0, O_RDWR | sock_info.status_flags));
m_open_files[socket_vector[0]].descriptor_flags = sock_info.descriptor_flags;
m_open_files[socket_vector[1]].description = TRY(BAN::RefPtr<OpenFileDescription>::create(VirtualFileSystem::File(socket2, "<socketpair>"_sv), 0, O_RDWR | sock_info.status_flags));
m_open_files[socket_vector[1]].descriptor_flags = sock_info.descriptor_flags;
return {};
}
BAN::ErrorOr<void> OpenFileDescriptorSet::pipe(int fds[2])
{
LockGuard _(m_mutex);

View File

@ -682,9 +682,9 @@ namespace Kernel::PCI
auto& prt_entry_fields = prt_entry.as.package->elements;
if (TRY(ACPI::AML::convert_node(TRY(prt_entry_fields[0].value.node->copy()), ACPI::AML::ConvInteger, -1)).as.integer.value != acpi_device_id)
return BAN::Error::from_errno(ENOENT);
continue;
if (TRY(ACPI::AML::convert_node(TRY(prt_entry_fields[1].value.node->copy()), ACPI::AML::ConvInteger, -1)).as.integer.value != acpi_pin)
return BAN::Error::from_errno(ENOENT);
continue;
auto ret = route_prt_entry(prt_entry);
if (!ret.is_error())
@ -714,16 +714,14 @@ namespace Kernel::PCI
return InterruptMechanism::NONE;
}
const bool is_xhci = false && m_class_code == 0x0C && m_subclass == 0x03 && m_prog_if == 0x30;
if (!is_xhci && m_offset_msi_x.has_value())
if (m_offset_msi_x.has_value())
{
const uint16_t msg_ctrl = read_word(*m_offset_msi_x + 0x02);
if (count <= (msg_ctrl & 0x7FF) + 1)
return InterruptMechanism::MSIX;
}
if (!is_xhci && m_offset_msi.has_value())
if (m_offset_msi.has_value())
{
if (count == 1)
return InterruptMechanism::MSI;

View File

@ -301,8 +301,14 @@ namespace Kernel
);
}
while (!m_threads.empty())
m_threads.front()->on_exit();
for (size_t i = 0; i < m_threads.size(); i++)
{
if (m_threads[i] == &Thread::current())
continue;
m_threads[i]->add_signal(SIGKILL);
}
Thread::current().on_exit();
ASSERT_NOT_REACHED();
}
@ -1192,17 +1198,23 @@ namespace Kernel
BAN::ErrorOr<long> Process::sys_pread(int fd, void* buffer, size_t count, off_t offset)
{
LockGuard _(m_process_lock);
if (count == 0)
{
TRY(m_open_file_descriptors.inode_of(fd));
return 0;
}
TRY(validate_pointer_access(buffer, count, true));
auto inode = TRY(m_open_file_descriptors.inode_of(fd));
return TRY(inode->read(offset, { (uint8_t*)buffer, count }));
auto* buffer_region = TRY(validate_and_pin_pointer_access(buffer, count, true));
BAN::ScopeGuard _([buffer_region]{ if (buffer_region) buffer_region->unpin(); });
return TRY(inode->read(offset, { reinterpret_cast<uint8_t*>(buffer), count }));
}
BAN::ErrorOr<long> Process::sys_pwrite(int fd, const void* buffer, size_t count, off_t offset)
{
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(); });
return TRY(inode->write(offset, { reinterpret_cast<const uint8_t*>(buffer), count })); }
BAN::ErrorOr<long> Process::sys_fchmodat(int fd, const char* path, mode_t mode, int flag)
{
if (mode & S_IFMASK)
@ -1258,6 +1270,14 @@ namespace Kernel
return TRY(m_open_file_descriptors.socket(domain, type, protocol));
}
BAN::ErrorOr<long> Process::sys_socketpair(int domain, int type, int protocol, int socket_vector[2])
{
LockGuard _(m_process_lock);
TRY(validate_pointer_access(socket_vector, sizeof(int) * 2, true));
TRY(m_open_file_descriptors.socketpair(domain, type, protocol, socket_vector));
return 0;
}
BAN::ErrorOr<long> Process::sys_getsockname(int socket, sockaddr* address, socklen_t* address_len)
{
LockGuard _(m_process_lock);
@ -1272,6 +1292,20 @@ namespace Kernel
return 0;
}
BAN::ErrorOr<long> Process::sys_getpeername(int socket, sockaddr* address, socklen_t* address_len)
{
LockGuard _(m_process_lock);
TRY(validate_pointer_access(address_len, sizeof(address_len), true));
TRY(validate_pointer_access(address, *address_len, true));
auto inode = TRY(m_open_file_descriptors.inode_of(socket));
if (!inode->mode().ifsock())
return BAN::Error::from_errno(ENOTSOCK);
TRY(inode->getpeername(address, address_len));
return 0;
}
BAN::ErrorOr<long> Process::sys_getsockopt(int socket, int level, int option_name, void* option_value, socklen_t* option_len)
{
LockGuard _(m_process_lock);
@ -2304,14 +2338,10 @@ namespace Kernel
return BAN::Error::from_errno(EINVAL);
TRY(m_exited_pthreads.emplace_back(Thread::current().tid(), value));
for (auto* thread : m_threads)
{
if (thread != &Thread::current())
continue;
m_pthread_exit_blocker.unblock();
m_process_lock.unlock();
thread->on_exit();
}
m_pthread_exit_blocker.unblock();
m_process_lock.unlock();
Thread::current().on_exit();
ASSERT_NOT_REACHED();
}

View File

@ -39,6 +39,7 @@ set(LIBC_SOURCES
sys/stat.cpp
sys/statvfs.cpp
sys/time.cpp
sys/uio.cpp
sys/utsname.cpp
sys/wait.cpp
syslog.cpp

View File

@ -2,6 +2,7 @@
#include <arpa/inet.h>
#include <errno.h>
#include <netinet/in.h>
#include <stdio.h>
uint32_t htonl(uint32_t hostlong)

View File

@ -19,7 +19,7 @@ static int malloc_environ()
ASSERT(!s_environ_malloced);
size_t environ_count = 0;
while (environ[environ_count])
while (environ && environ[environ_count])
environ_count++;
const size_t bitmap_size = (environ_count + 7) / 8;
@ -111,12 +111,37 @@ static int putenv_impl(char* string, bool malloced)
return 0;
}
int clearenv(void)
{
if (s_environ_malloced)
{
ASSERT(environ);
for (size_t i = 0; environ[i]; i++)
{
const size_t byte = i / 8;
const size_t mask = 1 << (i % 8);
if (s_environ_bitmap[byte] & mask)
free(environ[i]);
}
free(s_environ_bitmap);
free(environ);
}
environ = nullptr;
s_environ_count = 0;
s_environ_bitmap = nullptr;
s_environ_malloced = false;
return 0;
}
char* getenv(const char* name)
{
if (environ == nullptr)
return nullptr;
const size_t namelen = strlen(name);
for (int i = 0; environ[i]; i++)
for (size_t i = 0; environ[i]; i++)
if (strncmp(name, environ[i], namelen) == 0)
if (environ[i][namelen] == '=')
return environ[i] + namelen + 1;
@ -154,6 +179,9 @@ int unsetenv(const char* name)
return -1;
}
if (environ == nullptr)
return 0;
const size_t namelen = strlen(name);
size_t i = 0;

View File

@ -1,5 +1,5 @@
#ifndef _INET_H
#define _INET_H 1
#ifndef _ARPA_INET_H
#define _ARPA_INET_H 1
// https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/arpa_inet.h.html
@ -7,13 +7,8 @@
__BEGIN_DECLS
#include <netinet/in.h>
#include <inttypes.h>
uint32_t htonl(uint32_t);
uint16_t htons(uint16_t);
uint32_t ntohl(uint32_t);
uint16_t ntohs(uint16_t);
#include <bits/inet_common.h>
#include <bits/types/socklen_t.h>
in_addr_t inet_addr(const char* cp);
char* inet_ntoa(struct in_addr in);

View File

@ -0,0 +1,28 @@
#ifndef _BITS_INET_COMMON_H
#define _BITS_INET_COMMON_H 1
#include <sys/cdefs.h>
__BEGIN_DECLS
#include <inttypes.h>
#define INET_ADDRSTRLEN 16
#define INET6_ADDRSTRLEN 46
typedef uint16_t in_port_t;
typedef uint32_t in_addr_t;
struct in_addr
{
in_addr_t s_addr;
};
uint32_t htonl(uint32_t);
uint16_t htons(uint16_t);
uint32_t ntohl(uint32_t);
uint16_t ntohs(uint16_t);
__END_DECLS
#endif

View File

@ -0,0 +1,12 @@
#ifndef _BITS_TYPES_SOCKLEN_T_H
#define _BITS_TYPES_SOCKLEN_T_H 1
#include <sys/cdefs.h>
__BEGIN_DECLS
typedef long socklen_t;
__END_DECLS
#endif

View File

@ -7,7 +7,7 @@
__BEGIN_DECLS
#include <inttypes.h>
#include <bits/inet_common.h>
#include <sys/socket.h>
#define IPPROTO_IP 1
@ -30,9 +30,6 @@ __BEGIN_DECLS
#define INADDR_BROADCAST 0xFFFFFFFF
#define INADDR_LOOPBACK 0x7F000001
#define INET_ADDRSTRLEN 16
#define INET6_ADDRSTRLEN 46
#define IN6ADDR_ANY_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } }
#define IN6ADDR_LOOPBACK_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } }
@ -51,14 +48,6 @@ __BEGIN_DECLS
#define IN6_IS_ADDR_MC_GLOBAL(addr)
#endif
typedef uint16_t in_port_t;
typedef uint32_t in_addr_t;
struct in_addr
{
in_addr_t s_addr;
};
struct sockaddr_in
{
sa_family_t sin_family; /* AF_INET. */

View File

@ -57,8 +57,8 @@ struct uthread
#define PTHREAD_SPIN_INITIALIZER (pthread_spinlock_t)0
#define PTHREAD_COND_INITIALIZER (pthread_cond_t){ { CLOCK_REALTIME, 0 }, PTHREAD_SPIN_INITIALIZER, NULL }
#define PTHREAD_MUTEX_INITIALIZER (pthread_mutex_t){ { PTHREAD_MUTEX_DEFAULT, false }, 0, 0 }
#define PTHREAD_RWLOCK_INITIALIZER (pthread_rwlock_t){ { false }, 0, 0 }
#define PTHREAD_MUTEX_INITIALIZER (pthread_mutex_t){ { PTHREAD_MUTEX_DEFAULT, 0 }, 0, 0 }
#define PTHREAD_RWLOCK_INITIALIZER (pthread_rwlock_t){ { 0 }, 0, 0 }
int pthread_atfork(void (*prepare)(void), void (*parent)(void), void(*child)(void));
int pthread_attr_destroy(pthread_attr_t* attr);

View File

@ -51,6 +51,7 @@ long atol(const char* str);
long long atoll(const char* str);
void* bsearch(const void* key, const void* base, size_t nel, size_t width, int (*compar)(const void*, const void*));
void* calloc(size_t nelem, size_t elsize);
int clearenv(void);
div_t div(int numer, int denom);
double drand48(void);
double erand48(unsigned short xsubi[3]);

View File

@ -14,7 +14,7 @@ __BEGIN_DECLS
#include <sys/uio.h>
#include <bits/types/sa_family_t.h>
typedef long socklen_t;
#include <bits/types/socklen_t.h>
#if !defined(FILENAME_MAX)
#define FILENAME_MAX 256

View File

@ -60,9 +60,11 @@ __BEGIN_DECLS
O(SYS_READLINKAT, readlinkat) \
O(SYS_MSYNC, msync) \
O(SYS_PREAD, pread) \
O(SYS_PWRITE, pwrite) \
O(SYS_FCHOWNAT, fchownat) \
O(SYS_LOAD_KEYMAP, load_keymap) \
O(SYS_SOCKET, socket) \
O(SYS_SOCKETPAIR, socketpair) \
O(SYS_BIND, bind) \
O(SYS_SENDTO, sendto) \
O(SYS_RECVFROM, recvfrom) \
@ -77,6 +79,7 @@ __BEGIN_DECLS
O(SYS_SMO_MAP, smo_map) \
O(SYS_ISATTY, isatty) \
O(SYS_GETSOCKNAME, getsockname) \
O(SYS_GETPEERNAME, getpeername) \
O(SYS_GETSOCKOPT, getsockopt) \
O(SYS_SETSOCKOPT, setsockopt) \
O(SYS_REALPATH, realpath) \

View File

@ -33,6 +33,36 @@ int gettimeofday(struct timeval* __restrict tp, void* __restrict tzp);
int setitimer(int which, const struct itimerval* __restrict value, struct itimerval* __restrict ovalue);
int utimes(const char* path, const struct timeval times[2]);
#define timeradd(a, b, res) \
do { \
(res)->tv_sec = (a)->tv_sec + (b)->tv_sec; \
(res)->tv_usec = (a)->tv_usec + (b)->tv_usec; \
(res)->tv_sec += (res)->tv_usec / 1000000; \
(res)->tv_usec %= 1000000; \
} while (0)
#define timersub(a, b, res) \
do { \
(res)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
(res)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
(res)->tv_sec += (res)->tv_usec / 1000000; \
(res)->tv_usec %= 1000000; \
} while (0)
#define timerclear(tvp) \
do { \
(tvp)->tv_sec = 0; \
(tvp)->tv_usec = 0; \
} while (0)
#define timerisset(tvp) \
((tvp)->tv_sec || (tvp)->tv_usec)
#define timercmp(a, b, CMP) \
(((a)->tv_sec == (b)->tv_sec) \
? ((a)->tv_usec CMP (b)->tv_usec) \
: ((a)->tv_sec CMP (b)->tv_sec))
__END_DECLS
#endif

View File

@ -185,6 +185,8 @@ __BEGIN_DECLS
typedef int bits32_t;
typedef unsigned int u_bits32_t;
typedef char* bits64_t;
typedef unsigned char u_char;
typedef unsigned short u_short;
typedef unsigned int u_int;
typedef unsigned long u_long;
#endif

View File

@ -70,7 +70,7 @@ int getaddrinfo(const char* __restrict nodename, const char* __restrict servname
return EAI_SOCKTYPE;
}
if (!nodename)
if (!nodename && !servname)
return EAI_NONAME;
int port = 0;
@ -147,9 +147,34 @@ error_close_socket:
return EAI_FAIL;
}
int getnameinfo(const struct sockaddr* __restrict, socklen_t, char* __restrict, socklen_t, char* __restrict, socklen_t, int)
#include <BAN/Debug.h>
int getnameinfo(const struct sockaddr* __restrict sa, socklen_t salen, char* __restrict node, socklen_t nodelen, char* __restrict service, socklen_t servicelen, int flags)
{
ASSERT_NOT_REACHED();
printf("getnameinfo(%p, %p, %p, 0x%X)\n", sa, node, service, flags);
switch (sa->sa_family)
{
case AF_INET:
if (salen < static_cast<socklen_t>(sizeof(sockaddr_in)))
return EAI_FAMILY;
if (service && snprintf(service, servicelen, "%d", reinterpret_cast<sockaddr_in*>(service)->sin_port) < 0)
return EAI_SYSTEM;
break;
case AF_INET6:
if (salen < static_cast<socklen_t>(sizeof(sockaddr_in6)))
return EAI_FAMILY;
if (service && snprintf(service, servicelen, "%d", reinterpret_cast<sockaddr_in6*>(service)->sin6_port) < 0)
return EAI_SYSTEM;
break;
default:
return EAI_FAIL;
}
if (node && inet_ntop(sa->sa_family, sa, node, nodelen) == nullptr)
return EAI_SYSTEM;
return 0;
}
struct hostent* gethostbyname(const char* name)

View File

@ -552,6 +552,7 @@ extern "C" int printf_impl(const char* format, va_list arguments, int (*putc_fun
conversion[0] = va_arg(arguments, int);
conversion[1] = '\0';
string = conversion;
length = 1;
format++;
break;
}
@ -633,7 +634,7 @@ extern "C" int printf_impl(const char* format, va_list arguments, int (*putc_fun
for (int i = length; i < options.width; i++)
BAN_PRINTF_PUTC(' ');
for (int i = 0; i < length && string[i]; i++)
for (int i = 0; i < length; i++)
BAN_PRINTF_PUTC(string[i]);
if (options.left_justified)

View File

@ -82,13 +82,10 @@ static void init_closed_file(FILE* file)
static int drop_read_buffer(FILE* file)
{
if (file->buffer_rd_size == 0)
return 0;
ASSERT(file->buffer_idx != 0);
if (file->buffer_idx == 1)
return 0;
if (syscall(SYS_SEEK, file->fd, file->buffer_idx - 1, SEEK_CUR) == -1)
return EOF;
const off_t bytes_remaining = file->buffer_rd_size - file->buffer_idx;
if (bytes_remaining > 0)
if (syscall(SYS_SEEK, file->fd, -bytes_remaining, SEEK_CUR) == -1)
return EOF;
file->buffer_rd_size = 0;
file->buffer_idx = 0;
return 0;
@ -452,8 +449,7 @@ int fseeko(FILE* file, off_t offset, int whence)
ScopeLock _(file);
if (fflush(file) == EOF)
return -1;
long ret = syscall(SYS_SEEK, file->fd, offset, whence);
if (ret < 0)
if (syscall(SYS_SEEK, file->fd, offset, whence) == -1)
return -1;
file->eof = false;
return 0;
@ -472,12 +468,12 @@ long ftell(FILE* file)
off_t ftello(FILE* file)
{
ScopeLock _(file);
if (fflush(file) == EOF)
auto offset = syscall(SYS_TELL, file->fd);
if (offset == -1)
return -1;
long ret = syscall(SYS_TELL, file->fd);
if (ret < 0)
return -1;
return ret;
if (file->buffer_rd_size)
offset -= file->buffer_rd_size - file->buffer_idx;
return offset - file->unget_buf_idx;
}
int ftrylockfile(FILE* fp)
@ -541,10 +537,7 @@ int getc_unlocked(FILE* file)
if (file->unget_buf_idx)
{
file->unget_buf_idx--;
unsigned char ch = file->unget_buffer[file->unget_buf_idx];
if (fseeko(file, 1, SEEK_CUR) == -1)
return EOF;
return ch;
return file->unget_buffer[file->unget_buf_idx];
}
// read from unbuffered file
@ -582,8 +575,6 @@ int getc_unlocked(FILE* file)
((nread == 0) ? file->eof : file->error) = true;
return EOF;
}
if (fseeko(file, 1 - nread, SEEK_CUR) == -1)
return EOF;
file->buffer_rd_size = nread;
file->buffer_idx = 1;
return file->buffer[0];
@ -965,7 +956,29 @@ char* tempnam(const char*, const char*);
FILE* tmpfile(void)
{
ASSERT_NOT_REACHED();
for (;;)
{
char path[PATH_MAX];
if (tmpnam(path) == nullptr)
return nullptr;
int fd = open(path, O_CREAT | O_EXCL | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
if (fd == -1)
{
if (errno == EEXIST)
continue;
return nullptr;
}
(void)unlink(path);
FILE* fp = fdopen(fd, "wb+");
if (fp != nullptr)
return fp;
close(fd);
return nullptr;
}
}
char* tmpnam(char* storage)
@ -998,9 +1011,6 @@ int ungetc_unlocked(int c, FILE* stream)
return EOF;
}
if (fseeko(stream, -1, SEEK_CUR) == -1)
return EOF;
stream->unget_buffer[stream->unget_buf_idx] = c;
stream->unget_buf_idx++;
stream->eof = false;

View File

@ -69,10 +69,8 @@ static constexpr int get_base_digit(char c, int base)
}
template<BAN::integral T>
static constexpr bool will_digit_append_overflow(bool negative, T current, int digit, int base)
static constexpr bool will_digit_append_overflow(T current, int digit, int base)
{
if (BAN::is_unsigned_v<T> && negative && digit)
return true;
if (BAN::Math::will_multiplication_overflow<T>(current, base))
return true;
if (BAN::Math::will_addition_overflow<T>(current * base, current < 0 ? -digit : digit))
@ -86,6 +84,8 @@ static T strtoT(const char* str, char** endp, int base, int& error)
// validate base
if (base != 0 && (base < 2 || base > 36))
{
if (endp)
*endp = const_cast<char*>(str);
error = EINVAL;
return 0;
}
@ -134,11 +134,18 @@ static T strtoT(const char* str, char** endp, int base, int& error)
break;
str++;
overflow = will_digit_append_overflow(negative, result, digit, base);
overflow = will_digit_append_overflow(result, digit, base);
if (!overflow)
result = result * base + (negative ? -digit : digit);
{
if (negative && !BAN::is_unsigned_v<T>)
digit = -digit;
result = result * base + digit;
}
}
if (negative && BAN::is_unsigned_v<T>)
result = -result;
// save endp if asked
if (endp)
{
@ -540,6 +547,26 @@ char* ptsname(int fildes)
return buffer;
}
int mblen(const char* s, size_t n)
{
if (s == nullptr)
return 0;
if (n == 0)
return -1;
switch (__getlocale(LC_CTYPE))
{
case LOCALE_INVALID:
ASSERT_NOT_REACHED();
case LOCALE_POSIX:
return 1;
case LOCALE_UTF8:
if (const auto bytes = BAN::UTF8::byte_length(*s); n >= bytes)
return bytes;
return -1;
}
ASSERT_NOT_REACHED();
}
size_t mbstowcs(wchar_t* __restrict pwcs, const char* __restrict s, size_t n)
{
auto* us = reinterpret_cast<const unsigned char*>(s);

View File

@ -147,11 +147,12 @@ char* strcat(char* __restrict__ dest, const char* __restrict__ src)
char* strncat(char* __restrict__ dest, const char* __restrict__ src, size_t n)
{
char* ret = dest;
dest += strlen(dest);
while (*src && n--)
*dest++ = *src++;
*dest = '\0';
return dest;
return ret;
}
int strcoll(const char* s1, const char* s2)

View File

@ -68,11 +68,21 @@ int socket(int domain, int type, int protocol)
return syscall(SYS_SOCKET, domain, type, protocol);
}
int socketpair(int domain, int type, int protocol, int socket_vector[2])
{
return syscall(SYS_SOCKETPAIR, domain, type, protocol, socket_vector);
}
int getsockname(int socket, struct sockaddr* __restrict address, socklen_t* __restrict address_len)
{
return syscall(SYS_GETSOCKNAME, socket, address, address_len);
}
int getpeername(int socket, struct sockaddr* __restrict address, socklen_t* __restrict address_len)
{
return syscall(SYS_GETPEERNAME, socket, address, address_len);
}
int getsockopt(int socket, int level, int option_name, void* __restrict option_value, socklen_t* __restrict option_len)
{
return syscall(SYS_GETSOCKOPT, socket, level, option_name, option_value, option_len);
@ -87,11 +97,6 @@ int setsockopt(int socket, int level, int option_name, const void* option_value,
#include <BAN/Assert.h>
int getpeername(int, struct sockaddr* __restrict, socklen_t* __restrict)
{
ASSERT_NOT_REACHED();
}
int shutdown(int, int)
{
ASSERT_NOT_REACHED();

View File

@ -0,0 +1,46 @@
#include <sys/uio.h>
#include <unistd.h>
ssize_t readv(int fildes, const struct iovec* iov, int iovcnt)
{
size_t result = 0;
for (int i = 0; i < iovcnt; i++)
{
uint8_t* base = static_cast<uint8_t*>(iov->iov_base);
size_t nread = 0;
while (nread < iov[i].iov_len)
{
const ssize_t ret = read(fildes, base + nread, iov[i].iov_len - nread);
if (ret == -1 && result == 0)
return -1;
if (ret <= 0)
return result;
nread += ret;
}
result += nread;
}
return result;
}
ssize_t writev(int fildes, const struct iovec* iov, int iovcnt)
{
size_t result = 0;
for (int i = 0; i < iovcnt; i++)
{
const uint8_t* base = static_cast<const uint8_t*>(iov->iov_base);
size_t nwrite = 0;
while (nwrite < iov[i].iov_len)
{
const ssize_t ret = write(fildes, base + nwrite, iov[i].iov_len - nwrite);
if (ret == -1 && result == 0)
return -1;
if (ret <= 0)
return result;
nwrite += ret;
}
result += nwrite;
}
return result;
}

View File

@ -9,6 +9,10 @@
#include <time.h>
#include <unistd.h>
int daylight;
long timezone;
char* tzname[2];
int clock_gettime(clockid_t clock_id, struct timespec* tp)
{
return syscall(SYS_CLOCK_GETTIME, clock_id, tp);
@ -127,8 +131,8 @@ time_t mktime(struct tm* tm)
tm->tm_mon %= 12;
tm->tm_yday = tm->tm_mday - 1;
if (tm->tm_mon > 0)
tm->tm_yday += month_days[tm->tm_mon - 1];
for (int i = 0; i < tm->tm_mon; i++)
tm->tm_yday += month_days[i];
const time_t num_febs = (tm->tm_mon > 1) ? tm->tm_year + 1 : tm->tm_year;
const time_t leap_years = (num_febs - 69) / 4 - (num_febs - 1) / 100 + (num_febs + 299) / 400;
@ -196,6 +200,14 @@ struct tm* localtime(const time_t* timer)
return localtime_r(timer, &tm);
}
void tzset()
{
daylight = 0;
timezone = 0;
tzname[0] = const_cast<char*>("UTC");
tzname[1] = const_cast<char*>("UTC");
}
size_t strftime(char* __restrict s, size_t maxsize, const char* __restrict format, const struct tm* __restrict timeptr)
{
size_t len = 0;
@ -544,13 +556,3 @@ size_t strftime(char* __restrict s, size_t maxsize, const char* __restrict forma
s[len++] = '\0';
return len;
}
#include <BAN/Assert.h>
long timezone;
void tzset()
{
ASSERT_NOT_REACHED();
}

View File

@ -127,6 +127,11 @@ ssize_t pread(int fildes, void* buf, size_t nbyte, off_t offset)
return syscall(SYS_PREAD, fildes, buf, nbyte, offset);
}
ssize_t pwrite(int fildes, const void* buf, size_t nbyte, off_t offset)
{
return syscall(SYS_PWRITE, fildes, buf, nbyte, offset);
}
off_t lseek(int fildes, off_t offset, int whence)
{
return syscall(SYS_SEEK, fildes, offset, whence);