Compare commits

..

17 Commits

Author SHA1 Message Date
Bananymous 06015d006d ports/binutils: Fix compilation when zstd is installed
binutils uses pkg-config to find zstd for the host when building. If our
zstd port is installed, it finds it instead and ends up including our
own sysroot which is incompatible with host's.

unsetting pkg-config related variables fixes this and allows binutils to
build fine even when zstd is installed. We can now make it a dependency.
2025-08-11 03:45:38 +03:00
Bananymous 0dbfd8ac66 ports/quake2: Use SDL2 instead of our own frontend 2025-08-11 03:45:38 +03:00
Bananymous 58c1fd36b9 ports/tinygb: Use SDL2 instead of our own frontend 2025-08-11 03:45:38 +03:00
Bananymous 2f725848f4 ports/doom: Use SDL2 instead of our own frontend
This allows doom to play sounds!
2025-08-11 03:45:38 +03:00
Bananymous 6250710bbd ports: Add SDL2_mixer port
This allows some ports to use audio :D

I did not port any audio libraries so loading sounds probably doesn't
work :D
2025-08-11 03:45:38 +03:00
Bananymous 028024b0da ports: Add timidity port 2025-08-11 03:45:38 +03:00
Bananymous 4f61230506 init: Start AudioServer on boot 2025-08-11 03:45:38 +03:00
Bananymous 309ec660b6 Kernel/LibC: Implement chroot 2025-08-11 03:45:38 +03:00
Bananymous 695262624d Kernel: Fix potential UB in AML OpRegion initialization 2025-08-11 03:45:38 +03:00
Bananymous c96c264801 LibC: Implement fnmatch 2025-08-10 19:57:31 +03:00
Bananymous af0bca74e4 Kernel/LibC: Implement {get,set,init}groups
This allows dropping /etc/group parsing from the kernel :D
2025-08-10 19:57:31 +03:00
Bananymous f41e254e35 Kernel: Fix dead lock on process exit 2025-08-10 19:57:31 +03:00
Bananymous 7e472a9c1d Kernel: Fix USB FS device default max packet size
Apparently this is a common non spec compliant issue on many
controllers/devices.

thanks @sasdallas
2025-08-10 19:57:31 +03:00
Bananymous ee3f10313a BuildSystem: Flip USB_ARGS and DISK_ARGS in qemu.sh
This allows attaching usb disk :D
2025-08-10 19:57:31 +03:00
Bananymous 5b587d199e Kernel/LibC: Implement FIONREAD for tcp and udp sockets 2025-08-10 19:57:31 +03:00
Bananymous 009b073892 LibC: Add IN6_IS_ADDR_* and IN_MULTICAST macros
These are assumed to exist by some ports
2025-08-10 19:57:31 +03:00
Bananymous 92e962430b LibC: Make sockaddr and sockaddr_in compatible with other systems
sockaddr:
make sa_data is 14 bytes on all systems

sockaddr_in:
add sin_zero
2025-08-10 19:57:31 +03:00
48 changed files with 722 additions and 1488 deletions

View File

@ -35,10 +35,8 @@ namespace Kernel
bool has_egid(gid_t) const;
BAN::ErrorOr<void> initialize_supplementary_groups();
private:
BAN::ErrorOr<BAN::String> find_username() const;
BAN::Span<const gid_t> groups() const { return m_supplementary.span(); }
BAN::ErrorOr<void> set_groups(BAN::Span<const gid_t> groups);
private:
uid_t m_ruid, m_euid, m_suid;

View File

@ -20,6 +20,6 @@ namespace Kernel::ELF
BAN::Vector<BAN::UniqPtr<MemoryRegion>> regions;
};
BAN::ErrorOr<LoadResult> load_from_inode(BAN::RefPtr<Inode>, const Credentials&, PageTable&);
BAN::ErrorOr<LoadResult> load_from_inode(BAN::RefPtr<Inode> root, BAN::RefPtr<Inode> inode, const Credentials&, PageTable&);
}

View File

@ -71,13 +71,13 @@ namespace Kernel
File root_file()
{
return File(root_inode(), "/"_sv);
return File { root_inode(), "/"_sv };
}
BAN::ErrorOr<File> file_from_relative_path(const File& parent, const Credentials&, BAN::StringView, int);
BAN::ErrorOr<File> file_from_absolute_path(const Credentials& credentials, BAN::StringView path, int flags)
BAN::ErrorOr<File> file_from_relative_path(BAN::RefPtr<Inode> root_inode, const File& parent, const Credentials&, BAN::StringView, int);
BAN::ErrorOr<File> file_from_absolute_path(BAN::RefPtr<Inode> root_inode, const Credentials& credentials, BAN::StringView path, int flags)
{
return file_from_relative_path(root_file(), credentials, path, flags);
return file_from_relative_path(root_inode, File { root_inode, "/"_sv }, credentials, path, flags);
}
private:

View File

@ -1,5 +1,6 @@
#pragma once
#include <BAN/HashMap.h>
#include <BAN/Endianness.h>
#include <BAN/Queue.h>
#include <kernel/Lock/Mutex.h>
@ -63,6 +64,8 @@ namespace Kernel
virtual BAN::ErrorOr<size_t> recvfrom_impl(BAN::ByteSpan, sockaddr*, socklen_t*) override;
virtual BAN::ErrorOr<void> getpeername_impl(sockaddr*, socklen_t*) override;
virtual BAN::ErrorOr<long> ioctl_impl(int, void*) override;
virtual void receive_packet(BAN::ConstByteSpan, const sockaddr* sender, socklen_t sender_len) override;
virtual bool can_read_impl() const override;

View File

@ -38,6 +38,8 @@ namespace Kernel
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 BAN::ErrorOr<long> ioctl_impl(int, void*) override;
virtual bool can_read_impl() const override { return !m_packets.empty(); }
virtual bool can_write_impl() const override { return true; }
virtual bool has_error_impl() const override { return false; }
@ -59,7 +61,7 @@ namespace Kernel
BAN::CircularQueue<PacketInfo, 32> m_packets;
size_t m_packet_total_size { 0 };
SpinLock m_packet_lock;
ThreadBlocker m_packet_thread_blocker;
ThreadBlocker m_packet_thread_blocker;
friend class BAN::RefPtr<UDPSocket>;
};

View File

@ -5,6 +5,7 @@
#include <BAN/WeakPtr.h>
#include <kernel/FS/Socket.h>
#include <kernel/FS/TmpFS/Inode.h>
#include <kernel/FS/VirtualFileSystem.h>
#include <kernel/Lock/SpinLock.h>
namespace Kernel
@ -39,8 +40,8 @@ namespace Kernel
BAN::ErrorOr<void> add_packet(BAN::ConstByteSpan);
bool is_bound() const { return !m_bound_path.empty(); }
bool is_bound_to_unused() const { return m_bound_path == "X"_sv; }
bool is_bound() const { return !m_bound_file.canonical_path.empty(); }
bool is_bound_to_unused() const { return !m_bound_file.inode; }
bool is_streaming() const;
@ -62,8 +63,8 @@ namespace Kernel
};
private:
const Socket::Type m_socket_type;
BAN::String m_bound_path;
const Socket::Type m_socket_type;
VirtualFileSystem::File m_bound_file;
BAN::Variant<ConnectionInfo, ConnectionlessInfo> m_info;

View File

@ -76,6 +76,7 @@ namespace Kernel
BAN::ErrorOr<long> sys_getcwd(char* buffer, size_t size);
BAN::ErrorOr<long> sys_chdir(const char* path);
BAN::ErrorOr<long> sys_fchdir(int fildes);
BAN::ErrorOr<long> sys_chroot(const char* path);
BAN::ErrorOr<long> sys_setuid(uid_t);
BAN::ErrorOr<long> sys_setgid(gid_t);
@ -95,6 +96,9 @@ namespace Kernel
BAN::ErrorOr<long> sys_getppid() const { return m_parent; }
BAN::ErrorOr<long> sys_getpid() const { return pid(); }
BAN::ErrorOr<long> sys_getgroups(gid_t groups[], size_t count);
BAN::ErrorOr<long> sys_setgroups(const gid_t groups[], size_t count);
BAN::ErrorOr<long> open_inode(VirtualFileSystem::File&&, int flags);
BAN::ErrorOr<void> create_file_or_dir(int fd, const char* path, mode_t mode) const;
@ -231,6 +235,7 @@ namespace Kernel
static void update_alarm_queue();
const VirtualFileSystem::File& working_directory() const { return m_working_directory; }
const VirtualFileSystem::File& root_file() const { return m_root_file; }
private:
Process(const Credentials&, pid_t pid, pid_t parent, pid_t sid, pid_t pgrp);
@ -310,6 +315,7 @@ namespace Kernel
mutable Mutex m_process_lock;
VirtualFileSystem::File m_working_directory;
VirtualFileSystem::File m_root_file;
BAN::Vector<Thread*> m_threads;
@ -334,6 +340,8 @@ namespace Kernel
BAN::Vector<ChildExitStatus> m_child_exit_statuses;
ThreadBlocker m_child_exit_blocker;
BAN::Atomic<bool> m_is_exiting { false };
bool m_has_called_exec { false };
BAN::UniqPtr<PageTable> m_page_table;

View File

@ -243,14 +243,27 @@ namespace Kernel::ACPI::AML
BAN::ErrorOr<void> Namespace::initialize_op_regions()
{
struct FullNode
{
Scope scope;
Reference* reference;
};
BAN::Vector<FullNode> op_regions;
for (const auto& [obj_path, obj_ref] : m_named_objects)
{
if (obj_ref->node.type != Node::Type::OpRegion)
continue;
// FIXME: if _REG adds stuff to namespace, iterators are invalidated
(void)opregion_call_reg(obj_path, obj_ref->node);
TRY(op_regions.emplace_back(
TRY(obj_path.copy()),
obj_ref
));
}
for (const auto& [obj_path, obj_ref] : op_regions)
(void)opregion_call_reg(obj_path, obj_ref->node);
return {};
}

View File

@ -1,157 +1,9 @@
#include <kernel/Credentials.h>
#include <kernel/FS/VirtualFileSystem.h>
#include <ctype.h>
#include <fcntl.h>
namespace Kernel
{
static id_t parse_id(BAN::StringView line)
{
id_t id = 0;
for (char c : line)
{
if (!isdigit(c))
return -1;
id = (id * 10) + (c - '0');
}
return id;
};
BAN::ErrorOr<BAN::String> Credentials::find_username() const
{
auto inode = TRY(VirtualFileSystem::get().file_from_absolute_path(*this, "/etc/passwd"_sv, O_RDONLY)).inode;
BAN::String line;
off_t offset = 0;
uint8_t buffer[128];
while (offset < inode->size())
{
size_t nread = TRY(inode->read(offset, { buffer, sizeof(buffer) }));
bool line_done = false;
for (size_t i = 0; i < nread; i++)
{
if (buffer[i] == '\n')
{
TRY(line.append({ (const char*)buffer, i }));
line_done = true;
offset += i + 1;
break;
}
}
if (!line_done)
{
offset += nread;
TRY(line.append({ (const char*)buffer, nread }));
continue;
}
auto parts = TRY(line.sv().split(':', true));
if (parts.size() == 7 && m_euid == parse_id(parts[2]))
{
BAN::String result;
TRY(result.append(parts[0]));
return result;
}
line.clear();
}
auto parts = TRY(line.sv().split(':', true));
if (parts.size() == 7 && m_euid == parse_id(parts[2]))
{
BAN::String result;
TRY(result.append(parts[0]));
return result;
}
return BAN::Error::from_errno(EINVAL);
}
BAN::ErrorOr<void> Credentials::initialize_supplementary_groups()
{
m_supplementary.clear();
auto username = TRY(find_username());
auto file_or_error = VirtualFileSystem::get().file_from_absolute_path(*this, "/etc/group", O_RDONLY);
if (file_or_error.is_error())
{
if (file_or_error.error().get_error_code() == ENOENT)
return {};
return file_or_error.error();
}
auto inode = file_or_error.value().inode;
BAN::String line;
off_t offset = 0;
uint8_t buffer[128];
while (offset < inode->size())
{
size_t nread = TRY(inode->read(offset, { buffer, sizeof(buffer) }));
bool line_done = false;
for (size_t i = 0; i < nread; i++)
{
if (buffer[i] == '\n')
{
TRY(line.append({ (const char*)buffer, i }));
line_done = true;
offset += i + 1;
break;
}
}
if (!line_done)
{
offset += nread;
TRY(line.append({ (const char*)buffer, nread }));
continue;
}
auto parts = TRY(line.sv().split(':', true));
if (parts.size() != 4)
{
line.clear();
continue;
}
auto users = TRY(parts[3].split(','));
for (auto user : users)
{
if (user != username)
continue;
if (gid_t gid = parse_id(parts[2]); gid != -1)
{
TRY(m_supplementary.push_back(gid));
break;
}
}
line.clear();
}
auto parts = TRY(line.sv().split(':', true));
if (parts.size() == 4)
{
auto users = TRY(parts[3].split(','));
for (auto user : users)
{
if (user != username)
continue;
if (gid_t gid = parse_id(parts[2]); gid != -1)
{
TRY(m_supplementary.push_back(gid));
break;
}
}
}
return {};
}
bool Credentials::has_egid(gid_t gid) const
{
if (m_egid == gid)
@ -162,4 +14,13 @@ namespace Kernel
return false;
}
BAN::ErrorOr<void> Credentials::set_groups(BAN::Span<const gid_t> groups)
{
m_supplementary.clear();
TRY(m_supplementary.resize(groups.size()));
for (size_t i = 0; i < groups.size(); i++)
m_supplementary[i] = groups[i];
return {};
}
}

View File

