Compare commits
23 Commits
91d513a672
...
9e79ef2a91
Author | SHA1 | Date |
---|---|---|
Bananymous | 9e79ef2a91 | |
Bananymous | 4d1b32f770 | |
Bananymous | a5a097fa4a | |
Bananymous | ad645f31d0 | |
Bananymous | f08d429851 | |
Bananymous | bac3219a01 | |
Bananymous | 09a527fb12 | |
Bananymous | 58a3a480b9 | |
Bananymous | a12bfe4639 | |
Bananymous | 6cda639869 | |
Bananymous | 2797fe116f | |
Bananymous | e768cd53fb | |
Bananymous | 83e2ad40d6 | |
Bananymous | 7ebd0699e3 | |
Bananymous | 46b1d4d194 | |
Bananymous | f60e265397 | |
Bananymous | 2e642327ea | |
Bananymous | a87ce41030 | |
Bananymous | 0c8cae4cc3 | |
Bananymous | ed325b4a45 | |
Bananymous | 1c67b5e812 | |
Bananymous | b6c964c444 | |
Bananymous | 6fedf06150 |
|
@ -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
|
||||
|
|
|
@ -9,7 +9,7 @@ namespace Kernel
|
|||
{
|
||||
Framebuffer = 1,
|
||||
TTY,
|
||||
Serial,
|
||||
PTSMaster,
|
||||
Null,
|
||||
Zero,
|
||||
Debug,
|
||||
|
|
|
@ -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 };
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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 };
|
||||
|
||||
|
|
|
@ -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>;
|
||||
};
|
||||
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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); }
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -361,6 +361,8 @@ namespace Kernel
|
|||
else
|
||||
m_block_queue.add_thread_with_wake_time(node);
|
||||
|
||||
m_thread_count++;
|
||||
|
||||
Processor::set_interrupt_state(state);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
)
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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();
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#include <stdarg.h>
|
||||
#include <stropts.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <unistd.h>
|
||||
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
#include <BAN/Assert.h>
|
||||
|
||||
#include <utime.h>
|
||||
|
||||
int utime(const char*, const struct utimbuf*)
|
||||
{
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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')
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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 };
|
||||
|
|
|
@ -5,6 +5,7 @@ set(USERSPACE_TESTS
|
|||
test-mmap-shared
|
||||
test-mouse
|
||||
test-popen
|
||||
test-setjmp
|
||||
test-sort
|
||||
test-tcp
|
||||
test-udp
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
set(SOURCES
|
||||
main.cpp
|
||||
)
|
||||
|
||||
add_executable(test-setjmp ${SOURCES})
|
||||
banan_link_library(test-setjmp libc)
|
||||
|
||||
install(TARGETS test-setjmp OPTIONAL)
|
|
@ -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();
|
||||
}
|
Loading…
Reference in New Issue