Compare commits

...

23 Commits

Author SHA1 Message Date
Bananymous 9e79ef2a91 Terminal: Use pseudo terminal instead of pipes
Terminal can now send signals from keyboard (ctrl+c) to programs running
in the terminal!
2024-08-11 01:02:59 +03:00
Bananymous 4d1b32f770 Kernel: open does not need TTY_INIT to set the controlling terminal 2024-08-11 01:02:59 +03:00
Bananymous a5a097fa4a Kernel/LibC: Add initial pseudo terminal support
This patch implements posix_openpt() and ptsname()

grantpt() and unlockpt() are left in LibC as stubs, as posix_openpt
currently does all of the needed work.
2024-08-11 01:02:59 +03:00
Bananymous ad645f31d0 Kernel/LibC: Add setsid() 2024-08-11 00:58:12 +03:00
Bananymous f08d429851 Terminal: Add utf8 parsing for input
This patch adds possibility to render multibyte utf8 codepoints!
2024-08-11 00:54:51 +03:00
Bananymous bac3219a01 Kernel: Fix `Pipe::can_read_impl()`
The logic was inversed, which made all select calls report incorrectly
for pipes. This made terminal emulator just freeze.
2024-08-10 18:18:25 +03:00
Bananymous 09a527fb12 Kernel: Fix scheduler thread counter
I was actually never incrementing the counter :D
2024-08-10 18:18:25 +03:00
Bananymous 58a3a480b9 Ports: Update the port system once again! 2024-08-10 18:18:25 +03:00
Bananymous a12bfe4639 LibC: Don't crash when calling tcflush() 2024-08-09 17:03:21 +03:00
Bananymous 6cda639869 LibC: Add stubs for tmpfile, mktemp and fchmod 2024-08-09 17:02:49 +03:00
Bananymous 2797fe116f LibC: Add stubs for some functions in {dlfcn,ftw,utime,wchar}.h 2024-08-09 17:01:41 +03:00
Bananymous e768cd53fb LibC: Add definition for SIGWINCH
This is actually not yet sent, but programs can install signal handlers
for it!
2024-08-09 17:00:13 +03:00
Bananymous 83e2ad40d6 LibC: Implement gai_strerror and add stubs for {get,free}addrinfo 2024-08-09 16:59:49 +03:00
Bananymous 7ebd0699e3 LibC: Add _PC* definitions to unistd.h
These are not used for anything yet
2024-08-09 16:58:58 +03:00
Bananymous 46b1d4d194 LibC: Remove cxx abi stuff from libc
These will cause multiple definitions when linking with libstdc++
2024-08-09 16:58:11 +03:00
Bananymous f60e265397 LibC: Add ldexp to math.cpp 2024-08-09 16:57:16 +03:00
Bananymous 2e642327ea LibC: Implement localeconv() 2024-08-09 16:56:48 +03:00
Bananymous a87ce41030 LibC: rename fd_set internal variable
binutils seems to need access to the internal type and uses this name
for lookup.
2024-08-09 16:55:52 +03:00
Bananymous 0c8cae4cc3 LibC: Move ioctl to <sys/ioctl.h>
Some ports seem to be assuming that ioctl exists there and not in
stropts.h
2024-08-09 16:54:30 +03:00
Bananymous ed325b4a45 Kernel: Fix typo in userspace address validation 2024-08-09 16:52:57 +03:00
Bananymous 1c67b5e812 Kernel: Fix wait syscall to report status of exited children 2024-08-09 16:52:35 +03:00
Bananymous b6c964c444 Kernel: Rewrite pipes
Pipes have now a fixed size buffer and pipe clone and close is working
again.
2024-08-09 16:50:19 +03:00
Bananymous 6fedf06150 LibC: Implement {sig,_,}{longjmp,setjmp} 2024-08-09 15:58:56 +03:00
57 changed files with 1032 additions and 293 deletions

View File

@ -86,6 +86,7 @@ set(KERNEL_SOURCES
kernel/Storage/StorageDevice.cpp
kernel/Syscall.cpp
kernel/Terminal/FramebufferTerminal.cpp
kernel/Terminal/PseudoTerminal.cpp
kernel/Terminal/Serial.cpp
kernel/Terminal/TTY.cpp
kernel/Terminal/VirtualTTY.cpp

View File

@ -9,7 +9,7 @@ namespace Kernel
{
Framebuffer = 1,
TTY,
Serial,
PTSMaster,
Null,
Zero,
Debug,

View File

@ -1,5 +1,6 @@
#pragma once
#include <BAN/Array.h>
#include <kernel/FS/Inode.h>
#include <kernel/ThreadBlocker.h>
@ -33,7 +34,7 @@ namespace Kernel
virtual BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) override;
virtual BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan) override;
virtual bool can_read_impl() const override { return !m_buffer.empty(); }
virtual bool can_read_impl() const override { return m_buffer_size > 0; }
virtual bool can_write_impl() const override { return true; }
virtual bool has_error_impl() const override { return false; }
@ -46,10 +47,13 @@ namespace Kernel
timespec m_atime {};
timespec m_mtime {};
timespec m_ctime {};
BAN::Vector<uint8_t> m_buffer;
ThreadBlocker m_thread_blocker;
uint32_t m_writing_count { 1 };
BAN::Array<uint8_t, PAGE_SIZE> m_buffer;
BAN::Atomic<size_t> m_buffer_size { 0 };
size_t m_buffer_tail { 0 };
BAN::Atomic<uint32_t> m_writing_count { 1 };
};
}

View File

@ -85,6 +85,7 @@ namespace Kernel
BAN::ErrorOr<long> sys_setuid(uid_t);
BAN::ErrorOr<long> sys_setgid(gid_t);
BAN::ErrorOr<long> sys_setsid();
BAN::ErrorOr<long> sys_seteuid(uid_t);
BAN::ErrorOr<long> sys_setegid(gid_t);
BAN::ErrorOr<long> sys_setreuid(uid_t, uid_t);
@ -173,6 +174,8 @@ namespace Kernel
BAN::ErrorOr<long> sys_ttyname(int fildes, char* storage);
BAN::ErrorOr<long> sys_isatty(int fildes);
BAN::ErrorOr<long> sys_posix_openpt(int flags);
BAN::ErrorOr<long> sys_ptsname(int fildes, char* buffer, size_t buffer_len);
BAN::ErrorOr<long> sys_tty_ctrl(int fildes, int command, int flags);
@ -219,8 +222,6 @@ namespace Kernel
// Load elf from a file
static BAN::ErrorOr<BAN::UniqPtr<LibELF::LoadableELF>> load_elf_for_exec(const Credentials&, BAN::StringView file_path, const BAN::String& cwd, Kernel::PageTable&);
BAN::ErrorOr<int> block_until_exit(pid_t pid);
BAN::ErrorOr<void> validate_string_access(const char*);
BAN::ErrorOr<void> validate_pointer_access_check(const void*, size_t);
BAN::ErrorOr<void> validate_pointer_access(const void*, size_t);
@ -255,12 +256,12 @@ namespace Kernel
}
private:
struct ExitStatus
struct ChildExitStatus
{
ThreadBlocker thread_blocker;
int exit_code { 0 };
BAN::Atomic<bool> exited { false };
BAN::Atomic<int> waiting { 0 };
pid_t pid { 0 };
pid_t pgrp { 0 };
int exit_code { 0 };
bool exited { false };
};
Credentials m_credentials;
@ -292,7 +293,10 @@ namespace Kernel
bool m_is_userspace { false };
userspace_info_t m_userspace_info;
ExitStatus m_exit_status;
SpinLock m_child_exit_lock;
BAN::Vector<ChildExitStatus> m_child_exit_statuses;
ThreadBlocker m_child_exit_blocker;
bool m_has_called_exec { false };

View File

@ -0,0 +1,84 @@
#pragma once
#include <BAN/WeakPtr.h>
#include <kernel/Terminal/TTY.h>
namespace Kernel
{
class PseudoTerminalSlave;
class PseudoTerminalMaster final : public CharacterDevice, public BAN::Weakable<PseudoTerminalMaster>
{
public:
static BAN::ErrorOr<BAN::RefPtr<PseudoTerminalMaster>> create(mode_t, uid_t, gid_t);
dev_t rdev() const override { return m_rdev; }
BAN::StringView name() const override { return "<ptmx>"_sv; }
BAN::ErrorOr<BAN::RefPtr<PseudoTerminalSlave>> slave();
BAN::ErrorOr<BAN::String> ptsname();
void putchar(uint8_t ch);
protected:
BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) override;
BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan) override;
bool can_read_impl() const override { SpinLockGuard _(m_buffer_lock); return m_buffer_size > 0; }
bool can_write_impl() const override { SpinLockGuard _(m_buffer_lock); return m_buffer_size < m_buffer->size(); }
bool has_error_impl() const override { return false; }
private:
PseudoTerminalMaster(BAN::UniqPtr<VirtualRange>, mode_t, uid_t, gid_t);
~PseudoTerminalMaster();
private:
BAN::WeakPtr<PseudoTerminalSlave> m_slave;
mutable SpinLock m_buffer_lock;
ThreadBlocker m_buffer_blocker;
BAN::UniqPtr<VirtualRange> m_buffer;
size_t m_buffer_tail { 0 };
size_t m_buffer_size { 0 };
const dev_t m_rdev;
friend class BAN::RefPtr<PseudoTerminalMaster>;
};
class PseudoTerminalSlave final : public TTY, public BAN::Weakable<PseudoTerminalSlave>
{
public:
static BAN::ErrorOr<BAN::RefPtr<PseudoTerminalSlave>> create(BAN::String&& name, mode_t, uid_t, gid_t);
BAN::StringView name() const override { return m_name; }
uint32_t height() const override { return m_height; }
uint32_t width() const override { return m_width; }
void clear() override;
protected:
void putchar_impl(uint8_t ch) override;
private:
PseudoTerminalSlave(BAN::UniqPtr<VirtualRange>, BAN::String&& name, mode_t, uid_t, gid_t);
private:
BAN::String m_name;
BAN::WeakPtr<PseudoTerminalMaster> m_master;
BAN::UniqPtr<VirtualRange> m_buffer;
size_t m_buffer_tail { 0 };
size_t m_buffer_size { 0 };
uint32_t m_width { 0 };
uint32_t m_height { 0 };
friend class PseudoTerminalMaster;
friend class BAN::RefPtr<PseudoTerminalSlave>;
};
}

View File

@ -63,11 +63,6 @@ namespace Kernel
Serial m_serial;
BAN::CircularQueue<uint8_t, 128> m_input;
SpinLock m_input_lock;
public:
virtual dev_t rdev() const override { return m_rdev; }
private:
const dev_t m_rdev;
};
}

View File

@ -42,6 +42,8 @@ namespace Kernel
virtual uint32_t width() const = 0;
void putchar(uint8_t ch);
virtual dev_t rdev() const final override { return m_rdev; }
virtual void clear() = 0;
virtual BAN::ErrorOr<void> chmod_impl(mode_t) override;
@ -54,17 +56,7 @@ namespace Kernel
virtual bool has_error_impl() const override { return false; }
protected:
TTY(mode_t mode, uid_t uid, gid_t gid)
: CharacterDevice(mode, uid, gid)
{
// FIXME: add correct baud and flags
m_termios.c_iflag = 0;
m_termios.c_oflag = 0;
m_termios.c_cflag = CS8;
m_termios.c_lflag = ECHO | ICANON;
m_termios.c_ospeed = B38400;
m_termios.c_ispeed = B38400;
}
TTY(mode_t mode, uid_t uid, gid_t gid);
virtual void putchar_impl(uint8_t ch) = 0;
virtual BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) override;
@ -79,6 +71,8 @@ namespace Kernel
termios m_termios;
private:
const dev_t m_rdev;
pid_t m_foreground_pgrp { 0 };
struct tty_ctrl_t

View File

@ -83,11 +83,6 @@ namespace Kernel
bool m_show_cursor { true };
TerminalDriver* m_terminal_driver { nullptr };
public:
virtual dev_t rdev() const override { return m_rdev; }
private:
const dev_t m_rdev;
};
}

View File

@ -49,6 +49,8 @@ namespace Kernel
bool add_signal(int signal);
// blocks current thread and returns either on unblock, eintr, spuriously or after timeout
BAN::ErrorOr<void> sleep_or_eintr_ms(uint64_t ms) { return sleep_or_eintr_ns(ms * 1'000'000); }
BAN::ErrorOr<void> sleep_or_eintr_ns(uint64_t ns);
BAN::ErrorOr<void> block_or_eintr_indefinite(ThreadBlocker& thread_blocker);
BAN::ErrorOr<void> block_or_eintr_or_timeout_ms(ThreadBlocker& thread_blocker, uint64_t timeout_ms, bool etimedout) { return block_or_eintr_or_timeout_ns(thread_blocker, timeout_ms * 1'000'000, etimedout); }
BAN::ErrorOr<void> block_or_eintr_or_waketime_ms(ThreadBlocker& thread_blocker, uint64_t wake_time_ms, bool etimedout) { return block_or_eintr_or_waketime_ns(thread_blocker, wake_time_ms * 1'000'000, etimedout); }

View File

