Compare commits

..

No commits in common. "1f467580eed557e70d6857b9ba472c0b30f9fbb7" and "9314528b9bd6d656f2b445d7617c2d506864564a" have entirely different histories.

24 changed files with 268 additions and 1270 deletions

View File

@ -62,9 +62,7 @@ namespace BAN
if (m_error_code & kernel_error_mask)
return Kernel::error_string(kernel_error());
#endif
if (auto* desc = strerrordesc_np(m_error_code))
return desc;
return "Unknown error"sv;
return strerror(m_error_code);
}
private:

View File

@ -141,9 +141,9 @@ set(BAN_SOURCES
../BAN/BAN/Time.cpp
)
set(KLIBC_SOURCES
klibc/ctype.cpp
klibc/string.cpp
set(LIBC_SOURCES
../libc/ctype.cpp
../libc/string.cpp
)
set(LIBELF_SOURCES
@ -154,7 +154,7 @@ set(KERNEL_SOURCES
${KERNEL_SOURCES}
${LAI_SOURCES}
${BAN_SOURCES}
${KLIBC_SOURCES}
${LIBC_SOURCES}
${LIBELF_SOURCES}
)

View File

@ -48,6 +48,7 @@ namespace Kernel
timespec m_mtime {};
timespec m_ctime {};
BAN::Vector<uint8_t> m_buffer;
SpinLock m_lock;
Semaphore m_semaphore;
uint32_t m_writing_count { 1 };

View File

@ -6,13 +6,10 @@
namespace Kernel
{
struct HPETRegisters;
class HPET final : public Timer, public Interruptable
{
public:
static BAN::ErrorOr<BAN::UniqPtr<HPET>> create(bool force_pic);
~HPET();
virtual uint64_t ms_since_boot() const override;
virtual uint64_t ns_since_boot() const override;
@ -24,19 +21,11 @@ namespace Kernel
HPET() = default;
BAN::ErrorOr<void> initialize(bool force_pic);
volatile HPETRegisters& registers();
const volatile HPETRegisters& registers() const;
uint64_t read_main_counter() const;
void write_register(ptrdiff_t reg, uint64_t value) const;
uint64_t read_register(ptrdiff_t reg) const;
private:
bool m_is_64bit { false };
uint64_t m_last_ticks { 0 };
uint32_t m_32bit_wraps { 0 };
uint32_t m_ticks_per_s { 0 };
uint64_t m_counter_tick_period_fs { 0 };
vaddr_t m_mmio_base { 0 };
};

View File

@ -253,8 +253,6 @@ namespace Kernel
if (m_info.has<ConnectionInfo>())
{
auto& connection_info = m_info.get<ConnectionInfo>();
if (!connection_info.pending_connections.empty())
return true;
if (!connection_info.connection)
return false;
}

View File

@ -1048,8 +1048,8 @@ namespace Kernel
fd_set writefds; FD_ZERO(&writefds);
fd_set errorfds; FD_ZERO(&errorfds);
int set_bits = 0;
for (;;)
long set_bits = 0;
while (set_bits == 0)
{
if (arguments->timeout && SystemTimer::get().ms_since_boot() >= timedout_ms)
break;
@ -1072,7 +1072,7 @@ namespace Kernel
if (!mode.ifreg() && !mode.ififo() && !mode.ifsock() && !inode->is_pipe() && !inode->is_tty())
return;
if ((inode.ptr()->*func)())
if ((inode_or_error.value().ptr()->*func)())
{
FD_SET(fd, dest);
set_bits++;
@ -1083,33 +1083,18 @@ namespace Kernel
{
update_fds(i, arguments->readfds, &readfds, &Inode::can_read);
update_fds(i, arguments->writefds, &writefds, &Inode::can_write);
update_fds(i, arguments->errorfds, &errorfds, &Inode::has_error);
update_fds(i, arguments->errorfds, &errorfds, &Inode::can_read);
}
if (set_bits > 0)
break;
LockFreeGuard free(m_lock);
SystemTimer::get().sleep(1);
}
if (arguments->readfds)
FD_ZERO(arguments->readfds);
memcpy(arguments->readfds, &readfds, sizeof(fd_set));
if (arguments->writefds)
FD_ZERO(arguments->writefds);
memcpy(arguments->writefds, &writefds, sizeof(fd_set));
if (arguments->errorfds)
FD_ZERO(arguments->errorfds);
for (int i = 0; i < arguments->nfds; i++)
{
if (arguments->readfds && FD_ISSET(i, &readfds))
FD_SET(i, arguments->readfds);
if (arguments->writefds && FD_ISSET(i, &writefds))
FD_SET(i, arguments->writefds);
if (arguments->errorfds && FD_ISSET(i, &errorfds))
FD_SET(i, arguments->errorfds);
}
memcpy(arguments->errorfds, &errorfds, sizeof(fd_set));
return set_bits;
}

View File

@ -46,16 +46,15 @@ namespace Kernel
BAN::ErrorOr<void> NVMeNamespace::initialize()
{
BAN::String name_prefix;
TRY(name_prefix.append(m_name));
TRY(name_prefix.push_back('p'));
m_dma_region = TRY(DMARegion::create(PAGE_SIZE));
add_disk_cache();
DevFileSystem::get().add_device(this);
char name_prefix[20];
strcpy(name_prefix, m_name);
strcat(name_prefix, "p");
if (auto res = initialize_partitions(name_prefix); res.is_error())
dprintln("{}", res.error());

View File

@ -7,7 +7,21 @@
#include <kernel/Scheduler.h>
#include <kernel/Timer/HPET.h>
#define HPET_PERIOD_MAX 0x05F5E100
#define HPET_REG_CAPABILIES 0x00
#define HPET_REG_CONFIG 0x10
#define HPET_REG_COUNTER 0xF0
#define HPET_CONFIG_ENABLE 0x01
#define HPET_CONFIG_LEG_RT 0x02
#define HPET_REG_TIMER_CONFIG(N) (0x100 + 0x20 * N)
#define HPET_REG_TIMER_COMPARATOR(N) (0x108 + 0x20 * N)
#define HPET_Tn_INT_ENB_CNF (1 << 2)
#define HPET_Tn_TYPE_CNF (1 << 3)
#define HPET_Tn_PER_INT_CAP (1 << 4)
#define HPET_Tn_VAL_SET_CNF (1 << 6)
#define HPET_Tn_INT_ROUTE_CNF_SHIFT 9
#define FS_PER_S 1'000'000'000'000'000
#define FS_PER_MS 1'000'000'000'000
@ -17,116 +31,17 @@
namespace Kernel
{
enum HPETCapabilities : uint32_t
{
LEG_RT_CAP = 1 << 16,
COUNT_SIZE_CAP = 1 << 13,
NUM_TIM_CAP_MASK = 0x1F << 8,
NUM_TIM_CAP_SHIFT = 8,
};
enum HPETConfiguration : uint32_t
{
LEG_RT_CNF = 1 << 1,
ENABLE_CNF = 1 << 0,
};
enum HPETTimerConfiguration : uint32_t
{
Tn_INT_TYPE_CNF = 1 << 1,
Tn_INT_ENB_CNF = 1 << 2,
Tn_TYPE_CNF = 1 << 3,
Tn_PER_INT_CAP = 1 << 4,
Tn_SIZE_CAP = 1 << 5,
Tn_VAL_SET_CNF = 1 << 6,
Tn_32MODE_CNF = 1 << 8,
Tn_FSB_EN_CNF = 1 << 14,
Tn_FSB_INT_DEL_CAP = 1 << 14,
Tn_INT_ROUTE_CNF_MASK = 0x1F << 9,
Tn_INT_ROUTE_CNF_SHIFT = 9,
};
struct HPETRegister
{
union
{
uint64_t full;
struct
{
uint32_t low;
uint32_t high;
};
};
};
static_assert(sizeof(HPETRegister) == 8);
struct HPETTimer
{
uint32_t configuration;
uint32_t int_route_cap;
HPETRegister comparator;
HPETRegister fsb_interrupt_route;
uint64_t __reserved;
};
static_assert(sizeof(HPETTimer) == 32);
struct HPETRegisters
{
/*
63:32 COUNTER_CLK_PERIOD
31:16 VENDOR_ID
15 LEG_RT_CAP
13 COUNT_SIZE_CAP
12:8 NUM_TIM_CAP
7:0 REV_ID
*/
uint32_t capabilities;
uint32_t counter_clk_period;
uint64_t __reserved0;
/*
1 LEG_RT_CNF
0 ENABLE_CNF
*/
HPETRegister configuration;
uint64_t __reserved1;
/*
N Tn_INT_STS
*/
HPETRegister interrupt_status;
uint8_t __reserved2[0xF0 - 0x28];
HPETRegister main_counter;
uint64_t __reserved3;
HPETTimer timers[32];
};
static_assert(offsetof(HPETRegisters, main_counter) == 0xF0);
static_assert(offsetof(HPETRegisters, timers[0]) == 0x100);
static_assert(offsetof(HPETRegisters, timers[1]) == 0x120);
BAN::ErrorOr<BAN::UniqPtr<HPET>> HPET::create(bool force_pic)
{
HPET* hpet_ptr = new HPET();
if (hpet_ptr == nullptr)
HPET* hpet = new HPET();
if (hpet == nullptr)
return BAN::Error::from_errno(ENOMEM);
auto hpet = BAN::UniqPtr<HPET>::adopt(hpet_ptr);
TRY(hpet->initialize(force_pic));
return hpet;
}
HPET::~HPET()
{
if (m_mmio_base)
PageTable::kernel().unmap_page(m_mmio_base);
m_mmio_base = 0;
if (auto ret = hpet->initialize(force_pic); ret.is_error())
{
delete hpet;
return ret.release_error();
}
return BAN::UniqPtr<HPET>::adopt(hpet);
}
BAN::ErrorOr<void> HPET::initialize(bool force_pic)
@ -148,155 +63,115 @@ namespace Kernel
ASSERT(m_mmio_base);
PageTable::kernel().map_page_at(header->base_address.address, m_mmio_base, PageTable::Flags::ReadWrite | PageTable::Flags::Present);
BAN::ScopeGuard unmapper([this] { PageTable::kernel().unmap_page(m_mmio_base); });
auto& regs = registers();
m_counter_tick_period_fs = read_register(HPET_REG_CAPABILIES) >> 32;
m_is_64bit = regs.capabilities & COUNT_SIZE_CAP;
// Disable main counter and reset value
regs.configuration.low = regs.configuration.low & ~ENABLE_CNF;
regs.main_counter.high = 0;
regs.main_counter.low = 0;
// Enable legacy routing if available
if (regs.capabilities & LEG_RT_CAP)
regs.configuration.low = regs.configuration.low | LEG_RT_CNF;
uint32_t period_fs = regs.counter_clk_period;
if (period_fs == 0 || period_fs > HPET_PERIOD_MAX)
{
dwarnln("HPET: Invalid counter period");
// period has to be less than 100 ns
if (m_counter_tick_period_fs == 0 || m_counter_tick_period_fs > FS_PER_NS * 100)
return BAN::Error::from_errno(EINVAL);
uint64_t ticks_per_ms = FS_PER_MS / m_counter_tick_period_fs;
{
const char* units[] = { "fs", "ps", "ns" };
int index = 0;
uint64_t temp = m_counter_tick_period_fs;
while (temp >= 1000)
{
temp /= 1000;
index++;
}
dprintln("HPET percision {} {}", temp, units[index]);
}
m_ticks_per_s = FS_PER_S / period_fs;
dprintln("HPET frequency {} Hz", m_ticks_per_s);
uint8_t last_timer = (regs.capabilities & NUM_TIM_CAP_MASK) >> NUM_TIM_CAP_SHIFT;
dprintln("HPET has {} timers", last_timer + 1);
// Disable all timers
for (uint8_t i = 0; i <= last_timer; i++)
uint64_t timer0_config = read_register(HPET_REG_TIMER_CONFIG(0));
if (!(timer0_config & HPET_Tn_PER_INT_CAP))
{
auto& timer_regs = regs.timers[i];
timer_regs.configuration = timer_regs.configuration & ~Tn_INT_ENB_CNF;
}
auto& timer0 = regs.timers[0];
if (!(timer0.configuration & Tn_PER_INT_CAP))
{
dwarnln("HPET: timer0 cannot be periodic");
dwarnln("timer 0 doesn't support periodic");
return BAN::Error::from_errno(ENOTSUP);
}
// enable interrupts
timer0.configuration = timer0.configuration | Tn_INT_ENB_CNF;
// clear interrupt mask (set irq to 0)
timer0.configuration = timer0.configuration & ~Tn_INT_ROUTE_CNF_MASK;
// edge triggered interrupts
timer0.configuration = timer0.configuration & ~Tn_INT_TYPE_CNF;
// periodic timer
timer0.configuration = timer0.configuration | Tn_TYPE_CNF;
// disable 32 bit mode
timer0.configuration = timer0.configuration & ~Tn_32MODE_CNF;
// disable FSB interrupts
if (timer0.configuration & Tn_FSB_INT_DEL_CAP)
timer0.configuration = timer0.configuration & ~Tn_FSB_EN_CNF;
// set timer period to 1000 Hz
uint64_t ticks_per_ms = m_ticks_per_s / 1000;
timer0.configuration = timer0.configuration | Tn_VAL_SET_CNF;
timer0.comparator.low = ticks_per_ms;
if (timer0.configuration & Tn_SIZE_CAP)
int irq = 0;
if (!force_pic)
{
timer0.configuration = timer0.configuration | Tn_VAL_SET_CNF;
timer0.comparator.high = ticks_per_ms >> 32;
}
else if (ticks_per_ms > 0xFFFFFFFF)
{
dprintln("HPET: cannot create 1 kHz timer");
return BAN::Error::from_errno(ENOTSUP);
uint32_t irq_cap = timer0_config >> 32;
if (irq_cap == 0)
{
dwarnln("HPET doesn't have any interrupts available");
return BAN::Error::from_errno(EINVAL);
}
for (irq = 0; irq < 32; irq++)
if (irq_cap & (1 << irq))
break;
}
TRY(InterruptController::get().reserve_irq(irq));
// enable main counter
regs.configuration.low = regs.configuration.low | ENABLE_CNF;
unmapper.disable();
TRY(InterruptController::get().reserve_irq(0));
set_irq(0);
uint64_t main_flags = HPET_CONFIG_ENABLE;
if (force_pic)
main_flags |= HPET_CONFIG_LEG_RT;
// Enable main counter
write_register(HPET_REG_CONFIG, read_register(HPET_REG_CONFIG) | main_flags);
uint64_t timer0_flags = 0;
timer0_flags |= HPET_Tn_INT_ENB_CNF;
timer0_flags |= HPET_Tn_TYPE_CNF;
timer0_flags |= HPET_Tn_VAL_SET_CNF;
if (!force_pic)
timer0_flags |= irq << HPET_Tn_INT_ROUTE_CNF_SHIFT;
// Enable timer 0 as 1 ms periodic
write_register(HPET_REG_TIMER_CONFIG(0), timer0_flags);
write_register(HPET_REG_TIMER_COMPARATOR(0), read_register(HPET_REG_COUNTER) + ticks_per_ms);
write_register(HPET_REG_TIMER_COMPARATOR(0), ticks_per_ms);
// Disable timers 1->
for (int i = 1; i <= header->comparator_count; i++)
write_register(HPET_REG_TIMER_CONFIG(i), 0);
set_irq(irq);
enable_interrupt();
return {};
}
volatile HPETRegisters& HPET::registers()
{
return *reinterpret_cast<volatile HPETRegisters*>(m_mmio_base);
}
const volatile HPETRegisters& HPET::registers() const
{
return *reinterpret_cast<const volatile HPETRegisters*>(m_mmio_base);
}
uint64_t HPET::read_main_counter() const
{
auto& regs = registers();
if (m_is_64bit)
return regs.main_counter.full;
uint32_t current = regs.main_counter.low;
uint64_t wraps = m_32bit_wraps;
if (current < (uint32_t)m_last_ticks)
wraps++;
return (wraps << 32) | current;
}
void HPET::handle_irq()
{
auto& regs = registers();
uint64_t current_ticks { 0 };
if (m_is_64bit)
current_ticks = regs.main_counter.full;
else
{
uint32_t current = regs.main_counter.low;
if (current < (uint32_t)m_last_ticks)
m_32bit_wraps++;
current_ticks = ((uint64_t)m_32bit_wraps << 32) | current;
}
m_last_ticks = current_ticks;
Scheduler::get().timer_reschedule();
}
uint64_t HPET::ms_since_boot() const
{
return ns_since_boot() / 1'000'000;
// FIXME: 32 bit CPUs should use 32 bit counter with 32 bit reads
return read_register(HPET_REG_COUNTER) * m_counter_tick_period_fs / FS_PER_MS;
}
uint64_t HPET::ns_since_boot() const
{
auto current = time_since_boot();
return current.tv_sec * 1'000'000'000 + current.tv_nsec;
// FIXME: 32 bit CPUs should use 32 bit counter with 32 bit reads
return read_register(HPET_REG_COUNTER) * m_counter_tick_period_fs / FS_PER_NS;
}
timespec HPET::time_since_boot() const
{
auto& regs = registers();
uint64_t counter = read_main_counter();
uint64_t seconds = counter / m_ticks_per_s;
uint64_t ticks_this_second = counter % m_ticks_per_s;
long ns_this_second = ticks_this_second * regs.counter_clk_period / FS_PER_NS;
uint64_t time_fs = read_register(HPET_REG_COUNTER) * m_counter_tick_period_fs;
return timespec {
.tv_sec = seconds,
.tv_nsec = ns_this_second
.tv_sec = time_fs / FS_PER_S,
.tv_nsec = (long)((time_fs % FS_PER_S) / FS_PER_NS)
};
}
void HPET::write_register(ptrdiff_t reg, uint64_t value) const
{
MMIO::write64(m_mmio_base + reg, value);
}
uint64_t HPET::read_register(ptrdiff_t reg) const
{
return MMIO::read64(m_mmio_base + reg);
}
}

View File

@ -1,80 +0,0 @@
#include <ctype.h>
int isalnum(int c)
{
return isdigit(c) || isalpha(c);
}
int isalpha(int c)
{
return islower(c) || isupper(c);
}
int isascii(int c)
{
return c <= 0x7F;
}
int isblank(int c)
{
return c == ' ' || c == '\t';
}
int iscntrl(int c)
{
return c < 32 || c == 0x7F;
}
int isdigit(int c)
{
return '0' <= c && c <= '9';
}
int isgraph(int c)
{
return 0x21 <= c && c <= 0x7E;
}
int islower(int c)
{
return 'a' <= c && c <= 'z';
}
int isprint(int c)
{
return isgraph(c) || c == ' ';
}
int ispunct(int c)
{
return isgraph(c) && !isalnum(c);
}
int isspace(int c)
{
return c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v';
}
int isupper(int c)
{
return 'A' <= c && c <= 'Z';
}
int isxdigit(int c)
{
return isdigit(c) || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F');
}
int toupper(int c)
{
if (!islower(c))
return c;
return 'A' + (c - 'a');
}
int tolower(int c)
{
if (!isupper(c))
return c;
return 'a' + (c - 'A');
}

View File

@ -1,166 +0,0 @@
#include <errno.h>
#include <string.h>
int memcmp(const void* s1, const void* s2, size_t n)
{
auto* u1 = static_cast<const unsigned char*>(s1);
auto* u2 = static_cast<const unsigned char*>(s2);
for (size_t i = 0; i < n; i++)
if (u1[i] != u2[i])
return u1[i] - u2[i];
return 0;
}
void* memcpy(void* __restrict s1, const void* __restrict s2, size_t n)
{
auto* dst = static_cast<unsigned char*>(s1);
auto* src = static_cast<const unsigned char*>(s2);
for (size_t i = 0; i < n; i++)
dst[i] = src[i];
return s1;
}
void* memmove(void* s1, const void* s2, size_t n)
{
auto* dst = static_cast<unsigned char*>(s1);
auto* src = static_cast<const unsigned char*>(s2);
if (dst < src)
{
for (size_t i = 0; i < n; i++)
dst[i] = src[i];
}
else
{
for (size_t i = 1; i <= n; i++)
dst[n - i] = src[n - i];
}
return s1;
}
void* memset(void* s, int c, size_t n)
{
auto* u = static_cast<unsigned char*>(s);
for (size_t i = 0; i < n; i++)
u[i] = c;
return s;
}
size_t strlen(const char* str)
{
size_t len = 0;
while (str[len])
len++;
return len;
}
char* strcpy(char* __restrict dst, const char* __restrict src)
{
size_t i = 0;
for (; src[i]; i++)
dst[i] = src[i];
dst[i] = '\0';
return dst;
}
char* strncpy(char* __restrict dst, const char* __restrict src, size_t len)
{
size_t i = 0;
for (; i < len && src[i]; i++)
dst[i] = src[i];
if (i < len)
dst[i] = '\0';
return dst;
}
const char* strerrordesc_np(int error)
{
switch (error)
{
case 0: return "Success";
case E2BIG: return "Argument list too long.";
case EACCES: return "Permission denied.";
case EADDRINUSE: return "Address in use.";
case EADDRNOTAVAIL: return "Address not available.";
case EAFNOSUPPORT: return "Address family not supported.";
case EAGAIN: return "Resource unavailable, try again.";
case EALREADY: return "Connection already in progress.";
case EBADF: return "Bad file descriptor.";
case EBADMSG: return "Bad message.";
case EBUSY: return "Device or resource busy.";
case ECANCELED: return "Operation canceled.";
case ECHILD: return "No child processes.";
case ECONNABORTED: return "Connection aborted.";
case ECONNREFUSED: return "Connection refused.";
case ECONNRESET: return "Connection reset.";
case EDEADLK: return "Resource deadlock would occur.";
case EDESTADDRREQ: return "Destination address required.";
case EDOM: return "Mathematics argument out of domain of function.";
case EDQUOT: return "Reserved.";
case EEXIST: return "File exists.";
case EFAULT: return "Bad address.";
case EFBIG: return "File too large.";
case EHOSTUNREACH: return "Host is unreachable.";
case EIDRM: return "Identifier removed.";
case EILSEQ: return "Illegal byte sequence.";
case EINPROGRESS: return "Operation in progress.";
case EINTR: return "Interrupted function.";
case EINVAL: return "Invalid argument.";
case EIO: return "I/O error.";
case EISCONN: return "Socket is connected.";
case EISDIR: return "Is a directory.";
case ELOOP: return "Too many levels of symbolic links.";
case EMFILE: return "File descriptor value too large.";
case EMLINK: return "Too many links.";
case EMSGSIZE: return "Message too large.";
case EMULTIHOP: return "Reserved.";
case ENAMETOOLONG: return "Filename too long.";
case ENETDOWN: return "Network is down.";
case ENETRESET: return "Connection aborted by network.";
case ENETUNREACH: return "Network unreachable.";
case ENFILE: return "Too many files open in system.";
case ENOBUFS: return "No buffer space available.";
case ENODATA: return "No message is available on the STREAM head read queue.";
case ENODEV: return "No such device.";
case ENOENT: return "No such file or directory.";
case ENOEXEC: return "Executable file format error.";
case ENOLCK: return "No locks available.";
case ENOLINK: return "Reserved.";
case ENOMEM: return "Not enough space.";
case ENOMSG: return "No message of the desired type.";
case ENOPROTOOPT: return "Protocol not available.";
case ENOSPC: return "No space left on device.";
case ENOSR: return "No STREAM resources.";
case ENOSTR: return "Not a STREAM.";
case ENOSYS: return "Functionality not supported.";
case ENOTCONN: return "The socket is not connected.";
case ENOTDIR: return "Not a directory or a symbolic link to a directory.";
case ENOTEMPTY: return "Directory not empty.";
case ENOTRECOVERABLE: return "State not recoverable.";
case ENOTSOCK: return "Not a socket.";
case ENOTSUP: return "Not supported.";
case ENOTTY: return "Inappropriate I/O control operation.";
case ENXIO: return "No such device or address.";
case EOPNOTSUPP: return "Operation not supported on socket .";
case EOVERFLOW: return "Value too large to be stored in data type.";
case EOWNERDEAD: return "Previous owner died.";
case EPERM: return "Operation not permitted.";
case EPIPE: return "Broken pipe.";
case EPROTO: return "Protocol error.";
case EPROTONOSUPPORT: return "Protocol not supported.";
case EPROTOTYPE: return "Protocol wrong type for socket.";
case ERANGE: return "Result too large.";
case EROFS: return "Read-only file system.";
case ESPIPE: return "Invalid seek.";
case ESRCH: return "No such process.";
case ESTALE: return "Reserved.";
case ETIME: return "Stream ioctl() timeout.";
case ETIMEDOUT: return "Connection timed out.";
case ETXTBSY: return "Text file busy.";
case EWOULDBLOCK: return "Operation would block.";
case EXDEV: return "Cross-device link.";
case EEXISTS: return "File exists";
case ENOTBLK: return "Block device required";
case EUNKNOWN: return "Unknown error";
}
return nullptr;
}

View File

@ -12,7 +12,7 @@ __BEGIN_DECLS
struct timeval
{
time_t tv_sec; /* Seconds. */
suseconds_t tv_usec; /* Microseconds. */
suseconds_t tc_usec; /* Microseconds. */
};
__END_DECLS

View File

@ -25,7 +25,7 @@ int strcmp(const char* s1, const char* s2);
int strcoll(const char* s1, const char* s2);
int strcoll_l(const char* s1, const char* s2, locale_t locale);
char* strcpy(char* __restrict s1, const char* __restrict s2);
size_t strcspn(const char* s1, const char* s2);
size_t strcspn(const char* , const char* );
char* strdup(const char* s);
char* strerror(int errnum);
char* strerror_l(int errnum, locale_t locale);

View File

@ -66,7 +66,6 @@ struct stat
#define S_IFLNK ((mode_t)0120000)
#define S_IFSOCK ((mode_t)0140000)
#define S_IFMASK ((mode_t)0170000)
#define S_IFMT S_IFMASK
#define S_ISBLK(mode) ((mode & S_IFMASK) == S_IFBLK)
#define S_ISCHR(mode) ((mode & S_IFMASK) == S_IFCHR)

View File

@ -160,7 +160,7 @@ long gethostid(void);
int gethostname(char* name, size_t namelen);
char* getlogin(void);
int getlogin_r(char* name, size_t namesize);
int getopt(int argc, char* const argv[], const char* optstring);
int getopt(int argc, char* const argv[], const char* optstring);
pid_t getpgid(pid_t pid);
pid_t getpgrp(void);
pid_t getpid(void);

View File

@ -4,7 +4,6 @@
#include <scanf_impl.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/syscall.h>
#include <unistd.h>
@ -12,37 +11,18 @@
struct FILE
{
int fd { -1 };
mode_t mode { 0 };
bool eof { false };
bool error { false };
int pid { -1 };
unsigned char buffer[BUFSIZ] {};
uint32_t buffer_index { 0 };
};
struct ScopeLock
{
ScopeLock(FILE* file)
: m_file(file)
{
flockfile(m_file);
}
~ScopeLock()
{
funlockfile(m_file);
}
FILE* m_file;
};
static FILE s_files[FOPEN_MAX] {
{ .fd = STDIN_FILENO, .mode = O_RDONLY },
{ .fd = STDOUT_FILENO, .mode = O_WRONLY },
{ .fd = STDERR_FILENO, .mode = O_WRONLY },
{ .fd = STDDBG_FILENO, .mode = O_WRONLY },
{ .fd = STDIN_FILENO },
{ .fd = STDOUT_FILENO },
{ .fd = STDERR_FILENO },
{ .fd = STDDBG_FILENO },
};
FILE* stdin = &s_files[0];
@ -52,7 +32,6 @@ FILE* stddbg = &s_files[3];
void clearerr(FILE* file)
{
ScopeLock _(file);
file->eof = false;
file->error = false;
}
@ -67,51 +46,22 @@ char* ctermid(char* buffer)
int fclose(FILE* file)
{
ScopeLock _(file);
(void)fflush(file);
int ret = (close(file->fd) == -1) ? EOF : 0;
if (close(file->fd) == -1)
return EOF;
file->fd = -1;
return ret;
}
static mode_t parse_mode_string(const char* mode_str)
{
size_t len = strlen(mode_str);
if (len == 0 || len > 3)
return 0;
if (len == 3 && mode_str[1] == mode_str[2])
return 0;
if (strcspn(mode_str + 1, "b+") != len - 1)
return 0;
bool plus = (mode_str[1] == '+' || mode_str[2] == '+');
switch (mode_str[0])
{
case 'r': return plus ? O_RDWR : O_RDONLY;
case 'w': return plus ? O_RDWR | O_CREAT | O_TRUNC : O_WRONLY | O_CREAT | O_TRUNC;
case 'a': return plus ? O_RDWR | O_CREAT | O_APPEND : O_WRONLY | O_CREAT | O_APPEND;
}
return 0;
}
FILE* fdopen(int fd, const char* mode_str)
FILE* fdopen(int fd, const char* mode)
{
mode_t mode = parse_mode_string(mode_str);
if (mode == 0)
{
errno = EINVAL;
return nullptr;
}
mode &= ~O_TRUNC;
// FIXME
(void)mode;
// FIXME: when threads are implemented
for (int i = 0; i < FOPEN_MAX; i++)
{
if (s_files[i].fd == -1)
{
s_files[i] = {
.fd = fd,
.mode = mode & O_ACCMODE,
};
s_files[i] = { .fd = fd };
return &s_files[i];
}
}
@ -141,8 +91,6 @@ int fflush(FILE* file)
return 0;
}
ScopeLock _(file);
if (file->buffer_index == 0)
return 0;
@ -158,13 +106,29 @@ int fflush(FILE* file)
int fgetc(FILE* file)
{
ScopeLock _(file);
return getc_unlocked(file);
if (file->eof)
return EOF;
unsigned char c;
long ret = syscall(SYS_READ, file->fd, &c, 1);
if (ret < 0)
{
file->error = true;
return EOF;
}
if (ret == 0)
{
file->eof = true;
return EOF;
}
return c;
}
int fgetpos(FILE* file, fpos_t* pos)
{
ScopeLock _(file);
off_t offset = ftello(file);
if (offset == -1)
return -1;
@ -176,11 +140,10 @@ char* fgets(char* str, int size, FILE* file)
{
if (size == 0)
return nullptr;
ScopeLock _(file);
int i = 0;
for (; i < size - 1; i++)
{
int c = getc_unlocked(file);
char c = fgetc(file);
if (c == EOF)
{
if (i == 0)
@ -205,33 +168,54 @@ int fileno(FILE* fp)
return fp->fd;
}
void flockfile(FILE*)
{
// FIXME: when threads are implemented
}
// TODO
void flockfile(FILE*);
FILE* fopen(const char* pathname, const char* mode_str)
FILE* fopen(const char* pathname, const char* mode)
{
mode_t mode = parse_mode_string(mode_str);
if (mode == 0)
uint8_t flags = 0;
if (mode[0] == 'r')
flags |= O_RDONLY;
else if (mode[0] == 'w')
flags |= O_WRONLY | O_CREAT | O_TRUNC;
else if (mode[0] == 'a')
flags |= O_WRONLY | O_CREAT | O_APPEND;
else
{
errno = EINVAL;
return nullptr;
}
int fd = open(pathname, mode, 0666);
if (mode[1] && mode[2] && mode[1] == mode[2])
{
errno = EINVAL;
return nullptr;
}
for (int i = 1; i <= 2; i++)
{
if (mode[i] == 0)
break;
else if (mode[i] == '+')
flags |= O_RDWR;
else if (mode[i] == 'b')
continue;
else
{
errno = EINVAL;
return nullptr;
}
}
int fd = open(pathname, flags);
if (fd == -1)
return nullptr;
// FIXME: when threads are implemented
for (int i = 0; i < FOPEN_MAX; i++)
{
if (s_files[i].fd == -1)
{
s_files[i] = {
.fd = fd,
.mode = mode & O_ACCMODE
};
s_files[i] = { .fd = fd };
return &s_files[i];
}
}
@ -251,16 +235,18 @@ int fprintf(FILE* file, const char* format, ...)
int fputc(int c, FILE* file)
{
ScopeLock _(file);
return putc_unlocked(c, file);
file->buffer[file->buffer_index++] = c;
if (c == '\n' || file->buffer_index == sizeof(file->buffer))
if (fflush(file) == EOF)
return EOF;
return (unsigned char)c;
}
int fputs(const char* str, FILE* file)
{
ScopeLock _(file);
while (*str)
{
if (putc_unlocked(*str, file) == EOF)
if (fputc(*str, file) == EOF)
return EOF;
str++;
}
@ -269,7 +255,6 @@ int fputs(const char* str, FILE* file)
size_t fread(void* buffer, size_t size, size_t nitems, FILE* file)
{
ScopeLock _(file);
if (file->eof || nitems * size == 0)
return 0;
@ -294,51 +279,11 @@ size_t fread(void* buffer, size_t size, size_t nitems, FILE* file)
return nread / size;
}
FILE* freopen(const char* pathname, const char* mode_str, FILE* file)
{
mode_t mode = parse_mode_string(mode_str);
if (mode == 0)
{
errno = EINVAL;
return nullptr;
}
// TODO
FILE* freopen(const char*, const char*, FILE*);
ScopeLock _(file);
(void)fflush(file);
if (pathname)
{
close(file->fd);
file->fd = open(pathname, mode, 0666);
file->mode = mode & O_ACCMODE;
if (file->fd == -1)
return nullptr;
}
else
{
mode &= O_ACCMODE;
if ((file->mode & mode) != mode)
{
close(file->fd);
file->fd = -1;
errno = EBADF;
return nullptr;
}
file->mode = mode;
}
return file;
}
int fscanf(FILE* file, const char* format, ...)
{
va_list arguments;
va_start(arguments, format);
int ret = vfscanf(file, format, arguments);
va_end(arguments);
return ret;
}
// TODO
int fscanf(FILE*, const char*, ...);
int fseek(FILE* file, long offset, int whence)
{
@ -347,10 +292,10 @@ int fseek(FILE* file, long offset, int whence)
int fseeko(FILE* file, off_t offset, int whence)
{
ScopeLock _(file);
long ret = syscall(SYS_SEEK, file->fd, offset, whence);
if (ret < 0)
return -1;
file->eof = false;
return 0;
}
@ -367,38 +312,30 @@ long ftell(FILE* file)
off_t ftello(FILE* file)
{
ScopeLock _(file);
long ret = syscall(SYS_TELL, file->fd);
if (ret < 0)
return -1;
return ret;
}
int ftrylockfile(FILE*)
{
// FIXME: when threads are implemented
return 0;
}
// TODO
int ftrylockfile(FILE*);
void funlockfile(FILE*)
{
// FIXME: when threads are implemented
}
// TODO
void funlockfile(FILE*);
size_t fwrite(const void* buffer, size_t size, size_t nitems, FILE* file)
{
ScopeLock _(file);
unsigned char* ubuffer = (unsigned char*)buffer;
for (size_t byte = 0; byte < nitems * size; byte++)
if (putc_unlocked(ubuffer[byte], file) == EOF)
if (fputc(ubuffer[byte], file) == EOF)
return byte / size;
return nitems;
}
int getc(FILE* file)
{
ScopeLock _(file);
return getc_unlocked(file);
return fgetc(file);
}
int getchar(void)
@ -406,33 +343,11 @@ int getchar(void)
return getc(stdin);
}
int getc_unlocked(FILE* file)
{
if (file->eof)
return EOF;
// TODO
int getc_unlocked(FILE*);
unsigned char c;
long ret = syscall(SYS_READ, file->fd, &c, 1);
if (ret < 0)
{
file->error = true;
return EOF;
}
if (ret == 0)
{
file->eof = true;
return EOF;
}
return c;
}
int getchar_unlocked(void)
{
return getc_unlocked(stdin);
}
// TODO
int getchar_unlocked(void);
char* gets(char* buffer)
{
@ -458,32 +373,11 @@ char* gets(char* buffer)
}
}
int pclose(FILE* file)
{
if (file->pid == -1)
{
errno = EBADF;
return -1;
}
pid_t pid = file->pid;
(void)fclose(file);
int stat;
while (waitpid(pid, &stat, 0) != -1)
{
if (errno != EINTR)
{
stat = -1;
break;
}
}
return stat;
}
// TODO
int pclose(FILE*);
void perror(const char* string)
{
ScopeLock _(stderr);
if (string && *string)
{
fputs(string, stderr);
@ -494,60 +388,8 @@ void perror(const char* string)
stderr->error = true;
}
FILE* popen(const char* command, const char* mode_str)
{
if ((mode_str[0] != 'r' && mode_str[0] != 'w') || mode_str[1] != '\0')
{
errno = EINVAL;
return nullptr;
}
bool read = (mode_str[0] == 'r');
int fds[2];
if (pipe(fds) == -1)
return nullptr;
pid_t pid = fork();
if (pid == 0)
{
if (read)
dup2(fds[1], STDOUT_FILENO);
else
dup2(fds[0], STDIN_FILENO);
close(fds[0]);
close(fds[1]);
execl("/bin/Shell", "sh", "-c", command, nullptr);
exit(1);
}
if (pid == -1)
{
close(fds[0]);
close(fds[1]);
return nullptr;
}
close(read ? fds[1] : fds[0]);
// FIXME: when threads are implemented
for (int i = 0; i < FOPEN_MAX; i++)
{
if (s_files[i].fd == -1)
{
s_files[i] = {
.fd = read ? fds[0] : fds[1],
.mode = (unsigned)(read ? O_RDONLY : O_WRONLY),
.pid = pid
};
return &s_files[i];
}
}
errno = EMFILE;
return nullptr;
}
// TODO
FILE* popen(const char*, const char*);
int printf(const char* format, ...)
{
@ -568,23 +410,14 @@ int putchar(int c)
return putc(c, stdout);
}
int putc_unlocked(int c, FILE* file)
{
file->buffer[file->buffer_index++] = c;
if (c == '\n' || file->buffer_index == sizeof(file->buffer))
if (fflush(file) == EOF)
return EOF;
return (unsigned char)c;
}
// TODO
int putc_unlocked(int, FILE*);
int putchar_unlocked(int c)
{
return putc_unlocked(c, stdout);
}
// TODO
int putchar_unlocked(int);
int puts(const char* string)
{
ScopeLock _(stdout);
if (fputs(string, stdout) == EOF)
return EOF;
if (fputc('\n', stdout) == EOF)
@ -605,12 +438,8 @@ int remove(const char* path)
// TODO
int rename(const char*, const char*);
void rewind(FILE* file)
{
ScopeLock _(file);
file->error = false;
(void)fseek(file, 0L, SEEK_SET);
}
// TODO
void rewind(FILE*);
int scanf(const char* format, ...)
{
@ -668,14 +497,12 @@ int ungetc(int, FILE*);
int vfprintf(FILE* file, const char* format, va_list arguments)
{
ScopeLock _(file);
return printf_impl(format, arguments, [](int c, void* file) { return putc_unlocked(c, static_cast<FILE*>(file)); }, file);
return printf_impl(format, arguments, [](int c, void* file) { return fputc(c, static_cast<FILE*>(file)); }, file);
}
int vfscanf(FILE* file, const char* format, va_list arguments)
{
ScopeLock _(file);
return scanf_impl(format, arguments, [](void* file) { return getc_unlocked(static_cast<FILE*>(file)); }, file);
return scanf_impl(format, arguments, [](void* file) { return fgetc(static_cast<FILE*>(file)); }, file);
}
int vprintf(const char* format, va_list arguments)

View File

@ -1,30 +1,10 @@
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int errno = 0;
void* memccpy(void* __restrict s1, const void* __restrict s2, int c, size_t n)
{
unsigned char* dst = static_cast<unsigned char*>(s1);
const unsigned char* src = static_cast<const unsigned char*>(s2);
for (size_t i = 0; i < n; i++)
if ((dst[i] = src[i]) == c)
return dst + i + 1;
return nullptr;
}
void* memchr(const void* s, int c, size_t n)
{
const unsigned char* u = static_cast<const unsigned char*>(s);
for (size_t i = 0; i < n; i++)
if (u[i] == c)
return const_cast<unsigned char*>(u + i);
return nullptr;
}
int memcmp(const void* s1, const void* s2, size_t n)
{
const unsigned char* a = static_cast<const unsigned char*>(s1);
@ -136,6 +116,7 @@ char* strncat(char* __restrict__ dest, const char* __restrict__ src, size_t n)
return dest;
}
#ifndef __is_kernel
char* strdup(const char* str)
{
const size_t size = strlen(str) + 1;
@ -161,7 +142,9 @@ char* strndup(const char* str, size_t size)
memcpy(new_str, str, size);
return new_str;
}
#endif
__attribute__((optimize("-O0")))
size_t strlen(const char* str)
{
size_t len = 0;
@ -170,14 +153,6 @@ size_t strlen(const char* str)
return len;
}
size_t strnlen(const char* str, size_t maxlen)
{
size_t len = 0;
while (len < maxlen && str[len])
len++;
return len;
}
char* strchr(const char* str, int c)
{
while (*str)
@ -214,156 +189,20 @@ char* strrchr(const char* str, int c)
char* strstr(const char* haystack, const char* needle)
{
size_t needle_len = strlen(needle);
for (size_t i = 0; haystack[i]; i++)
if (strncmp(haystack + i, needle, needle_len) == 0)
return const_cast<char*>(haystack + i);
return nullptr;
}
size_t strcspn(const char* s1, const char* s2)
{
size_t i = 0;
for (; s1[i]; i++)
for (size_t j = 0; s2[j]; j++)
if (s1[i] == s2[j])
return i;
return i;
}
char* strpbrk(const char* s1, const char* s2)
{
for (size_t i = 0; s1[i]; i++)
for (size_t j = 0; s2[j]; j++)
if (s1[i] == s2[j])
return const_cast<char*>(s1 + i);
return nullptr;
}
size_t strspn(const char* s1, const char* s2)
{
size_t i = 0;
for (; s1[i]; i++)
{
bool found = false;
for (size_t j = 0; s2[j] && !found; j++)
if (s1[i] == s2[j])
found = true;
if (!found)
break;
}
return i;
}
char* strtok(char* __restrict s, const char* __restrict sep)
{
static char* state = nullptr;
return strtok_r(s, sep, &state);
}
char* strtok_r(char* __restrict str, const char* __restrict sep, char** __restrict state)
{
if (str)
{
while (*str)
{
bool found = false;
for (size_t i = 0; sep[i] && !found; i++)
if (*str == sep[i])
found = true;
if (!found)
break;
str++;
}
if (!*str)
{
*state = nullptr;
return nullptr;
}
*state = str;
}
if (!*state)
return nullptr;
str = *state;
for (size_t i = 0; str[i]; i++)
{
for (size_t j = 0; sep[j]; j++)
{
if (str[i] == sep[j])
{
str[i] = '\0';
*state = str + i + 1;
return str;
}
}
}
*state = nullptr;
return str;
}
char* strsignal(int signum)
{
static char buffer[128];
switch (signum)
{
case SIGABRT: strcpy(buffer, "SIGABRT"); break;
case SIGALRM: strcpy(buffer, "SIGALRM"); break;
case SIGBUS: strcpy(buffer, "SIGBUS"); break;
case SIGCHLD: strcpy(buffer, "SIGCHLD"); break;
case SIGCONT: strcpy(buffer, "SIGCONT"); break;
case SIGFPE: strcpy(buffer, "SIGFPE"); break;
case SIGHUP: strcpy(buffer, "SIGHUP"); break;
case SIGILL: strcpy(buffer, "SIGILL"); break;
case SIGINT: strcpy(buffer, "SIGINT"); break;
case SIGKILL: strcpy(buffer, "SIGKILL"); break;
case SIGPIPE: strcpy(buffer, "SIGPIPE"); break;
case SIGQUIT: strcpy(buffer, "SIGQUIT"); break;
case SIGSEGV: strcpy(buffer, "SIGSEGV"); break;
case SIGSTOP: strcpy(buffer, "SIGSTOP"); break;
case SIGTERM: strcpy(buffer, "SIGTERM"); break;
case SIGTSTP: strcpy(buffer, "SIGTSTP"); break;
case SIGTTIN: strcpy(buffer, "SIGTTIN"); break;
case SIGTTOU: strcpy(buffer, "SIGTTOU"); break;
case SIGUSR1: strcpy(buffer, "SIGUSR1"); break;
case SIGUSR2: strcpy(buffer, "SIGUSR2"); break;
case SIGPOLL: strcpy(buffer, "SIGPOLL"); break;
case SIGPROF: strcpy(buffer, "SIGPROF"); break;
case SIGSYS: strcpy(buffer, "SIGSYS"); break;
case SIGTRAP: strcpy(buffer, "SIGTRAP"); break;
case SIGURG: strcpy(buffer, "SIGURG"); break;
case SIGVTALRM: strcpy(buffer, "SIGVTALRM"); break;
case SIGXCPU: strcpy(buffer, "SIGXCPU"); break;
case SIGXFSZ: strcpy(buffer, "SIGXFSZ"); break;
}
return buffer;
if (memcmp(haystack + i, needle, strlen(needle)) == 0)
return (char*)haystack + i;
return NULL;
}
char* strerror(int error)
{
static char buffer[128];
if (const char* str = strerrordesc_np(error))
strcpy(buffer, str);
else
sprintf(buffer, "Unknown error %d", error);
static char buffer[1024];
buffer[0] = 0;
strcpy(buffer, strerrordesc_np(error));
return buffer;
}
int strerror_r(int error, char* strerrbuf, size_t buflen)
{
const char* str = strerrordesc_np(error);
if (!str)
return EINVAL;
if (strlen(str) + 1 > buflen)
return ERANGE;
strcpy(strerrbuf, str);
return 0;
}
const char* strerrorname_np(int error)
{
switch (error)
@ -456,7 +295,7 @@ const char* strerrorname_np(int error)
}
errno = EINVAL;
return nullptr;
return "EUNKNOWN";
}
const char* strerrordesc_np(int error)
@ -551,5 +390,5 @@ const char* strerrordesc_np(int error)
}
errno = EINVAL;
return nullptr;
return "Unknown error";
}

View File

@ -22,7 +22,7 @@ int select(int nfds, fd_set* __restrict readfds, fd_set* __restrict writefds, fd
if (timeout)
{
ts.tv_sec = timeout->tv_sec;
ts.tv_nsec = timeout->tv_usec * 1000;
ts.tv_nsec = timeout->tc_usec * 1000;
pts = &ts;
}

View File

@ -295,91 +295,6 @@ int rmdir(const char* path)
return syscall(SYS_UNLINK, path);
}
char* optarg = nullptr;
int opterr = 1;
int optind = 1;
int optopt = 0;
int getopt(int argc, char* const argv[], const char* optstring)
{
if (optind >= argc)
return -1;
static int idx = 1;
const char* current = argv[optind];
// if "--" is encountered, no more options are parsed
if (idx == -1)
return -1;
// if current is nullptr, does not start with '-' or is string "-", return -1
if (current == nullptr || current[0] != '-' || current[1] == '\0')
return -1;
// if current points to string "--" increment optind and return -1
if (current[1] == '-' && current[2] == '\0')
{
idx = -1;
optind++;
return -1;
}
for (size_t i = 0; optstring[i]; i++)
{
if (optstring[i] == ':')
continue;
if (current[idx] != optstring[i])
continue;
if (optstring[i + 1] == ':')
{
if (current[idx + 1])
{
optarg = const_cast<char*>(current + idx + 1);
optind += 1;
}
else
{
optarg = const_cast<char*>(argv[optind + 1]);
optind += 2;
}
idx = 1;
if (optind > argc)
{
if (opterr && optstring[0] != ':')
fprintf(stderr, "%s: option requires an argument -- %c\n", argv[0], optstring[i]);
optopt = optstring[i];
return optstring[0] == ':' ? ':' : '?';
}
return optstring[i];
}
else
{
if (current[++idx] == '\0')
{
idx = 1;
optind++;
}
return optstring[i];
}
}
if (opterr && optstring[0] != ':')
fprintf(stderr, "%s: illegal option -- %c\n", argv[0], current[idx]);
if (current[++idx] == '\0')
{
idx = 1;
optind++;
}
return '?';
}
pid_t getpid(void)
{
return syscall(SYS_GET_PID);

View File

@ -10,7 +10,6 @@ set(USERSPACE_PROJECTS
dd
dhcp-client
echo
getopt
id
image
init
@ -34,7 +33,6 @@ set(USERSPACE_PROJECTS
test-framebuffer
test-globals
test-mouse
test-popen
test-sort
test-tcp
test-udp

View File

@ -1,16 +0,0 @@
cmake_minimum_required(VERSION 3.26)
project(getopt CXX)
set(SOURCES
main.cpp
)
add_executable(getopt ${SOURCES})
target_compile_options(getopt PUBLIC -O2 -g)
target_link_libraries(getopt PUBLIC libc ban)
add_custom_target(getopt-install
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/getopt ${BANAN_BIN}/
DEPENDS getopt
)

View File

@ -1,44 +0,0 @@
#include <BAN/String.h>
#include <BAN/Vector.h>
#include <stdio.h>
#include <unistd.h>
int main(int argc, char** argv)
{
if (argc < 2)
{
fprintf(stderr, "usage: %s OPTSTRING [PARAMETERS]...", argv[0]);
return 1;
}
BAN::Vector<char*> argv_copy(argc - 1);
argv_copy[0] = argv[0];
for (int i = 2; i < argc; i++)
argv_copy[i - 1] = argv[i];
int opt;
BAN::String parsed;
while ((opt = getopt(argc - 1, argv_copy.data(), argv[1])) != -1)
{
if (opt == ':' || opt == '?')
continue;
MUST(parsed.append(" -"));
MUST(parsed.push_back(opt));
if (optarg)
{
MUST(parsed.push_back(' '));
MUST(parsed.append(optarg));
}
optarg = nullptr;
}
printf("%s --", parsed.data());
for (; optind < argc - 1; optind++)
printf(" %s", argv_copy[optind]);
printf("\n");
return 0;
}

View File

@ -11,7 +11,6 @@
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/un.h>
@ -54,12 +53,6 @@ struct DNSEntry
BAN::IPv4Address address { 0 };
};
struct DNSResponse
{
uint16_t id;
DNSEntry entry;
};
bool send_dns_query(int socket, BAN::StringView domain, uint16_t id)
{
static uint8_t buffer[4096];
@ -98,7 +91,7 @@ bool send_dns_query(int socket, BAN::StringView domain, uint16_t id)
return true;
}
BAN::Optional<DNSResponse> read_dns_response(int socket)
BAN::Optional<DNSEntry> read_dns_response(int socket, uint16_t id)
{
static uint8_t buffer[4096];
@ -110,6 +103,11 @@ BAN::Optional<DNSResponse> read_dns_response(int socket)
}
DNSPacket& reply = *reinterpret_cast<DNSPacket*>(buffer);
if (reply.identification != id)
{
dprintln("Reply to invalid packet");
return {};
}
if (reply.flags & 0x0F)
{
dprintln("DNS error (rcode {})", (unsigned)(reply.flags & 0xF));
@ -136,10 +134,9 @@ BAN::Optional<DNSResponse> read_dns_response(int socket)
return {};
}
DNSResponse result;
result.id = reply.identification;
result.entry.valid_until = time(nullptr) + answer.ttl();
result.entry.address = BAN::IPv4Address(*reinterpret_cast<uint32_t*>(answer.data));
DNSEntry result;
result.valid_until = time(nullptr) + answer.ttl();
result.address = BAN::IPv4Address(*reinterpret_cast<uint32_t*>(answer.data));
return result;
}
@ -210,125 +207,55 @@ int main(int, char**)
BAN::HashMap<BAN::String, DNSEntry> dns_cache;
struct Client
{
const int socket;
bool close { false };
uint16_t query_id { 0 };
BAN::String query;
};
BAN::LinkedList<Client> clients;
for (;;)
{
int max_sock = BAN::Math::max(service_socket, dns_socket);
fd_set fds;
FD_ZERO(&fds);
FD_SET(service_socket, &fds);
FD_SET(dns_socket, &fds);
for (auto& client : clients)
int client = accept(service_socket, nullptr, nullptr);
if (client == -1)
{
FD_SET(client.socket, &fds);
max_sock = BAN::Math::max(max_sock, client.socket);
}
int nselect = select(max_sock + 1, &fds, nullptr, nullptr, nullptr);
if (nselect == -1)
{
perror("select");
dprintln("accept: {}", strerror(errno));
continue;
}
if (FD_ISSET(service_socket, &fds))
auto query = read_service_query(client);
if (!query.has_value())
{
int client = accept(service_socket, nullptr, nullptr);
if (client == -1)
{
perror("accept");
continue;
}
MUST(clients.emplace_back(client));
close(client);
continue;
}
if (FD_ISSET(dns_socket, &fds))
BAN::Optional<DNSEntry> result;
if (dns_cache.contains(*query))
{
auto result = read_dns_response(dns_socket);
if (!result.has_value())
continue;
auto& cached = dns_cache[*query];
if (time(nullptr) <= cached.valid_until)
result = cached;
else
dns_cache.remove(*query);
}
for (auto& client : clients)
if (!result.has_value())
{
uint16_t id = rand() % 0xFFFF;
if (send_dns_query(dns_socket, *query, id))
{
if (client.query_id != result->id)
continue;
(void)dns_cache.insert(client.query, result->entry);
sockaddr_storage storage;
storage.ss_family = AF_INET;
memcpy(storage.ss_storage, &result->entry.address.raw, sizeof(result->entry.address.raw));
if (send(client.socket, &storage, sizeof(storage), 0) == -1)
dprintln("send: {}", strerror(errno));
client.close = true;
break;
result = read_dns_response(dns_socket, id);
if (result.has_value())
(void)dns_cache.insert(*query, *result);
}
}
for (auto& client : clients)
{
if (!FD_ISSET(client.socket, &fds))
continue;
if (!result.has_value())
result = DNSEntry { .valid_until = 0, .address = BAN::IPv4Address(INADDR_ANY) };
if (!client.query.empty())
{
dprintln("Client already has a query");
continue;
}
sockaddr_storage storage;
storage.ss_family = AF_INET;
memcpy(storage.ss_storage, &result->address.raw, sizeof(result->address.raw));
auto query = read_service_query(client.socket);
if (!query.has_value())
continue;
if (send(client, &storage, sizeof(storage), 0) == -1)
dprintln("send: {}", strerror(errno));
BAN::Optional<DNSEntry> result;
if (dns_cache.contains(*query))
{
auto& cached = dns_cache[*query];
if (time(nullptr) <= cached.valid_until)
result = cached;
else
dns_cache.remove(*query);
}
if (result.has_value())
{
sockaddr_storage storage;
storage.ss_family = AF_INET;
memcpy(storage.ss_storage, &result->address.raw, sizeof(result->address.raw));
if (send(client.socket, &storage, sizeof(storage), 0) == -1)
dprintln("send: {}", strerror(errno));
client.close = true;
continue;
}
client.query = query.release_value();
client.query_id = rand() % 0xFFFF;
send_dns_query(dns_socket, client.query, client.query_id);
}
for (auto it = clients.begin(); it != clients.end();)
{
if (!it->close)
{
it++;
continue;
}
close(it->socket);
it = clients.remove(it);
}
close(client);
}
return 0;

View File

@ -1,16 +0,0 @@
cmake_minimum_required(VERSION 3.26)
project(test-popen CXX)
set(SOURCES
main.cpp
)
add_executable(test-popen ${SOURCES})
target_compile_options(test-popen PUBLIC -O2 -g)
target_link_libraries(test-popen PUBLIC libc)
add_custom_target(test-popen-install
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/test-popen ${BANAN_BIN}/
DEPENDS test-popen
)

View File

@ -1,30 +0,0 @@
#include <stdio.h>
#include <unistd.h>
int main(int argc, char** argv)
{
if (argc != 2)
{
fprintf(stderr, "usage: %s COMMAND\n", argv[0]);
return 1;
}
FILE* fp = popen(argv[1], "r");
if (fp == nullptr)
{
perror("popen");
return 1;
}
char buffer[128];
while (fgets(buffer, sizeof(buffer), fp) != NULL)
printf("%s", buffer);
if (pclose(fp) == -1)
{
perror("pclose");
return 1;
}
return 0;
}