BAN: Error can now be constructed from c_string or format string

If the resulting string would overflow, we just truncate it to fit
the error message buffer (128) bytes
This commit is contained in:
Bananymous 2023-03-08 17:05:37 +02:00
parent d90aba0963
commit 7458f68c38
8 changed files with 77 additions and 84 deletions

View File

@ -21,20 +21,32 @@ namespace BAN
class Error class Error
{ {
public: public:
static Error from_string(const char* message) static Error from_c_string(const char* message)
{ {
static_assert(sizeof(message) < 128);
Error result; Error result;
strncpy(result.m_message, message, sizeof(m_message)); strncpy(result.m_message, message, sizeof(Error::m_message));
result.m_message[sizeof(result.m_message) - 1] = '\0'; result.m_message[sizeof(Error::m_message) - 1] = '\0';
result.m_error_code = 0xFF; result.m_error_code = 0xFF;
return result; return result;
} }
template<typename... Args>
static Error from_format(const char* format, Args&&... args)
{
char buffer[sizeof(Error::m_message)] {};
size_t index = 0;
auto putc = [&](char ch)
{
if (index < sizeof(buffer) - 1)
buffer[index++] = ch;
};
Formatter::print(putc, format, forward<Args>(args)...);
return from_c_string(buffer);
}
static Error from_errno(int error) static Error from_errno(int error)
{ {
Error result; Error result;
strncpy(result.m_message, strerror(error), sizeof(m_message)); strncpy(result.m_message, strerror(error), sizeof(Error::m_message));
result.m_message[sizeof(result.m_message) - 1] = '\0'; result.m_message[sizeof(Error::m_message) - 1] = '\0';
result.m_error_code = error; result.m_error_code = error;
return result; return result;
} }

View File

@ -19,7 +19,7 @@ namespace Kernel
private: private:
void rerender_buffer() const; void rerender_buffer() const;
BAN::Vector<BAN::String> parse_arguments(BAN::StringView) const; BAN::Vector<BAN::String> parse_arguments(BAN::StringView) const;
void process_command(const BAN::Vector<BAN::String>&); BAN::ErrorOr<void> process_command(const BAN::Vector<BAN::String>&);
void key_event_callback(Input::KeyEvent); void key_event_callback(Input::KeyEvent);
private: private:

View File

@ -222,7 +222,7 @@ namespace Kernel
} }
} }
return BAN::Error::from_string("Inode did not contain enough blocks"); return BAN::Error::from_c_string("Inode did not contain enough blocks");
} }
BAN::ErrorOr<BAN::Vector<uint8_t>> Ext2Inode::read_all() BAN::ErrorOr<BAN::Vector<uint8_t>> Ext2Inode::read_all()
@ -355,7 +355,7 @@ namespace Kernel
} }
if (m_superblock.magic != 0xEF53) if (m_superblock.magic != 0xEF53)
return BAN::Error::from_string("Not a ext2 filesystem"); return BAN::Error::from_c_string("Not a ext2 filesystem");
if (m_superblock.rev_level < 1) if (m_superblock.rev_level < 1)
{ {
@ -392,7 +392,7 @@ namespace Kernel
uint32_t number_of_block_groups = BAN::Math::div_round_up(m_superblock.inodes_count, m_superblock.inodes_per_group); uint32_t number_of_block_groups = BAN::Math::div_round_up(m_superblock.inodes_count, m_superblock.inodes_per_group);
uint32_t number_of_block_groups_check = BAN::Math::div_round_up(m_superblock.blocks_count, m_superblock.blocks_per_group); uint32_t number_of_block_groups_check = BAN::Math::div_round_up(m_superblock.blocks_count, m_superblock.blocks_per_group);
if (number_of_block_groups != number_of_block_groups_check) if (number_of_block_groups != number_of_block_groups_check)
return BAN::Error::from_string("Ambiguous number of blocks"); return BAN::Error::from_c_string("Ambiguous number of blocks");
uint32_t block_group_descriptor_table_block = m_superblock.first_data_block + 1; uint32_t block_group_descriptor_table_block = m_superblock.first_data_block + 1;
uint32_t block_group_descriptor_table_sector_count = BAN::Math::div_round_up(32u * number_of_block_groups, sector_size); uint32_t block_group_descriptor_table_sector_count = BAN::Math::div_round_up(32u * number_of_block_groups, sector_size);

View File

@ -109,13 +109,13 @@ namespace Kernel
if (m_root_inode) if (m_root_inode)
return {}; return {};
return BAN::Error::from_string("Could not locate root partition"); return BAN::Error::from_c_string("Could not locate root partition");
} }
BAN::ErrorOr<BAN::RefPtr<Inode>> VirtualFileSystem::from_absolute_path(BAN::StringView path) BAN::ErrorOr<BAN::RefPtr<Inode>> VirtualFileSystem::from_absolute_path(BAN::StringView path)
{ {
if (path.front() != '/') if (path.front() != '/')
return BAN::Error::from_string("Path must be an absolute path"); return BAN::Error::from_c_string("Path must be an absolute path");
auto inode = root_inode(); auto inode = root_inode();
auto path_parts = TRY(path.split('/')); auto path_parts = TRY(path.split('/'));

View File

@ -26,14 +26,14 @@ namespace Kernel
BAN::ErrorOr<Font> Font::load(BAN::StringView path) BAN::ErrorOr<Font> Font::load(BAN::StringView path)
{ {
if (!VirtualFileSystem::is_initialized()) if (!VirtualFileSystem::is_initialized())
return BAN::Error::from_string("Virtual Filesystem is not initialized"); return BAN::Error::from_c_string("Virtual Filesystem is not initialized");
auto inode = TRY(VirtualFileSystem::get().from_absolute_path(path)); auto inode = TRY(VirtualFileSystem::get().from_absolute_path(path));
auto file_data = TRY(inode->read_all()); auto file_data = TRY(inode->read_all());
if (file_data.size() < 4) if (file_data.size() < 4)
return BAN::Error::from_string("Font file is too small"); return BAN::Error::from_c_string("Font file is too small");
if (file_data[0] == 0x36 && file_data[1] == 0x04) if (file_data[0] == 0x36 && file_data[1] == 0x04)
return TRY(parse_psf1(file_data)); return TRY(parse_psf1(file_data));
@ -41,14 +41,14 @@ namespace Kernel
if (file_data[0] == 0x72 && file_data[1] == 0xB5 && file_data[2] == 0x4A && file_data[3] == 0x86) if (file_data[0] == 0x72 && file_data[1] == 0xB5 && file_data[2] == 0x4A && file_data[3] == 0x86)
return TRY(parse_psf2(file_data)); return TRY(parse_psf2(file_data));
return BAN::Error::from_string("Unsupported font format"); return BAN::Error::from_c_string("Unsupported font format");
} }
BAN::ErrorOr<Font> Font::parse_psf1(const BAN::Vector<uint8_t>& font_data) BAN::ErrorOr<Font> Font::parse_psf1(const BAN::Vector<uint8_t>& font_data)
{ {
if (font_data.size() < 4) if (font_data.size() < 4)
return BAN::Error::from_string("Font file is too small"); return BAN::Error::from_c_string("Font file is too small");
struct PSF1Header struct PSF1Header
{ {
@ -63,7 +63,7 @@ namespace Kernel
uint32_t glyph_data_size = glyph_size * glyph_count; uint32_t glyph_data_size = glyph_size * glyph_count;
if (font_data.size() < sizeof(PSF1Header) + glyph_data_size) if (font_data.size() < sizeof(PSF1Header) + glyph_data_size)
return BAN::Error::from_string("Font file is too small"); return BAN::Error::from_c_string("Font file is too small");
BAN::Vector<uint8_t> glyph_data; BAN::Vector<uint8_t> glyph_data;
TRY(glyph_data.resize(glyph_data_size)); TRY(glyph_data.resize(glyph_data_size));
@ -109,7 +109,7 @@ namespace Kernel
} }
if (glyph_index != glyph_count) if (glyph_index != glyph_count)
return BAN::Error::from_string("Font did not contain unicode entry for all glyphs"); return BAN::Error::from_c_string("Font did not contain unicode entry for all glyphs");
} }
else else
{ {
@ -146,7 +146,7 @@ namespace Kernel
}; };
if (font_data.size() < sizeof(PSF2Header)) if (font_data.size() < sizeof(PSF2Header))
return BAN::Error::from_string("Font file is too small"); return BAN::Error::from_c_string("Font file is too small");
PSF2Header header; PSF2Header header;
header.magic = BAN::Math::little_endian_to_host<uint32_t>(font_data.data() + 0); header.magic = BAN::Math::little_endian_to_host<uint32_t>(font_data.data() + 0);
@ -161,7 +161,7 @@ namespace Kernel
uint32_t glyph_data_size = header.glyph_count * header.glyph_size; uint32_t glyph_data_size = header.glyph_count * header.glyph_size;
if (font_data.size() < glyph_data_size + header.header_size) if (font_data.size() < glyph_data_size + header.header_size)
return BAN::Error::from_string("Font file is too small"); return BAN::Error::from_c_string("Font file is too small");
BAN::Vector<uint8_t> glyph_data; BAN::Vector<uint8_t> glyph_data;
TRY(glyph_data.resize(glyph_data_size)); TRY(glyph_data.resize(glyph_data_size));
@ -207,7 +207,7 @@ namespace Kernel
} }
} }
if (glyph_index != header.glyph_count) if (glyph_index != header.glyph_count)
return BAN::Error::from_string("Font did not contain unicode entry for all glyphs"); return BAN::Error::from_c_string("Font did not contain unicode entry for all glyphs");
} }
else else
{ {

View File

@ -137,7 +137,7 @@ argument_done:
return result; return result;
} }
void Shell::process_command(const Vector<String>& arguments) BAN::ErrorOr<void> Shell::process_command(const Vector<String>& arguments)
{ {
if (arguments.empty()) if (arguments.empty())
{ {
@ -146,7 +146,7 @@ argument_done:
else if (arguments.front() == "date") else if (arguments.front() == "date")
{ {
if (arguments.size() != 1) if (arguments.size() != 1)
return TTY_PRINTLN("'date' does not support command line arguments"); return BAN::Error::from_c_string("'date' does not support command line arguments");
auto time = RTC::get_current_time(); auto time = RTC::get_current_time();
TTY_PRINTLN("{}", time); TTY_PRINTLN("{}", time);
} }
@ -163,7 +163,7 @@ argument_done:
else if (arguments.front() == "clear") else if (arguments.front() == "clear")
{ {
if (arguments.size() != 1) if (arguments.size() != 1)
return TTY_PRINTLN("'clear' does not support command line arguments"); return BAN::Error::from_c_string("'clear' does not support command line arguments");
m_tty->clear(); m_tty->clear();
m_tty->set_cursor_position(0, 0); m_tty->set_cursor_position(0, 0);
} }
@ -172,7 +172,7 @@ argument_done:
auto new_args = arguments; auto new_args = arguments;
new_args.remove(0); new_args.remove(0);
auto start = PIT::ms_since_boot(); auto start = PIT::ms_since_boot();
process_command(new_args); TRY(process_command(new_args));
auto duration = PIT::ms_since_boot() - start; auto duration = PIT::ms_since_boot() - start;
TTY_PRINTLN("took {} ms", duration); TTY_PRINTLN("took {} ms", duration);
} }
@ -182,39 +182,37 @@ argument_done:
s_thread_spinlock.lock(); s_thread_spinlock.lock();
auto thread_or_error = Thread::create( auto thread = TRY(Thread::create(
[this, &arguments] [this, &arguments]
{ {
auto args = arguments; auto args = arguments;
args.remove(0); args.remove(0);
s_thread_spinlock.unlock(); s_thread_spinlock.unlock();
PIT::sleep(5000); PIT::sleep(5000);
process_command(args); if (auto res = process_command(args); res.is_error())
TTY_PRINTLN("{}", res.error());
} }
); ));
if (thread_or_error.is_error()) TRY(Scheduler::get().add_thread(thread));
return TTY_PRINTLN("{}", thread_or_error.error());
MUST(Scheduler::get().add_thread(thread_or_error.release_value()));
while (s_thread_spinlock.is_locked()); while (s_thread_spinlock.is_locked());
} }
else if (arguments.front() == "memory") else if (arguments.front() == "memory")
{ {
if (arguments.size() != 1) if (arguments.size() != 1)
return TTY_PRINTLN("'memory' does not support command line arguments"); return BAN::Error::from_c_string("'memory' does not support command line arguments");
kmalloc_dump_info(); kmalloc_dump_info();
} }
else if (arguments.front() == "sleep") else if (arguments.front() == "sleep")
{ {
if (arguments.size() != 1) if (arguments.size() != 1)
return TTY_PRINTLN("'sleep' does not support command line arguments"); return BAN::Error::from_c_string("'sleep' does not support command line arguments");
PIT::sleep(5000); PIT::sleep(5000);
} }
else if (arguments.front() == "cpuinfo") else if (arguments.front() == "cpuinfo")
{ {
if (arguments.size() != 1) if (arguments.size() != 1)
return TTY_PRINTLN("'cpuinfo' does not support command line arguments"); return BAN::Error::from_c_string("'cpuinfo' does not support command line arguments");
uint32_t ecx, edx; uint32_t ecx, edx;
auto vendor = CPUID::get_vendor(); auto vendor = CPUID::get_vendor();
@ -235,11 +233,11 @@ argument_done:
else if (arguments.front() == "random") else if (arguments.front() == "random")
{ {
if (arguments.size() != 1) if (arguments.size() != 1)
return TTY_PRINTLN("'random' does not support command line arguments"); return BAN::Error::from_c_string("'random' does not support command line arguments");
uint32_t ecx, edx; uint32_t ecx, edx;
CPUID::get_features(ecx, edx); CPUID::get_features(ecx, edx);
if (!(ecx & CPUID::Features::ECX_RDRND)) if (!(ecx & CPUID::Features::ECX_RDRND))
return TTY_PRINTLN("cpu does not support RDRAND instruction"); return BAN::Error::from_c_string("cpu does not support RDRAND instruction");
for (int i = 0; i < 10; i++) for (int i = 0; i < 10; i++)
{ {
@ -251,7 +249,7 @@ argument_done:
else if (arguments.front() == "reboot") else if (arguments.front() == "reboot")
{ {
if (arguments.size() != 1) if (arguments.size() != 1)
return TTY_PRINTLN("'reboot' does not support command line arguments"); return BAN::Error::from_c_string("'reboot' does not support command line arguments");
uint8_t good = 0x02; uint8_t good = 0x02;
while (good & 0x02) while (good & 0x02)
good = IO::inb(0x64); good = IO::inb(0x64);
@ -261,31 +259,24 @@ argument_done:
else if (arguments.front() == "lspci") else if (arguments.front() == "lspci")
{ {
if (arguments.size() != 1) if (arguments.size() != 1)
return TTY_PRINTLN("'lspci' does not support command line arguments"); return BAN::Error::from_c_string("'lspci' does not support command line arguments");
for (auto& device : PCI::get().devices()) for (auto& device : PCI::get().devices())
TTY_PRINTLN("{2H}:{2H}.{2H} {2H}", device.bus(), device.dev(), device.func(), device.class_code()); TTY_PRINTLN("{2H}:{2H}.{2H} {2H}", device.bus(), device.dev(), device.func(), device.class_code());
} }
else if (arguments.front() == "ls") else if (arguments.front() == "ls")
{ {
if (!VirtualFileSystem::is_initialized()) if (!VirtualFileSystem::is_initialized())
return TTY_PRINTLN("VFS not initialized :("); return BAN::Error::from_c_string("VFS not initialized :(");
if (arguments.size() > 2) if (arguments.size() > 2)
return TTY_PRINTLN("usage: 'ls [path]'"); return BAN::Error::from_c_string("usage: 'ls [path]'");
BAN::StringView path = (arguments.size() == 2) ? arguments[1].sv() : "/"; BAN::StringView path = (arguments.size() == 2) ? arguments[1].sv() : "/";
if (path.front() != '/') if (path.front() != '/')
return TTY_PRINTLN("ls currently works only with absolute paths"); return BAN::Error::from_c_string("ls currently works only with absolute paths");
auto directory_or_error = VirtualFileSystem::get().from_absolute_path(path); auto directory = TRY(VirtualFileSystem::get().from_absolute_path(path));
if (directory_or_error.is_error()) auto inodes = TRY(directory->directory_inodes());
return TTY_PRINTLN("{}", directory_or_error.error());
auto directory = directory_or_error.release_value();
auto inodes_or_error = directory->directory_inodes();
if (inodes_or_error.is_error())
return TTY_PRINTLN("{}", inodes_or_error.error());
auto& inodes = inodes_or_error.value();
auto mode_string = [](Inode::Mode mode) auto mode_string = [](Inode::Mode mode)
{ {
@ -314,43 +305,32 @@ argument_done:
else if (arguments.front() == "cat") else if (arguments.front() == "cat")
{ {
if (!VirtualFileSystem::is_initialized()) if (!VirtualFileSystem::is_initialized())
return TTY_PRINTLN("VFS not initialized :("); return BAN::Error::from_c_string("VFS not initialized :(");
if (arguments.size() != 2) if (arguments.size() != 2)
return TTY_PRINTLN("usage: 'cat path'"); return BAN::Error::from_c_string("usage: 'cat path'");
auto file_or_error = VirtualFileSystem::get().from_absolute_path(arguments[1]);
if (file_or_error.is_error())
return TTY_PRINTLN("{}", file_or_error.error());
auto file = file_or_error.release_value();
auto data_or_error = file->read_all();
if (data_or_error.is_error())
return TTY_PRINTLN("{}", data_or_error.error());
auto data = data_or_error.release_value();
auto file = TRY(VirtualFileSystem::get().from_absolute_path(arguments[1]));
auto data = TRY(file->read_all());
TTY_PRINTLN("{}", BAN::StringView((const char*)data.data(), data.size())); TTY_PRINTLN("{}", BAN::StringView((const char*)data.data(), data.size()));
} }
else if (arguments.front() == "loadfont") else if (arguments.front() == "loadfont")
{ {
if (!VirtualFileSystem::is_initialized()) if (!VirtualFileSystem::is_initialized())
return TTY_PRINTLN("VFS not initialized :("); return BAN::Error::from_c_string("VFS not initialized :(");
if (arguments.size() != 2) if (arguments.size() != 2)
return TTY_PRINTLN("usage: 'loadfont font_path'"); return BAN::Error::from_c_string("usage: 'loadfont font_path'");
auto font_or_error = Font::load(arguments[1]);
if (font_or_error.is_error())
return TTY_PRINTLN("{}", font_or_error.error());
auto font = font_or_error.release_value();
auto font = TRY(Font::load(arguments[1]));
m_tty->set_font(font); m_tty->set_font(font);
} }
else else
{ {
TTY_PRINTLN("unrecognized command '{}'", arguments.front()); return BAN::Error::from_format("unrecognized command '{}'", arguments.front());
} }
return {};
} }
void Shell::rerender_buffer() const void Shell::rerender_buffer() const
@ -416,7 +396,8 @@ argument_done:
auto arguments = parse_arguments(current_buffer.sv()); auto arguments = parse_arguments(current_buffer.sv());
if (!arguments.empty()) if (!arguments.empty())
{ {
process_command(arguments); if (auto res = process_command(arguments); res.is_error())
TTY_PRINTLN("{}", res.error());
MUST(m_old_buffer.push_back(current_buffer)); MUST(m_old_buffer.push_back(current_buffer));
m_buffer = m_old_buffer; m_buffer = m_old_buffer;
MUST(m_buffer.push_back(""_sv)); MUST(m_buffer.push_back(""_sv));

View File

@ -187,7 +187,7 @@ namespace Kernel
BAN::ErrorOr<void> ATAController::read(ATADevice* device, uint64_t lba, uint8_t sector_count, uint8_t* buffer) BAN::ErrorOr<void> ATAController::read(ATADevice* device, uint64_t lba, uint8_t sector_count, uint8_t* buffer)
{ {
if (lba + sector_count > device->lba_count) if (lba + sector_count > device->lba_count)
return BAN::Error::from_string("Attempted to read outside of the device boundaries"); return BAN::Error::from_c_string("Attempted to read outside of the device boundaries");
LockGuard _(m_lock); LockGuard _(m_lock);
@ -274,21 +274,21 @@ namespace Kernel
{ {
uint8_t err = read(ATA_PORT_ERROR); uint8_t err = read(ATA_PORT_ERROR);
if (err & ATA_ERROR_AMNF) if (err & ATA_ERROR_AMNF)
return BAN::Error::from_string("Address mark not found."); return BAN::Error::from_c_string("Address mark not found.");
if (err & ATA_ERROR_TKZNF) if (err & ATA_ERROR_TKZNF)
return BAN::Error::from_string("Track zero not found."); return BAN::Error::from_c_string("Track zero not found.");
if (err & ATA_ERROR_ABRT) if (err & ATA_ERROR_ABRT)
return BAN::Error::from_string("Aborted command."); return BAN::Error::from_c_string("Aborted command.");
if (err & ATA_ERROR_MCR) if (err & ATA_ERROR_MCR)
return BAN::Error::from_string("Media change request."); return BAN::Error::from_c_string("Media change request.");
if (err & ATA_ERROR_IDNF) if (err & ATA_ERROR_IDNF)
return BAN::Error::from_string("ID not found."); return BAN::Error::from_c_string("ID not found.");
if (err & ATA_ERROR_MC) if (err & ATA_ERROR_MC)
return BAN::Error::from_string("Media changed."); return BAN::Error::from_c_string("Media changed.");
if (err & ATA_ERROR_UNC) if (err & ATA_ERROR_UNC)
return BAN::Error::from_string("Uncorrectable data error."); return BAN::Error::from_c_string("Uncorrectable data error.");
if (err & ATA_ERROR_BBK) if (err & ATA_ERROR_BBK)
return BAN::Error::from_string("Bad Block detected."); return BAN::Error::from_c_string("Bad Block detected.");
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
} }

View File

@ -193,7 +193,7 @@ namespace Kernel
GPTHeader header = parse_gpt_header(lba1); GPTHeader header = parse_gpt_header(lba1);
if (!is_valid_gpt_header(header, sector_size())) if (!is_valid_gpt_header(header, sector_size()))
return BAN::Error::from_string("Invalid GPT header"); return BAN::Error::from_c_string("Invalid GPT header");
uint32_t size = header.partition_entry_count * header.partition_entry_size; uint32_t size = header.partition_entry_count * header.partition_entry_size;
if (uint32_t remainder = size % sector_size()) if (uint32_t remainder = size % sector_size())
@ -203,7 +203,7 @@ namespace Kernel
TRY(read_sectors(header.partition_entry_lba, size / sector_size(), entry_array.data())); TRY(read_sectors(header.partition_entry_lba, size / sector_size(), entry_array.data()));
if (!is_valid_gpt_crc32(header, lba1, entry_array)) if (!is_valid_gpt_crc32(header, lba1, entry_array))
return BAN::Error::from_string("Invalid crc3 in the GPT header"); return BAN::Error::from_c_string("Invalid crc3 in the GPT header");
for (uint32_t i = 0; i < header.partition_entry_count; i++) for (uint32_t i = 0; i < header.partition_entry_count; i++)
{ {
@ -241,7 +241,7 @@ namespace Kernel
{ {
const uint32_t sectors_in_partition = m_lba_end - m_lba_start; const uint32_t sectors_in_partition = m_lba_end - m_lba_start;
if (lba + sector_count > sectors_in_partition) if (lba + sector_count > sectors_in_partition)
return BAN::Error::from_string("Attempted to read outside of the partition boundaries"); return BAN::Error::from_c_string("Attempted to read outside of the partition boundaries");
TRY(m_device.read_sectors(m_lba_start + lba, sector_count, buffer)); TRY(m_device.read_sectors(m_lba_start + lba, sector_count, buffer));
return {}; return {};
} }