Compare commits
7 Commits
5aca6c7c1f
...
91d513a672
Author | SHA1 | Date |
---|---|---|
Bananymous | 91d513a672 | |
Bananymous | 44f0ec601f | |
Bananymous | 2a659a9d03 | |
Bananymous | 7e7c3a1bb3 | |
Bananymous | 3b23458ecc | |
Bananymous | 7afdfb150f | |
Bananymous | 2ca7886f88 |
|
@ -4,8 +4,7 @@ if (NOT ${CMAKE_SYSTEM_NAME} STREQUAL "banan-os")
|
|||
message(FATAL_ERROR "CMAKE_SYSTEM_NAME is not banan-os")
|
||||
endif ()
|
||||
|
||||
#add_compile_options(-mno-sse -mno-sse2)
|
||||
add_compile_definitions(__enable_sse=1)
|
||||
set(BANAN_ENABLE_SSE 1)
|
||||
|
||||
project(banan-os CXX C ASM)
|
||||
|
||||
|
|
|
@ -172,7 +172,11 @@ set(KERNEL_SOURCES
|
|||
add_executable(kernel ${KERNEL_SOURCES})
|
||||
|
||||
target_compile_definitions(kernel PUBLIC __is_kernel)
|
||||
target_compile_definitions(kernel PUBLIC __arch=${BANAN_ARCH})
|
||||
target_compile_definitions(kernel PRIVATE __arch=${BANAN_ARCH})
|
||||
target_compile_definitions(kernel PRIVATE __enable_sse=${BANAN_ENABLE_SSE})
|
||||
if (NOT BANAN_ENABLE_SSE)
|
||||
target_compile_options(kernel PRIVATE -mno-sse -mno-sse2)
|
||||
endif ()
|
||||
|
||||
target_compile_options(kernel PUBLIC -O2 -g)
|
||||
target_compile_options(kernel PUBLIC $<$<COMPILE_LANGUAGE:CXX>:-Wno-literal-suffix -fno-rtti -fno-exceptions>)
|
||||
|
|
|
@ -10,7 +10,7 @@ namespace Kernel
|
|||
class ProcPidInode final : public TmpDirectoryInode
|
||||
{
|
||||
public:
|
||||
static BAN::ErrorOr<BAN::RefPtr<ProcPidInode>> create_new(Process&, TmpFileSystem&, mode_t, uid_t, gid_t);
|
||||
static BAN::ErrorOr<BAN::RefPtr<ProcPidInode>> create_new(Process&, TmpFileSystem&, mode_t);
|
||||
~ProcPidInode() = default;
|
||||
|
||||
virtual uid_t uid() const override { return m_process.credentials().ruid(); }
|
||||
|
@ -28,11 +28,11 @@ namespace Kernel
|
|||
Process& m_process;
|
||||
};
|
||||
|
||||
class ProcROInode final : public TmpInode
|
||||
class ProcROProcessInode final : public TmpInode
|
||||
{
|
||||
public:
|
||||
static BAN::ErrorOr<BAN::RefPtr<ProcROInode>> create_new(Process&, size_t (Process::*callback)(off_t, BAN::ByteSpan) const, TmpFileSystem&, mode_t, uid_t, gid_t);
|
||||
~ProcROInode() = default;
|
||||
static BAN::ErrorOr<BAN::RefPtr<ProcROProcessInode>> create_new(Process&, size_t (Process::*callback)(off_t, BAN::ByteSpan) const, TmpFileSystem&, mode_t);
|
||||
~ProcROProcessInode() = default;
|
||||
|
||||
virtual uid_t uid() const override { return m_process.credentials().ruid(); }
|
||||
virtual gid_t gid() const override { return m_process.credentials().rgid(); }
|
||||
|
@ -49,11 +49,35 @@ namespace Kernel
|
|||
virtual bool has_error_impl() const override { return false; }
|
||||
|
||||
private:
|
||||
ProcROInode(Process&, size_t (Process::*)(off_t, BAN::ByteSpan) const, TmpFileSystem&, const TmpInodeInfo&);
|
||||
ProcROProcessInode(Process&, size_t (Process::*)(off_t, BAN::ByteSpan) const, TmpFileSystem&, const TmpInodeInfo&);
|
||||
|
||||
private:
|
||||
Process& m_process;
|
||||
size_t (Process::*m_callback)(off_t, BAN::ByteSpan) const;
|
||||
};
|
||||
|
||||
class ProcROInode final : public TmpInode
|
||||
{
|
||||
public:
|
||||
static BAN::ErrorOr<BAN::RefPtr<ProcROInode>> create_new(size_t (*callback)(off_t, BAN::ByteSpan), TmpFileSystem&, mode_t, uid_t, gid_t);
|
||||
~ProcROInode() = default;
|
||||
|
||||
protected:
|
||||
virtual BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) override;
|
||||
|
||||
// You may not write here and this is always non blocking
|
||||
virtual BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan) override { return BAN::Error::from_errno(EINVAL); }
|
||||
virtual BAN::ErrorOr<void> truncate_impl(size_t) override { return BAN::Error::from_errno(EINVAL); }
|
||||
|
||||
virtual bool can_read_impl() const override { return true; }
|
||||
virtual bool can_write_impl() const override { return false; }
|
||||
virtual bool has_error_impl() const override { return false; }
|
||||
|
||||
private:
|
||||
ProcROInode(size_t (*callback)(off_t, BAN::ByteSpan), TmpFileSystem&, const TmpInodeInfo&);
|
||||
|
||||
private:
|
||||
size_t (*m_callback)(off_t, BAN::ByteSpan);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -76,7 +76,7 @@ namespace Kernel
|
|||
|
||||
bool is_userspace() const { return m_is_userspace; }
|
||||
|
||||
size_t virtual_page_count() const { return (m_kernel_stack->size() / PAGE_SIZE) + (m_userspace_stack->size() / PAGE_SIZE); }
|
||||
size_t virtual_page_count() const { return (m_kernel_stack ? (m_kernel_stack->size() / PAGE_SIZE) : 0) + (m_userspace_stack ? (m_userspace_stack->size() / PAGE_SIZE) : 0); }
|
||||
size_t physical_page_count() const { return virtual_page_count(); }
|
||||
|
||||
InterruptStack& interrupt_stack() { return m_interrupt_stack; }
|
||||
|
|
|
@ -14,6 +14,26 @@ namespace Kernel
|
|||
ASSERT(s_instance);
|
||||
|
||||
MUST(s_instance->TmpFileSystem::initialize(0555, 0, 0));
|
||||
|
||||
auto meminfo_inode = MUST(ProcROInode::create_new(
|
||||
[](off_t offset, BAN::ByteSpan buffer) -> size_t
|
||||
{
|
||||
ASSERT(offset >= 0);
|
||||
if ((size_t)offset >= sizeof(full_meminfo_t))
|
||||
return 0;
|
||||
|
||||
full_meminfo_t meminfo;
|
||||
meminfo.page_size = PAGE_SIZE;
|
||||
meminfo.free_pages = Heap::get().free_pages();
|
||||
meminfo.used_pages = Heap::get().used_pages();
|
||||
|
||||
size_t bytes = BAN::Math::min<size_t>(sizeof(full_meminfo_t) - offset, buffer.size());
|
||||
memcpy(buffer.data(), (uint8_t*)&meminfo + offset, bytes);
|
||||
return bytes;
|
||||
},
|
||||
*s_instance, 0444, 0, 0
|
||||
));
|
||||
MUST(static_cast<TmpDirectoryInode*>(s_instance->root_inode().ptr())->link_inode(*meminfo_inode, "meminfo"_sv));
|
||||
}
|
||||
|
||||
ProcFileSystem& ProcFileSystem::get()
|
||||
|
@ -30,7 +50,7 @@ namespace Kernel
|
|||
BAN::ErrorOr<void> ProcFileSystem::on_process_create(Process& process)
|
||||
{
|
||||
auto path = TRY(BAN::String::formatted("{}", process.pid()));
|
||||
auto inode = TRY(ProcPidInode::create_new(process, *this, 0555, process.credentials().ruid(), process.credentials().rgid()));
|
||||
auto inode = TRY(ProcPidInode::create_new(process, *this, 0555));
|
||||
TRY(static_cast<TmpDirectoryInode*>(root_inode().ptr())->link_inode(*inode, path));
|
||||
return {};
|
||||
}
|
||||
|
|
|
@ -3,18 +3,18 @@
|
|||
namespace Kernel
|
||||
{
|
||||
|
||||
BAN::ErrorOr<BAN::RefPtr<ProcPidInode>> ProcPidInode::create_new(Process& process, TmpFileSystem& fs, mode_t mode, uid_t uid, gid_t gid)
|
||||
BAN::ErrorOr<BAN::RefPtr<ProcPidInode>> ProcPidInode::create_new(Process& process, TmpFileSystem& fs, mode_t mode)
|
||||
{
|
||||
auto inode_info = create_inode_info(Mode::IFDIR | mode, uid, gid);
|
||||
auto inode_info = create_inode_info(Mode::IFDIR | mode, 0, 0);
|
||||
|
||||
auto* inode_ptr = new ProcPidInode(process, fs, inode_info);
|
||||
if (inode_ptr == nullptr)
|
||||
return BAN::Error::from_errno(ENOMEM);
|
||||
auto inode = BAN::RefPtr<ProcPidInode>::adopt(inode_ptr);
|
||||
|
||||
TRY(inode->link_inode(*MUST(ProcROInode::create_new(process, &Process::proc_meminfo, fs, 0400, uid, gid)), "meminfo"_sv));
|
||||
TRY(inode->link_inode(*MUST(ProcROInode::create_new(process, &Process::proc_cmdline, fs, 0400, uid, gid)), "cmdline"_sv));
|
||||
TRY(inode->link_inode(*MUST(ProcROInode::create_new(process, &Process::proc_environ, fs, 0400, uid, gid)), "environ"_sv));
|
||||
TRY(inode->link_inode(*MUST(ProcROProcessInode::create_new(process, &Process::proc_meminfo, fs, 0400)), "meminfo"_sv));
|
||||
TRY(inode->link_inode(*MUST(ProcROProcessInode::create_new(process, &Process::proc_cmdline, fs, 0400)), "cmdline"_sv));
|
||||
TRY(inode->link_inode(*MUST(ProcROProcessInode::create_new(process, &Process::proc_environ, fs, 0400)), "environ"_sv));
|
||||
|
||||
return inode;
|
||||
}
|
||||
|
@ -32,17 +32,17 @@ namespace Kernel
|
|||
(void)TmpDirectoryInode::unlink_impl("environ"_sv);
|
||||
}
|
||||
|
||||
BAN::ErrorOr<BAN::RefPtr<ProcROInode>> ProcROInode::create_new(Process& process, size_t (Process::*callback)(off_t, BAN::ByteSpan) const, TmpFileSystem& fs, mode_t mode, uid_t uid, gid_t gid)
|
||||
BAN::ErrorOr<BAN::RefPtr<ProcROProcessInode>> ProcROProcessInode::create_new(Process& process, size_t (Process::*callback)(off_t, BAN::ByteSpan) const, TmpFileSystem& fs, mode_t mode)
|
||||
{
|
||||
auto inode_info = create_inode_info(Mode::IFREG | mode, uid, gid);
|
||||
auto inode_info = create_inode_info(Mode::IFREG | mode, 0, 0);
|
||||
|
||||
auto* inode_ptr = new ProcROInode(process, callback, fs, inode_info);
|
||||
auto* inode_ptr = new ProcROProcessInode(process, callback, fs, inode_info);
|
||||
if (inode_ptr == nullptr)
|
||||
return BAN::Error::from_errno(ENOMEM);
|
||||
return BAN::RefPtr<ProcROInode>::adopt(inode_ptr);
|
||||
return BAN::RefPtr<ProcROProcessInode>::adopt(inode_ptr);
|
||||
}
|
||||
|
||||
ProcROInode::ProcROInode(Process& process, size_t (Process::*callback)(off_t, BAN::ByteSpan) const, TmpFileSystem& fs, const TmpInodeInfo& inode_info)
|
||||
ProcROProcessInode::ProcROProcessInode(Process& process, size_t (Process::*callback)(off_t, BAN::ByteSpan) const, TmpFileSystem& fs, const TmpInodeInfo& inode_info)
|
||||
: TmpInode(fs, MUST(fs.allocate_inode(inode_info)), inode_info)
|
||||
, m_process(process)
|
||||
, m_callback(callback)
|
||||
|
@ -50,12 +50,35 @@ namespace Kernel
|
|||
m_inode_info.mode |= Inode::Mode::IFREG;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<size_t> ProcROInode::read_impl(off_t offset, BAN::ByteSpan buffer)
|
||||
BAN::ErrorOr<size_t> ProcROProcessInode::read_impl(off_t offset, BAN::ByteSpan buffer)
|
||||
{
|
||||
ASSERT(offset >= 0);
|
||||
if ((size_t)offset >= sizeof(proc_meminfo_t))
|
||||
return 0;
|
||||
if (offset < 0)
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
return (m_process.*m_callback)(offset, buffer);
|
||||
}
|
||||
|
||||
BAN::ErrorOr<BAN::RefPtr<ProcROInode>> ProcROInode::create_new(size_t (*callback)(off_t, BAN::ByteSpan), TmpFileSystem& fs, mode_t mode, uid_t uid, gid_t gid)
|
||||
{
|
||||
auto inode_info = create_inode_info(Mode::IFREG | mode, uid, gid);
|
||||
|
||||
auto* inode_ptr = new ProcROInode(callback, fs, inode_info);
|
||||
if (inode_ptr == nullptr)
|
||||
return BAN::Error::from_errno(ENOMEM);
|
||||
return BAN::RefPtr<ProcROInode>::adopt(inode_ptr);
|
||||
}
|
||||
|
||||
ProcROInode::ProcROInode(size_t (*callback)(off_t, BAN::ByteSpan), TmpFileSystem& fs, const TmpInodeInfo& inode_info)
|
||||
: TmpInode(fs, MUST(fs.allocate_inode(inode_info)), inode_info)
|
||||
, m_callback(callback)
|
||||
{
|
||||
m_inode_info.mode |= Inode::Mode::IFREG;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<size_t> ProcROInode::read_impl(off_t offset, BAN::ByteSpan buffer)
|
||||
{
|
||||
if (offset < 0)
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
return m_callback(offset, buffer);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1826,16 +1826,6 @@ namespace Kernel
|
|||
|
||||
BAN::ErrorOr<long> Process::sys_sigprocmask(int how, const sigset_t* set, sigset_t* oset)
|
||||
{
|
||||
switch (how)
|
||||
{
|
||||
case SIG_BLOCK:
|
||||
case SIG_SETMASK:
|
||||
case SIG_UNBLOCK:
|
||||
break;
|
||||
default:
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
}
|
||||
|
||||
LockGuard _(m_process_lock);
|
||||
if (set)
|
||||
TRY(validate_pointer_access(set, sizeof(sigset_t)));
|
||||
|
@ -1857,8 +1847,10 @@ namespace Kernel
|
|||
Thread::current().m_signal_block_mask = mask;
|
||||
break;
|
||||
case SIG_UNBLOCK:
|
||||
Thread::current().m_signal_block_mask &= mask;
|
||||
Thread::current().m_signal_block_mask &= ~mask;
|
||||
break;
|
||||
default:
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -139,6 +139,24 @@ namespace Kernel
|
|||
case 45: m_background = TerminalColor::BRIGHT_MAGENTA; break;
|
||||
case 46: m_background = TerminalColor::BRIGHT_CYAN; break;
|
||||
case 47: m_background = TerminalColor::BRIGHT_WHITE; break;
|
||||
|
||||
case 90: m_foreground = TerminalColor::BLACK; break;
|
||||
case 91: m_foreground = TerminalColor::RED; break;
|
||||
case 92: m_foreground = TerminalColor::GREEN; break;
|
||||
case 93: m_foreground = TerminalColor::YELLOW; break;
|
||||
case 94: m_foreground = TerminalColor::BLUE; break;
|
||||
case 95: m_foreground = TerminalColor::MAGENTA; break;
|
||||
case 96: m_foreground = TerminalColor::CYAN; break;
|
||||
case 97: m_foreground = TerminalColor::WHITE; break;
|
||||
|
||||
case 100: m_background = TerminalColor::BLACK; break;
|
||||
case 101: m_background = TerminalColor::RED; break;
|
||||
case 102: m_background = TerminalColor::GREEN; break;
|
||||
case 103: m_background = TerminalColor::YELLOW; break;
|
||||
case 104: m_background = TerminalColor::BLUE; break;
|
||||
case 105: m_background = TerminalColor::MAGENTA; break;
|
||||
case 106: m_background = TerminalColor::CYAN; break;
|
||||
case 107: m_background = TerminalColor::WHITE; break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@ done
|
|||
build_dir="$NAME-$VERSION-$BANAN_ARCH"
|
||||
|
||||
if [ ! -d "$build_dir" ]; then
|
||||
rm -f ".compile_hash-$BANAN_ARCH"
|
||||
rm -f ".compile_hash"
|
||||
fi
|
||||
|
||||
if [ "$VERSION" = "git" ]; then
|
||||
|
@ -135,8 +135,8 @@ else
|
|||
fi
|
||||
|
||||
needs_compile=1
|
||||
if [ -f ".compile_hash-$BANAN_ARCH" ]; then
|
||||
sha256sum --check ".compile_hash-$BANAN_ARCH" &>/dev/null
|
||||
if [ -f ".compile_hash" ]; then
|
||||
sha256sum --check ".compile_hash" &>/dev/null
|
||||
needs_compile=$?
|
||||
fi
|
||||
|
||||
|
@ -144,7 +144,7 @@ cd "$build_dir"
|
|||
|
||||
if (( $needs_compile )); then
|
||||
build
|
||||
sha256sum "$BANAN_SYSROOT/usr/lib/libc.a" > "../.compile_hash-$BANAN_ARCH"
|
||||
sha256sum "$BANAN_SYSROOT/usr/lib/libc.a" > "../.compile_hash"
|
||||
fi
|
||||
|
||||
install
|
||||
|
|
|
@ -6,4 +6,4 @@ while IFS= read -r port; do
|
|||
pushd $(dirname "$port") >/dev/null
|
||||
./build.sh
|
||||
popd >/dev/null
|
||||
done < <(find . -name '.compile_hash*')
|
||||
done < <(find . -name '.compile_hash')
|
||||
|
|
|
@ -121,7 +121,7 @@ case $1 in
|
|||
;;
|
||||
distclean)
|
||||
rm -rf $BANAN_BUILD_DIR
|
||||
rm $BANAN_ROOT_DIR/ports/*/.compile_hash*
|
||||
find $BANAN_ROOT_DIR/ports -name '.compile_hash' -exec rm {} +
|
||||
;;
|
||||
*)
|
||||
build_target $1
|
||||
|
|
|
@ -36,6 +36,12 @@ set(LIBC_SOURCES
|
|||
)
|
||||
|
||||
add_library(libc ${LIBC_SOURCES})
|
||||
target_compile_definitions(libc PRIVATE __arch=${BANAN_ARCH})
|
||||
target_compile_definitions(libc PRIVATE __enable_sse=${BANAN_ENABLE_SSE})
|
||||
if (NOT BANAN_ENABLE_SSE)
|
||||
target_compile_options(libc PRIVATE -mno-sse -mno-sse2)
|
||||
endif ()
|
||||
|
||||
target_compile_options(libc PRIVATE -O2 -g -Wstack-usage=512 -fno-tree-loop-distribute-patterns -fno-exceptions -nostdlib)
|
||||
target_compile_options(libc PUBLIC -Wall -Wextra -Werror -Wno-error=stack-usage=)
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ __BEGIN_DECLS
|
|||
|
||||
#ifndef __locale_t_defined
|
||||
#define __locale_t_defined 1
|
||||
typedef int locale_t;
|
||||
typedef enum { LOCALE_INVALID, LOCALE_POSIX, LOCALE_UTF8 } locale_t;
|
||||
#endif
|
||||
|
||||
__END_DECLS
|
||||
|
|
|
@ -68,6 +68,8 @@ locale_t newlocale(int category_mask, const char* locale, locale_t base);
|
|||
char* setlocale(int category, const char* locale);
|
||||
locale_t uselocale(locale_t newloc);
|
||||
|
||||
locale_t __getlocale(int category);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif
|
||||
|
|
|
@ -24,6 +24,13 @@ struct proc_meminfo_t
|
|||
size_t phys_pages;
|
||||
};
|
||||
|
||||
struct full_meminfo_t
|
||||
{
|
||||
size_t page_size;
|
||||
size_t free_pages;
|
||||
size_t used_pages;
|
||||
};
|
||||
|
||||
/*
|
||||
fildes: refers to valid tty device
|
||||
command: one of TTY_CMD_* definitions
|
||||
|
|
|
@ -1,15 +1,112 @@
|
|||
#include <BAN/Assert.h>
|
||||
|
||||
#include <locale.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
// FIXME: Actually support locales
|
||||
char* setlocale(int category, const char* locale)
|
||||
{
|
||||
(void)category;
|
||||
static locale_t s_current_locales[LC_ALL] {
|
||||
LOCALE_POSIX,
|
||||
LOCALE_POSIX,
|
||||
LOCALE_POSIX,
|
||||
LOCALE_POSIX,
|
||||
LOCALE_POSIX,
|
||||
LOCALE_POSIX,
|
||||
};
|
||||
static_assert(LC_ALL == 6);
|
||||
|
||||
static char s_locale[] = "C";
|
||||
if (locale == nullptr)
|
||||
return s_locale;
|
||||
if (strcmp(locale, "") == 0 || strcmp(locale, "C") == 0 || strcmp(locale, "POSIX") == 0)
|
||||
return s_locale;
|
||||
return nullptr;
|
||||
static locale_t str_to_locale(const char* locale)
|
||||
{
|
||||
if (*locale == '\0')
|
||||
return LOCALE_UTF8;
|
||||
|
||||
if (strcmp(locale, "C") == 0 || strcmp(locale, "LOCALE_POSIX") == 0)
|
||||
return LOCALE_POSIX;
|
||||
if (strcmp(locale, "C.UTF8") == 0)
|
||||
return LOCALE_UTF8;
|
||||
return LOCALE_INVALID;
|
||||
}
|
||||
|
||||
static const char* locale_to_str(locale_t locale)
|
||||
{
|
||||
if (locale == LOCALE_POSIX)
|
||||
return "C";
|
||||
if (locale == LOCALE_UTF8)
|
||||
return "C.UTF8";
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
char* setlocale(int category, const char* locale_str)
|
||||
{
|
||||
static char s_locale_buffer[128];
|
||||
|
||||
if (locale_str == nullptr)
|
||||
{
|
||||
switch (category)
|
||||
{
|
||||
case LC_COLLATE:
|
||||
case LC_CTYPE:
|
||||
case LC_MESSAGES:
|
||||
case LC_MONETARY:
|
||||
case LC_NUMERIC:
|
||||
case LC_TIME:
|
||||
strcpy(s_locale_buffer, locale_to_str(s_current_locales[category]));
|
||||
break;
|
||||
case LC_ALL:
|
||||
sprintf(s_locale_buffer, "%s;%s;%s;%s;%s;%s",
|
||||
locale_to_str(s_current_locales[0]),
|
||||
locale_to_str(s_current_locales[1]),
|
||||
locale_to_str(s_current_locales[2]),
|
||||
locale_to_str(s_current_locales[3]),
|
||||
locale_to_str(s_current_locales[4]),
|
||||
locale_to_str(s_current_locales[5])
|
||||
);
|
||||
break;
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return s_locale_buffer;
|
||||
}
|
||||
|
||||
locale_t locale = str_to_locale(locale_str);
|
||||
if (locale == LOCALE_INVALID)
|
||||
return nullptr;
|
||||
|
||||
switch (category)
|
||||
{
|
||||
case LC_COLLATE:
|
||||
case LC_CTYPE:
|
||||
case LC_MESSAGES:
|
||||
case LC_MONETARY:
|
||||
case LC_NUMERIC:
|
||||
case LC_TIME:
|
||||
s_current_locales[category] = locale;
|
||||
break;
|
||||
case LC_ALL:
|
||||
for (auto& current : s_current_locales)
|
||||
current = locale;
|
||||
break;
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
strcpy(s_locale_buffer, locale_to_str(locale));
|
||||
return s_locale_buffer;
|
||||
}
|
||||
|
||||
|
||||
locale_t __getlocale(int category)
|
||||
{
|
||||
switch (category)
|
||||
{
|
||||
case LC_COLLATE:
|
||||
case LC_CTYPE:
|
||||
case LC_MESSAGES:
|
||||
case LC_MONETARY:
|
||||
case LC_NUMERIC:
|
||||
case LC_TIME:
|
||||
return s_current_locales[category];
|
||||
default:
|
||||
return LOCALE_INVALID;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,11 @@ void psignal(int signum, const char* message)
|
|||
fprintf(stderr, "%s\n", strsignal(signum));
|
||||
}
|
||||
|
||||
int pthread_sigmask(int how, const sigset_t* __restrict set, sigset_t* __restrict oset)
|
||||
{
|
||||
return syscall(SYS_SIGPROCMASK, how, set, oset);
|
||||
}
|
||||
|
||||
int raise(int sig)
|
||||
{
|
||||
// FIXME: won't work after multithreaded
|
||||
|
@ -72,5 +77,5 @@ int sigpending(sigset_t* set)
|
|||
|
||||
int sigprocmask(int how, const sigset_t* __restrict set, sigset_t* __restrict oset)
|
||||
{
|
||||
return syscall(SYS_SIGPROCMASK, how, set, oset);
|
||||
return pthread_sigmask(how, set, oset);
|
||||
}
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
#include <BAN/Assert.h>
|
||||
#include <BAN/Limits.h>
|
||||
#include <BAN/Math.h>
|
||||
#include <BAN/UTF8.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <locale.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
@ -512,6 +514,41 @@ int putenv(char* string)
|
|||
return 0;
|
||||
}
|
||||
|
||||
size_t mbstowcs(wchar_t* __restrict pwcs, const char* __restrict s, size_t n)
|
||||
{
|
||||
auto* us = reinterpret_cast<const unsigned char*>(s);
|
||||
|
||||
size_t len = 0;
|
||||
|
||||
switch (__getlocale(LC_CTYPE))
|
||||
{
|
||||
case LOCALE_INVALID:
|
||||
ASSERT_NOT_REACHED();
|
||||
case LOCALE_POSIX:
|
||||
while (*us && len < n)
|
||||
pwcs[len++] = *us++;
|
||||
break;
|
||||
case LOCALE_UTF8:
|
||||
while (*us && len < n)
|
||||
{
|
||||
auto wch = BAN::UTF8::to_codepoint(us);
|
||||
if (wch == BAN::UTF8::invalid)
|
||||
{
|
||||
errno = EILSEQ;
|
||||
return -1;
|
||||
}
|
||||
pwcs[len++] = wch;
|
||||
us += BAN::UTF8::byte_length(*us);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (len < n)
|
||||
pwcs[len] = 0;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
void* bsearch(const void* key, const void* base, size_t nel, size_t width, int (*compar)(const void*, const void*))
|
||||
{
|
||||
if (nel == 0)
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
#include <BAN/Assert.h>
|
||||
#include <BAN/UTF8.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <locale.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -138,8 +142,38 @@ char* strncat(char* __restrict__ dest, const char* __restrict__ src, size_t n)
|
|||
|
||||
int strcoll(const char* s1, const char* s2)
|
||||
{
|
||||
// FIXME: support locales
|
||||
return strcmp(s1, s2);
|
||||
switch (__getlocale(LC_COLLATE))
|
||||
{
|
||||
case LOCALE_INVALID:
|
||||
ASSERT_NOT_REACHED();
|
||||
case LOCALE_POSIX:
|
||||
return strcmp(s1, s2);
|
||||
case LOCALE_UTF8:
|
||||
{
|
||||
const unsigned char* u1 = (unsigned char*)s1;
|
||||
const unsigned char* u2 = (unsigned char*)s2;
|
||||
if (!*u1 || !*u2)
|
||||
return *u1 - *u2;
|
||||
|
||||
wchar_t wc1, wc2;
|
||||
while (*u1 && *u2)
|
||||
{
|
||||
wc1 = BAN::UTF8::to_codepoint(u1);
|
||||
wc2 = BAN::UTF8::to_codepoint(u2);
|
||||
if (wc1 == (wchar_t)BAN::UTF8::invalid || wc2 == (wchar_t)BAN::UTF8::invalid)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (wc1 != wc2)
|
||||
break;
|
||||
u1 += BAN::UTF8::byte_length(*u1);
|
||||
u2 += BAN::UTF8::byte_length(*u2);
|
||||
}
|
||||
return wc1 - wc2;
|
||||
}
|
||||
}
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
char* strdup(const char* str)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
set(USERSPACE_PROGRAMS
|
||||
bananfetch
|
||||
cat
|
||||
cat-mmap
|
||||
chmod
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
set(SOURCES
|
||||
main.cpp
|
||||
)
|
||||
|
||||
add_executable(bananfetch ${SOURCES})
|
||||
banan_link_library(bananfetch ban)
|
||||
banan_link_library(bananfetch libc)
|
||||
|
||||
install(TARGETS bananfetch OPTIONAL)
|
|
@ -0,0 +1,281 @@
|
|||
#include <BAN/IPv4.h>
|
||||
#include <BAN/String.h>
|
||||
#include <BAN/Vector.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stropts.h>
|
||||
#include <sys/banan-os.h>
|
||||
#include <sys/framebuffer.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define COLOR_ON "\e[33m"
|
||||
#define COLOR_OFF "\e[m"
|
||||
|
||||
static constexpr const char* s_banana_art1[] {
|
||||
" X. ",
|
||||
" :; ",
|
||||
" .:; ",
|
||||
" ::::.",
|
||||
" .::::;.",
|
||||
".;. ..::::;;; ",
|
||||
";:::;::::::::;;;. ",
|
||||
" x;;;;;;;;;;;;. ",
|
||||
" ..x+;.. "
|
||||
};
|
||||
static constexpr size_t s_banana_art1_width = 19;
|
||||
static constexpr size_t s_banana_art1_height = 9;
|
||||
|
||||
static constexpr const char* s_banana_art2[] {
|
||||
" Z¨ ",
|
||||
" )r ",
|
||||
" `• ",
|
||||
" «/¿7`",
|
||||
" `»!}[ì`",
|
||||
"”<` ``«•×}ï1= ",
|
||||
">**¿<+)//(†×¿vîr´ ",
|
||||
" U==íï<<ííîcoc´ ",
|
||||
" ´¨kC‰·` "
|
||||
};
|
||||
static constexpr size_t s_banana_art2_width = 19;
|
||||
static constexpr size_t s_banana_art2_height = 9;
|
||||
|
||||
const char* get_cpu_manufacturer()
|
||||
{
|
||||
uint32_t max_extended;
|
||||
asm volatile("cpuid" : "=a"(max_extended) : "a"(0x80000000));
|
||||
if (max_extended >= 0x80000004)
|
||||
{
|
||||
static char string[49];
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
uint32_t eax, ebx, ecx, edx;
|
||||
asm volatile("cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) : "a"(0x80000002 + i));
|
||||
memcpy(string + i * 16 + 0, &eax, 4);
|
||||
memcpy(string + i * 16 + 4, &ebx, 4);
|
||||
memcpy(string + i * 16 + 8, &ecx, 4);
|
||||
memcpy(string + i * 16 + 12, &edx, 4);
|
||||
}
|
||||
string[48] = '\0';
|
||||
return string;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t ebx, ecx, edx;
|
||||
asm volatile("cpuid" : "=b"(ebx), "=c"(ecx), "=d"(edx) : "a"(0));
|
||||
|
||||
char string[13];
|
||||
memcpy(string + 0, &ebx, 4);
|
||||
memcpy(string + 4, &edx, 4);
|
||||
memcpy(string + 8, &ecx, 4);
|
||||
string[12] = '\0';
|
||||
|
||||
if (strcmp(string, "AuthenticAMD") == 0) return "AMD";
|
||||
if (strcmp(string, "CentaurHauls") == 0) return "Centaur";
|
||||
if (strcmp(string, "CyrixInstead") == 0) return "Cyrix";
|
||||
if (strcmp(string, "GenuineIntel") == 0) return "Intel";
|
||||
if (strcmp(string, "GenuineIotel") == 0) return "Intel";
|
||||
if (strcmp(string, "TransmetaCPU") == 0) return "Transmeta";
|
||||
if (strcmp(string, "GenuineTMx86") == 0) return "Transmeta";
|
||||
if (strcmp(string, "Geode by NSC") == 0) return "National Semiconductor";
|
||||
if (strcmp(string, "NexGenDriven") == 0) return "NexGen";
|
||||
if (strcmp(string, "RiseRiseRise") == 0) return "Rise";
|
||||
if (strcmp(string, "SiS SiS SiS ") == 0) return "Sis";
|
||||
if (strcmp(string, "UMC UMC UMC ") == 0) return "UMC";
|
||||
if (strcmp(string, "Vortex86 SoC") == 0) return "Vortex86";
|
||||
if (strcmp(string, " Shanghai ") == 0) return "Zhaoxin";
|
||||
if (strcmp(string, "HygonGenuine") == 0) return "Hygon";
|
||||
if (strcmp(string, "Genuine RDC") == 0) return "RDC Semiconductor";
|
||||
if (strcmp(string, "E2K MACHINE ") == 0) return "MCST Elbrus";
|
||||
if (strcmp(string, "VIA VIA VIA ") == 0) return "VIA";
|
||||
if (strcmp(string, "AMD ISBETTER") == 0) return "AMD";
|
||||
|
||||
if (strcmp(string, "GenuineAO486") == 0) return "ao486";
|
||||
if (strcmp(string, "MiSTer AO486") == 0) return "ao486";
|
||||
|
||||
if (strcmp(string, "MicrosoftXTA") == 0) return "Microsoft x86-to-ARM";
|
||||
if (strcmp(string, "VirtualApple") == 0) return "Apple Rosetta 2";
|
||||
|
||||
return "<unknown>";
|
||||
}
|
||||
}
|
||||
|
||||
BAN::ErrorOr<BAN::Vector<BAN::String>> get_info_lines()
|
||||
{
|
||||
BAN::Vector<BAN::String> info_lines;
|
||||
|
||||
struct utsname utsname;
|
||||
if (uname(&utsname) == -1)
|
||||
{
|
||||
perror("uname");
|
||||
return BAN::Error::from_errno(errno);
|
||||
}
|
||||
|
||||
char hostname[HOST_NAME_MAX];
|
||||
if (gethostname(hostname, sizeof(hostname)) == -1)
|
||||
{
|
||||
perror("gethostname");
|
||||
return BAN::Error::from_errno(errno);
|
||||
}
|
||||
|
||||
const char* login = getlogin();
|
||||
if (login == nullptr)
|
||||
{
|
||||
perror("getlogin");
|
||||
return BAN::Error::from_errno(errno);
|
||||
}
|
||||
|
||||
timespec uptime;
|
||||
if (clock_gettime(CLOCK_MONOTONIC, &uptime) == -1)
|
||||
{
|
||||
perror("clock_gettime");
|
||||
return BAN::Error::from_errno(errno);
|
||||
}
|
||||
|
||||
TRY(info_lines.push_back(TRY(BAN::String::formatted(COLOR_ON "{}" COLOR_OFF "@" COLOR_ON "{}", login, hostname))));
|
||||
|
||||
{
|
||||
const size_t host_length = strlen(login) + strlen(hostname) + 1;
|
||||
TRY(info_lines.emplace_back());
|
||||
TRY(info_lines.back().reserve(host_length));
|
||||
for (size_t i = 0; i < host_length; i++)
|
||||
MUST(info_lines.back().push_back('-'));
|
||||
}
|
||||
|
||||
TRY(info_lines.push_back(TRY(BAN::String::formatted(COLOR_ON "OS" COLOR_OFF ": {} {}", utsname.sysname, utsname.machine))));
|
||||
|
||||
TRY(info_lines.push_back(TRY(BAN::String::formatted(COLOR_ON "Kernel" COLOR_OFF ": {}", utsname.release))));
|
||||
|
||||
{
|
||||
const uint32_t uptime_day = uptime.tv_sec / (60 * 60 * 24);
|
||||
uptime.tv_sec %= 60 * 60 * 24;
|
||||
|
||||
const uint32_t uptime_hour = uptime.tv_sec / (60 * 60);
|
||||
uptime.tv_sec %= 60 * 60;
|
||||
|
||||
const uint32_t uptime_minute = uptime.tv_sec / 60;
|
||||
uptime.tv_sec %= 60;
|
||||
|
||||
TRY(info_lines.emplace_back(COLOR_ON "Uptime" COLOR_OFF ": "_sv));
|
||||
if (uptime_day)
|
||||
TRY(info_lines.back().append(TRY(BAN::String::formatted("{}d ", uptime_day))));
|
||||
if (uptime_hour)
|
||||
TRY(info_lines.back().append(TRY(BAN::String::formatted("{}h ", uptime_hour))));
|
||||
TRY(info_lines.back().append(TRY(BAN::String::formatted("{}m ", uptime_minute))));
|
||||
}
|
||||
|
||||
if (DIR* dirp = opendir("/usr/bin"); dirp != nullptr)
|
||||
{
|
||||
size_t program_count = 0;
|
||||
struct dirent* dirent;
|
||||
while ((dirent = readdir(dirp)))
|
||||
{
|
||||
if (dirent->d_type != DT_REG)
|
||||
continue;
|
||||
|
||||
struct stat st;
|
||||
if (fstatat(dirfd(dirp), dirent->d_name, &st, 0) == -1)
|
||||
continue;
|
||||
|
||||
program_count += !!(st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH));
|
||||
}
|
||||
|
||||
closedir(dirp);
|
||||
|
||||
TRY(info_lines.push_back(TRY(BAN::String::formatted(COLOR_ON "Programs" COLOR_OFF ": {}", program_count))));
|
||||
}
|
||||
|
||||
TRY(info_lines.push_back(TRY(BAN::String::formatted(COLOR_ON "CPU" COLOR_OFF ": {}", get_cpu_manufacturer()))));
|
||||
|
||||
if (int meminfo_fd = open("/proc/meminfo", O_RDONLY); meminfo_fd != -1)
|
||||
{
|
||||
full_meminfo_t meminfo;
|
||||
if (read(meminfo_fd, &meminfo, sizeof(meminfo)) == sizeof(meminfo))
|
||||
{
|
||||
const size_t total_bytes = (meminfo.free_pages + meminfo.used_pages) * meminfo.page_size;
|
||||
const size_t used_bytes = meminfo.used_pages * meminfo.page_size;
|
||||
TRY(info_lines.push_back(TRY(BAN::String::formatted(COLOR_ON "Memory" COLOR_OFF ": {}MiB / {}MiB", used_bytes >> 20, total_bytes >> 20))));
|
||||
}
|
||||
close(meminfo_fd);
|
||||
}
|
||||
|
||||
if (int fb_fd = open("/dev/fb0", O_RDONLY); fb_fd != -1)
|
||||
{
|
||||
framebuffer_info_t fb_info;
|
||||
if (pread(fb_fd, &fb_info, sizeof(fb_info), -1) == sizeof(framebuffer_info_t))
|
||||
TRY(info_lines.push_back(TRY(BAN::String::formatted(COLOR_ON "Resolution" COLOR_OFF ": {}x{}", fb_info.width, fb_info.height))));
|
||||
close(fb_fd);
|
||||
}
|
||||
|
||||
if (int socket = ::socket(AF_INET, SOCK_DGRAM, 0); socket != -1)
|
||||
{
|
||||
sockaddr_in sockaddr;
|
||||
sockaddr.sin_family = AF_INET;
|
||||
sockaddr.sin_port = 0;
|
||||
sockaddr.sin_addr.s_addr = INADDR_ANY;
|
||||
if (bind(socket, reinterpret_cast<struct sockaddr*>(&sockaddr), sizeof(sockaddr)) == 0)
|
||||
{
|
||||
ifreq ifreq;
|
||||
if (ioctl(socket, SIOCGIFADDR, &ifreq) == 0)
|
||||
{
|
||||
auto& ifru_addr = *reinterpret_cast<sockaddr_in*>(&ifreq.ifr_ifru.ifru_addr);
|
||||
if (ifru_addr.sin_family == AF_INET)
|
||||
TRY(info_lines.push_back(TRY(BAN::String::formatted(COLOR_ON "Local IPv4" COLOR_OFF ": {}", BAN::IPv4Address(ifru_addr.sin_addr.s_addr)))));
|
||||
}
|
||||
}
|
||||
|
||||
close(socket);
|
||||
}
|
||||
|
||||
TRY(info_lines.emplace_back());
|
||||
|
||||
TRY(info_lines.emplace_back());
|
||||
for (int color = 40; color <= 47; color++)
|
||||
TRY(info_lines.back().append(TRY(BAN::String::formatted("\e[{}m ", color))));
|
||||
|
||||
TRY(info_lines.emplace_back());
|
||||
for (int color = 100; color <= 107; color++)
|
||||
TRY(info_lines.back().append(TRY(BAN::String::formatted("\e[{}m ", color))));
|
||||
|
||||
return info_lines;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
constexpr auto& banana_art = s_banana_art2;
|
||||
constexpr size_t banana_width = s_banana_art2_width;
|
||||
constexpr size_t banana_height = s_banana_art2_height;
|
||||
|
||||
auto info_lines_or_error = get_info_lines();
|
||||
if (info_lines_or_error.is_error())
|
||||
{
|
||||
fprintf(stderr, "Could not get system information: %s\n", info_lines_or_error.error().get_message());
|
||||
return 1;
|
||||
}
|
||||
auto info_lines = info_lines_or_error.release_value();
|
||||
|
||||
for (size_t i = 0; i < BAN::Math::max(banana_height, info_lines.size()); i++)
|
||||
{
|
||||
if (i < banana_height)
|
||||
{
|
||||
printf("\e[1G" COLOR_ON);
|
||||
printf("%s", banana_art[i]);
|
||||
}
|
||||
|
||||
if (i < info_lines.size())
|
||||
{
|
||||
printf("\e[%zuG" COLOR_OFF, banana_width + 2);
|
||||
printf("%s", info_lines[i].data());
|
||||
}
|
||||
|
||||
printf(COLOR_OFF "\n");
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue