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.
This commit is contained in:
parent
ad645f31d0
commit
a5a097fa4a
|
@ -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,
|
||||
|
|
|
@ -174,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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
@ -1734,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);
|
||||
|
@ -1936,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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -88,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
|
||||
{
|
||||
|
|
|
@ -519,6 +519,31 @@ 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);
|
||||
|
|
Loading…
Reference in New Issue