@ -3,6 +3,8 @@
#include <kernel/Thread.h>
#include <kernel/Timer/Timer.h>
#include <kernel/Process.h>
namespace Kernel
{
@ -26,24 +28,23 @@ namespace Kernel
void Pipe::clone_writing()
{
LockGuard _(m_mutex);
ASSERT(m_writing_count > 0);
m_writing_count++;
[[maybe_unused]] auto old_writing_count = m_writing_count.fetch_add(1);
ASSERT(old_writing_count > 0);
}
void Pipe::close_writing()
{
LockGuard _(m_mutex);
ASSERT(m_writing_count > 0);
m_writing_count--;
if (m_writing_count == 0)
auto old_writing_count = m_writing_count.fetch_sub(1);
ASSERT(old_writing_count > 0);
if (old_writing_count == 1)
m_thread_blocker.unblock();
}
BAN::ErrorOr<size_t> Pipe::read_impl(off_t, BAN::ByteSpan buffer)
{
LockGuard _(m_mutex);
while (m_buffer.empty())
while (m_buffer_size == 0)
{
if (m_writing_count == 0)
return 0;
@ -51,11 +52,20 @@ namespace Kernel
TRY(Thread::current().block_or_eintr_indefinite(m_thread_blocker));
}
size_t to_copy = BAN::Math::min<size_t>(buffer.size(), m_buffer.size());
memcpy(buffer.data(), m_buffer.data(), to_copy);
const size_t to_copy = BAN::Math::min<size_t>(buffer.size(), m_buffer_size);
memmove(m_buffer.data(), m_buffer.data() + to_copy, m_buffer.size() - to_copy);
MUST(m_buffer.resize(m_buffer.size() - to_copy));
if (m_buffer_tail + to_copy <= m_buffer.size())
memcpy(buffer.data(), m_buffer.data() + m_buffer_tail, to_copy);
else
{
const size_t before_wrap = m_buffer.size() - m_buffer_tail;
const size_t after_wrap = to_copy - before_wrap;
memcpy(buffer.data(), m_buffer.data() + m_buffer_tail, before_wrap);
memcpy(buffer.data() + before_wrap, m_buffer.data(), after_wrap);
}
m_buffer_tail = (m_buffer_tail + to_copy) % m_buffer.size();
m_buffer_size -= to_copy;
m_atime = SystemTimer::get().real_time();
@ -68,10 +78,29 @@ namespace Kernel
{
LockGuard _(m_mutex);
size_t old_size = m_buffer.size();
if (buffer.size() > m_buffer.size())
buffer = buffer.slice(0, m_buffer.size());
TRY(m_buffer.resize(old_size + buffer.size()));
memcpy(m_buffer.data() + old_size, buffer.data(), buffer.size());
while (m_buffer.size() - m_buffer_size < buffer.size())
{
LockFreeGuard lock_free(m_mutex);
TRY(Thread::current().block_or_eintr_indefinite(m_thread_blocker));
}
const size_t to_copy = buffer.size();
const size_t buffer_head = (m_buffer_tail + m_buffer_size) % m_buffer.size();
if (buffer_head + to_copy <= m_buffer.size())
memcpy(m_buffer.data() + buffer_head, buffer.data(), to_copy);
else
{
const size_t before_wrap = m_buffer.size() - buffer_head;
const size_t after_wrap = to_copy - before_wrap;
memcpy(m_buffer.data() + buffer_head, buffer.data(), before_wrap);
memcpy(m_buffer.data(), buffer.data() + before_wrap, after_wrap);
}
m_buffer_size += to_copy;
timespec current_time = SystemTimer::get().real_time();
m_mtime = current_time;
@ -79,7 +108,7 @@ namespace Kernel
m_thread_blocker.unblock();
return buffer.size();
return to_copy;
}
}

View File

@ -48,8 +48,11 @@ namespace Kernel
m_open_files[fd] = result.release_value();
if (m_open_files[fd]->flags & O_WRONLY && m_open_files[fd]->inode->is_pipe())
((Pipe*)m_open_files[fd]->inode.ptr())->clone_writing();
if (m_open_files[fd]->path == "<pipe wr>"_sv)
{
ASSERT(m_open_files[fd]->inode->is_pipe());
static_cast<Pipe*>(m_open_files[fd]->inode.ptr())->clone_writing();
}
}
return {};
@ -59,7 +62,7 @@ namespace Kernel
{
ASSERT(file.inode);
if (flags & ~(O_ACCMODE | O_NOFOLLOW | O_APPEND | O_TRUNC | O_CLOEXEC | O_TTY_INIT | O_DIRECTORY | O_CREAT | O_EXCL | O_NONBLOCK))
if (flags & ~(O_ACCMODE | O_NOFOLLOW | O_APPEND | O_TRUNC | O_CLOEXEC | O_TTY_INIT | O_NOCTTY | O_DIRECTORY | O_CREAT | O_EXCL | O_NONBLOCK))
return BAN::Error::from_errno(ENOTSUP);
if ((flags & O_ACCMODE) != O_RDWR && __builtin_popcount(flags & O_ACCMODE) != 1)
@ -139,8 +142,8 @@ namespace Kernel
TRY(get_free_fd_pair(fds));
auto pipe = TRY(Pipe::create(m_credentials));
m_open_files[fds[0]] = TRY(BAN::RefPtr<OpenFileDescription>::create(pipe, ""_sv, 0, O_RDONLY));
m_open_files[fds[1]] = TRY(BAN::RefPtr<OpenFileDescription>::create(pipe, ""_sv, 0, O_WRONLY));
m_open_files[fds[0]] = TRY(BAN::RefPtr<OpenFileDescription>::create(pipe, "<pipe rd>"_sv, 0, O_RDONLY));
m_open_files[fds[1]] = TRY(BAN::RefPtr<OpenFileDescription>::create(pipe, "<pipe wr>"_sv, 0, O_WRONLY));
return {};
}
@ -152,8 +155,11 @@ namespace Kernel
int result = TRY(get_free_fd());
m_open_files[result] = m_open_files[fildes];
if (m_open_files[result]->flags & O_WRONLY && m_open_files[result]->inode->is_pipe())
((Pipe*)m_open_files[result]->inode.ptr())->clone_writing();
if (m_open_files[result]->path == "<pipe wr>"_sv)
{
ASSERT(m_open_files[result]->inode->is_pipe());
static_cast<Pipe*>(m_open_files[result]->inode.ptr())->clone_writing();
}
return result;
}
@ -172,8 +178,11 @@ namespace Kernel
m_open_files[fildes2] = m_open_files[fildes];
m_open_files[fildes2]->flags &= ~O_CLOEXEC;
if (m_open_files[fildes]->flags & O_WRONLY && m_open_files[fildes]->inode->is_pipe())
((Pipe*)m_open_files[fildes]->inode.ptr())->clone_writing();
if (m_open_files[fildes2]->path == "<pipe wr>"_sv)
{
ASSERT(m_open_files[fildes2]->inode->is_pipe());
static_cast<Pipe*>(m_open_files[fildes2]->inode.ptr())->clone_writing();
}
return fildes;
}
@ -303,8 +312,11 @@ namespace Kernel
{
TRY(validate_fd(fd));
if (m_open_files[fd]->flags & O_WRONLY && m_open_files[fd]->inode->is_pipe())
((Pipe*)m_open_files[fd]->inode.ptr())->close_writing();
if (m_open_files[fd]->path == "<pipe wr>"_sv)
{
ASSERT(m_open_files[fd]->inode->is_pipe());
static_cast<Pipe*>(m_open_files[fd]->inode.ptr())->close_writing();
}
m_open_files[fd].clear();

View File

@ -13,6 +13,7 @@
#include <kernel/Process.h>
#include <kernel/Scheduler.h>
#include <kernel/Storage/StorageDevice.h>
#include <kernel/Terminal/PseudoTerminal.h>
#include <kernel/Timer/Timer.h>
#include <LibELF/LoadableELF.h>
@ -185,7 +186,6 @@ namespace Kernel
ASSERT(m_threads.empty());
ASSERT(m_mapped_regions.empty());
ASSERT(!m_loadable_elf);
ASSERT(m_exit_status.waiting == 0);
ASSERT(&PageTable::current() != m_page_table.ptr());
}
@ -201,21 +201,15 @@ namespace Kernel
SpinLockGuard _(s_process_lock);
for (size_t i = 0; i < s_processes.size(); i++)
{
if (m_parent && s_processes[i]->pid() == m_parent)
s_processes[i]->add_pending_signal(SIGCHLD);
if (s_processes[i] == this)
s_processes.remove(i);
if (s_processes[i] != this)
continue;
s_processes.remove(i);
break;
}
}
ProcFileSystem::get().on_process_delete(*this);
m_exit_status.exited = true;
m_exit_status.thread_blocker.unblock();
while (m_exit_status.waiting > 0)
Processor::yield();
m_process_lock.lock();
m_open_file_descriptors.close_all();
@ -252,7 +246,35 @@ namespace Kernel
void Process::exit(int status, int signal)
{
m_exit_status.exit_code = __WGENEXITCODE(status, signal);
if (m_parent)
{
for_each_process(
[&](Process& parent) -> BAN::Iteration
{
if (parent.pid() != m_parent)
return BAN::Iteration::Continue;
for (auto& child : parent.m_child_exit_statuses)
{
if (child.pid != pid())
continue;
child.exit_code = __WGENEXITCODE(status, signal);
child.exited = true;
parent.add_pending_signal(SIGCHLD);
Processor::scheduler().unblock_thread(parent.m_threads.front());
parent.m_child_exit_blocker.unblock();
break;
}
return BAN::Iteration::Break;
}
);
}
while (!m_threads.empty())
m_threads.front()->on_exit();
}
@ -397,6 +419,20 @@ namespace Kernel
LockGuard _(m_process_lock);
ChildExitStatus* child_exit_status = nullptr;
for (auto& child : m_child_exit_statuses)
{
if (child.pid != 0)
continue;
child_exit_status = &child;
break;
}
if (child_exit_status == nullptr)
{
TRY(m_child_exit_statuses.emplace_back());
child_exit_status = &m_child_exit_statuses.back();
}
BAN::String working_directory;
TRY(working_directory.append(m_working_directory));
@ -422,6 +458,10 @@ namespace Kernel
forked->m_has_called_exec = false;
memcpy(forked->m_signal_handlers, m_signal_handlers, sizeof(m_signal_handlers));
*child_exit_status = {};
child_exit_status->pid = forked->pid();
child_exit_status->pgrp = forked->pgrp();
ASSERT(this == &Process::current());
// FIXME: this should be able to fail
Thread* thread = MUST(Thread::current().clone(forked, sp, ip));
@ -541,58 +581,72 @@ namespace Kernel
ASSERT_NOT_REACHED();
}
BAN::ErrorOr<int> Process::block_until_exit(pid_t pid)
{
ASSERT(this->pid() != pid);
Process* target = nullptr;
for_each_process(
[pid, &target](Process& process)
{
if (process.pid() == pid)
{
process.m_exit_status.waiting++;
target = &process;
return BAN::Iteration::Break;
}
return BAN::Iteration::Continue;
}
);
if (target == nullptr)
return BAN::Error::from_errno(ECHILD);
while (!target->m_exit_status.exited)
{
if (auto ret = Thread::current().block_or_eintr_indefinite(target->m_exit_status.thread_blocker); ret.is_error())
{
target->m_exit_status.waiting--;
return ret.release_error();
}
}
int exit_status = target->m_exit_status.exit_code;
target->m_exit_status.waiting--;
return exit_status;
}
BAN::ErrorOr<long> Process::sys_wait(pid_t pid, int* stat_loc, int options)
{
{
LockGuard _(m_process_lock);
TRY(validate_pointer_access(stat_loc, sizeof(int)));
}
// FIXME: support options
if (options)
if (options & ~(WCONTINUED | WNOHANG | WUNTRACED))
return BAN::Error::from_errno(EINVAL);
int stat = TRY(block_until_exit(pid));
if (stat_loc)
*stat_loc = stat;
// FIXME: support options stopped processes
if (options & ~(WCONTINUED | WUNTRACED))
return BAN::Error::from_errno(ENOTSUP);
return pid;
const auto pid_matches =
[&](const ChildExitStatus& child)
{
if (pid == -1)
return true;
if (pid == 0)
return child.pgrp == pgrp();
if (pid < 0)
return child.pgrp == -pid;
return child.pid == pid;
};
for (;;)
{
pid_t exited_pid = 0;
int exit_code = 0;
{
SpinLockGuard _(m_child_exit_lock);
bool found = false;
for (auto& child : m_child_exit_statuses)
{
if (!pid_matches(child))
continue;
found = true;
if (!child.exited)
continue;
exited_pid = child.pid;
exit_code = child.exit_code;
child = {};
break;
}
if (!found)
return BAN::Error::from_errno(ECHILD);
}
if (exited_pid != 0)
{
if (stat_loc)
{
LockGuard _(m_process_lock);
TRY(validate_pointer_access(stat_loc, sizeof(stat_loc)));
*stat_loc = exit_code;
}
remove_pending_signal(SIGCHLD);
return exited_pid;
}
if (Thread::current().is_interrupted_by_signal())
return BAN::Error::from_errno(EINTR);
if (options & WNOHANG)
return 0;
m_child_exit_blocker.block_indefinite();
}
}
BAN::ErrorOr<long> Process::sys_sleep(int seconds)
@ -860,8 +914,8 @@ namespace Kernel
int fd = TRY(m_open_file_descriptors.open(file, flags));
// Open controlling terminal
if ((flags & O_TTY_INIT) && !(flags & O_NOCTTY) && file.inode->is_tty() && is_session_leader() && !m_controlling_terminal)
m_controlling_terminal = (TTY*)file.inode.ptr();
if (!(flags & O_NOCTTY) && file.inode->is_tty() && is_session_leader() && !m_controlling_terminal)
m_controlling_terminal = static_cast<TTY*>(file.inode.ptr());
return fd;
}
@ -1289,7 +1343,7 @@ namespace Kernel
break;
LockFreeGuard free(m_process_lock);
SystemTimer::get().sleep_ms(1);
TRY(Thread::current().sleep_or_eintr_ms(1));
}
if (arguments->readfds)
@ -1681,6 +1735,50 @@ namespace Kernel
return 0;
}
BAN::ErrorOr<long> Process::sys_posix_openpt(int flags)
{
if (flags & ~(O_RDWR | O_NOCTTY))
return BAN::Error::from_errno(EINVAL);
mode_t mode = 0440;
if (flags & O_WRONLY)
mode = 0660;
auto pts_master = TRY(PseudoTerminalMaster::create(mode, m_credentials.ruid(), m_credentials.rgid()));
auto pts_slave = TRY(pts_master->slave());
VirtualFileSystem::File file;
file.inode = pts_master;
TRY(file.canonical_path.append(pts_master->name()));
LockGuard _(m_process_lock);
int pts_master_fd = TRY(m_open_file_descriptors.open(file, flags));
if (!(flags & O_NOCTTY) && is_session_leader() && !m_controlling_terminal)
m_controlling_terminal = (TTY*)pts_slave.ptr();
return pts_master_fd;
}
BAN::ErrorOr<long> Process::sys_ptsname(int fildes, char* buffer, size_t buffer_len)
{
LockGuard _(m_process_lock);
TRY(validate_pointer_access(buffer, buffer_len));
auto inode = TRY(m_open_file_descriptors.inode_of(fildes));
if (TRY(m_open_file_descriptors.path_of(fildes)) != "<ptmx>"_sv)
return BAN::Error::from_errno(ENOTTY);
auto ptsname = TRY(static_cast<PseudoTerminalMaster*>(inode.ptr())->ptsname());
const size_t to_copy = BAN::Math::min(ptsname.size() + 1, buffer_len);
memcpy(buffer, ptsname.data(), to_copy);
buffer[to_copy] = '\0';
return 0;
}
BAN::ErrorOr<long> Process::sys_tty_ctrl(int fildes, int command, int flags)
{
LockGuard _(m_process_lock);
@ -1883,10 +1981,11 @@ namespace Kernel
if (!inode->is_tty())
return BAN::Error::from_errno(ENOTTY);
if ((TTY*)inode.ptr() != m_controlling_terminal.ptr())
auto* tty = static_cast<TTY*>(inode.ptr());
if (tty != m_controlling_terminal.ptr())
return BAN::Error::from_errno(ENOTTY);
((TTY*)inode.ptr())->set_foreground_pgrp(pgrp);
tty->set_foreground_pgrp(pgrp);
return 0;
}
@ -1948,6 +2047,20 @@ namespace Kernel
return BAN::Error::from_errno(EPERM);
}
BAN::ErrorOr<long> Process::sys_setsid()
{
LockGuard _(m_process_lock);
if (is_session_leader() || m_pid == m_pgrp)
return BAN::Error::from_errno(EPERM);
m_sid = m_pid;
m_pgrp = m_pid;
m_controlling_terminal.clear();
return 0;
}
BAN::ErrorOr<long> Process::sys_seteuid(uid_t uid)
{
if (uid < 0 || uid >= 1'000'000'000)
@ -2225,7 +2338,7 @@ namespace Kernel
// FIXME: should we allow cross mapping access?
for (auto& mapped_region : m_mapped_regions)
mapped_region->contains_fully(vaddr, size);
if (mapped_region->contains_fully(vaddr, size))
return {};
// FIXME: elf should contain full range [vaddr, vaddr + size)

View File

@ -361,6 +361,8 @@ namespace Kernel
else
m_block_queue.add_thread_with_wake_time(node);
m_thread_count++;
Processor::set_interrupt_state(state);
}

View File

@ -0,0 +1,142 @@
#include <kernel/Device/DeviceNumbers.h>
#include <kernel/FS/DevFS/FileSystem.h>
#include <kernel/Terminal/PseudoTerminal.h>
#include <sys/sysmacros.h>
namespace Kernel
{
BAN::Atomic<uint32_t> s_pts_master_minor = 0;
BAN::Atomic<uint32_t> s_pts_slave_number = 0;
BAN::ErrorOr<BAN::RefPtr<PseudoTerminalMaster>> PseudoTerminalMaster::create(mode_t mode, uid_t uid, gid_t gid)
{
auto pts_master_buffer = TRY(VirtualRange::create_to_vaddr_range(
PageTable::kernel(),
KERNEL_OFFSET, static_cast<vaddr_t>(-1),
16 * PAGE_SIZE,
PageTable::Flags::ReadWrite | PageTable::Flags::Present, true
));
auto pts_master = TRY(BAN::RefPtr<PseudoTerminalMaster>::create(BAN::move(pts_master_buffer), mode, uid, gid));
auto pts_slave_buffer = TRY(VirtualRange::create_to_vaddr_range(
PageTable::kernel(),
KERNEL_OFFSET, static_cast<vaddr_t>(-1),
16 * PAGE_SIZE,
PageTable::Flags::ReadWrite | PageTable::Flags::Present, true
));
auto pts_slave_name = TRY(BAN::String::formatted("pts{}", s_pts_slave_number++));
auto pts_slave = TRY(BAN::RefPtr<PseudoTerminalSlave>::create(BAN::move(pts_slave_buffer), BAN::move(pts_slave_name), 0610, uid, gid));
pts_master->m_slave = TRY(pts_slave->get_weak_ptr());
pts_slave->m_master = TRY(pts_master->get_weak_ptr());
DevFileSystem::get().add_device(pts_slave);
return pts_master;
}
PseudoTerminalMaster::PseudoTerminalMaster(BAN::UniqPtr<VirtualRange> buffer, mode_t mode, uid_t uid, gid_t gid)
: CharacterDevice(mode, uid, gid)
, m_buffer(BAN::move(buffer))
, m_rdev(makedev(DeviceNumber::PTSMaster, s_pts_master_minor++))
{ }
PseudoTerminalMaster::~PseudoTerminalMaster()
{
if (auto slave = m_slave.lock())
DevFileSystem::get().remove_device(slave);
}
BAN::ErrorOr<BAN::RefPtr<PseudoTerminalSlave>> PseudoTerminalMaster::slave()
{
if (auto slave = m_slave.lock())
return slave;
return BAN::Error::from_errno(ENODEV);
}
BAN::ErrorOr<BAN::String> PseudoTerminalMaster::ptsname()
{
if (auto slave = m_slave.lock())
return TRY(BAN::String::formatted("/dev/{}", slave->name()));
return BAN::Error::from_errno(ENODEV);
}
void PseudoTerminalMaster::putchar(uint8_t ch)
{
SpinLockGuard _(m_buffer_lock);
if (m_buffer_size == m_buffer->size())
{
dwarnln("PseudoTerminalMaster buffer full");
m_buffer_tail = (m_buffer_tail + 1) % m_buffer->size();
m_buffer_size--;
}
*reinterpret_cast<uint8_t*>(m_buffer->vaddr() + (m_buffer_tail + m_buffer_size) % m_buffer->size()) = ch;
m_buffer_size++;
}
BAN::ErrorOr<size_t> PseudoTerminalMaster::read_impl(off_t, BAN::ByteSpan buffer)
{
auto state = m_buffer_lock.lock();
while (m_buffer_size == 0)
{
m_buffer_lock.unlock(state);
TRY(Thread::current().block_or_eintr_indefinite(m_buffer_blocker));
m_buffer_lock.lock();
}
const size_t to_copy = BAN::Math::min(buffer.size(), m_buffer_size);
if (m_buffer_tail + to_copy < m_buffer->size())
memcpy(buffer.data(), reinterpret_cast<void*>(m_buffer->vaddr() + m_buffer_tail), to_copy);
else
{
const size_t before_wrap = m_buffer_size - m_buffer_tail;
const size_t after_wrap = to_copy - before_wrap;
memcpy(buffer.data(), reinterpret_cast<void*>(m_buffer->vaddr() + m_buffer_tail), before_wrap);
memcpy(buffer.data() + before_wrap, reinterpret_cast<void*>(m_buffer->vaddr()), after_wrap);
}
m_buffer_size -= to_copy;
m_buffer_tail = (m_buffer_tail + to_copy) % m_buffer->size();
m_buffer_lock.unlock(state);
return to_copy;
}
BAN::ErrorOr<size_t> PseudoTerminalMaster::write_impl(off_t, BAN::ConstByteSpan buffer)
{
auto slave = m_slave.lock();
if (!slave)
return BAN::Error::from_errno(ENODEV);
for (size_t i = 0; i < buffer.size(); i++)
slave->handle_input_byte(buffer[i]);
return buffer.size();
}
PseudoTerminalSlave::PseudoTerminalSlave(BAN::UniqPtr<VirtualRange> buffer, BAN::String&& name, mode_t mode, uid_t uid, gid_t gid)
: TTY(mode, uid, gid)
, m_name(BAN::move(name))
, m_buffer(BAN::move(buffer))
{}
void PseudoTerminalSlave::clear()
{
const char message[] { '\e', '[', '2', 'J' };
(void)write_impl(0, BAN::ConstByteSpan::from(message));
}
void PseudoTerminalSlave::putchar_impl(uint8_t ch)
{
if (auto master = m_master.lock())
master->putchar(ch);
}
}

View File

@ -1,5 +1,4 @@
#include <BAN/Array.h>
#include <kernel/Device/DeviceNumbers.h>
#include <kernel/FS/DevFS/FileSystem.h>
#include <kernel/IDT.h>
#include <kernel/InterruptController.h>
@ -7,7 +6,6 @@
#include <kernel/Terminal/Serial.h>
#include <ctype.h>
#include <sys/sysmacros.h>
#define MAX_BAUD 115200
@ -33,6 +31,8 @@
namespace Kernel
{
static BAN::Atomic<uint32_t> s_next_tty_number = 0;
static constexpr uint16_t s_serial_ports[] = { 0x3F8, 0x2F8, 0x3E8, 0x2E8, 0x5F8, 0x4F8, 0x5E8, 0x4E8 };
static BAN::Array<Serial, sizeof(s_serial_ports) / sizeof(*s_serial_ports)> s_serial_drivers;
static bool s_has_devices { false };
@ -40,12 +40,6 @@ namespace Kernel
static BAN::RefPtr<SerialTTY> s_com1;
static BAN::RefPtr<SerialTTY> s_com2;
static dev_t next_rdev()
{
static dev_t minor = 0;
return makedev(DeviceNumber::Serial, minor++);
}
void Serial::initialize()
{
int count = 0;
@ -179,9 +173,8 @@ namespace Kernel
SerialTTY::SerialTTY(Serial serial)
: TTY(0600, 0, 0)
, m_name(MUST(BAN::String::formatted("ttyS{}", minor(rdev()))))
, m_name(MUST(BAN::String::formatted("ttyS{}", s_next_tty_number++)))
, m_serial(serial)
, m_rdev(next_rdev())
{}
BAN::ErrorOr<BAN::RefPtr<SerialTTY>> SerialTTY::create(Serial serial)

View File

@ -2,6 +2,7 @@
#include <BAN/ScopeGuard.h>
#include <BAN/UTF8.h>
#include <kernel/Debug.h>
#include <kernel/Device/DeviceNumbers.h>
#include <kernel/FS/DevFS/FileSystem.h>
#include <kernel/FS/VirtualFileSystem.h>
#include <kernel/Lock/LockGuard.h>
@ -20,6 +21,25 @@ namespace Kernel
static BAN::RefPtr<TTY> s_tty;
static dev_t next_tty_rdev()
{
static BAN::Atomic<dev_t> s_minor = 0;
return makedev(DeviceNumber::TTY, s_minor++);
}
TTY::TTY(mode_t mode, uid_t uid, gid_t gid)
: CharacterDevice(mode, uid, gid)
, m_rdev(next_tty_rdev())
{
// FIXME: add correct baud and flags
m_termios.c_iflag = 0;
m_termios.c_oflag = 0;
m_termios.c_cflag = CS8;
m_termios.c_lflag = ECHO | ICANON;
m_termios.c_ospeed = B38400;
m_termios.c_ispeed = B38400;
}
BAN::RefPtr<TTY> TTY::current()
{
ASSERT(s_tty);

View File

@ -2,7 +2,6 @@
#include <BAN/ScopeGuard.h>
#include <BAN/UTF8.h>
#include <kernel/Debug.h>
#include <kernel/Device/DeviceNumbers.h>
#include <kernel/FS/DevFS/FileSystem.h>
#include <kernel/Lock/LockGuard.h>
#include <kernel/Process.h>
@ -10,7 +9,6 @@
#include <fcntl.h>
#include <string.h>
#include <sys/sysmacros.h>
#define BEL 0x07
#define BS 0x08
@ -25,11 +23,7 @@
namespace Kernel
{
static dev_t next_rdev()
{
static dev_t minor = 0;
return makedev(DeviceNumber::TTY, minor++);
}
static BAN::Atomic<uint32_t> s_next_tty_number = 0;
BAN::ErrorOr<BAN::RefPtr<VirtualTTY>> VirtualTTY::create(TerminalDriver* driver)
{
@ -43,9 +37,8 @@ namespace Kernel
VirtualTTY::VirtualTTY(TerminalDriver* driver)
: TTY(0600, 0, 0)
, m_name(MUST(BAN::String::formatted("tty{}", minor(rdev()))))
, m_name(MUST(BAN::String::formatted("tty{}", s_next_tty_number++)))
, m_terminal_driver(driver)
, m_rdev(next_rdev())
{
m_width = m_terminal_driver->width();
m_height = m_terminal_driver->height();

View File

@ -423,6 +423,16 @@ namespace Kernel
return false;
}
BAN::ErrorOr<void> Thread::sleep_or_eintr_ns(uint64_t ns)
{
if (is_interrupted_by_signal())
return BAN::Error::from_errno(EINTR);
SystemTimer::get().sleep_ns(ns);
if (is_interrupted_by_signal())
return BAN::Error::from_errno(EINTR);
return {};
}
BAN::ErrorOr<void> Thread::block_or_eintr_indefinite(ThreadBlocker& thread_blocker)
{
if (is_interrupted_by_signal())

View File

@ -4,6 +4,10 @@ NAME='doom'
VERSION='git'
DOWNLOAD_URL="https://github.com/ozkl/doomgeneric.git#613f870b6fa83ede448a247de5a2571092fa729d"
configure() {
:
}
build() {
if [ ! -f doom1.wad ]; then
wget https://distro.ibiblio.org/slitaz/sources/packages/d/doom1.wad || exit 1

View File

@ -6,7 +6,7 @@ if (( $# != 1 )); then
fi
if [[ -z $BANAN_ROOT_DIR ]]; then
BANAN_ROOT_DIR="$(dirname $(realpath $0))/.."
BANAN_ROOT_DIR="$(realpath $(dirname $(realpath $0))/..)"
fi
source "$BANAN_ROOT_DIR/script/config.sh"
@ -18,6 +18,10 @@ export PKG_CONFIG_SYSROOT_DIR="$BANAN_SYSROOT"
export PKG_CONFIG_LIBDIR="$PKG_CONFIG_SYSROOT_DIR/usr/lib/pkgconfig"
export PKG_CONFIG_PATH="$PKG_CONFIG_SYSROOT_DIR/usr/share/pkgconfig"
export CC="$BANAN_TOOLCHAIN_TRIPLE-gcc"
export CXX="$BANAN_TOOLCHAIN_TRIPLE-g++"
export LD="$BANAN_TOOLCHAIN_TRIPLE-ld"
if [ ! -f "$BANAN_SYSROOT/usr/lib/libc.a" ]; then
pushd "$BANAN_ROOT_DIR" >/dev/null
./bos libc || exit 1
@ -29,11 +33,13 @@ clean() {
find . -mindepth 1 -maxdepth 1 -not -name 'patches' -not -name 'build.sh' -exec rm -rf {} +
}
build() {
configure() {
configure_options=("--host=$BANAN_ARCH-banan_os" '--prefix=/usr')
configure_options+=(${CONFIGURE_OPTIONS[*]})
configure_options+=("${CONFIGURE_OPTIONS[@]}")
./configure "${configure_options[@]}" || exit 1
}
./configure ${configure_options[*]} || exit 1
build() {
make -j$(nproc) || exit 1
}
@ -143,6 +149,7 @@ fi
cd "$build_dir"
if (( $needs_compile )); then
configure
build
sha256sum "$BANAN_SYSROOT/usr/lib/libc.a" > "../.compile_hash"
fi

View File

@ -4,7 +4,10 @@ NAME='ncurses'
VERSION='6.5'
DOWNLOAD_URL="https://ftp.gnu.org/gnu/ncurses/ncurses-$VERSION.tar.gz#136d91bc269a9a5785e5f9e980bc76ab57428f604ce3e5a5a90cebc767971cc6"
CONFIGURE_OPTIONS=(
'--disable-db-intall'
"--with-pkg-config='$PKG_CONFIG'"
"--with-pkg-config-libdir=/usr/lib/pkgconfig"
'--enable-pc-files'
'--enable-sigwinch'
'--disable-widec'
'--without-ada'
'--without-manpages'

View File

@ -1,9 +1,16 @@
#!/bin/bash
if [ -z $BANAN_PORT_DIR ]; then
echo "You must set the BANAN_PORT_DIR environment variable" >&2
exit 1
fi
cd $(dirname $(realpath $0))
rm -f $BANAN_PORT_DIR/.installed
while IFS= read -r port; do
pushd $(dirname "$port") >/dev/null
./build.sh
popd >/dev/null
done < <(find . -name '.compile_hash')
done < <(find $BANAN_PORT_DIR -name '.compile_hash')

View File

@ -4,7 +4,7 @@ NAME='vim'
VERSION='9.0'
DOWNLOAD_URL="ftp://ftp.vim.org/pub/vim/unix/vim-$VERSION.tar.bz2#a6456bc154999d83d0c20d968ac7ba6e7df0d02f3cb6427fb248660bacfb336e"
TAR_CONTENT='vim90'
DEPENDENCIES=('ncurses' )
DEPENDENCIES=('ncurses')
CONFIGURE_OPTIONS=(
'--with-tlib=ncurses'
'--disable-nls'

View File

@ -1,6 +1,6 @@
if [[ -z $BANAN_ROOT_DIR ]]; then
if ! [[ -z $BANAN_SCRIPT_DIR ]]; then
export BANAN_ROOT_DIR=$BANAN_SCRIPT_DIR/..
export BANAN_ROOT_DIR="$(realpath $BANAN_SCRIPT_DIR/..)"
else
echo "You must set the BANAN_ROOT_DIR environment variable" >&2
exit 1
@ -13,10 +13,12 @@ fi
export BANAN_TOOLCHAIN_DIR=$BANAN_ROOT_DIR/toolchain
export BANAN_TOOLCHAIN_PREFIX=$BANAN_TOOLCHAIN_DIR/local
export BANAN_TOOLCHAIN_TRIPLE_PREFIX=$BANAN_ARCH-banan_os
export BANAN_TOOLCHAIN_TRIPLE=$BANAN_ARCH-banan_os
export BANAN_BUILD_DIR=$BANAN_ROOT_DIR/build
export BANAN_PORT_DIR=$BANAN_ROOT_DIR/ports
export BANAN_SYSROOT=$BANAN_BUILD_DIR/sysroot
export BANAN_SYSROOT_TAR=$BANAN_SYSROOT.tar

View File

@ -47,8 +47,8 @@ if [[ -z $BANAN_TOOLCHAIN_PREFIX ]]; then
exit 1
fi
if [[ -z $BANAN_TOOLCHAIN_TRIPLE_PREFIX ]]; then
echo "You must set the BANAN_TOOLCHAIN_TRIPLE_PREFIX environment variable" >&2
if [[ -z $BANAN_TOOLCHAIN_TRIPLE ]]; then
echo "You must set the BANAN_TOOLCHAIN_TRIPLE environment variable" >&2
exit 1
fi
@ -89,7 +89,7 @@ build_binutils () {
enter_clean_build
../configure \
--target="$BANAN_TOOLCHAIN_TRIPLE_PREFIX" \
--target="$BANAN_TOOLCHAIN_TRIPLE" \
--prefix="$BANAN_TOOLCHAIN_PREFIX" \
--with-sysroot="$BANAN_SYSROOT" \
--disable-initfini-array \
@ -116,7 +116,7 @@ build_gcc () {
enter_clean_build
../configure \
--target="$BANAN_TOOLCHAIN_TRIPLE_PREFIX" \
--target="$BANAN_TOOLCHAIN_TRIPLE" \
--prefix="$BANAN_TOOLCHAIN_PREFIX" \
--with-sysroot="$BANAN_SYSROOT" \
--disable-initfini-array \
@ -189,7 +189,7 @@ build_cmake() {
}
BUILD_BINUTILS=1
if [[ -f $BANAN_TOOLCHAIN_PREFIX/bin/$BANAN_TOOLCHAIN_TRIPLE_PREFIX-ld ]]; then
if [[ -f $BANAN_TOOLCHAIN_PREFIX/bin/$BANAN_TOOLCHAIN_TRIPLE-ld ]]; then
echo "You already seem to have a binutils installed."
read -e -p "Do you want to rebuild it [y/N]? " choice
if ! [[ "$choice" == [Yy]* ]]; then
@ -198,7 +198,7 @@ if [[ -f $BANAN_TOOLCHAIN_PREFIX/bin/$BANAN_TOOLCHAIN_TRIPLE_PREFIX-ld ]]; then
fi
BUILD_GCC=1
if [[ -f $BANAN_TOOLCHAIN_PREFIX/bin/$BANAN_TOOLCHAIN_TRIPLE_PREFIX-gcc ]]; then
if [[ -f $BANAN_TOOLCHAIN_PREFIX/bin/$BANAN_TOOLCHAIN_TRIPLE-gcc ]]; then
echo "You already seem to have a gcc installed."
read -e -p "Do you want to rebuild it [y/N]? " choice
if ! [[ "$choice" == [Yy]* ]]; then

View File

@ -3,7 +3,9 @@ set(LIBC_SOURCES
assert.cpp
ctype.cpp
dirent.cpp
dlfcn.cpp
fcntl.cpp
ftw.cpp
grp.cpp
inttypes.cpp
locale.cpp
@ -13,13 +15,14 @@ set(LIBC_SOURCES
printf_impl.cpp
pwd.cpp
scanf_impl.cpp
setjmp.cpp
signal.cpp
stdio.cpp
stdlib.cpp
string.cpp
strings.cpp
stropts.cpp
sys/banan-os.cpp
sys/ioctl.cpp
sys/mman.cpp
sys/select.cpp
sys/socket.cpp
@ -30,8 +33,12 @@ set(LIBC_SOURCES
termios.cpp
time.cpp
unistd.cpp
utime.cpp
wchar.cpp
icxxabi.cpp
arch/${BANAN_ARCH}/setjmp.S
../../../BAN/BAN/Assert.cpp
)

View File

@ -0,0 +1,28 @@
// int setjmp(jmp_buf env)
.global setjmp
setjmp:
movl 4(%esp), %edx
leal 4(%esp), %eax
movl %eax, 0(%edx)
movl (%esp), %eax
movl %eax, 4(%edx)
xorl %eax, %eax
ret
// void longjmp(jmp_buf env, int val)
.global longjmp
longjmp:
movl 4(%esp), %edx
movl 8(%esp), %ecx
movl $1, %eax
testl %ecx, %ecx
cmovnzl %ecx, %eax
movl 0(%edx), %esp
movl 4(%edx), %ecx
jmp *%ecx

View File

@ -0,0 +1,23 @@
// int setjmp(jmp_buf env)
.global setjmp
setjmp:
leaq 8(%rsp), %rax
movq %rax, 0(%rdi)
movq (%rsp), %rax
movq %rax, 8(%rdi)
xorq %rax, %rax
ret
// void longjmp(jmp_buf env, int val)
.global longjmp
longjmp:
movq $1, %rax
testq %rsi, %rsi
cmovnzq %rsi, %rax
movq 0(%rdi), %rsp
movq 8(%rdi), %rcx
jmp *%rcx

View File

@ -0,0 +1,23 @@
#include <BAN/Assert.h>
#include <dlfcn.h>
int dlclose(void*)
{
ASSERT_NOT_REACHED();
}
char* dlerror(void)
{
ASSERT_NOT_REACHED();
}
void* dlopen(const char*, int)
{
ASSERT_NOT_REACHED();
}
void* dlsym(void* __restrict, const char* __restrict)
{
ASSERT_NOT_REACHED();
}

View File

@ -0,0 +1,13 @@
#include <BAN/Assert.h>
#include <ftw.h>
int ftw(const char*, int (*)(const char*, const struct stat*, int), int)
{
ASSERT_NOT_REACHED();
}
int nftw(const char*, int (*)(const char*, const struct stat*, int, struct FTW*), int, int)
{
ASSERT_NOT_REACHED();
}

View File

@ -39,26 +39,3 @@ extern "C" void __cxa_finalize(void* f)
}
}
};
namespace __cxxabiv1
{
using __guard = uint64_t;
extern "C" int __cxa_guard_acquire (__guard* g)
{
uint8_t* byte = reinterpret_cast<uint8_t*>(g);
uint8_t zero = 0;
return __atomic_compare_exchange_n(byte, &zero, 1, false, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE);
}
extern "C" void __cxa_guard_release (__guard* g)
{
uint8_t* byte = reinterpret_cast<uint8_t*>(g);
__atomic_store_n(byte, 0, __ATOMIC_RELEASE);
}
extern "C" void __cxa_guard_abort (__guard*)
{
ASSERT_NOT_REACHED();
}
}

View File

@ -7,13 +7,16 @@
__BEGIN_DECLS
typedef int jmp_buf[1];
typedef int sigjmp_buf[1];
typedef long jmp_buf[2];
typedef long sigjmp_buf[2 + 1 + (sizeof(long long) / sizeof(long))];
void longjmp(jmp_buf env, int val);
void siglongjmp(sigjmp_buf env, int val);
int setjmp(jmp_buf env);
int sigsetjmp(sigjmp_buf env, int savemask);
#define _longjmp longjmp
void longjmp(jmp_buf env, int val);
void siglongjmp(sigjmp_buf env, int val);
#define _setjmp setjmp
int setjmp(jmp_buf env);
int sigsetjmp(sigjmp_buf env, int savemask);
__END_DECLS

View File

@ -71,7 +71,8 @@ struct sigevent
#define SIGVTALRM 26
#define SIGXCPU 27
#define SIGXFSZ 28
#define SIGRTMIN 29
#define SIGWINCH 29
#define SIGRTMIN 30
#define SIGRTMAX (SIGRTMIN+32)
#define _SIGMIN SIGABRT

View File

@ -73,6 +73,7 @@ int mblen(const char* s, size_t n);
size_t mbstowcs(wchar_t* __restrict pwcs, const char* __restrict s, size_t n);
int mbtowc(wchar_t* __restrict pwc, const char* __restrict s, size_t n);
char* mkdtemp(char* _template);
char* mktemp(char* _template);
int mkstemp(char* _template);
long mrand48(void);
long nrand48(unsigned short xsubi[3]);

View File

@ -7,6 +7,8 @@
__BEGIN_DECLS
#include <sys/ioctl.h>
#define __need_uid_t
#define __need_gid_t
#include <sys/types.h>
@ -71,45 +73,6 @@ struct str_list
int sl_nmods; /* Number of STREAMS module names. */
};
#define I_ATMARK 1
#define I_CANPUT 2
#define I_CKBAND 3
#define I_FDINSERT 4
#define I_FIND 5
#define I_FLUSH 6
#define I_FLUSHBAND 7
#define I_GETBAND 8
#define I_GETCLTIME 9
#define I_GETSIG 10
#define I_GRDOPT 11
#define I_GWROPT 12
#define I_LINK 13
#define I_LIST 14
#define I_LOOK 15
#define I_NREAD 16
#define I_PEEK 17
#define I_PLINK 18
#define I_POP 19
#define I_PUNLINK 20
#define I_PUSH 21
#define I_RECVFD 22
#define I_SENDFD 23
#define I_SETCLTIME 24
#define I_SETSIG 25
#define I_SRDOPT 26
#define I_STR 27
#define I_SWROPT 28
#define I_UNLINK 29
#define KDLOADFONT 30
struct winsize
{
unsigned short ws_row;
unsigned short ws_col;
};
#define TIOCGWINSZ 50
#define FLUSHR 1
#define FLUSHRW 2
#define FLUSHW 3
@ -152,7 +115,6 @@ int fattach(int, const char*);
int fdetach(const char*);
int getmsg(int, struct strbuf* __restrict, struct strbuf* __restrict, int* __restrict);
int getpmsg(int, struct strbuf* __restrict, struct strbuf* __restrict, int* __restrict, int* __restrict);
int ioctl(int, int, ...);
int isastream(int);
int putmsg(int, const struct strbuf*, const struct strbuf*, int);
int putpmsg(int, const struct strbuf*, const struct strbuf*, int, int);

View File

@ -0,0 +1,52 @@
#ifndef _SYS_IOCTL_H
#define _SYS_IOCTL_H 1
#include <sys/cdefs.h>
__BEGIN_DECLS
#define I_ATMARK 1
#define I_CANPUT 2
#define I_CKBAND 3
#define I_FDINSERT 4
#define I_FIND 5
#define I_FLUSH 6
#define I_FLUSHBAND 7
#define I_GETBAND 8
#define I_GETCLTIME 9
#define I_GETSIG 10
#define I_GRDOPT 11
#define I_GWROPT 12
#define I_LINK 13
#define I_LIST 14
#define I_LOOK 15
#define I_NREAD 16
#define I_PEEK 17
#define I_PLINK 18
#define I_POP 19
#define I_PUNLINK 20
#define I_PUSH 21
#define I_RECVFD 22
#define I_SENDFD 23
#define I_SETCLTIME 24
#define I_SETSIG 25
#define I_SRDOPT 26
#define I_STR 27
#define I_SWROPT 28
#define I_UNLINK 29
#define KDLOADFONT 30
struct winsize
{
unsigned short ws_row;
unsigned short ws_col;
};
#define TIOCGWINSZ 50
#define TIOCSWINSZ 51
int ioctl(int, int, ...);
__END_DECLS
#endif

View File

@ -18,34 +18,34 @@ typedef unsigned long __fd_mask;
#define __FD_MASK_SIZE (8 * sizeof(__fd_mask))
typedef struct {
__fd_mask __bits[FD_SETSIZE / __FD_MASK_SIZE];
__fd_mask __fds_bits[FD_SETSIZE / __FD_MASK_SIZE];
} fd_set;
#define FD_CLR(fd, setp) \
do { \
__fd_mask off = (fd) / __FD_MASK_SIZE; \
__fd_mask bit = (fd) % __FD_MASK_SIZE; \
(setp)->__bits[off] &= ~((__fd_mask)1 << bit); \
(setp)->__fds_bits[off] &= ~((__fd_mask)1 << bit); \
} while (0)
#define FD_ISSET(fd, setp) \
({ \
__fd_mask off = (fd) / __FD_MASK_SIZE; \
__fd_mask bit = (fd) % __FD_MASK_SIZE; \
(setp)->__bits[off] & ((__fd_mask)1 << bit); \
(setp)->__fds_bits[off] & ((__fd_mask)1 << bit); \
})
#define FD_SET(fd, setp) \
do { \
__fd_mask off = (fd) / __FD_MASK_SIZE; \
__fd_mask bit = (fd) % __FD_MASK_SIZE; \
(setp)->__bits[off] |= ((__fd_mask)1 << bit); \
(setp)->__fds_bits[off] |= ((__fd_mask)1 << bit); \
} while (0)
#define FD_ZERO(setp) \
do { \
for (int i = 0; i < (int)FD_SETSIZE / (int)__FD_MASK_SIZE; i++) \
(setp)->__bits[i] = (__fd_mask)0; \
(setp)->__fds_bits[i] = (__fd_mask)0; \
} while (0)
struct sys_pselect_t

View File

@ -25,6 +25,7 @@ __BEGIN_DECLS
O(SYS_READ_DIR, readdir) \
O(SYS_SET_UID, setuid) \
O(SYS_SET_GID, setgid) \
O(SYS_SET_SID, setsid) \
O(SYS_SET_EUID, seteuid) \
O(SYS_SET_EGID, setegid) \
O(SYS_SET_REUID, setreuid) \
@ -87,6 +88,8 @@ __BEGIN_DECLS
O(SYS_SIGPENDING, sigpending) \
O(SYS_SIGPROCMASK, sigprocmask) \
O(SYS_SETITIMER, setitimer) \
O(SYS_POSIX_OPENPT, posix_openpt) \
O(SYS_PTSNAME, ptsname) \
enum Syscall
{

View File

@ -106,7 +106,30 @@ __BEGIN_DECLS
// FIXME: _CS prefixed definitions
// FIXME: _PC prefixed definitions
enum
{
_PC_2_SYMLINKS,
_PC_ALLOC_SIZE_MIN,
_PC_ASYNC_IO,
_PC_CHOWN_RESTRICTED,
_PC_FILESIZEBITS,
_PC_LINK_MAX,
_PC_MAX_CANON,
_PC_MAX_INPUT,
_PC_NAME_MAX,
_PC_NO_TRUNC,
_PC_PATH_MAX,
_PC_PIPE_BUF,
_PC_PRIO_IO,
_PC_REC_INCR_XFER_SIZE,
_PC_REC_MAX_XFER_SIZE,
_PC_REC_MIN_XFER_SIZE,
_PC_REC_XFER_ALIGN,
_PC_SYMLINK_MAX,
_PC_SYNC_IO,
_PC_TIMESTAMP_RESOLUTION,
_PC_VDISABLE,
};
#define F_OK 0x01
#define R_OK 0x02

View File

@ -1,5 +1,6 @@
#include <BAN/Assert.h>
#include <limits.h>
#include <locale.h>
#include <stdio.h>
#include <string.h>
@ -35,6 +36,38 @@ static const char* locale_to_str(locale_t locale)
ASSERT_NOT_REACHED();
}
struct lconv* localeconv(void)
{
constexpr char CHAR_MAX = __SCHAR_MAX__;
static lconv lconv;
lconv.currency_symbol = const_cast<char*>("");
lconv.decimal_point = const_cast<char*>(".");
lconv.frac_digits = CHAR_MAX;
lconv.grouping = const_cast<char*>("");
lconv.int_curr_symbol = const_cast<char*>("");
lconv.int_frac_digits = CHAR_MAX;
lconv.int_n_cs_precedes = CHAR_MAX;
lconv.int_n_sep_by_space = CHAR_MAX;
lconv.int_n_sign_posn = CHAR_MAX;
lconv.int_p_cs_precedes = CHAR_MAX;
lconv.int_p_sep_by_space = CHAR_MAX;
lconv.int_p_sign_posn = CHAR_MAX;
lconv.mon_decimal_point = const_cast<char*>("");
lconv.mon_grouping = const_cast<char*>("");
lconv.mon_thousands_sep = const_cast<char*>("");
lconv.negative_sign = const_cast<char*>("");
lconv.n_cs_precedes = CHAR_MAX;
lconv.n_sep_by_space = CHAR_MAX;
lconv.n_sign_posn = CHAR_MAX;
lconv.positive_sign = const_cast<char*>("");
lconv.p_cs_precedes = CHAR_MAX;
lconv.p_sep_by_space = CHAR_MAX;
lconv.p_sign_posn = CHAR_MAX;
lconv.thousands_sep = const_cast<char*>("");
return &lconv;
}
char* setlocale(int category, const char* locale_str)
{
static char s_locale_buffer[128];
@ -94,7 +127,6 @@ char* setlocale(int category, const char* locale_str)
return s_locale_buffer;
}
locale_t __getlocale(int category)
{
switch (category)

View File

@ -8,7 +8,12 @@
#define BUILTINS2(func) \
float func##f(float a, float b) { return __builtin_##func##f(a, b); } \
double func(double a, double b) { return __builtin_##func(a, b); } \
long double func##l(long double a, long double b) { return __builtin_##func##l(a, b); } \
long double func##l(long double a, long double b) { return __builtin_##func##l(a, b); }
#define BUILTINS2_TYPE(func, type) \
float func##f(float a, type b) { return __builtin_##func##f(a, b); } \
double func(double a, type b) { return __builtin_##func(a, b); } \
long double func##l(long double a, type b) { return __builtin_##func##l(a, b); }
__BEGIN_DECLS
@ -38,6 +43,7 @@ BUILTINS2(fmod)
BUILTINS2(hypot)
BUILTINS1(j0)
BUILTINS1(j1)
BUILTINS2_TYPE(ldexp, int)
BUILTINS1(lgamma)
BUILTINS1(log)
BUILTINS1(log10)

View File

@ -1,3 +1,4 @@
#include <BAN/Assert.h>
#include <BAN/Bitcast.h>
#include <arpa/inet.h>
@ -11,6 +12,35 @@
int h_errno = 0;
void freeaddrinfo(struct addrinfo*)
{
ASSERT_NOT_REACHED();
}
const char* gai_strerror(int ecode)
{
switch (ecode)
{
case 0: return "Success";
case EAI_AGAIN: return "The name could not be resolved at this time.";
case EAI_BADFLAGS: return "The flags had an invalid value.";
case EAI_FAIL: return "A non-recoverable error occurred.";
case EAI_FAMILY: return "The address family was not recognized or the address length was invalid for the specified family.";
case EAI_MEMORY: return "There was a memory allocation failure.";
case EAI_NONAME: return "The name does not resolve for the supplied parameters. ";
case EAI_SERVICE: return "The service passed was not recognized for the specified socket type.";
case EAI_SOCKTYPE: return "The intended socket type was not recognized.";
case EAI_SYSTEM: return "A system error occurred. The error code can be found in errno.";
case EAI_OVERFLOW: return "An argument buffer overflowed.";
default: return "Unknown error.";
}
}
int getaddrinfo(const char* __restrict, const char* __restrict, const struct addrinfo* __restrict, struct addrinfo** __restrict)
{
ASSERT_NOT_REACHED();
}
struct hostent* gethostbyname(const char* name)
{
static char name_buffer[HOST_NAME_MAX + 1];

View File

@ -0,0 +1,19 @@
#include <setjmp.h>
#include <signal.h>
static_assert(sizeof(sigjmp_buf) == sizeof(jmp_buf) + sizeof(long) + sizeof(sigset_t));
void siglongjmp(sigjmp_buf env, int val)
{
if (env[2])
pthread_sigmask(SIG_SETMASK, reinterpret_cast<sigset_t*>(&env[3]), nullptr);
return longjmp(env, val);
}
int sigsetjmp(sigjmp_buf env, int savemask)
{
env[2] = savemask;
if (savemask)
pthread_sigmask(0, nullptr, reinterpret_cast<sigset_t*>(&env[3]));
return setjmp(env);
}

View File

@ -733,14 +733,12 @@ FILE* tmpfile(void);
char* tmpnam(char* storage)
{
static int s_counter = rand();
static char s_storage[PATH_MAX];
if (storage == nullptr)
storage = s_storage;
for (int i = 0; i < TMP_MAX; i++)
{
sprintf(storage, "/tmp/tmp_%04x", s_counter);
s_counter = rand();
sprintf(storage, "/tmp/tmp_%04x", rand());
struct stat st;
if (stat(storage, &st) == -1 && errno == ENOENT)
@ -842,3 +840,8 @@ int vsscanf(const char* s, const char* format, va_list arguments)
}, &s
);
}
FILE* tmpfile(void)
{
ASSERT_NOT_REACHED();
}

View File

@ -514,6 +514,36 @@ int putenv(char* string)
return 0;
}
char* mktemp(char*)
{
ASSERT_NOT_REACHED();
}
int posix_openpt(int oflag)
{
return syscall(SYS_POSIX_OPENPT, oflag);
}
int grantpt(int)
{
// currently posix_openpt() does this
return 0;
}
int unlockpt(int)
{
// currently posix_openpt() does this
return 0;
}
char* ptsname(int fildes)
{
static char buffer[PATH_MAX];
if (syscall(SYS_PTSNAME, fildes, buffer, sizeof(buffer)) == -1)
return nullptr;
return buffer;
}
size_t mbstowcs(wchar_t* __restrict pwcs, const char* __restrict s, size_t n)
{
auto* us = reinterpret_cast<const unsigned char*>(s);

View File

@ -1,5 +1,5 @@
#include <stdarg.h>
#include <stropts.h>
#include <sys/ioctl.h>
#include <sys/syscall.h>
#include <unistd.h>

View File

@ -1,3 +1,5 @@
#include <BAN/Assert.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
@ -11,6 +13,11 @@ int chmod(const char* path, mode_t mode)
return syscall(SYS_CHMOD, path, mode);
}
int fchmod(int, mode_t)
{
ASSERT_NOT_REACHED();
}
int fstat(int fildes, struct stat* buf)
{
return syscall(SYS_FSTAT, fildes, buf);

View File

@ -71,7 +71,7 @@ int tcflow(int, int);
int tcflush(int fd, int queue_selector)
{
dwarnln("FIXME: tcflush({}, {})", fd, queue_selector);
ASSERT_NOT_REACHED();
return 0;
}
int tcgetattr(int fildes, struct termios* termios)

View File

@ -475,6 +475,11 @@ int setgid(gid_t gid)
return syscall(SYS_SET_GID, gid);
}
int setsid(void)
{
return syscall(SYS_SET_SID);
}
int setreuid(uid_t ruid, uid_t euid)
{
return syscall(SYS_SET_REUID, ruid, euid);

View File

@ -0,0 +1,8 @@
#include <BAN/Assert.h>
#include <utime.h>
int utime(const char*, const struct utimbuf*)
{
ASSERT_NOT_REACHED();
}

View File

@ -0,0 +1,8 @@
#include <BAN/Assert.h>
#include <wchar.h>
size_t mbrtowc(wchar_t* __restrict, const char* __restrict, size_t, mbstate_t* __restrict)
{
ASSERT_NOT_REACHED();
}

View File

@ -147,7 +147,7 @@ BAN::Optional<BAN::String> parse_dollar(BAN::StringView command, size_t& i)
close(fds[0]);
int status;
if (waitpid(pid, &status, 0) == -1 && errno != ECHILD)
if (waitpid(pid, &status, 0) == -1)
ERROR_RETURN("waitpid", {});
while (!output.empty() && output.back() == '\n')

View File

@ -4,59 +4,63 @@
#include <BAN/UTF8.h>
#include <ctype.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/select.h>
#include <unistd.h>
void Terminal::start_shell()
{
int shell_stdin[2];
if (pipe(shell_stdin) == -1)
int pts_master = posix_openpt(O_RDWR | O_NOCTTY);
if (pts_master == -1)
{
dwarnln("pipe: {}", strerror(errno));
dwarnln("posix_openpt: {}", strerror(errno));
exit(1);
}
int shell_stdout[2];
if (pipe(shell_stdout) == -1)
if (grantpt(pts_master) == -1)
{
dwarnln("pipe: {}", strerror(errno));
dwarnln("grantpt: {}", strerror(errno));
exit(1);
}
int shell_stderr[2];
if (pipe(shell_stderr) == -1)
if (unlockpt(pts_master) == -1)
{
dwarnln("pipe: {}", strerror(errno));
dwarnln("unlockpt: {}", strerror(errno));
exit(1);
}
pid_t shell_pid = fork();
if (shell_pid == 0)
{
if (dup2(shell_stdin[0], STDIN_FILENO) == -1)
if (setsid() == -1)
{
dwarnln("dup2: {}", strerror(errno));
dwarnln("setsid: {}", strerror(errno));
exit(1);
}
close(shell_stdin[0]);
close(shell_stdin[1]);
if (dup2(shell_stdout[1], STDOUT_FILENO) == -1)
char* pts_slave_name = ptsname(pts_master);
if (pts_slave_name == nullptr)
{
dwarnln("dup2: {}", strerror(errno));
dwarnln("ptsname: {}", strerror(errno));
exit(1);
}
close(shell_stdout[0]);
close(shell_stdout[1]);
if (dup2(shell_stderr[1], STDERR_FILENO) == -1)
int pts_slave = open(pts_slave_name, O_RDWR);
if (pts_slave == -1)
{
dwarnln("open: {}", strerror(errno));
exit(1);
}
if (dup2(pts_slave, STDIN_FILENO) == -1 || dup2(pts_slave, STDOUT_FILENO) == -1 || dup2(pts_slave, STDERR_FILENO) == -1)
{
dwarnln("dup2: {}", strerror(errno));
exit(1);
}
close(shell_stderr[0]);
close(shell_stderr[1]);
close(pts_slave);
close(pts_master);
execl("/bin/Shell", "Shell", NULL);
exit(1);
@ -68,14 +72,8 @@ void Terminal::start_shell()
exit(1);
}
close(shell_stdin[0]);
close(shell_stdout[1]);
close(shell_stderr[1]);
m_shell_info = {
.in = shell_stdin[1],
.out = shell_stdout[0],
.err = shell_stderr[0],
.pts_master = pts_master,
.pid = shell_pid
};
}
@ -95,22 +93,18 @@ void Terminal::run()
m_window->set_key_event_callback([&](LibGUI::EventPacket::KeyEvent event) { on_key_event(event); });
const int max_fd = BAN::Math::max(BAN::Math::max(m_shell_info.out, m_shell_info.err), m_window->server_fd());
const int max_fd = BAN::Math::max(m_shell_info.pts_master, m_window->server_fd());
while (!s_shell_exited)
{
fd_set fds;
FD_ZERO(&fds);
FD_SET(m_shell_info.out, &fds);
FD_SET(m_shell_info.err, &fds);
FD_SET(m_shell_info.pts_master, &fds);
FD_SET(m_window->server_fd(), &fds);
select(max_fd + 1, &fds, nullptr, nullptr, nullptr);
if (FD_ISSET(m_shell_info.out, &fds))
if (!read_shell(m_shell_info.out))
break;
if (FD_ISSET(m_shell_info.err, &fds))
if (!read_shell(m_shell_info.err))
if (FD_ISSET(m_shell_info.pts_master, &fds))
if (!read_shell())
break;
if (FD_ISSET(m_window->server_fd(), &fds))
m_window->poll_events();
@ -118,10 +112,10 @@ void Terminal::run()
}
bool Terminal::read_shell(int fd)
bool Terminal::read_shell()
{
char buffer[128];
ssize_t nread = read(fd, buffer, sizeof(buffer) - 1);
ssize_t nread = read(m_shell_info.pts_master, buffer, sizeof(buffer) - 1);
if (nread < 0)
dwarnln("read: {}", strerror(errno));
if (nread <= 0)
@ -295,13 +289,13 @@ void Terminal::handle_csi(char ch)
m_state = State::Normal;
}
void Terminal::putchar(uint32_t codepoint)
void Terminal::putchar(uint8_t ch)
{
if (m_state == State::ESC)
{
if (codepoint != '[')
if (ch != '[')
{
dprintln("unknown escape character 0x{H}", codepoint);
dprintln("unknown escape character 0x{2H}", ch);
m_state = State::Normal;
return;
}
@ -314,13 +308,46 @@ void Terminal::putchar(uint32_t codepoint)
if (m_state == State::CSI)
{
if (codepoint < 0x20 || codepoint > 0xFE)
if (ch < 0x20 || ch > 0xFE)
{
dprintln("invalid CSI 0x{H}", codepoint);
dprintln("invalid CSI 0x{2H}", ch);
m_state = State::Normal;
return;
}
handle_csi(codepoint);
handle_csi(ch);
return;
}
m_utf8_bytes[m_utf8_index++] = ch;
const size_t utf8_len = BAN::UTF8::byte_length(m_utf8_bytes[0]);
if (utf8_len == 0)
{
dwarnln("invalid utf8 leading byte 0x{2H}", ch);
m_utf8_index = 0;
return;
}
if (m_utf8_index < utf8_len)
return;
const uint32_t codepoint = BAN::UTF8::to_codepoint(m_utf8_bytes);
m_utf8_index = 0;
if (codepoint == BAN::UTF8::invalid)
{
char utf8_hex[20];
char* ptr = utf8_hex;
for (uint8_t i = 0; i < utf8_len; i++)
{
*ptr++ = '0';
*ptr++ = 'x';
*ptr++ = (m_utf8_bytes[i] >> 4) < 10 ? (m_utf8_bytes[i] >> 4) + '0' : (m_utf8_bytes[i] >> 4) - 10 + 'A';
*ptr++ = (m_utf8_bytes[i] & 0xF) < 10 ? (m_utf8_bytes[i] & 0xF) + '0' : (m_utf8_bytes[i] & 0xF) - 10 + 'A';
*ptr++ = ' ';
}
*--ptr = '\0';
dwarnln("invalid utf8 {}", utf8_hex);
return;
}
@ -376,5 +403,5 @@ void Terminal::on_key_event(LibGUI::EventPacket::KeyEvent event)
if (event.released())
return;
if (const char* text = LibInput::key_to_utf8_ansi(event.key, event.modifier))
write(m_shell_info.in, text, strlen(text));
write(m_shell_info.pts_master, text, strlen(text));
}

View File

@ -15,8 +15,8 @@ public:
private:
void handle_csi(char ch);
void handle_sgr();
void putchar(uint32_t codepoint);
bool read_shell(int fd);
void putchar(uint8_t ch);
bool read_shell();
void on_key_event(LibGUI::EventPacket::KeyEvent);
@ -31,9 +31,7 @@ private:
struct ShellInfo
{
int in;
int out;
int err;
int pts_master;
pid_t pid;
};
@ -58,6 +56,9 @@ private:
State m_state { State::Normal };
CSIInfo m_csi_info;
uint8_t m_utf8_index { 0 };
uint8_t m_utf8_bytes[4] { };
Cursor m_saved_cursor { 0, 0 };
uint32_t m_fg_color { 0xFFFFFF };
uint32_t m_bg_color { 0x000000 };

View File

@ -5,6 +5,7 @@ set(USERSPACE_TESTS
test-mmap-shared
test-mouse
test-popen
test-setjmp
test-sort
test-tcp
test-udp

View File

@ -0,0 +1,8 @@
set(SOURCES
main.cpp
)
add_executable(test-setjmp ${SOURCES})
banan_link_library(test-setjmp libc)
install(TARGETS test-setjmp OPTIONAL)

View File

@ -0,0 +1,22 @@
#include <setjmp.h>
#include <stdio.h>
jmp_buf env;
void iterate()
{
static volatile int count = 0;
if (count < 10)
{
count = count + 1;
longjmp(env, count);
}
}
int main()
{
printf("start\n");
if (int ret = setjmp(env))
printf("longjmp %d\n", ret);
iterate();
}