@ -104,7 +104,7 @@ namespace Kernel::ELF
return BAN::move(program_headers);
}
BAN::ErrorOr<LoadResult> load_from_inode(BAN::RefPtr<Inode> inode, const Credentials& credentials, PageTable& page_table)
BAN::ErrorOr<LoadResult> load_from_inode(BAN::RefPtr<Inode> root, BAN::RefPtr<Inode> inode, const Credentials& credentials, PageTable& page_table)
{
auto file_header = TRY(read_and_validate_file_header(inode));
auto program_headers = TRY(read_program_headers(inode, file_header));
@ -143,7 +143,7 @@ namespace Kernel::ELF
if (!interpreter.empty())
{
auto interpreter_inode = TRY(VirtualFileSystem::get().file_from_absolute_path(credentials, interpreter, O_EXEC)).inode;
auto interpreter_inode = TRY(VirtualFileSystem::get().file_from_absolute_path(root, credentials, interpreter, O_EXEC)).inode;
auto interpreter_file_header = TRY(read_and_validate_file_header(interpreter_inode));
auto interpreter_program_headers = TRY(read_program_headers(interpreter_inode, interpreter_file_header));

View File

@ -186,7 +186,8 @@ namespace Kernel
BAN::ErrorOr<void> VirtualFileSystem::mount(const Credentials& credentials, BAN::StringView block_device_path, BAN::StringView target)
{
auto block_device_file = TRY(file_from_absolute_path(credentials, block_device_path, true));
// TODO: allow custom root
auto block_device_file = TRY(file_from_absolute_path(root_inode(), credentials, block_device_path, true));
if (!block_device_file.inode->is_device())
return BAN::Error::from_errno(ENOTBLK);
@ -200,7 +201,8 @@ namespace Kernel
BAN::ErrorOr<void> VirtualFileSystem::mount(const Credentials& credentials, BAN::RefPtr<FileSystem> file_system, BAN::StringView path)
{
auto file = TRY(file_from_absolute_path(credentials, path, true));
// TODO: allow custom root
auto file = TRY(file_from_absolute_path(root_inode(), credentials, path, true));
if (!file.inode->mode().ifdir())
return BAN::Error::from_errno(ENOTDIR);
@ -227,7 +229,7 @@ namespace Kernel
return nullptr;
}
BAN::ErrorOr<VirtualFileSystem::File> VirtualFileSystem::file_from_relative_path(const File& parent, const Credentials& credentials, BAN::StringView path, int flags)
BAN::ErrorOr<VirtualFileSystem::File> VirtualFileSystem::file_from_relative_path(BAN::RefPtr<Inode> root_inode, const File& parent, const Credentials& credentials, BAN::StringView path, int flags)
{
LockGuard _(m_mutex);
@ -270,13 +272,16 @@ namespace Kernel
// resolve file name
{
auto parent_inode = inode;
if (path_part == ".."_sv)
if (auto* mount_point = mount_from_root_inode(inode))
parent_inode = mount_point->host.inode;
if (!parent_inode->can_access(credentials, O_SEARCH))
return BAN::Error::from_errno(EACCES);
inode = TRY(parent_inode->find_inode(path_part));
if (!(inode == root_inode && path_part == ".."_sv))
{
auto parent_inode = inode;
if (path_part == ".."_sv)
if (auto* mount_point = mount_from_root_inode(inode))
parent_inode = mount_point->host.inode;
if (!parent_inode->can_access(credentials, O_SEARCH))
return BAN::Error::from_errno(EACCES);
inode = TRY(parent_inode->find_inode(path_part));
}
if (path_part == ".."_sv)
{
@ -310,7 +315,7 @@ namespace Kernel
if (link_target.front() == '/')
{
inode = root_inode();
inode = root_inode;
canonical_path.clear();
}
else

View File

@ -8,6 +8,7 @@
#include <fcntl.h>
#include <netinet/in.h>
#include <sys/epoll.h>
#include <sys/ioctl.h>
namespace Kernel
{
@ -255,6 +256,18 @@ namespace Kernel
return {};
}
BAN::ErrorOr<long> TCPSocket::ioctl_impl(int request, void* argument)
{
switch (request)
{
case FIONREAD:
*static_cast<int*>(argument) = m_recv_window.data_size;
return 0;
}
return NetworkSocket::ioctl_impl(request, argument);
}
bool TCPSocket::can_read_impl() const
{
if (m_has_connected && !m_has_sent_zero && m_state != State::Established && m_state != State::Listen)

View File

@ -4,6 +4,7 @@
#include <kernel/Thread.h>
#include <sys/epoll.h>
#include <sys/ioctl.h>
namespace Kernel
{
@ -138,4 +139,22 @@ namespace Kernel
return TRY(m_network_layer.sendto(*this, message, address, address_len));
}
BAN::ErrorOr<long> UDPSocket::ioctl_impl(int request, void* argument)
{
switch (request)
{
case FIONREAD:
{
SpinLockGuard guard(m_packet_lock);
if (m_packets.empty())
*static_cast<int*>(argument) = 0;
else
*static_cast<int*>(argument) = m_packets.front().packet_size;
return 0;
}
}
return NetworkSocket::ioctl_impl(request, argument);
}
}

View File

@ -13,8 +13,16 @@
namespace Kernel
{
static BAN::HashMap<BAN::String, BAN::WeakPtr<UnixDomainSocket>> s_bound_sockets;
static SpinLock s_bound_socket_lock;
struct UnixSocketHash
{
BAN::hash_t operator()(const BAN::RefPtr<Inode>& socket)
{
return BAN::hash<const Inode*>{}(socket.ptr());
}
};
static BAN::HashMap<BAN::RefPtr<Inode>, BAN::WeakPtr<UnixDomainSocket>, UnixSocketHash> s_bound_sockets;
static SpinLock s_bound_socket_lock;
static constexpr size_t s_packet_buffer_size = 10 * PAGE_SIZE;
@ -57,9 +65,7 @@ namespace Kernel
if (is_bound() && !is_bound_to_unused())
{
SpinLockGuard _(s_bound_socket_lock);
auto it = s_bound_sockets.find(m_bound_path);
if (it != s_bound_sockets.end())
s_bound_sockets.remove(it);
s_bound_sockets.remove(m_bound_file.inode);
}
if (m_info.has<ConnectionInfo>())
{
@ -117,17 +123,22 @@ namespace Kernel
return_inode = reinterpret_cast<UnixDomainSocket*>(return_inode_tmp.ptr());
}
TRY(return_inode->m_bound_path.push_back('X'));
TRY(return_inode->m_bound_file.canonical_path.push_back('X'));
return_inode->m_info.get<ConnectionInfo>().connection = TRY(pending->get_weak_ptr());
pending->m_info.get<ConnectionInfo>().connection = TRY(return_inode->get_weak_ptr());
pending->m_info.get<ConnectionInfo>().connection_done = true;
if (address && address_len && !is_bound_to_unused())
{
size_t copy_len = BAN::Math::min<size_t>(*address_len, sizeof(sockaddr) + m_bound_path.size() + 1);
auto& sockaddr_un = *reinterpret_cast<struct sockaddr_un*>(address);
sockaddr_un.sun_family = AF_UNIX;
strncpy(sockaddr_un.sun_path, pending->m_bound_path.data(), copy_len);
sockaddr_un sa_un {
.sun_family = AF_UNIX,
.sun_path {},
};
strcpy(sa_un.sun_path, pending->m_bound_file.canonical_path.data());
const size_t to_copy = BAN::Math::min<size_t>(*address_len, sizeof(sockaddr_un));
memcpy(address, &sa_un, to_copy);
*address_len = to_copy;
}
return TRY(Process::current().open_inode(VirtualFileSystem::File(return_inode, "<unix socket>"_sv), O_RDWR | flags));
@ -141,10 +152,11 @@ namespace Kernel
if (sockaddr_un.sun_family != AF_UNIX)
return BAN::Error::from_errno(EAFNOSUPPORT);
if (!is_bound())
TRY(m_bound_path.push_back('X'));
TRY(m_bound_file.canonical_path.push_back('X'));
auto absolute_path = TRY(Process::current().absolute_path_of(sockaddr_un.sun_path));
auto file = TRY(VirtualFileSystem::get().file_from_absolute_path(
Process::current().root_file().inode,
Process::current().credentials(),
absolute_path,
O_RDWR
@ -154,7 +166,7 @@ namespace Kernel
{
SpinLockGuard _(s_bound_socket_lock);
auto it = s_bound_sockets.find(file.canonical_path);
auto it = s_bound_sockets.find(file.inode);
if (it == s_bound_sockets.end())
return BAN::Error::from_errno(ECONNREFUSED);
target = it->value.lock();
@ -236,7 +248,7 @@ namespace Kernel
// FIXME: This feels sketchy
auto parent_file = bind_path.front() == '/'
? VirtualFileSystem::get().root_file()
? TRY(Process::current().root_file().clone())
: TRY(Process::current().working_directory().clone());
if (auto ret = Process::current().create_file_or_dir(AT_FDCWD, bind_path.data(), 0755 | S_IFSOCK); ret.is_error())
{
@ -245,6 +257,7 @@ namespace Kernel
return ret.release_error();
}
auto file = TRY(VirtualFileSystem::get().file_from_relative_path(
Process::current().root_file().inode,
parent_file,
Process::current().credentials(),
bind_path,
@ -252,10 +265,10 @@ namespace Kernel
));
SpinLockGuard _(s_bound_socket_lock);
if (s_bound_sockets.contains(file.canonical_path))
if (s_bound_sockets.contains(file.inode))
return BAN::Error::from_errno(EADDRINUSE);
TRY(s_bound_sockets.emplace(file.canonical_path, TRY(get_weak_ptr())));
m_bound_path = BAN::move(file.canonical_path);
TRY(s_bound_sockets.emplace(file.inode, TRY(get_weak_ptr())));
m_bound_file = BAN::move(file);
return {};
}
@ -354,14 +367,21 @@ namespace Kernel
}
else
{
BAN::String canonical_path;
BAN::RefPtr<Inode> target_inode;
if (!address)
{
auto& connectionless_info = m_info.get<ConnectionlessInfo>();
if (connectionless_info.peer_address.empty())
return BAN::Error::from_errno(EDESTADDRREQ);
TRY(canonical_path.append(connectionless_info.peer_address));
auto absolute_path = TRY(Process::current().absolute_path_of(connectionless_info.peer_address));
target_inode = TRY(VirtualFileSystem::get().file_from_absolute_path(
Process::current().root_file().inode,
Process::current().credentials(),
absolute_path,
O_RDWR
)).inode;
}
else
{
@ -372,17 +392,16 @@ namespace Kernel
return BAN::Error::from_errno(EAFNOSUPPORT);
auto absolute_path = TRY(Process::current().absolute_path_of(sockaddr_un.sun_path));
auto file = TRY(VirtualFileSystem::get().file_from_absolute_path(
target_inode = TRY(VirtualFileSystem::get().file_from_absolute_path(
Process::current().root_file().inode,
Process::current().credentials(),
absolute_path,
O_WRONLY
));
canonical_path = BAN::move(file.canonical_path);
)).inode;
}
SpinLockGuard _(s_bound_socket_lock);
auto it = s_bound_sockets.find(canonical_path);
auto it = s_bound_sockets.find(target_inode);
if (it == s_bound_sockets.end())
return BAN::Error::from_errno(EDESTADDRREQ);
auto target = it->value.lock();
@ -449,20 +468,11 @@ namespace Kernel
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;
}
}
sockaddr_un sa_un {
.sun_family = AF_UNIX,
.sun_path = {},
};
strcpy(sa_un.sun_path, connection->m_bound_file.canonical_path.data());
const size_t to_copy = BAN::Math::min<socklen_t>(sizeof(sockaddr_un), *address_len);
memcpy(address, &sa_un, to_copy);

View File

@ -77,7 +77,7 @@ namespace Kernel
BAN::ErrorOr<int> OpenFileDescriptorSet::open(BAN::StringView absolute_path, int flags)
{
return open(TRY(VirtualFileSystem::get().file_from_absolute_path(m_credentials, absolute_path, flags)), flags);
return open(TRY(VirtualFileSystem::get().file_from_absolute_path(Process::current().root_file().inode, m_credentials, absolute_path, flags)), flags);
}
struct SocketInfo

View File

@ -101,9 +101,10 @@ namespace Kernel
BAN::ErrorOr<Process*> Process::create_userspace(const Credentials& credentials, BAN::StringView path, BAN::Span<BAN::StringView> arguments)
{
auto* process = create_process(credentials, 0);
TRY(process->m_credentials.initialize_supplementary_groups());
process->m_working_directory = VirtualFileSystem::get().root_file();
process->m_root_file = VirtualFileSystem::get().root_file();
process->m_page_table = BAN::UniqPtr<PageTable>::adopt(MUST(PageTable::create_userspace()));
TRY(process->m_cmdline.emplace_back());
@ -119,7 +120,7 @@ namespace Kernel
auto executable_file = TRY(process->find_file(AT_FDCWD, path.data(), O_EXEC));
auto executable_inode = executable_file.inode;
auto executable = TRY(ELF::load_from_inode(executable_inode, process->m_credentials, process->page_table()));
auto executable = TRY(ELF::load_from_inode(process->m_root_file.inode, executable_inode, process->m_credentials, process->page_table()));
process->m_mapped_regions = BAN::move(executable.regions);
if (executable_inode->mode().mode & +Inode::Mode::ISUID)
@ -257,6 +258,16 @@ namespace Kernel
void Process::exit(int status, int signal)
{
bool expected = false;
if (!m_is_exiting.compare_exchange(expected, true))
{
Thread::current().on_exit();
ASSERT_NOT_REACHED();
}
const auto state = Processor::get_interrupt_state();
Processor::set_interrupt_state(InterruptState::Enabled);
if (m_parent)
{
Process* parent_process = nullptr;
@ -294,13 +305,18 @@ namespace Kernel
}
}
for (size_t i = 0; i < m_threads.size(); i++)
{
if (m_threads[i] == &Thread::current())
continue;
m_threads[i]->add_signal(SIGKILL);
LockGuard _(m_process_lock);
for (auto* thread : m_threads)
if (thread != &Thread::current())
ASSERT(thread->add_signal(SIGKILL));
}
while (m_threads.size() > 1)
Processor::yield();
Processor::set_interrupt_state(state);
Thread::current().on_exit();
ASSERT_NOT_REACHED();
@ -442,7 +458,7 @@ namespace Kernel
auto parent_file = TRY(find_relative_parent(fd, path));
auto file = path
? TRY(VirtualFileSystem::get().file_from_relative_path(parent_file, m_credentials, path, flags))
? TRY(VirtualFileSystem::get().file_from_relative_path(m_root_file.inode, parent_file, m_credentials, path, flags))
: BAN::move(parent_file);
return file;
@ -466,7 +482,7 @@ namespace Kernel
if (auto index = path_sv.rfind('/'); index.has_value())
{
parent = TRY(VirtualFileSystem::get().file_from_relative_path(relative_parent, m_credentials, path_sv.substring(0, index.value()), flags));
parent = TRY(VirtualFileSystem::get().file_from_relative_path(m_root_file.inode, relative_parent, m_credentials, path_sv.substring(0, index.value()), flags));
file_name = path_sv.substring(index.value() + 1);
}
else
@ -496,7 +512,7 @@ namespace Kernel
ASSERT(m_process_lock.is_locked());
if (path && path[0] == '/')
return VirtualFileSystem::get().root_file();
return TRY(m_root_file.clone());
if (fd == AT_FDCWD)
return TRY(m_working_directory.clone());
@ -507,7 +523,6 @@ namespace Kernel
BAN::ErrorOr<long> Process::sys_exit(int status)
{
ASSERT(this == &Process::current());
LockGuard _(m_process_lock);
exit(status, 0);
ASSERT_NOT_REACHED();
}
@ -569,6 +584,7 @@ namespace Kernel
}
auto working_directory = TRY(m_working_directory.clone());
auto root_file = TRY(m_root_file.clone());
BAN::Vector<BAN::String> cmdline;
TRY(cmdline.resize(m_cmdline.size()));
@ -591,6 +607,7 @@ namespace Kernel
Process* forked = create_process(m_credentials, m_pid, m_sid, m_pgrp);
forked->m_controlling_terminal = m_controlling_terminal;
forked->m_working_directory = BAN::move(working_directory);
forked->m_root_file = BAN::move(root_file);
forked->m_cmdline = BAN::move(cmdline);
forked->m_environ = BAN::move(environ);
forked->m_page_table = BAN::move(page_table);
@ -643,7 +660,7 @@ namespace Kernel
auto executable_file = TRY(find_file(AT_FDCWD, path, O_EXEC));
auto executable_inode = executable_file.inode;
auto executable = TRY(ELF::load_from_inode(executable_inode, m_credentials, *new_page_table));
auto executable = TRY(ELF::load_from_inode(m_root_file.inode, executable_inode, m_credentials, *new_page_table));
auto new_mapped_regions = BAN::move(executable.regions);
BAN::Vector<LibELF::AuxiliaryVector> auxiliary_vector;
@ -1031,7 +1048,7 @@ namespace Kernel
TRY(validate_string_access(path));
auto [parent, file_name] = TRY(find_parent_file(fd, path, O_RDONLY));
auto file_or_error = VirtualFileSystem::get().file_from_relative_path(parent, m_credentials, file_name, flags);
auto file_or_error = VirtualFileSystem::get().file_from_relative_path(m_root_file.inode, parent, m_credentials, file_name, flags);
VirtualFileSystem::File file;
if (file_or_error.is_error())
@ -1041,7 +1058,7 @@ namespace Kernel
// FIXME: There is a race condition between next two lines
TRY(parent.inode->create_file(file_name, (mode & 0777) | Inode::Mode::IFREG, m_credentials.euid(), m_credentials.egid()));
file = TRY(VirtualFileSystem::get().file_from_relative_path(parent, m_credentials, file_name, flags & ~O_RDWR));
file = TRY(VirtualFileSystem::get().file_from_relative_path(m_root_file.inode, parent, m_credentials, file_name, flags & ~O_RDWR));
}
else
{
@ -1122,7 +1139,7 @@ namespace Kernel
credentials.set_egid(credentials.rgid());
auto relative_parent = TRY(find_relative_parent(AT_FDCWD, path));
TRY(VirtualFileSystem::get().file_from_relative_path(relative_parent, credentials, path, flags));
TRY(VirtualFileSystem::get().file_from_relative_path(m_root_file.inode, relative_parent, credentials, path, flags));
return 0;
}
@ -1245,6 +1262,7 @@ namespace Kernel
flag = O_NOFOLLOW;
LockGuard _(m_process_lock);
TRY(validate_string_access(path));
auto inode = TRY(find_file(fd, path, flag)).inode;
@ -1267,6 +1285,7 @@ namespace Kernel
flag = O_NOFOLLOW;
LockGuard _(m_process_lock);
TRY(validate_string_access(path));
auto inode = TRY(find_file(fd, path, flag)).inode;
@ -2082,22 +2101,25 @@ namespace Kernel
BAN::ErrorOr<long> Process::sys_chdir(const char* path)
{
LockGuard _(m_process_lock);
TRY(validate_string_access(path));
auto file = TRY(find_file(AT_FDCWD, path, O_SEARCH));
m_working_directory = BAN::move(file);
m_working_directory = TRY(find_file(AT_FDCWD, path, O_SEARCH));
return 0;
}
BAN::ErrorOr<long> Process::sys_fchdir(int fildes)
{
LockGuard _(m_process_lock);
m_working_directory = TRY(m_open_file_descriptors.file_of(fildes));
return 0;
}
auto file = TRY(m_open_file_descriptors.file_of(fildes));
m_working_directory = BAN::move(file);
BAN::ErrorOr<long> Process::sys_chroot(const char* path)
{
LockGuard _(m_process_lock);
TRY(validate_string_access(path));
if (!m_credentials.is_superuser())
return BAN::Error::from_errno(EACCES);
m_root_file = TRY(find_file(AT_FDCWD, path, O_SEARCH));
return 0;
}
@ -2905,7 +2927,6 @@ namespace Kernel
m_credentials.set_euid(uid);
m_credentials.set_ruid(uid);
m_credentials.set_suid(uid);
TRY(m_credentials.initialize_supplementary_groups());
return 0;
}
@ -2914,7 +2935,6 @@ namespace Kernel
if (uid == m_credentials.ruid() || uid == m_credentials.suid())
{
m_credentials.set_euid(uid);
TRY(m_credentials.initialize_supplementary_groups());
return 0;
}
@ -2975,7 +2995,6 @@ namespace Kernel
if (uid == m_credentials.ruid() || uid == m_credentials.suid() || m_credentials.is_superuser())
{
m_credentials.set_euid(uid);
TRY(m_credentials.initialize_supplementary_groups());
return 0;
}
@ -3042,8 +3061,6 @@ namespace Kernel
if (euid != -1)
m_credentials.set_euid(euid);
TRY(m_credentials.initialize_supplementary_groups());
return 0;
}
@ -3191,6 +3208,28 @@ namespace Kernel
return BAN::Error::from_errno(error);
}
BAN::ErrorOr<long> Process::sys_getgroups(gid_t groups[], size_t count)
{
LockGuard _(m_process_lock);
TRY(validate_pointer_access(groups, count * sizeof(gid_t), true));
auto current = m_credentials.groups();
if (current.size() > count)
return BAN::Error::from_errno(EINVAL);
for (size_t i = 0; i < current.size(); i++)
groups[i] = current[i];
return current.size();
}
BAN::ErrorOr<long> Process::sys_setgroups(const gid_t groups[], size_t count)
{
LockGuard _(m_process_lock);
TRY(validate_pointer_access(groups, count * sizeof(gid_t), true));
if (!m_credentials.is_superuser())
return BAN::Error::from_errno(EPERM);
TRY(m_credentials.set_groups({ groups, count }));
return 0;
}
BAN::ErrorOr<BAN::String> Process::absolute_path_of(BAN::StringView path) const
{
LockGuard _(m_process_lock);

View File

@ -121,8 +121,8 @@ namespace Kernel
void TTY::keyboard_task(void*)
{
BAN::RefPtr<Inode> keyboard_inode;
if (auto ret = VirtualFileSystem::get().file_from_absolute_path({ 0, 0, 0, 0 }, "/dev/keyboard"_sv, O_RDONLY); !ret.is_error())
keyboard_inode = ret.value().inode;
if (auto ret = DevFileSystem::get().root_inode()->find_inode("keyboard"_sv); !ret.is_error())
keyboard_inode = ret.release_value();
else
{
dprintln("could not open keyboard device: {}", ret.error());

View File

@ -40,10 +40,9 @@ namespace Kernel
switch (m_speed_class)
{
case USB::SpeedClass::LowSpeed:
case USB::SpeedClass::FullSpeed:
m_endpoints[0].max_packet_size = 8;
is_ls_or_fs_device_on_hs_hub = m_info.parent_hub && (m_info.parent_hub->speed_class() == USB::SpeedClass::HighSpeed);
break;
case USB::SpeedClass::FullSpeed:
case USB::SpeedClass::HighSpeed:
m_endpoints[0].max_packet_size = 64;
break;
@ -53,6 +52,16 @@ namespace Kernel
default: ASSERT_NOT_REACHED();
}
switch (m_speed_class)
{
case USB::SpeedClass::LowSpeed:
case USB::SpeedClass::FullSpeed:
is_ls_or_fs_device_on_hs_hub = m_info.parent_hub && (m_info.parent_hub->speed_class() == USB::SpeedClass::HighSpeed);
break;
default:
break;
}
m_input_context = TRY(DMARegion::create(33 * context_size));
memset(reinterpret_cast<void*>(m_input_context->vaddr()), 0, m_input_context->size());

26
ports/SDL2_mixer/build.sh Executable file
View File

@ -0,0 +1,26 @@
#!/bin/bash ../install.sh
NAME='SDL2_mixer'
VERSION='2.8.1'
DOWNLOAD_URL="https://github.com/libsdl-org/SDL_mixer/releases/download/release-$VERSION/SDL2_mixer-$VERSION.tar.gz#cb760211b056bfe44f4a1e180cc7cb201137e4d1572f2002cc1be728efd22660"
DEPENDENCIES=('SDL2')
configure() {
$BANAN_CMAKE --fresh -S . -B build -G Ninja \
--toolchain="$BANAN_TOOLCHAIN_DIR/Toolchain.txt" \
-DCMAKE_INSTALL_PREFIX='/usr' \
-DCMAKE_BUILD_TYPE=Release \
-DSDL2MIXER_WAVPACK=OFF \
-DSDL2MIXER_MIDI=OFF \
-DSDL2MIXER_OPUS=OFF \
-DSDL2MIXER_MOD=OFF \
|| exit 1
}
build() {
$BANAN_CMAKE --build build || exit 1
}
install() {
$BANAN_CMAKE --install build || exit 1
}

View File

@ -3,7 +3,7 @@
NAME='binutils'
VERSION='2.44'
DOWNLOAD_URL="https://ftp.gnu.org/gnu/binutils/binutils-$VERSION.tar.gz#0cdd76777a0dfd3dd3a63f215f030208ddb91c2361d2bcc02acec0f1c16b6a2e"
DEPENDENCIES=('zlib')
DEPENDENCIES=('zlib' 'zstd')
MAKE_INSTALL_TARGETS=('install-strip')
CONFIGURE_OPTIONS=(
"--target=$BANAN_TOOLCHAIN_TRIPLE"
@ -16,6 +16,13 @@ CONFIGURE_OPTIONS=(
'--disable-werror'
)
pre_configure() {
unset PKG_CONFIG_DIR
unset PKG_CONFIG_SYSROOT_DIR
unset PKG_CONFIG_LIBDIR
unset PKG_CONFIG_PATH
}
post_install() {
# remove libtool files
rm -f $BANAN_SYSROOT/usr/lib/libbfd.la

View File

@ -2,20 +2,22 @@
NAME='doom'
VERSION='git'
DOWNLOAD_URL="https://github.com/ozkl/doomgeneric.git#613f870b6fa83ede448a247de5a2571092fa729d"
DOWNLOAD_URL="https://github.com/ozkl/doomgeneric.git#5041246e859052e2e258ca6edb4e1e9bbd98fcf5"
DEPENDENCIES=('SDL2' 'SDL2_mixer' 'timidity')
configure() {
make --directory doomgeneric clean
rm -rf doomgeneric/build
}
build() {
if [ ! -f ../doom1.wad ]; then
wget https://distro.ibiblio.org/slitaz/sources/packages/d/doom1.wad -O ../doom1.wad || exit 1
fi
make --directory doomgeneric --file Makefile.banan_os -j$(nproc) || exit 1
CFLAGS='-std=c11' make --directory doomgeneric --file Makefile.sdl CC="$CC" SDL_PATH="$BANAN_SYSROOT/usr/bin/" || exit 1
}
install() {
cp doomgeneric/build/doom "${BANAN_SYSROOT}/bin/" || exit 1
cp doomgeneric/doomgeneric "${BANAN_SYSROOT}/bin/doom" || exit 1
cp ../doom1.wad "$BANAN_SYSROOT/home/user/" || exit 1
}

View File

@ -1,224 +0,0 @@
From 0f37d9f2df042eb8ba021dd91b898c1f07d86b58 Mon Sep 17 00:00:00 2001
From: Bananymous <bananymousosq@gmail.com>
Date: Fri, 18 Oct 2024 03:44:10 +0300
Subject: [PATCH] Add support for banan-os
---
doomgeneric/Makefile.banan_os | 57 +++++++++++
doomgeneric/doomgeneric_banan_os.cpp | 138 +++++++++++++++++++++++++++
2 files changed, 200 insertions(+)
create mode 100644 doomgeneric/Makefile.banan_os
create mode 100644 doomgeneric/doomgeneric_banan_os.cpp
diff --git a/doomgeneric/Makefile.banan_os b/doomgeneric/Makefile.banan_os
new file mode 100644
index 0000000..0878148
--- /dev/null
+++ b/doomgeneric/Makefile.banan_os
@@ -0,0 +1,57 @@
+################################################################
+#
+# $Id:$
+#
+# $Log:$
+#
+
+ifeq ($(V),1)
+ VB=''
+else
+ VB=@
+endif
+
+CC=$(BANAN_ARCH)-pc-banan_os-gcc
+CXX=$(BANAN_ARCH)-pc-banan_os-g++
+CFLAGS+=-O3 -std=c11 -Wall -DNORMALUNIX -DLINUX -DSNDSERV -D_DEFAULT_SOURCE
+CXXFLAGS+=$(CFLAGS) --std=c++20
+LDFLAGS+=
+LIBS+=-lgui -linput -lstdc++
+
+# subdirectory for objects
+OBJDIR=build
+OUTPUT=$(OBJDIR)/doom
+
+SRC_DOOM = dummy.o am_map.o doomdef.o doomstat.o dstrings.o d_event.o d_items.o d_iwad.o d_loop.o d_main.o d_mode.o d_net.o f_finale.o f_wipe.o g_game.o hu_lib.o hu_stuff.o info.o i_cdmus.o i_endoom.o i_joystick.o i_scale.o i_sound.o i_system.o i_timer.o memio.o m_argv.o m_bbox.o m_cheat.o m_config.o m_controls.o m_fixed.o m_menu.o m_misc.o m_random.o p_ceilng.o p_doors.o p_enemy.o p_floor.o p_inter.o p_lights.o p_map.o p_maputl.o p_mobj.o p_plats.o p_pspr.o p_saveg.o p_setup.o p_sight.o p_spec.o p_switch.o p_telept.o p_tick.o p_user.o r_bsp.o r_data.o r_draw.o r_main.o r_plane.o r_segs.o r_sky.o r_things.o sha1.o sounds.o statdump.o st_lib.o st_stuff.o s_sound.o tables.o v_video.o wi_stuff.o w_checksum.o w_file.o w_main.o w_wad.o z_zone.o w_file_stdc.o i_input.o i_video.o doomgeneric.o doomgeneric_banan_os.o
+OBJS += $(addprefix $(OBJDIR)/, $(SRC_DOOM))
+
+all: $(OUTPUT)
+
+clean:
+ rm -rf $(OBJDIR)
+ rm -f $(OUTPUT)
+ rm -f $(OUTPUT).gdb
+ rm -f $(OUTPUT).map
+
+$(OUTPUT): $(OBJS)
+ @echo [Linking $@]
+ $(VB)$(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) \
+ -o $(OUTPUT) $(LIBS) -Wl,-Map,$(OUTPUT).map
+ @echo [Size]
+ -$(CROSS_COMPILE)size $(OUTPUT)
+
+$(OBJS): | $(OBJDIR)
+
+$(OBJDIR):
+ mkdir -p $(OBJDIR)
+
+$(OBJDIR)/%.o: %.c
+ @echo [Compiling $<]
+ $(VB)$(CC) $(CFLAGS) -c $< -o $@
+
+$(OBJDIR)/%.o: %.cpp
+ @echo [Compiling $<]
+ $(VB)$(CXX) $(CXXFLAGS) -c $< -o $@
+
+print:
+ @echo OBJS: $(OBJS)
\ No newline at end of file
diff --git a/doomgeneric/doomgeneric_banan_os.cpp b/doomgeneric/doomgeneric_banan_os.cpp
new file mode 100644
index 0000000..9161771
--- /dev/null
+++ b/doomgeneric/doomgeneric_banan_os.cpp
@@ -0,0 +1,139 @@
+extern "C"
+{
+#include "doomgeneric.h"
+#include "doomkeys.h"
+}
+
+#include <assert.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/banan-os.h>
+#include <sys/framebuffer.h>
+#include <sys/mman.h>
+#include <time.h>
+
+#include <LibGUI/Window.h>
+
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+
+static BAN::UniqPtr<LibGUI::Window> s_window;
+
+static constexpr size_t s_key_queue_size = 16;
+static unsigned short s_key_queue[s_key_queue_size];
+static size_t s_key_read_index = 0;
+static size_t s_key_write_index = 0;
+
+extern "C"
+{
+
+void DG_Init()
+{
+ s_window = MUST(LibGUI::Window::create(DOOMGENERIC_RESX, DOOMGENERIC_RESY, "DOOM"_sv));
+ s_window->set_key_event_callback(
+ [](LibGUI::EventPacket::KeyEvent::event_t event)
+ {
+ unsigned short doom_key = 0;
+ switch (event.key)
+ {
+ case LibInput::Key::Enter:
+ doom_key = KEY_ENTER;
+ break;
+ case LibInput::Key::Escape:
+ doom_key = KEY_ESCAPE;
+ break;
+ case LibInput::Key::ArrowLeft:
+ doom_key = KEY_LEFTARROW;
+ break;
+ case LibInput::Key::ArrowUp:
+ doom_key = KEY_UPARROW;
+ break;
+ case LibInput::Key::ArrowRight:
+ doom_key = KEY_RIGHTARROW;
+ break;
+ case LibInput::Key::ArrowDown:
+ doom_key = KEY_DOWNARROW;
+ break;
+ case LibInput::Key::LeftCtrl:
+ case LibInput::Key::RightCtrl:
+ doom_key = KEY_FIRE;
+ break;
+ case LibInput::Key::Space:
+ doom_key = KEY_USE;
+ break;
+ case LibInput::Key::RightShift:
+ doom_key = KEY_RSHIFT;
+ break;
+ default:
+ {
+ const char* utf8 = LibInput::key_to_utf8(event.key, event.modifier);
+ if (utf8 && strlen(utf8) == 1 && isalpha(*utf8))
+ doom_key = tolower(*utf8);
+ }
+ }
+
+ if (doom_key == 0)
+ return;
+
+ s_key_queue[s_key_write_index] = doom_key | (int)event.pressed() << 8;
+ s_key_write_index = (s_key_write_index + 1) % s_key_queue_size;
+ }
+ );
+}
+
+void DG_DrawFrame()
+{
+ auto& texture = s_window->texture();
+ for (size_t y = 0; y < DOOMGENERIC_RESY; y++)
+ for (size_t x = 0; x < DOOMGENERIC_RESX; x++)
+ texture.set_pixel(x, y, 0xFF000000 | DG_ScreenBuffer[y * DOOMGENERIC_RESX + x]);
+ s_window->invalidate();
+ s_window->poll_events();
+}
+
+void DG_SleepMs(uint32_t ms)
+{
+ struct timespec ts;
+ ts.tv_sec = ms / 1000;
+ ts.tv_nsec = (ms % 1000) * 1000000;
+ nanosleep(&ts, NULL);
+}
+
+uint32_t DG_GetTicksMs()
+{
+ struct timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ return (ts.tv_sec * 1000) + (ts.tv_nsec / 1000000);
+}
+
+int DG_GetKey(int* pressed, unsigned char* doomKey)
+{
+ if (s_key_read_index == s_key_write_index)
+ return 0;
+
+ unsigned short key_data = s_key_queue[s_key_read_index];
+ s_key_read_index = (s_key_read_index + 1) % s_key_queue_size;
+
+ *pressed = key_data >> 8;
+ *doomKey = key_data & 0xFF;
+
+ return 1;
+}
+
+void DG_SetWindowTitle(const char* title)
+{
+ (void)title;
+}
+
+int main(int argc, char** argv)
+{
+ doomgeneric_Create(argc, argv);
+
+ for (;;)
+ doomgeneric_Tick();
+
+ return 0;
+}
+
+}
--
2.45.2

View File

@ -0,0 +1,27 @@
From a4e6b807885a7cb4a507b4e114743aa0004376ad Mon Sep 17 00:00:00 2001
From: Oskari Alaranta <oskari.alaranta@bananymous.com>
Date: Sun, 10 Aug 2025 01:57:38 +0300
Subject: [PATCH] add support for custom SDL path
---
doomgeneric/Makefile.sdl | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/doomgeneric/Makefile.sdl b/doomgeneric/Makefile.sdl
index 38402da..8c2f84e 100644
--- a/doomgeneric/Makefile.sdl
+++ b/doomgeneric/Makefile.sdl
@@ -12,8 +12,8 @@ else
endif
-SDL_CFLAGS = `sdl2-config --cflags`
-SDL_LIBS = `sdl2-config --cflags --libs` -lSDL2_mixer
+SDL_CFLAGS = `$(SDL_PATH)sdl2-config --cflags`
+SDL_LIBS = `$(SDL_PATH)sdl2-config --cflags --libs` -lSDL2_mixer
CC=clang # gcc or g++
--
2.50.1

View File

@ -1,34 +0,0 @@
From c28fd460c15a3d4cc5aac35d1ea5744f1722cab4 Mon Sep 17 00:00:00 2001
From: Bananymous <bananymousosq@gmail.com>
Date: Wed, 3 Apr 2024 21:39:22 +0300
Subject: [PATCH] Call exit() on I_Quit() and I_Error()
---
doomgeneric/i_system.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/doomgeneric/i_system.c b/doomgeneric/i_system.c
index 5d00091..bfb204f 100644
--- a/doomgeneric/i_system.c
+++ b/doomgeneric/i_system.c
@@ -257,6 +257,8 @@ void I_Quit (void)
entry = entry->next;
}
+ exit(0);
+
#if ORIGCODE
SDL_Quit();
@@ -403,6 +405,8 @@ void I_Error (char *error, ...)
entry = entry->next;
}
+ exit(1);
+
exit_gui_popup = !M_ParmExists("-nogui");
// Pop up a GUI dialog box to show the error message, if the
--
2.47.1

View File

@ -0,0 +1,25 @@
From fd5308b45021ca18e7703d810e2e2ba86c174669 Mon Sep 17 00:00:00 2001
From: Oskari Alaranta <oskari.alaranta@bananymous.com>
Date: Sun, 10 Aug 2025 01:56:26 +0300
Subject: [PATCH] set timidity config path
---
doomgeneric/i_sdlmusic.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/doomgeneric/i_sdlmusic.c b/doomgeneric/i_sdlmusic.c
index f56392f..80b9021 100644
--- a/doomgeneric/i_sdlmusic.c
+++ b/doomgeneric/i_sdlmusic.c
@@ -110,7 +110,7 @@ static boolean sdl_was_initialized = false;
static boolean musicpaused = false;
static int current_music_volume;
-char *timidity_cfg_path = "";
+char *timidity_cfg_path = "/etc/timidity.cfg";
static char *temp_timidity_cfg = NULL;
--
2.50.1

View File

@ -1,48 +0,0 @@
From 70c235938f0b64c4f08a478d3107e5254ad904c6 Mon Sep 17 00:00:00 2001
From: Bananymous <bananymousosq@gmail.com>
Date: Wed, 27 Nov 2024 13:28:42 +0200
Subject: [PATCH] Remove unnecessary copy from framebuffer
---
doomgeneric/doomgeneric.c | 2 --
doomgeneric/doomgeneric_banan_os.cpp | 6 +++---
2 files changed, 3 insertions(+), 5 deletions(-)
diff --git a/doomgeneric/doomgeneric.c b/doomgeneric/doomgeneric.c
index 782a7e7..f4eb63e 100644
--- a/doomgeneric/doomgeneric.c
+++ b/doomgeneric/doomgeneric.c
@@ -18,8 +18,6 @@ void doomgeneric_Create(int argc, char **argv)
M_FindResponseFile();
- DG_ScreenBuffer = malloc(DOOMGENERIC_RESX * DOOMGENERIC_RESY * 4);
-
DG_Init();
D_DoomMain ();
diff --git a/doomgeneric/doomgeneric_banan_os.cpp b/doomgeneric/doomgeneric_banan_os.cpp
index d00c30d..9d13b43 100644
--- a/doomgeneric/doomgeneric_banan_os.cpp
+++ b/doomgeneric/doomgeneric_banan_os.cpp
@@ -80,14 +80,13 @@ void DG_Init()
s_key_write_index = (s_key_write_index + 1) % s_key_queue_size;
}
);
+
+ ASSERT(DG_ScreenBuffer == nullptr);
+ DG_ScreenBuffer = s_window->texture().pixels().data();
}
void DG_DrawFrame()
{
- auto& texture = s_window->texture();
- for (size_t y = 0; y < DOOMGENERIC_RESY; y++)
- for (size_t x = 0; x < DOOMGENERIC_RESX; x++)
- texture.set_pixel(x, y, 0xFF000000 | DG_ScreenBuffer[y * DOOMGENERIC_RESX + x]);
s_window->invalidate();
s_window->poll_events();
}
--
2.47.1

View File

@ -2,10 +2,11 @@
NAME='quake2'
VERSION='git'
DOWNLOAD_URL="https://github.com/ozkl/quake2generic.git#a967e4f567a98941326fc7fe76eee5e52a04a633"
DOWNLOAD_URL="https://github.com/ozkl/quake2generic.git#50190797664fd42fc1b0266150c54f76f92bfa15"
DEPENDENCIES=('SDL2' 'SDL2_mixer')
configure() {
:
make clean
}
build() {
@ -24,11 +25,13 @@ build() {
echo "File hash does not match" >&2
exit 1
fi
make -j$(nproc) || exit 1
cflags='-Dstricmp=strcasecmp -Wno-incompatible-pointer-types'
make CC="$CC" BASE_CFLAGS="$cflags" SDL_PATH="$BANAN_SYSROOT/usr/bin/" -j$(nproc) || exit 1
}
install() {
cp build/quake2 "${BANAN_SYSROOT}/bin/" || exit 1
cp -v build/quake2-soft "${BANAN_SYSROOT}/bin/quake2" || exit 1
baseq2_tar=$(realpath ../baseq2.tar.gz || exit 1)
cd "$BANAN_SYSROOT/home/user/"

View File

@ -1,482 +0,0 @@
From f900c2967edc684334b663e522aeec79e8fee10d Mon Sep 17 00:00:00 2001
From: Bananymous <bananymousosq@gmail.com>
Date: Thu, 14 Nov 2024 12:33:39 +0200
Subject: [PATCH] Add support for banan-os
---
Makefile | 106 +++-------------
port_soft_banan_os.cpp | 277 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 295 insertions(+), 88 deletions(-)
create mode 100644 port_soft_banan_os.cpp
diff --git a/Makefile b/Makefile
index 46142df..4437418 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,3 @@
-
-SDL_CFLAGS = `sdl2-config --cflags`
-SDL_LIBS = `sdl2-config --cflags --libs` -lSDL2_mixer
-
MOUNT_DIR=.
BUILDDIR=build
@@ -18,21 +14,19 @@ GAME_DIR=$(MOUNT_DIR)/game
CTF_DIR=$(MOUNT_DIR)/ctf
XATRIX_DIR=$(MOUNT_DIR)/xatrix
-CC=clang #emcc
+CC=$(BANAN_ARCH)-banan_os-gcc
BASE_CFLAGS=-Dstricmp=strcasecmp
+CXX=$(BANAN_ARCH)-banan_os-g++
+CXXFLAGS=--std=c++20
RELEASE_CFLAGS=$(BASE_CFLAGS) -O6 -ffast-math -funroll-loops \
-fomit-frame-pointer -fexpensive-optimizations -malign-loops=2 \
-malign-jumps=2 -malign-functions=2
DEBUG_CFLAGS=$(BASE_CFLAGS) -g
-LDFLAGS=-ldl -lm
-XCFLAGS=-I/opt/X11/include
-
-GLLDFLAGS=-L/usr/X11/lib -L/usr/local/lib \
- $(SDL_LIBS) -lGL
-GLCFLAGS=$(SDL_CFLAGS)
+LDFLAGS=-lgui -linput
+XCFLAGS=
SHLIBEXT=so
@@ -43,6 +37,10 @@ DO_CC=$(CC) $(CFLAGS) -o $@ -c $<
DO_SHLIB_CC=$(CC) $(CFLAGS) $(SHLIBCFLAGS) -o $@ -c $<
DO_GL_SHLIB_CC=$(CC) $(CFLAGS) $(SHLIBCFLAGS) $(GLCFLAGS) $(XCFLAGS) -o $@ -c $<
+DO_CXX=$(CXX) $(CFLAGS) $(CXXFLAGS) -o $@ -c $<
+DO_SHLIB_CXX=$(CXX) $(CFLAGS) $(CXXFLAGS) $(SHLIBCFLAGS) -o $@ -c $<
+DO_GL_SHLIB_CXX=$(CXX) $(CFLAGS) $(CXXFLAGS) $(SHLIBCFLAGS) $(GLCFLAGS) $(XCFLAGS) -o $@ -c $<
+
#############################################################################
# SETUP AND BUILD
#############################################################################
@@ -61,14 +59,12 @@ createdirs:
@-mkdir -p $(BUILDDIR) \
$(BUILDDIR)/client \
$(BUILDDIR)/ref_soft \
- $(BUILDDIR)/ref_softsdl \
- $(BUILDDIR)/ref_gl \
$(BUILDDIR)/net \
$(BUILDDIR)/sound \
$(BUILDDIR)/game
-TARGETS: $(BUILDDIR)/quake2-soft $(BUILDDIR)/quake2-gl
+TARGETS: $(BUILDDIR)/quake2
#############################################################################
# CLIENT/SERVER
@@ -122,7 +118,7 @@ QUAKE2_OBJS = \
\
$(BUILDDIR)/client/pmove.o \
\
- $(BUILDDIR)/net/net_unix.o \
+ $(BUILDDIR)/net/net_loopback.o \
\
$(BUILDDIR)/sound/snddma_null.o \
\
@@ -200,38 +196,11 @@ REF_SOFT_OBJS = \
$(BUILDDIR)/ref_soft/r_rast.o \
$(BUILDDIR)/ref_soft/r_scan.o \
$(BUILDDIR)/ref_soft/r_sprite.o \
- $(BUILDDIR)/ref_soft/r_surf.o
-
-
-REF_SOFT_SDL_OBJS = \
- $(BUILDDIR)/ref_soft/port_soft_sdl.o
-
-
-#############################################################################
-# REF_GL
-#############################################################################
-
-REF_GL_OBJS = \
- $(BUILDDIR)/ref_gl/gl_draw.o \
- $(BUILDDIR)/ref_gl/gl_image.o \
- $(BUILDDIR)/ref_gl/gl_light.o \
- $(BUILDDIR)/ref_gl/gl_mesh.o \
- $(BUILDDIR)/ref_gl/gl_model.o \
- $(BUILDDIR)/ref_gl/gl_rmain.o \
- $(BUILDDIR)/ref_gl/gl_rmisc.o \
- $(BUILDDIR)/ref_gl/gl_rsurf.o \
- $(BUILDDIR)/ref_gl/gl_warp.o \
- \
- $(BUILDDIR)/ref_gl/qgl_system.o \
- $(BUILDDIR)/ref_gl/port_gl_sdl.o
-
-
-$(BUILDDIR)/quake2-soft : $(QUAKE2_OBJS) $(GAME_OBJS) $(REF_SOFT_OBJS) $(REF_SOFT_SDL_OBJS)
- $(CC) $(CFLAGS) -o $@ $(QUAKE2_OBJS) $(GAME_OBJS) $(REF_SOFT_OBJS) $(REF_SOFT_SDL_OBJS) $(LDFLAGS) $(GLLDFLAGS)
-
-$(BUILDDIR)/quake2-gl : $(QUAKE2_OBJS) $(GAME_OBJS) $(REF_GL_OBJS)
- $(CC) $(CFLAGS) -o $@ $(QUAKE2_OBJS) $(GAME_OBJS) $(REF_GL_OBJS) $(LDFLAGS) $(GLLDFLAGS)
+ $(BUILDDIR)/ref_soft/r_surf.o \
+ $(BUILDDIR)/ref_soft/port_soft_banan_os.o
+$(BUILDDIR)/quake2 : $(QUAKE2_OBJS) $(GAME_OBJS) $(REF_SOFT_OBJS)
+ $(CC) $(CFLAGS) -o $@ $(QUAKE2_OBJS) $(GAME_OBJS) $(REF_SOFT_OBJS) $(LDFLAGS)
$(BUILDDIR)/client/cl_cin.o : $(CLIENT_DIR)/cl_cin.c
$(DO_CC)
@@ -362,7 +331,7 @@ $(BUILDDIR)/client/q_system.o : $(OTHER_DIR)/q_system.c
$(BUILDDIR)/client/glob.o : $(OTHER_DIR)/glob.c
$(DO_CC)
-$(BUILDDIR)/net/net_unix.o : $(NET_DIR)/net_unix.c
+$(BUILDDIR)/net/net_loopback.o : $(NET_DIR)/net_loopback.c
$(DO_CC)
$(BUILDDIR)/port_platform_unix.o : $(MOUNT_DIR)/port_platform_unix.c
@@ -689,45 +658,8 @@ $(BUILDDIR)/ref_soft/r_sprite.o : $(REF_SOFT_DIR)/r_sprite.c
$(BUILDDIR)/ref_soft/r_surf.o : $(REF_SOFT_DIR)/r_surf.c
$(DO_GL_SHLIB_CC)
-$(BUILDDIR)/ref_soft/port_soft_sdl.o : $(MOUNT_DIR)/port_soft_sdl.c
- $(DO_GL_SHLIB_CC)
-
-#############################################################################
-# REF_GL
-#############################################################################
-
-$(BUILDDIR)/ref_gl/gl_draw.o : $(REF_GL_DIR)/gl_draw.c
- $(DO_GL_SHLIB_CC)
-
-$(BUILDDIR)/ref_gl/gl_image.o : $(REF_GL_DIR)/gl_image.c
- $(DO_GL_SHLIB_CC)
-
-$(BUILDDIR)/ref_gl/gl_light.o : $(REF_GL_DIR)/gl_light.c
- $(DO_GL_SHLIB_CC)
-
-$(BUILDDIR)/ref_gl/gl_mesh.o : $(REF_GL_DIR)/gl_mesh.c
- $(DO_GL_SHLIB_CC)
-
-$(BUILDDIR)/ref_gl/gl_model.o : $(REF_GL_DIR)/gl_model.c
- $(DO_GL_SHLIB_CC)
-
-$(BUILDDIR)/ref_gl/gl_rmain.o : $(REF_GL_DIR)/gl_rmain.c
- $(DO_GL_SHLIB_CC)
-
-$(BUILDDIR)/ref_gl/gl_rmisc.o : $(REF_GL_DIR)/gl_rmisc.c
- $(DO_GL_SHLIB_CC)
-
-$(BUILDDIR)/ref_gl/gl_rsurf.o : $(REF_GL_DIR)/gl_rsurf.c
- $(DO_GL_SHLIB_CC)
-
-$(BUILDDIR)/ref_gl/gl_warp.o : $(REF_GL_DIR)/gl_warp.c
- $(DO_GL_SHLIB_CC)
-
-$(BUILDDIR)/ref_gl/qgl_system.o : $(REF_GL_DIR)/qgl_system.c
- $(DO_GL_SHLIB_CC)
-
-$(BUILDDIR)/ref_gl/port_gl_sdl.o : $(MOUNT_DIR)/port_gl_sdl.c
- $(DO_GL_SHLIB_CC)
+$(BUILDDIR)/ref_soft/port_soft_banan_os.o : $(MOUNT_DIR)/port_soft_banan_os.cpp
+ $(DO_GL_SHLIB_CXX)
#############################################################################
@@ -738,8 +670,6 @@ clean:
-rm -rf \
$(BUILDDIR)/client \
$(BUILDDIR)/ref_soft \
- $(BUILDDIR)/ref_softsdl \
- $(BUILDDIR)/ref_gl \
$(BUILDDIR)/game \
$(BUILDDIR)/net \
$(BUILDDIR)/sound \
diff --git a/port_soft_banan_os.cpp b/port_soft_banan_os.cpp
new file mode 100644
index 0000000..c7d7e16
--- /dev/null
+++ b/port_soft_banan_os.cpp
@@ -0,0 +1,278 @@
+#include <LibGUI/Window.h>
+#include <LibInput/KeyEvent.h>
+#include <LibInput/MouseEvent.h>
+#include <LibImage/Image.h>
+
+#include <BAN/Debug.h>
+
+extern "C" {
+
+#include "ref_soft/r_local.h"
+#include "client/keys.h"
+
+#include "quake2.h"
+
+static LibImage::Image::Color s_palette[256];
+
+static int s_mouse_dx { 0 };
+static int s_mouse_dy { 0 };
+static bool s_relative_mouse { false };
+
+static BAN::Vector<uint8_t> s_buffer;
+static BAN::UniqPtr<LibGUI::Window> s_window;
+static bool s_is_fullscreen { false };
+
+static int key_to_quake_key(LibInput::Key key)
+{
+ using namespace LibInput;
+
+ switch (key)
+ {
+ case Key::PageUp: return K_PGUP;
+ case Key::PageDown: return K_PGDN;
+ case Key::Home: return K_HOME;
+ case Key::End: return K_END;
+ case Key::ArrowLeft: return K_LEFTARROW;
+ case Key::ArrowRight: return K_RIGHTARROW;
+ case Key::ArrowDown: return K_DOWNARROW;
+ case Key::ArrowUp: return K_UPARROW;
+ case Key::Escape: return K_ESCAPE;
+ case Key::Enter: return K_ENTER;
+ case Key::Tab: return K_TAB;
+ case Key::F1: return K_F1;
+ case Key::F2: return K_F2;
+ case Key::F3: return K_F3;
+ case Key::F4: return K_F4;
+ case Key::F5: return K_F5;
+ case Key::F6: return K_F6;
+ case Key::F7: return K_F7;
+ case Key::F8: return K_F8;
+ case Key::F9: return K_F9;
+ case Key::F10: return K_F10;
+ case Key::F11: return K_F11;
+ case Key::F12: return K_F12;
+ case Key::Backspace: return K_BACKSPACE;
+ case Key::Delete: return K_DEL;
+ case Key::LeftShift:
+ case Key::RightShift: return K_SHIFT;
+ case Key::LeftCtrl:
+ case Key::RightCtrl: return K_CTRL;
+ case Key::LeftAlt:
+ case Key::RightAlt: return K_ALT;
+ case Key::Insert: return K_INS;
+ default:
+ if (const char* ascii = key_to_utf8(key, 0); ascii && strlen(ascii) == 1)
+ return *ascii;
+ break;
+ }
+
+ return 0;
+}
+
+static int button_to_quake_button(LibInput::MouseButton button)
+{
+ using namespace LibInput;
+
+ switch (button)
+ {
+ case LibInput::MouseButton::Left: return K_MOUSE1;
+ case LibInput::MouseButton::Right: return K_MOUSE2;
+ case LibInput::MouseButton::Middle: return K_MOUSE3;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static void create_window(uint32_t width, uint32_t height)
+{
+ ASSERT(!s_window);
+ s_window = MUST(LibGUI::Window::create(width, height, "Quake2"_sv));
+
+ s_window->set_mouse_move_event_callback(
+ [](auto event)
+ {
+ if (!s_relative_mouse)
+ return;
+ s_mouse_dx += event.x;
+ s_mouse_dy += event.y;
+ }
+ );
+
+ s_window->set_mouse_button_event_callback(
+ [](auto event)
+ {
+ if (int button = button_to_quake_button(event.button))
+ Quake2_SendKey(button, event.pressed);
+ }
+ );
+
+ s_window->set_key_event_callback(
+ [](auto event)
+ {
+ if (int key = key_to_quake_key(event.key))
+ Quake2_SendKey(key, event.pressed());
+ }
+ );
+
+ s_window->set_close_window_event_callback(
+ []()
+ {
+ char command[] = "quit";
+ ri.Cmd_ExecuteText(EXEC_NOW, command);
+ }
+ );
+}
+
+rserr_t SWimp_SetMode(int* pwidth, int* pheight, int mode, qboolean fullscreen)
+{
+ int width, height;
+
+ if (!ri.Vid_GetModeInfo(&width, &height, mode))
+ return rserr_invalid_mode;
+
+ if (!s_window)
+ create_window(width, height);
+ else if (s_window->width() != width || s_window->height() != height)
+ {
+ s_window->request_resize(width, height);
+
+ bool resized { false };
+ s_window->set_resize_window_event_callback([&]() { resized = true; });
+ while (!resized)
+ s_window->poll_events();
+ s_window->set_resize_window_event_callback({});
+
+ ASSERT(s_window->width() == width && s_window->height() == height);
+ }
+
+ if (s_is_fullscreen != fullscreen)
+ {
+ s_is_fullscreen = fullscreen;
+ s_window->set_fullscreen(fullscreen);
+ }
+
+ MUST(s_buffer.resize(s_window->width() * s_window->height()));
+ vid.rowbytes = s_window->width();
+ vid.buffer = s_buffer.data();
+
+ *pwidth = s_window->width();
+ *pheight = s_window->height();
+
+ ri.Vid_NewWindow(s_window->width(), s_window->height());
+
+ return rserr_ok;
+}
+
+void SWimp_Shutdown(void)
+{
+}
+
+int SWimp_Init(void* hInstance, void* wndProc)
+{
+ return true;
+}
+
+static qboolean SWimp_InitGraphics(qboolean fullscreen)
+{
+ return rserr_ok;
+}
+
+void SWimp_SetPalette(const unsigned char* palette)
+{
+ for (int i = 0; i < 256; i++)
+ {
+ s_palette[i].r = *palette++;
+ s_palette[i].g = *palette++;
+ s_palette[i].b = *palette++;
+ s_palette[i].a = *palette++;
+ }
+}
+
+void SWimp_BeginFrame(float camera_seperation)
+{
+}
+
+void SWimp_EndFrame(void)
+{
+ auto& texture = s_window->texture();
+ const uint32_t width = s_window->width();
+ const uint32_t height = s_window->height();
+ for (int y = 0; y < height; y++)
+ for (int x = 0; x < width; x++)
+ texture.set_pixel(x, y, s_palette[s_buffer[y * width + x]].as_argb());
+ s_window->invalidate();
+}
+
+void SWimp_AppActivate(qboolean active)
+{
+}
+
+int QG_Milliseconds(void)
+{
+ struct timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ return (ts.tv_sec * 1'000) + (ts.tv_nsec / 1'000'000);
+}
+
+void QG_GetMouseDiff(int* dx, int* dy)
+{
+ *dx = s_mouse_dx;
+ s_mouse_dx = 0;
+
+ *dy = s_mouse_dy;
+ s_mouse_dy = 0;
+}
+
+void QG_CaptureMouse(void)
+{
+ s_relative_mouse = true;
+ s_window->set_mouse_capture(true);
+}
+
+void QG_ReleaseMouse(void)
+{
+ s_relative_mouse = false;
+ s_window->set_mouse_capture(false);
+}
+
+static uint64_t get_current_ns()
+{
+ timespec last_ts;
+ clock_gettime(CLOCK_MONOTONIC, &last_ts);
+ return (uint64_t)last_ts.tv_sec * 1'000'000'000 + last_ts.tv_nsec;
+}
+
+int main(int argc, char** argv)
+{
+ Quake2_Init(argc, argv);
+
+ uint64_t last_ns = get_current_ns();
+ for (;;)
+ {
+ s_window->poll_events();
+
+ const uint64_t current_ns = get_current_ns();
+ uint64_t duration_ns = current_ns - last_ns;
+
+ if (duration_ns < 1'000'000)
+ {
+ timespec sleep_ts {
+ .tv_sec = 0,
+ .tv_nsec = (long)(1'000'000 - duration_ns)
+ };
+ while (nanosleep(&sleep_ts, &sleep_ts))
+ continue;
+ duration_ns = get_current_ns() - last_ns;
+ }
+
+ Quake2_Frame(duration_ns / 1'000'000);
+
+ last_ns = current_ns;
+ }
+
+ return 0;
+}
+
+}
--
2.47.0

View File

@ -0,0 +1,52 @@
From fd08d90bb7ee8388a9e005bae23edcccbfc73dbb Mon Sep 17 00:00:00 2001
From: Oskari Alaranta <oskari.alaranta@bananymous.com>
Date: Sun, 10 Aug 2025 19:52:20 +0300
Subject: [PATCH] add support for custom SDL path and add sound support
---
Makefile | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/Makefile b/Makefile
index 8edbffa..de2f605 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
-SDL_CFLAGS = `sdl2-config --cflags`
-SDL_LIBS = `sdl2-config --cflags --libs` -lSDL2_mixer
+SDL_CFLAGS = `$(SDL_PATH)sdl2-config --cflags`
+SDL_LIBS = `$(SDL_PATH)sdl2-config --cflags --libs` -lSDL2_mixer
MOUNT_DIR=.
@@ -124,7 +124,7 @@ QUAKE2_OBJS = \
\
$(BUILDDIR)/net/net_unix.o \
\
- $(BUILDDIR)/sound/snddma_null.o \
+ $(BUILDDIR)/sound/snd_sdl.o \
\
$(BUILDDIR)/port_platform_unix.o
@@ -353,7 +353,7 @@ $(BUILDDIR)/client/vid_menu.o : $(OTHER_DIR)/vid_menu.c
$(BUILDDIR)/client/vid_lib.o : $(OTHER_DIR)/vid_lib.c
$(DO_CC)
-$(BUILDDIR)/client/snddma_null.o : $(NULL_DIR)/snddma_null.c
+$(BUILDDIR)/client/snd_sdl.o : $(NULL_DIR)/snd_sdl.c
$(DO_CC)
$(BUILDDIR)/client/q_system.o : $(OTHER_DIR)/q_system.c
@@ -368,7 +368,7 @@ $(BUILDDIR)/net/net_unix.o : $(NET_DIR)/net_unix.c
$(BUILDDIR)/port_platform_unix.o : $(MOUNT_DIR)/port_platform_unix.c
$(DO_CC)
-$(BUILDDIR)/sound/snddma_null.o : $(SOUND_DIR)/snddma_null.c
+$(BUILDDIR)/sound/snd_sdl.o : $(SOUND_DIR)/snd_sdl.c
$(DO_GL_SHLIB_CC)
--
2.50.1

View File

@ -0,0 +1,42 @@
From fbdf3e7c40c1de83a2361bb904d8dbd3464ccebd Mon Sep 17 00:00:00 2001
From: Oskari Alaranta <oskari.alaranta@bananymous.com>
Date: Sun, 10 Aug 2025 19:54:38 +0300
Subject: [PATCH 2/2] fix socket creation
---
net/net_unix.c | 10 +---------
1 file changed, 1 insertion(+), 9 deletions(-)
diff --git a/net/net_unix.c b/net/net_unix.c
index a92e57c..f297dff 100644
--- a/net/net_unix.c
+++ b/net/net_unix.c
@@ -451,24 +451,16 @@ int NET_Socket (char *net_interface, int port)
qboolean _true = true;
int i = 1;
- if ((newsocket = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
+ if ((newsocket = socket (PF_INET, SOCK_DGRAM | SOCK_NONBLOCK, IPPROTO_UDP)) == -1)
{
Com_Printf ("ERROR: UDP_OpenSocket: socket:", NET_ErrorString());
return 0;
}
- // make it non-blocking
- if (ioctl (newsocket, FIONBIO, &_true) == -1)
- {
- Com_Printf ("ERROR: UDP_OpenSocket: ioctl FIONBIO:%s\n", NET_ErrorString());
- return 0;
- }
-
// make it broadcast capable
if (setsockopt(newsocket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i)) == -1)
{
Com_Printf ("ERROR: UDP_OpenSocket: setsockopt SO_BROADCAST:%s\n", NET_ErrorString());
- return 0;
}
if (!net_interface || !net_interface[0] || !stricmp(net_interface, "localhost"))
--
2.50.1

31
ports/timidity/build.sh Executable file
View File

@ -0,0 +1,31 @@
#!/bin/bash ../install.sh
NAME='timidity'
VERSION='2.15.0'
DOWNLOAD_URL="https://sourceforge.net/projects/timidity/files/TiMidity++/TiMidity++-$VERSION/TiMidity++-$VERSION.tar.gz#0b6109a3c64604c8851cd9bb4cbafc014a4e13b0025f597e586d9742388f6fb7"
TAR_CONTENT="TiMidity++-$VERSION"
CONFIG_SUB=('autoconf/config.sub')
CONFIGURE_OPTIONS=(
'--without-x'
'lib_cv_va_copy=y'
'lib_cv___va_copy=n'
'lib_cv_va_val_copy=n'
'CFLAGS=-std=c11'
)
pre_configure() {
unset CC CXX LD
}
post_install() {
if [ ! -f ../eawpats.zip ]; then
wget https://www.quaddicted.com/files/idgames/sounds/eawpats.zip -O ../eawpats.zip || exit 1
fi
eawpats_dir="/usr/share/eawpats"
mkdir -p "$BANAN_SYSROOT/$eawpats_dir"
unzip -qod "$BANAN_SYSROOT/$eawpats_dir" ../eawpats.zip
cp "$BANAN_SYSROOT/$eawpats_dir/timidity.cfg" "$BANAN_SYSROOT/etc/"
sed -i "s|^dir .*$|dir $eawpats_dir|g" "$BANAN_SYSROOT/etc/timidity.cfg"
}

View File

@ -3,13 +3,15 @@
NAME='tinygb'
VERSION='git'
DOWNLOAD_URL="https://github.com/jewelcodes/tinygb.git#57fdaff675a6b5b963b2b6624868d9698eabe375"
DEPENDENCIES=('SDL2')
configure() {
make -f Makefile.banan_os clean
sed -i "s|shell sdl2-config|shell $BANAN_SYSROOT/usr/bin/sdl2-config|g" Makefile
make clean
}
build() {
make -f Makefile.banan_os -j$(nproc) || exit 1
make CC="$CC" LD="$CC" || exit 1
}
install() {

View File

@ -1,420 +0,0 @@
From 7f7c6402e384591bca63021aa97d60a8107de88d Mon Sep 17 00:00:00 2001
From: Bananymous <bananymousosq@gmail.com>
Date: Mon, 5 May 2025 00:59:03 +0300
Subject: [PATCH] Add support for banan-os
---
Makefile.banan_os | 28 +++
src/platform/banan-os/main.cpp | 362 +++++++++++++++++++++++++++++++++
2 files changed, 390 insertions(+)
create mode 100644 Makefile.banan_os
create mode 100644 src/platform/banan-os/main.cpp
diff --git a/Makefile.banan_os b/Makefile.banan_os
new file mode 100644
index 0000000..22e191e
--- /dev/null
+++ b/Makefile.banan_os
@@ -0,0 +1,28 @@
+CC = $(BANAN_ARCH)-banan_os-gcc
+CXX = $(BANAN_ARCH)-banan_os-g++
+LD = $(BANAN_ARCH)-banan_os-gcc
+
+CFLAGS = -c -O2 -Isrc/include -Wall
+CXXFLAGS = --std=c++20
+LDFLAGS = -O2 -lgui -linput
+
+SRC := $(shell find src -name "*.c" -not -path 'src/platform/*') $(shell find src/platform/banan-os -name "*.c" -or -name "*.cpp")
+OBJ := $(addsuffix .o,$(SRC))
+
+all: tinygb
+
+clean:
+ @rm -f $(OBJ)
+ @rm -f tinygb
+
+%.c.o: %.c
+ @echo -e "\x1B[0;1;35m [ CC ]\x1B[0m $@"
+ $(CC) -o $@ $(CFLAGS) $<
+
+%.cpp.o: %.cpp
+ @echo -e "\x1B[0;1;35m [ CC ]\x1B[0m $@"
+ $(CXX) -o $@ $(CFLAGS) $(CXXFLAGS) $<
+
+tinygb: $(OBJ)
+ @echo -e "\x1B[0;1;36m [ LD ]\x1B[0m tinygb"
+ $(LD) $(OBJ) -o tinygb $(LDFLAGS)
diff --git a/src/platform/banan-os/main.cpp b/src/platform/banan-os/main.cpp
new file mode 100644
index 0000000..94f249e
--- /dev/null
+++ b/src/platform/banan-os/main.cpp
@@ -0,0 +1,364 @@
+
+/* tinygb - a tiny gameboy emulator
+ (c) 2022 by jewel */
+
+extern "C" {
+#include <tinygb.h>
+}
+
+#include <LibGUI/Window.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+long rom_size;
+int scaling = 4;
+int frameskip = 0; // no skip
+
+timing_t timing;
+char *rom_filename;
+
+BAN::UniqPtr<LibGUI::Window> s_window;
+
+// Key Config
+LibInput::Key key_a;
+LibInput::Key key_b;
+LibInput::Key key_start;
+LibInput::Key key_select;
+LibInput::Key key_up;
+LibInput::Key key_down;
+LibInput::Key key_left;
+LibInput::Key key_right;
+LibInput::Key key_throttle;
+
+LibInput::Key get_key(const char* keyname)
+{
+ if (keyname == nullptr);
+ else if (!strcmp("a", keyname)) return LibInput::Key::A;
+ else if (!strcmp("b", keyname)) return LibInput::Key::B;
+ else if (!strcmp("c", keyname)) return LibInput::Key::C;
+ else if (!strcmp("d", keyname)) return LibInput::Key::D;
+ else if (!strcmp("e", keyname)) return LibInput::Key::E;
+ else if (!strcmp("f", keyname)) return LibInput::Key::F;
+ else if (!strcmp("g", keyname)) return LibInput::Key::G;
+ else if (!strcmp("h", keyname)) return LibInput::Key::H;
+ else if (!strcmp("i", keyname)) return LibInput::Key::I;
+ else if (!strcmp("j", keyname)) return LibInput::Key::J;
+ else if (!strcmp("k", keyname)) return LibInput::Key::K;
+ else if (!strcmp("l", keyname)) return LibInput::Key::L;
+ else if (!strcmp("m", keyname)) return LibInput::Key::M;
+ else if (!strcmp("n", keyname)) return LibInput::Key::N;
+ else if (!strcmp("o", keyname)) return LibInput::Key::O;
+ else if (!strcmp("p", keyname)) return LibInput::Key::P;
+ else if (!strcmp("q", keyname)) return LibInput::Key::Q;
+ else if (!strcmp("r", keyname)) return LibInput::Key::R;
+ else if (!strcmp("s", keyname)) return LibInput::Key::S;
+ else if (!strcmp("t", keyname)) return LibInput::Key::T;
+ else if (!strcmp("u", keyname)) return LibInput::Key::U;
+ else if (!strcmp("v", keyname)) return LibInput::Key::V;
+ else if (!strcmp("w", keyname)) return LibInput::Key::W;
+ else if (!strcmp("x", keyname)) return LibInput::Key::X;
+ else if (!strcmp("y", keyname)) return LibInput::Key::Y;
+ else if (!strcmp("z", keyname)) return LibInput::Key::Z;
+ else if (!strcmp("0", keyname)) return LibInput::Key::_0;
+ else if (!strcmp("1", keyname)) return LibInput::Key::_1;
+ else if (!strcmp("2", keyname)) return LibInput::Key::_2;
+ else if (!strcmp("3", keyname)) return LibInput::Key::_3;
+ else if (!strcmp("4", keyname)) return LibInput::Key::_4;
+ else if (!strcmp("5", keyname)) return LibInput::Key::_5;
+ else if (!strcmp("6", keyname)) return LibInput::Key::_6;
+ else if (!strcmp("7", keyname)) return LibInput::Key::_7;
+ else if (!strcmp("8", keyname)) return LibInput::Key::_8;
+ else if (!strcmp("9", keyname)) return LibInput::Key::_9;
+ else if (!strcmp("up", keyname)) return LibInput::Key::ArrowUp;
+ else if (!strcmp("down", keyname)) return LibInput::Key::ArrowDown;
+ else if (!strcmp("left", keyname)) return LibInput::Key::ArrowLeft;
+ else if (!strcmp("right", keyname)) return LibInput::Key::ArrowRight;
+ else if (!strcmp("space", keyname)) return LibInput::Key::Space;
+ else if (!strcmp("rshift", keyname)) return LibInput::Key::RightShift;
+ else if (!strcmp("lshift", keyname)) return LibInput::Key::LeftShift;
+ else if (!strcmp("backspace", keyname)) return LibInput::Key::Backspace;
+ else if (!strcmp("delete", keyname)) return LibInput::Key::Delete;
+ else if (!strcmp("tab", keyname)) return LibInput::Key::Tab;
+ else if (!strcmp("escape", keyname)) return LibInput::Key::Escape;
+ else if (!strcmp("exclamation", keyname)) return LibInput::Key::ExclamationMark;
+ else if (!strcmp("at", keyname)) return LibInput::Key::AtSign;
+ else if (!strcmp("hash", keyname)) return LibInput::Key::Hashtag;
+ else if (!strcmp("dollar", keyname)) return LibInput::Key::Dollar;
+ else if (!strcmp("percent", keyname)) return LibInput::Key::Percent;
+ else if (!strcmp("caret", keyname)) return LibInput::Key::Caret;
+ else if (!strcmp("ampersand", keyname)) return LibInput::Key::Ampersand;
+ else if (!strcmp("asterisk", keyname)) return LibInput::Key::Asterix;
+ else if (!strcmp("leftparenthesis", keyname)) return LibInput::Key::OpenParenthesis;
+ else if (!strcmp("rightparenthesis", keyname)) return LibInput::Key::CloseParenthesis;
+
+ return LibInput::Key::None;
+}
+
+static void load_keys()
+{
+ key_a = get_key(config_file.a);
+ if (key_a == LibInput::Key::None)
+ key_a = LibInput::Key::Z;
+
+ key_b = get_key(config_file.b);
+ if (key_b == LibInput::Key::None)
+ key_b = LibInput::Key::X;
+
+ key_start = get_key(config_file.start);
+ if (key_start == LibInput::Key::None)
+ key_start = LibInput::Key::Enter;
+
+ key_select = get_key(config_file.select);
+ if (key_select == LibInput::Key::None)
+ key_select = LibInput::Key::RightShift;
+
+ key_up = get_key(config_file.up);
+ if (key_up == LibInput::Key::None)
+ key_up = LibInput::Key::ArrowUp;
+
+ key_down = get_key(config_file.down);
+ if (key_down == LibInput::Key::None)
+ key_down = LibInput::Key::ArrowDown;
+
+ key_left = get_key(config_file.left);
+ if (key_left == LibInput::Key::None)
+ key_left = LibInput::Key::ArrowLeft;
+
+ key_right = get_key(config_file.right);
+ if (key_right == LibInput::Key::None)
+ key_right = LibInput::Key::ArrowRight;
+
+ key_throttle = get_key(config_file.throttle);
+ if (key_throttle == LibInput::Key::None)
+ key_throttle = LibInput::Key::Space;
+}
+
+void delay(int ms)
+{
+ const timespec ts {
+ .tv_sec = static_cast<time_t>(ms / 1000),
+ .tv_nsec = (ms % 1000) * 1000000
+ };
+ nanosleep(&ts, nullptr);
+}
+
+void destroy_window()
+{
+ s_window.clear();
+}
+
+void update_window(uint32_t *framebuffer)
+{
+ auto pixels = s_window->texture().pixels();
+ for (int i = 0; i < scaled_h; i++)
+ {
+ uint32_t* src = &framebuffer[i * scaled_w];
+ uint32_t* dst = using_sgb_border
+ ? &pixels[(i + gb_y) * s_window->width() + gb_x]
+ : &pixels[i * s_window->width()];
+ memcpy(dst, src, scaled_w * 4);
+ }
+
+ if (framecount > frameskip)
+ {
+ s_window->invalidate();
+ framecount = 0;
+ drawn_frames++;
+ }
+}
+
+void update_border(uint32_t *framebuffer)
+{
+ auto pixels = s_window->texture().pixels();
+ for (int i = 0; i < sgb_scaled_h; i++)
+ {
+ uint32_t* src = &framebuffer[i * sgb_scaled_w];
+ uint32_t* dst = &pixels[i * s_window->width()];
+ memcpy(dst, src, sgb_scaled_w*4);
+ }
+}
+
+void resize_sgb_window()
+{
+ s_window->request_resize(SGB_WIDTH * scaling, SGB_HEIGHT * scaling);
+
+ bool resized { false };
+ s_window->set_resize_window_event_callback([&]() { resized = true; });
+ while (!resized)
+ s_window->poll_events();
+ s_window->set_resize_window_event_callback({});
+
+ ASSERT(s_window->width() == static_cast<uint32_t>(SGB_WIDTH * scaling));
+ ASSERT(s_window->height() == static_cast<uint32_t>(SGB_HEIGHT * scaling));
+}
+
+int main(int argc, char **argv) {
+ if(argc != 2) {
+ fprintf(stdout, "usage: %s rom_name\n", argv[0]);
+ return 1;
+ }
+
+ rom_filename = argv[1];
+
+ open_log();
+ open_config();
+ load_keys();
+
+ // open the rom
+ FILE *rom_file = fopen(rom_filename, "r");
+ if(!rom_file) {
+ write_log("unable to open %s for reading: %s\n", rom_filename, strerror(errno));
+ return 1;
+ }
+
+ fseek(rom_file, 0L, SEEK_END);
+ rom_size = ftell(rom_file);
+ fseek(rom_file, 0L, SEEK_SET);
+
+ write_log("loading rom from file %s, %d KiB\n", rom_filename, rom_size / 1024);
+
+ rom = malloc(rom_size);
+ if(!rom) {
+ write_log("unable to allocate memory\n");
+ fclose(rom_file);
+ return 1;
+ }
+
+ if (fread(rom, 1, rom_size, rom_file) <= 0)
+ {
+ write_log("an error occured while reading from rom file: %s\n", strerror(errno));
+ fclose(rom_file);
+ free(rom);
+ return 1;
+ }
+
+ fclose(rom_file);
+
+ if (auto ret = LibGUI::Window::create(GB_WIDTH * scaling, GB_HEIGHT * scaling, "tinygb"_sv); !ret.is_error())
+ s_window = ret.release_value();
+ else
+ {
+ write_log("couldn't create SDL window: %s\n", ret.error().get_message());
+ free(rom);
+ return 1;
+ }
+
+ s_window->set_key_event_callback([](LibGUI::EventPacket::KeyEvent::event_t event) {
+ int key = 0;
+ if (event.key == key_left)
+ key = JOYPAD_LEFT;
+ else if (event.key == key_right)
+ key = JOYPAD_RIGHT;
+ else if (event.key == key_up)
+ key = JOYPAD_UP;
+ else if (event.key == key_down)
+ key = JOYPAD_DOWN;
+ else if (event.key == key_a)
+ key = JOYPAD_A;
+ else if (event.key == key_b)
+ key = JOYPAD_B;
+ else if (event.key == key_start)
+ key = JOYPAD_START;
+ else if (event.key == key_select)
+ key = JOYPAD_SELECT;
+ else if (event.key == key_throttle)
+ throttle_enabled = event.released();
+ else if (event.pressed() && (event.key == LibInput::Key::Plus || event.key == LibInput::Key::Equals))
+ next_palette();
+ else if (event.pressed() && (event.key == LibInput::Key::Hyphen))
+ prev_palette();
+
+ if (key)
+ joypad_handle(event.pressed(), key);
+ });
+
+ // start emulation
+ memory_start();
+ cpu_start();
+ display_start();
+ timer_start();
+ sound_start();
+
+ time_t rawtime;
+ struct tm *timeinfo;
+ int sec = 500; // any invalid number
+ char new_title[256];
+ int percentage;
+ int throttle_underflow = 0;
+ int throttle_target = throttle_lo + SPEED_ALLOWANCE;
+
+ while(1) {
+ s_window->poll_events();
+
+ for(timing.current_cycles = 0; timing.current_cycles < timing.main_cycles; ) {
+ cpu_cycle();
+ display_cycle();
+ timer_cycle();
+ }
+
+
+ time(&rawtime);
+ timeinfo = localtime(&rawtime);
+
+ if(sec != timeinfo->tm_sec) {
+ sec = timeinfo->tm_sec;
+ percentage = (drawn_frames * 1000) / 597;
+ sprintf(new_title, "tinygb (%d fps - %d%%)", drawn_frames, percentage);
+ s_window->set_title(new_title);
+
+ // adjust cpu throttle according to acceptable fps (98%-102%)
+ if(throttle_enabled) {
+ if(percentage < throttle_lo) {
+ // emulation is too slow
+ if(!throttle_time) {
+ // throttle_time--;
+
+ if(!throttle_underflow) {
+ throttle_underflow = 1;
+ write_log("WARNING: CPU throttle interval has underflown, emulation may be too slow\n");
+ }
+ } else {
+ //write_log("too slow; decreasing throttle time: %d\n", throttle_time);
+
+ // this will speed up the speed adjustments for a more natural feel
+ if(percentage < (throttle_target/3)) throttle_time /= 3;
+ else if(percentage < (throttle_target/2)) throttle_time /= 2;
+ else throttle_time--;
+ }
+
+ // prevent this from going too low
+ if(throttle_time <= (THROTTLE_THRESHOLD/3)) {
+ cycles_per_throttle += (cycles_per_throttle/5); // delay 20% less often
+ throttle_time = (THROTTLE_THRESHOLD/3);
+ }
+ } else if(percentage > throttle_hi) {
+ // emulation is too fast
+ //write_log("too fast; increasing throttle time: %d\n", throttle_time);
+
+ if(throttle_time) {
+ // to make sure we're not multiplying zero
+ if(percentage > (throttle_target*3)) throttle_time *= 3;
+ else if(percentage > (throttle_target*2)) throttle_time *= 2;
+ else throttle_time++;
+ }
+ else {
+ throttle_time++;
+ }
+
+ // prevent unnecessary lag
+ if(throttle_time > THROTTLE_THRESHOLD) {
+ cycles_per_throttle -= (cycles_per_throttle/5); // delay 20% more often
+ throttle_time = THROTTLE_THRESHOLD;
+ }
+ }
+ }
+
+ drawn_frames = 0;
+ }
+ }
+
+ die(0, "");
+ return 0;
+}
\ No newline at end of file
--
2.49.0

View File

@ -39,8 +39,8 @@ SOUND_ARGS='-device ac97'
qemu-system-$QEMU_ARCH \
-m 1G -smp 4 \
$BIOS_ARGS \
$DISK_ARGS \
$USB_ARGS \
$DISK_ARGS \
$NET_ARGS \
$SOUND_ARGS \
$@ \

View File

@ -10,6 +10,7 @@ set(LIBC_SOURCES
errno.cpp
fcntl.cpp
fenv.cpp
fnmatch.cpp
ftw.cpp
grp.cpp
ifaddrs.cpp

View File

@ -0,0 +1,80 @@
#include <fnmatch.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
static int fnmatch_impl(const char* pattern, const char* string, int flags, bool leading)
{
while (*pattern)
{
if ((flags & FNM_PERIOD) && leading && *string == '.' && *pattern != '.')
return FNM_NOMATCH;
leading = false;
switch (*pattern)
{
case '*':
{
const char* ptr = strchrnul(string, (flags & FNM_PATHNAME) ? '/' : '0');
while (ptr >= string)
if (fnmatch_impl(pattern + 1, ptr--, flags, false) == 0)
return 0;
return FNM_NOMATCH;
}
case '[':
{
if (strchr(pattern, ']') == nullptr)
break;
pattern++;
const bool negate = (*pattern == '!');
if (negate)
pattern++;
uint8_t ch;
uint32_t bitmap[0x100 / 8] {};
while ((ch = *pattern++) != ']')
bitmap[ch / 32] |= 1 << (ch % 32);
ch = *string++;
if (!!(bitmap[ch / 32] & (1 << (ch % 32))) == negate)
return FNM_NOMATCH;
continue;
}
case '?':
{
if (*string == '\0')
return FNM_NOMATCH;
if ((flags & FNM_PATHNAME) && *string == '/')
return FNM_NOMATCH;
pattern++;
string++;
continue;
}
case '\\':
{
if (!(flags & FNM_NOESCAPE))
pattern++;
break;
}
}
if (*pattern == '\0')
break;
if (*pattern != *string)
return FNM_NOMATCH;
if ((flags & FNM_PATHNAME) && *string == '/')
leading = true;
pattern++;
string++;
}
return *string ? FNM_NOMATCH : 0;
}
int fnmatch(const char* pattern, const char* string, int flags)
{
return fnmatch_impl(pattern, string, flags, true);
}

View File

@ -4,6 +4,7 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/syscall.h>
static FILE* s_grent_fp = nullptr;
static group s_grent_struct;
@ -211,3 +212,106 @@ int getgrnam_r(const char* name, struct group* grp, char* buffer, size_t bufsize
fclose(fp);
return ret;
}
static gid_t* get_user_groups(const char* user)
{
FILE* fp = fopen("/etc/group", "r");
if (fp == nullptr)
return nullptr;
const long initial_len = sysconf(_SC_GETGR_R_SIZE_MAX);
size_t buffer_len = (initial_len == -1) ? 512 : initial_len;
char* buffer = static_cast<char*>(malloc(buffer_len));
if (buffer == nullptr)
{
fclose(fp);
return nullptr;
}
size_t group_count = 0;
gid_t* groups = static_cast<gid_t*>(malloc(sizeof(gid_t)));
if (groups == nullptr)
{
free(buffer);
fclose(fp);
return nullptr;
}
for (;;)
{
struct group result;
struct group* resultp;
int error = getgrent_impl(fp, &result, buffer, buffer_len, &resultp);
if (error == ERANGE)
{
const size_t new_buffer_len = buffer_len * 2;
char* new_buffer = static_cast<char*>(realloc(buffer, new_buffer_len));
if (new_buffer == nullptr)
{
error = ENOMEM;
break;
}
buffer = new_buffer;
buffer_len = new_buffer_len;
continue;
}
if (error != 0)
{
free(buffer);
free(groups);
fclose(fp);
return nullptr;
}
if (resultp == nullptr)
break;
bool contains = false;
for (size_t i = 0; result.gr_mem[i] && !contains; i++)
contains = (strcmp(result.gr_mem[i], user) == 0);
if (!contains)
continue;
gid_t* new_groups = static_cast<gid_t*>(realloc(groups, group_count * sizeof(gid_t)));
if (new_groups == nullptr)
{
free(buffer);
free(groups);
fclose(fp);
return nullptr;
}
groups = new_groups;
groups[group_count++] = result.gr_gid;
}
groups[group_count] = -1;
free(buffer);
fclose(fp);
return groups;
}
int initgroups(const char* user, gid_t group)
{
gid_t* groups = get_user_groups(user);
if (groups == nullptr)
return -1;
size_t group_count = 0;
while (groups[group_count] != -1)
group_count++;
groups[group_count] = group;
int result = setgroups(group_count + 1, groups);
free(groups);
return result;
}
int setgroups(size_t size, const gid_t list[])
{
return syscall(SYS_SETGROUPS, list, size);
}

View File

@ -14,7 +14,7 @@ __BEGIN_DECLS
struct group
{
char* gr_name; /* The name of the group. */
char* gr_passwd;/* The password of the group */
char* gr_passwd; /* The password of the group */
gid_t gr_gid; /* Numerical group ID. */
char** gr_mem; /* Pointer to a null-terminated array of character pointers to member names. */
};
@ -27,6 +27,9 @@ struct group* getgrnam(const char* name);
int getgrnam_r(const char* name, struct group* grp, char* buffer, size_t bufsize, struct group** result);
void setgrent(void);
int initgroups(const char* user, gid_t group);
int setgroups(size_t size, const gid_t list[]);
__END_DECLS
#endif

View File

@ -59,6 +59,8 @@ enum
#define IPV6_V6ONLY IPV6_V6ONLY
};
#define IN_MULTICAST(a) (((in_addr_t)(a) & 0xF0000000) == 0xE0000000)
#define INADDR_ANY 0
#define INADDR_NONE 0xFFFFFFFF
#define INADDR_BROADCAST 0xFFFFFFFF
@ -67,31 +69,63 @@ enum
#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 } } }
#if 0
#define IN6_IS_ADDR_UNSPECIFIED(addr)
#define IN6_IS_ADDR_LOOPBACK(addr)
#define IN6_IS_ADDR_MULTICAST(addr)
#define IN6_IS_ADDR_LINKLOCAL(addr)
#define IN6_IS_ADDR_SITELOCAL(addr)
#define IN6_IS_ADDR_V4MAPPED(addr)
#define IN6_IS_ADDR_V4COMPAT(addr)
#define IN6_IS_ADDR_MC_NODELOCAL(addr)
#define IN6_IS_ADDR_MC_LINKLOCAL(addr)
#define IN6_IS_ADDR_MC_SITELOCAL(addr)
#define IN6_IS_ADDR_MC_ORGLOCAL(addr)
#define IN6_IS_ADDR_MC_GLOBAL(addr)
#endif
#define IN6_IS_ADDR_UNSPECIFIED(a) \
((a)->s6_addr32[0] == 0 && \
(a)->s6_addr32[1] == 0 && \
(a)->s6_addr32[2] == 0 && \
(a)->s6_addr32[3] == 0)
#define IN6_IS_ADDR_LOOPBACK(a) \
((a)->s6_addr32[0] == 0 && \
(a)->s6_addr32[1] == 0 && \
(a)->s6_addr32[2] == 0 && \
(a)->s6_addr32[3] == htonl(1))
#define IN6_IS_ADDR_MULTICAST(a) \
((a)->s6_addr[0] == 0xFF)
#define IN6_IS_ADDR_LINKLOCAL(a) \
((a)->s6_addr[0] == 0xFE && \
((a)->s6_addr[1] & 0xC0) == 0x80)
#define IN6_IS_ADDR_SITELOCAL(a) \
((a)->s6_addr[0] == 0xFE && \
((a)->s6_addr[1] & 0xC0) == 0xC0)
#define IN6_IS_ADDR_V4MAPPED(a) \
((a)->s6_addr32[0] == 0 && \
(a)->s6_addr32[1] == 0 && \
(a)->s6_addr32[2] == htonl(0x0000FFFF))
#define IN6_IS_ADDR_V4COMPAT(a) \
((a)->s6_addr32[0] == 0 && \
(a)->s6_addr32[1] == 0 && \
(a)->s6_addr32[2] == 0 && \
ntohl((a)->s6_addr32[3]) > 1)
#define IN6_IS_ADDR_MC_NODELOCAL(a) \
(IN6_IS_ADDR_MULTICAST(a) && \
((a)->s6_addr[1] & 0x0F) == 0x01)
#define IN6_IS_ADDR_MC_LINKLOCAL(a) \
(IN6_IS_ADDR_MULTICAST(a) && \
((a)->s6_addr[1] & 0x0F) == 0x02)
#define IN6_IS_ADDR_MC_SITELOCAL(a) \
(IN6_IS_ADDR_MULTICAST(a) && \
((a)->s6_addr[1] & 0x0F) == 0x05)
#define IN6_IS_ADDR_MC_ORGLOCAL(a) \
(IN6_IS_ADDR_MULTICAST(a) && \
((a)->s6_addr[1] & 0x0F) == 0x08)
#define IN6_IS_ADDR_MC_GLOBAL(a) \
(IN6_IS_ADDR_MULTICAST(a) && \
((a)->s6_addr[1] & 0x0F) == 0x0E)
struct sockaddr_in
{
sa_family_t sin_family; /* AF_INET. */
in_port_t sin_port; /* Port number. */
struct in_addr sin_addr; /* IP address. */
unsigned char sin_zero[8];
};
struct in6_addr
{
uint8_t s6_addr[16];
union {
uint8_t s6_addr[16];
uint32_t s6_addr32[4];
};
};
struct sockaddr_in6

View File

@ -37,6 +37,8 @@ __BEGIN_DECLS
#define KDLOADFONT 30
#define FIONREAD 40 /* get number of input bytes available */
struct winsize
{
unsigned short ws_row;

View File

@ -24,8 +24,8 @@ __BEGIN_DECLS
struct sockaddr
{
sa_family_t sa_family; /* Address family. */
char sa_data[0]; /* Socket address (variable-length data). */
sa_family_t sa_family; /* Address family. */
char sa_data[14]; /* Socket address (variable-length data). */
};
struct sockaddr_storage

View File

@ -111,6 +111,9 @@ __BEGIN_DECLS
O(SYS_FLOCK, flock) \
O(SYS_GET_NPROCESSOR, get_nprocessor) \
O(SYS_FUTEX, futex) \
O(SYS_GETGROUPS, getgroups) \
O(SYS_SETGROUPS, setgroups) \
O(SYS_CHROOT, chroot) \
enum Syscall
{

View File

@ -596,6 +596,7 @@ int unlinkat(int fd, const char* path, int flag);
int usleep(useconds_t usec);
ssize_t write(int fildes, const void* buf, size_t nbyte);
int chroot(const char* path);
int getpagesize(void);
char* getpass(const char* prompt);

View File

@ -626,6 +626,10 @@ int getopt(int argc, char* const argv[], const char* optstring)
return '?';
}
int chroot(const char* path)
return syscall(SYS_CHROOT, path);
}
int getpagesize(void)
{
return PAGE_SIZE;
@ -673,8 +677,7 @@ error:
int getgroups(int gidsetsize, gid_t grouplist[])
{
dwarnln("FIXME: getgroups({}, {})", gidsetsize, grouplist);
return 0;
return syscall(SYS_GETGROUPS, grouplist, gidsetsize);
}
pid_t getppid(void)

View File

@ -31,7 +31,8 @@ namespace LibFont
#if __is_kernel
{
auto inode = TRY(Kernel::VirtualFileSystem::get().file_from_absolute_path({ 0, 0, 0, 0 }, path, O_RDONLY)).inode;
// FIXME: This does not account for chroot
auto inode = TRY(Kernel::VirtualFileSystem::get().file_from_absolute_path(Kernel::VirtualFileSystem::get().root_inode(), { 0, 0, 0, 0 }, path, O_RDONLY)).inode;
TRY(file_data.resize(inode->size()));
TRY(inode->read(0, BAN::ByteSpan(file_data.span())));
}

View File

@ -128,7 +128,8 @@ namespace LibInput
#if __is_kernel
{
auto file = TRY(Kernel::VirtualFileSystem::get().file_from_absolute_path({ 0, 0, 0, 0 }, path, 0));
// FIXME: This does not account for chroot
auto file = TRY(Kernel::VirtualFileSystem::get().file_from_absolute_path(Kernel::VirtualFileSystem::get().root_inode(), { 0, 0, 0, 0 }, path, 0));
TRY(file_data.resize(file.inode->size()));
TRY(file.inode->read(0, BAN::ByteSpan { reinterpret_cast<uint8_t*>(file_data.data()), file_data.size() }));
canonical_path = file.canonical_path;

View File

@ -3,6 +3,7 @@
#include <BAN/Vector.h>
#include <fcntl.h>
#include <grp.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
@ -41,6 +42,12 @@ int main(int argc, char** argv)
exit(1);
}
if (fork() == 0)
{
execl("/bin/AudioServer", "AudioServer", NULL);
exit(1);
}
bool first = true;
termios termios;
@ -94,6 +101,8 @@ int main(int argc, char** argv)
printf("Welcome back %s!\n", pwd->pw_name);
if (initgroups(name_buffer, pwd->pw_gid) == -1)
perror("initgroups");
if (setgid(pwd->pw_gid) == -1)
perror("setgid");
if (setuid(pwd->pw_uid) == -1)

View File

@ -442,6 +442,7 @@ int main(int, char**)
.sin_family = AF_INET,
.sin_port = 0,
.sin_addr = { .s_addr = resolved->raw },
.sin_zero = {},
};
if (send(client.socket, &addr, sizeof(addr), 0) == -1)
@ -489,6 +490,7 @@ int main(int, char**)
.sin_family = AF_INET,
.sin_port = 0,
.sin_addr = { .s_addr = result->raw },
.sin_zero = {},
};
if (send(client.socket, &addr, sizeof(addr), 0) == -1)