Compare commits
55 Commits
9c0fab2e88
...
d896101268
Author | SHA1 | Date | |
---|---|---|---|
d896101268 | |||
ea25d823e5 | |||
b278ae2dbc | |||
41bf27e510 | |||
935aecb96f | |||
3025eadc86 | |||
4bc1530425 | |||
40b0f8c6ec | |||
47c358555d | |||
a411bb6594 | |||
2a06a12721 | |||
cf6fd6ea29 | |||
0c2e9551ca | |||
9fd5d0b874 | |||
f8a5f24352 | |||
dbf014b351 | |||
0a630af250 | |||
dbf9a6bad8 | |||
c3af9091b5 | |||
9fa426eadf | |||
7ddac3c36b | |||
9aad63474b | |||
fdc362d19c | |||
6407ec76e0 | |||
8e36d25e8a | |||
a4b6e988b6 | |||
442a188630 | |||
871d8cce52 | |||
6b32af81f7 | |||
dfe1697ae6 | |||
ad0e8bad4a | |||
987ebe3ef1 | |||
dd9f8afd5b | |||
4b277b38f0 | |||
b4ae8bfaa1 | |||
ba3e32917e | |||
cfb60fad25 | |||
9954fc1658 | |||
a98df9e743 | |||
e2a77bb3da | |||
0ae409ae22 | |||
181b4c151b | |||
0c64b6e040 | |||
fb3c31907d | |||
52064e0317 | |||
ec3c1132d2 | |||
5ea73197ad | |||
5a1adcb2a6 | |||
c4f6191e24 | |||
39e4fbd112 | |||
32fd6889b9 | |||
c6a5a81a7a | |||
3f55a70f6e | |||
b1e164f360 | |||
ed8b210639 |
6
.gitignore
vendored
6
.gitignore
vendored
@ -4,7 +4,11 @@ build/
|
|||||||
initrd/boot/moon
|
initrd/boot/moon
|
||||||
env-local.sh
|
env-local.sh
|
||||||
initrd/bin/**
|
initrd/bin/**
|
||||||
base/usr/**
|
base/usr/bin/**
|
||||||
|
base/usr/include/**
|
||||||
|
base/usr/lib/**
|
||||||
|
base/usr/share/pkgdb/**
|
||||||
|
!base/usr/share/fonts/*
|
||||||
.fakeroot
|
.fakeroot
|
||||||
kernel/config.cmake
|
kernel/config.cmake
|
||||||
ports/out/
|
ports/out/
|
||||||
|
@ -45,8 +45,10 @@ endif()
|
|||||||
|
|
||||||
add_subdirectory(libluna)
|
add_subdirectory(libluna)
|
||||||
add_subdirectory(libos)
|
add_subdirectory(libos)
|
||||||
|
add_subdirectory(libui)
|
||||||
add_subdirectory(libc)
|
add_subdirectory(libc)
|
||||||
add_subdirectory(kernel)
|
add_subdirectory(kernel)
|
||||||
add_subdirectory(apps)
|
add_subdirectory(apps)
|
||||||
add_subdirectory(tests)
|
add_subdirectory(tests)
|
||||||
add_subdirectory(shell)
|
add_subdirectory(shell)
|
||||||
|
add_subdirectory(wind)
|
||||||
|
@ -47,3 +47,4 @@ luna_app(socket-client.cpp socket-client)
|
|||||||
luna_app(input.cpp input)
|
luna_app(input.cpp input)
|
||||||
luna_app(shmem-test.cpp shmem-test)
|
luna_app(shmem-test.cpp shmem-test)
|
||||||
luna_app(touch.cpp touch)
|
luna_app(touch.cpp touch)
|
||||||
|
luna_app(gclient.cpp gclient)
|
||||||
|
20
apps/gclient.cpp
Normal file
20
apps/gclient.cpp
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#include <os/ArgumentParser.h>
|
||||||
|
#include <os/LocalClient.h>
|
||||||
|
|
||||||
|
Result<int> luna_main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
StringView socket_path = "/tmp/wind.sock";
|
||||||
|
|
||||||
|
os::ArgumentParser parser;
|
||||||
|
parser.add_description("A graphical user interface client."_sv);
|
||||||
|
parser.add_system_program_info("gclient"_sv);
|
||||||
|
parser.add_value_argument(socket_path, 's', "socket"_sv, "the path for the local IPC socket"_sv);
|
||||||
|
parser.parse(argc, argv);
|
||||||
|
|
||||||
|
auto client = TRY(os::LocalClient::connect(socket_path, false));
|
||||||
|
|
||||||
|
StringView message = "hello";
|
||||||
|
TRY(client->send((const u8*)message.chars(), message.length()));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
105
apps/init.cpp
105
apps/init.cpp
@ -4,9 +4,12 @@
|
|||||||
#include <luna/Sort.h>
|
#include <luna/Sort.h>
|
||||||
#include <luna/String.h>
|
#include <luna/String.h>
|
||||||
#include <luna/Vector.h>
|
#include <luna/Vector.h>
|
||||||
|
#include <os/ArgumentParser.h>
|
||||||
#include <os/Directory.h>
|
#include <os/Directory.h>
|
||||||
#include <os/File.h>
|
#include <os/File.h>
|
||||||
#include <os/Process.h>
|
#include <os/Process.h>
|
||||||
|
#include <os/Security.h>
|
||||||
|
#include <pwd.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -17,6 +20,8 @@
|
|||||||
#include <sys/sysmacros.h>
|
#include <sys/sysmacros.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
static bool g_is_system = false;
|
||||||
|
|
||||||
FILE* g_init_log = nullptr;
|
FILE* g_init_log = nullptr;
|
||||||
|
|
||||||
// Request a successful exit from the system (for tests)
|
// Request a successful exit from the system (for tests)
|
||||||
@ -40,6 +45,8 @@ struct Service
|
|||||||
String standard_output;
|
String standard_output;
|
||||||
String standard_error;
|
String standard_error;
|
||||||
String standard_input;
|
String standard_input;
|
||||||
|
Option<uid_t> user {};
|
||||||
|
Option<gid_t> group {};
|
||||||
bool wait { false };
|
bool wait { false };
|
||||||
Option<pid_t> pid {};
|
Option<pid_t> pid {};
|
||||||
};
|
};
|
||||||
@ -65,6 +72,12 @@ static Result<void> service_child(const Service& service, SharedPtr<os::File> ou
|
|||||||
if (error) dup2(error->fd(), STDERR_FILENO);
|
if (error) dup2(error->fd(), STDERR_FILENO);
|
||||||
if (input) dup2(input->fd(), STDIN_FILENO);
|
if (input) dup2(input->fd(), STDIN_FILENO);
|
||||||
|
|
||||||
|
if (service.user.has_value())
|
||||||
|
{
|
||||||
|
setgid(service.group.value());
|
||||||
|
setuid(service.user.value());
|
||||||
|
}
|
||||||
|
|
||||||
if (service.environment.is_empty()) { TRY(os::Process::exec(args[0].view(), args.slice(), false)); }
|
if (service.environment.is_empty()) { TRY(os::Process::exec(args[0].view(), args.slice(), false)); }
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -214,6 +227,15 @@ static Result<void> load_service(const os::Path& path)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (g_is_system && parts[0].view() == "User")
|
||||||
|
{
|
||||||
|
auto* pw = getpwnam(parts[1].chars());
|
||||||
|
if (!pw) continue;
|
||||||
|
service.user = pw->pw_uid;
|
||||||
|
service.group = pw->pw_gid;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (parts[0].view() == "Wait")
|
if (parts[0].view() == "Wait")
|
||||||
{
|
{
|
||||||
if (parts[1].view() == "true" || parts[1].view().to_uint().value_or(0) == 1)
|
if (parts[1].view() == "true" || parts[1].view().to_uint().value_or(0) == 1)
|
||||||
@ -247,9 +269,9 @@ static Result<void> load_service(const os::Path& path)
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
static Result<void> load_services()
|
static Result<void> load_services(StringView path)
|
||||||
{
|
{
|
||||||
auto dir = TRY(os::Directory::open("/etc/init"));
|
auto dir = TRY(os::Directory::open(path));
|
||||||
|
|
||||||
auto services = TRY(dir->list_names(os::Directory::Filter::ParentAndBase));
|
auto services = TRY(dir->list_names(os::Directory::Filter::ParentAndBase));
|
||||||
sort(services.begin(), services.end(), String::compare);
|
sort(services.begin(), services.end(), String::compare);
|
||||||
@ -259,9 +281,9 @@ static Result<void> load_services()
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
static Result<void> start_services()
|
static Result<void> start_services(StringView path)
|
||||||
{
|
{
|
||||||
TRY(load_services());
|
TRY(load_services(path));
|
||||||
for (auto& service : g_services)
|
for (auto& service : g_services)
|
||||||
{
|
{
|
||||||
do_log("[init] starting service %s\n", service.name.chars());
|
do_log("[init] starting service %s\n", service.name.chars());
|
||||||
@ -301,7 +323,7 @@ static void mount_shmfs()
|
|||||||
if (chmod("/dev/shm", 01777) < 0) exit(255);
|
if (chmod("/dev/shm", 01777) < 0) exit(255);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main()
|
Result<int> sysinit()
|
||||||
{
|
{
|
||||||
if (getpid() != 1)
|
if (getpid() != 1)
|
||||||
{
|
{
|
||||||
@ -309,12 +331,16 @@ int main()
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_is_system = true;
|
||||||
|
|
||||||
// Before this point, we don't even have an stdin, stdout and stderr. Set it up now so that child processes (and us)
|
// Before this point, we don't even have an stdin, stdout and stderr. Set it up now so that child processes (and us)
|
||||||
// can print stuff.
|
// can print stuff.
|
||||||
stdin = fopen("/dev/console", "r");
|
stdin = fopen("/dev/console", "r");
|
||||||
stdout = fopen("/dev/console", "w");
|
stdout = fopen("/dev/console", "w");
|
||||||
stderr = fopen("/dev/console", "w");
|
stderr = fopen("/dev/console", "w");
|
||||||
|
|
||||||
|
TRY(os::Security::pledge("stdio rpath wpath cpath fattr host mount proc exec signal", nullptr));
|
||||||
|
|
||||||
mount_tmpfs();
|
mount_tmpfs();
|
||||||
mount_shmfs();
|
mount_shmfs();
|
||||||
|
|
||||||
@ -330,7 +356,11 @@ int main()
|
|||||||
if (signal(SIGTERM, sigterm_handler) == SIG_ERR) do_log("[init] failed to register handler for SIGTERM\n");
|
if (signal(SIGTERM, sigterm_handler) == SIG_ERR) do_log("[init] failed to register handler for SIGTERM\n");
|
||||||
if (signal(SIGQUIT, sigquit_handler) == SIG_ERR) do_log("[init] failed to register handler for SIGQUIT\n");
|
if (signal(SIGQUIT, sigquit_handler) == SIG_ERR) do_log("[init] failed to register handler for SIGQUIT\n");
|
||||||
|
|
||||||
start_services();
|
TRY(os::Security::pledge("stdio rpath wpath cpath proc exec", nullptr));
|
||||||
|
|
||||||
|
start_services("/etc/init");
|
||||||
|
|
||||||
|
TRY(os::Security::pledge("stdio rpath wpath proc exec", nullptr));
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
@ -365,3 +395,66 @@ int main()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result<int> user_init()
|
||||||
|
{
|
||||||
|
setpgid(0, 0);
|
||||||
|
|
||||||
|
g_init_log = fopen("/dev/uart0", "w");
|
||||||
|
check(g_init_log);
|
||||||
|
setlinebuf(g_init_log);
|
||||||
|
fcntl(fileno(g_init_log), F_SETFD, FD_CLOEXEC);
|
||||||
|
|
||||||
|
TRY(os::Security::pledge("stdio rpath wpath cpath proc exec", nullptr));
|
||||||
|
|
||||||
|
start_services("/etc/user");
|
||||||
|
|
||||||
|
TRY(os::Security::pledge("stdio rpath wpath proc exec", nullptr));
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
int status;
|
||||||
|
auto rc = os::Process::wait(os::Process::ANY_CHILD, &status);
|
||||||
|
if (rc.has_error()) continue;
|
||||||
|
|
||||||
|
pid_t child = rc.release_value();
|
||||||
|
|
||||||
|
for (auto& service : g_services)
|
||||||
|
{
|
||||||
|
if (service.pid.has_value() && service.pid.value() == child)
|
||||||
|
{
|
||||||
|
if (WIFEXITED(status))
|
||||||
|
{
|
||||||
|
do_log("[init] service %s exited with status %d\n", service.name.chars(), WEXITSTATUS(status));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
do_log("[init] service %s was terminated by signal %d\n", service.name.chars(), WTERMSIG(status));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (service.restart)
|
||||||
|
{
|
||||||
|
do_log("[init] restarting service %s\n", service.name.chars());
|
||||||
|
|
||||||
|
start_service(service);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<int> luna_main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
bool user;
|
||||||
|
|
||||||
|
os::ArgumentParser parser;
|
||||||
|
parser.add_description("The init system for Luna.");
|
||||||
|
parser.add_system_program_info("init"_sv);
|
||||||
|
parser.add_switch_argument(user, 'u', "user"_sv, "initialize a user session instead of the system");
|
||||||
|
parser.parse(argc, argv);
|
||||||
|
|
||||||
|
if (user) return user_init();
|
||||||
|
return sysinit();
|
||||||
|
}
|
||||||
|
@ -6,6 +6,8 @@
|
|||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
|
pledge("stdio rpath wpath cpath proc", nullptr);
|
||||||
|
|
||||||
int fd = shm_open("/shared", O_CREAT | O_RDWR, 0666);
|
int fd = shm_open("/shared", O_CREAT | O_RDWR, 0666);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
{
|
{
|
||||||
|
@ -1,4 +0,0 @@
|
|||||||
Name=motd
|
|
||||||
Description=Show the message of the day to the user.
|
|
||||||
Command=/usr/bin/cat /etc/motd
|
|
||||||
Wait=true
|
|
@ -1,6 +0,0 @@
|
|||||||
Name=listen
|
|
||||||
Description=Start a Unix domain socket test server.
|
|
||||||
Command=/usr/bin/socket-test
|
|
||||||
StandardOutput=/dev/uart0
|
|
||||||
StandardError=/dev/uart0
|
|
||||||
Restart=true
|
|
@ -1,4 +1,6 @@
|
|||||||
Name=login
|
Name=login
|
||||||
Description=Start the command-line login program.
|
Description=Start the display server.
|
||||||
Command=/usr/bin/login
|
Command=/usr/bin/wind --user=selene
|
||||||
|
StandardOutput=/dev/uart0
|
||||||
|
StandardError=/dev/uart0
|
||||||
Restart=true
|
Restart=true
|
||||||
|
BIN
base/usr/share/cursors/default.tga
Normal file
BIN
base/usr/share/cursors/default.tga
Normal file
Binary file not shown.
After Width: | Height: | Size: 1004 B |
BIN
base/usr/share/fonts/Tamsyn-Bold.psf
Normal file
BIN
base/usr/share/fonts/Tamsyn-Bold.psf
Normal file
Binary file not shown.
BIN
base/usr/share/fonts/Tamsyn-Regular.psf
Normal file
BIN
base/usr/share/fonts/Tamsyn-Regular.psf
Normal file
Binary file not shown.
BIN
base/usr/share/icons/16x16/app-close.tga
Normal file
BIN
base/usr/share/icons/16x16/app-close.tga
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.0 KiB |
@ -6,6 +6,7 @@ set(SOURCES
|
|||||||
${HEADERS}
|
${HEADERS}
|
||||||
src/main.cpp
|
src/main.cpp
|
||||||
src/Log.cpp
|
src/Log.cpp
|
||||||
|
src/Pledge.cpp
|
||||||
src/cxxabi.cpp
|
src/cxxabi.cpp
|
||||||
src/video/Framebuffer.cpp
|
src/video/Framebuffer.cpp
|
||||||
src/video/TextConsole.cpp
|
src/video/TextConsole.cpp
|
||||||
@ -44,6 +45,8 @@ set(SOURCES
|
|||||||
src/sys/signal.cpp
|
src/sys/signal.cpp
|
||||||
src/sys/socket.cpp
|
src/sys/socket.cpp
|
||||||
src/sys/poll.cpp
|
src/sys/poll.cpp
|
||||||
|
src/sys/alarm.cpp
|
||||||
|
src/sys/pledge.cpp
|
||||||
src/fs/VFS.cpp
|
src/fs/VFS.cpp
|
||||||
src/fs/Pipe.cpp
|
src/fs/Pipe.cpp
|
||||||
src/fs/Mount.cpp
|
src/fs/Mount.cpp
|
||||||
|
@ -27,8 +27,8 @@ static void log_serial(LogLevel level, const char* format, va_list origin)
|
|||||||
va_list ap;
|
va_list ap;
|
||||||
va_copy(ap, origin);
|
va_copy(ap, origin);
|
||||||
|
|
||||||
const SafeScopeLock lock { g_serial_lock };
|
/*const SafeScopeLock lock { g_serial_lock };
|
||||||
if (!lock.did_succeed()) return;
|
if (!lock.did_succeed()) return;*/
|
||||||
|
|
||||||
Serial::printf("\x1b[%sm"
|
Serial::printf("\x1b[%sm"
|
||||||
"%c"
|
"%c"
|
||||||
@ -61,7 +61,7 @@ static void log_text_console(LogLevel level, const char* format, va_list origin)
|
|||||||
va_list ap;
|
va_list ap;
|
||||||
va_copy(ap, origin);
|
va_copy(ap, origin);
|
||||||
|
|
||||||
const ScopeLock lock { g_console_lock };
|
/*const ScopeLock lock { g_console_lock };*/
|
||||||
|
|
||||||
const u32 original_foreground = TextConsole::foreground();
|
const u32 original_foreground = TextConsole::foreground();
|
||||||
const u32 original_background = TextConsole::background();
|
const u32 original_background = TextConsole::background();
|
||||||
|
66
kernel/src/Pledge.cpp
Normal file
66
kernel/src/Pledge.cpp
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
#include "Pledge.h"
|
||||||
|
#include "Log.h"
|
||||||
|
#include "memory/MemoryManager.h"
|
||||||
|
|
||||||
|
static const char* promise_names[] = {
|
||||||
|
#define __enumerate(promise) #promise,
|
||||||
|
enumerate_promises(__enumerate)
|
||||||
|
#undef __enumerate
|
||||||
|
};
|
||||||
|
|
||||||
|
Result<void> check_pledge(Thread* thread, Promise promise)
|
||||||
|
{
|
||||||
|
// Thread has not called pledge().
|
||||||
|
if (thread->promises < 0) return {};
|
||||||
|
int mask = (1 << (int)promise);
|
||||||
|
if ((thread->promises & mask) != mask)
|
||||||
|
{
|
||||||
|
kerrorln("Pledge violation in thread %d! Has not pledged %s", thread->id, promise_names[(int)promise]);
|
||||||
|
if (thread->promises & (1 << (int)Promise::p_error)) return err(ENOSYS);
|
||||||
|
|
||||||
|
// Kill this thread with an uncatchable SIGABRT. For this, we reset the disposition of SIGABRT to the default
|
||||||
|
// (dump core). We could just kill the thread here and be done, but that discards anything on the current stack,
|
||||||
|
// which means that some destructors might not be called. Instead, leave the job to the next call of
|
||||||
|
// Thread::process_pending_signals().
|
||||||
|
thread->signal_handlers[SIGABRT - 1].sa_handler = SIG_DFL;
|
||||||
|
|
||||||
|
// If there are any other pending signals, they might be processed before SIGABRT. Avoid that by resetting the
|
||||||
|
// thread's pending signals.
|
||||||
|
thread->pending_signals = 0;
|
||||||
|
|
||||||
|
thread->send_signal(SIGABRT);
|
||||||
|
|
||||||
|
// This should never arrive to userspace.
|
||||||
|
return err(ENOSYS);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<int> parse_promises(u64 pledge)
|
||||||
|
{
|
||||||
|
if (!pledge) return -1;
|
||||||
|
|
||||||
|
auto text = TRY(MemoryManager::strdup_from_user(pledge));
|
||||||
|
if (text.is_empty()) return 0;
|
||||||
|
|
||||||
|
auto promises = TRY(text.split(" "));
|
||||||
|
|
||||||
|
int result = 0;
|
||||||
|
for (const auto& promise : promises)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < (int)Promise::num_promises; i++)
|
||||||
|
{
|
||||||
|
if (promise.view() == promise_names[i])
|
||||||
|
{
|
||||||
|
result |= (1 << i);
|
||||||
|
goto found;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err(EINVAL);
|
||||||
|
found:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
19
kernel/src/Pledge.h
Normal file
19
kernel/src/Pledge.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "thread/Thread.h"
|
||||||
|
#include <luna/Result.h>
|
||||||
|
|
||||||
|
#define enumerate_promises(_p) \
|
||||||
|
_p(stdio) _p(rpath) _p(wpath) _p(cpath) _p(fattr) _p(chown) _p(unix) _p(tty) _p(proc) _p(exec) _p(prot_exec) \
|
||||||
|
_p(id) _p(mount) _p(signal) _p(host) _p(error)
|
||||||
|
|
||||||
|
enum class Promise
|
||||||
|
{
|
||||||
|
#define __enumerate(promise) p_##promise,
|
||||||
|
enumerate_promises(__enumerate)
|
||||||
|
#undef __enumerate
|
||||||
|
num_promises,
|
||||||
|
};
|
||||||
|
|
||||||
|
Result<void> check_pledge(Thread* thread, Promise promise);
|
||||||
|
|
||||||
|
Result<int> parse_promises(u64 pledge);
|
@ -43,8 +43,8 @@ static void process_mouse_event(u8 data)
|
|||||||
packet.buttons = 0;
|
packet.buttons = 0;
|
||||||
|
|
||||||
u8 flags = g_mouse_packet[0];
|
u8 flags = g_mouse_packet[0];
|
||||||
if (flags & PS2_MOUSE_X_SIGN) packet.xdelta = -packet.xdelta;
|
if (flags & PS2_MOUSE_X_SIGN) packet.xdelta = -(256 - packet.xdelta);
|
||||||
if (flags & PS2_MOUSE_Y_SIGN) packet.ydelta = -packet.ydelta;
|
if (flags & PS2_MOUSE_Y_SIGN) packet.ydelta = -(256 - packet.ydelta);
|
||||||
|
|
||||||
if (flags & PS2_MOUSE_MIDDLE_BTN) packet.buttons |= moon::MouseButton::Middle;
|
if (flags & PS2_MOUSE_MIDDLE_BTN) packet.buttons |= moon::MouseButton::Middle;
|
||||||
if (flags & PS2_MOUSE_RIGHT_BTN) packet.buttons |= moon::MouseButton::Right;
|
if (flags & PS2_MOUSE_RIGHT_BTN) packet.buttons |= moon::MouseButton::Right;
|
||||||
|
@ -431,6 +431,18 @@ namespace ATA
|
|||||||
m_uses_dma = false;
|
m_uses_dma = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_drive_index == 0 && !(status & BMS_MasterInit))
|
||||||
|
{
|
||||||
|
kwarnln("ata: Drive %d does not have DMA support", m_drive_index);
|
||||||
|
m_uses_dma = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_drive_index == 1 && !(status & BMS_SlaveInit))
|
||||||
|
{
|
||||||
|
kwarnln("ata: Drive %d does not have DMA support", m_drive_index);
|
||||||
|
m_uses_dma = false;
|
||||||
|
}
|
||||||
|
|
||||||
auto frame = MemoryManager::alloc_frame();
|
auto frame = MemoryManager::alloc_frame();
|
||||||
if (frame.has_error() || frame.value() > 0xffffffff)
|
if (frame.has_error() || frame.value() > 0xffffffff)
|
||||||
{
|
{
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include "fs/devices/ConsoleDevice.h"
|
#include "fs/devices/ConsoleDevice.h"
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
|
#include "Pledge.h"
|
||||||
#include "fs/devices/DeviceRegistry.h"
|
#include "fs/devices/DeviceRegistry.h"
|
||||||
#include "fs/devices/KeyboardDevice.h"
|
#include "fs/devices/KeyboardDevice.h"
|
||||||
#include "memory/MemoryManager.h"
|
#include "memory/MemoryManager.h"
|
||||||
@ -199,6 +200,9 @@ void ConsoleDevice::process_key_event(u8 scancode)
|
|||||||
|
|
||||||
Result<u64> ConsoleDevice::ioctl(int request, void* arg)
|
Result<u64> ConsoleDevice::ioctl(int request, void* arg)
|
||||||
{
|
{
|
||||||
|
auto* current = Scheduler::current();
|
||||||
|
TRY(check_pledge(current, Promise::p_tty));
|
||||||
|
|
||||||
switch (request)
|
switch (request)
|
||||||
{
|
{
|
||||||
case TCGETS: {
|
case TCGETS: {
|
||||||
|
@ -65,6 +65,10 @@ class Socket : public VFS::FileInode
|
|||||||
m_metadata.nlinks--;
|
m_metadata.nlinks--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual bool can_accept_connections() const = 0;
|
||||||
|
|
||||||
|
virtual bool can_read_data() const = 0;
|
||||||
|
|
||||||
virtual ~Socket() = default;
|
virtual ~Socket() = default;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -17,6 +17,16 @@ class UnixSocket : public Socket
|
|||||||
return (m_state == Connected || m_state == Reset) && !m_data.size();
|
return (m_state == Connected || m_state == Reset) && !m_data.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool can_read_data() const override
|
||||||
|
{
|
||||||
|
return (m_state == Connected || m_state == Reset) && m_data.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool can_accept_connections() const override
|
||||||
|
{
|
||||||
|
return !m_listen_queue.is_empty();
|
||||||
|
}
|
||||||
|
|
||||||
Result<usize> send(const u8*, usize, int) override;
|
Result<usize> send(const u8*, usize, int) override;
|
||||||
Result<usize> recv(u8*, usize, int) const override;
|
Result<usize> recv(u8*, usize, int) const override;
|
||||||
|
|
||||||
|
18
kernel/src/sys/alarm.cpp
Normal file
18
kernel/src/sys/alarm.cpp
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#include "Pledge.h"
|
||||||
|
#include "sys/Syscall.h"
|
||||||
|
#include "thread/Scheduler.h"
|
||||||
|
|
||||||
|
Result<u64> sys_alarm(Registers*, SyscallArgs args)
|
||||||
|
{
|
||||||
|
unsigned int seconds = (unsigned int)args[0];
|
||||||
|
|
||||||
|
auto* current = Scheduler::current();
|
||||||
|
|
||||||
|
TRY(check_pledge(current, Promise::p_stdio));
|
||||||
|
|
||||||
|
u64 time_left = current->alarm_ticks_left;
|
||||||
|
|
||||||
|
current->alarm_ticks_left = seconds * 1000;
|
||||||
|
|
||||||
|
return time_left * 1000;
|
||||||
|
}
|
@ -1,3 +1,4 @@
|
|||||||
|
#include "Pledge.h"
|
||||||
#include "memory/MemoryManager.h"
|
#include "memory/MemoryManager.h"
|
||||||
#include "sys/Syscall.h"
|
#include "sys/Syscall.h"
|
||||||
#include "thread/Scheduler.h"
|
#include "thread/Scheduler.h"
|
||||||
@ -9,6 +10,8 @@ Result<u64> sys_chdir(Registers*, SyscallArgs args)
|
|||||||
|
|
||||||
Thread* current = Scheduler::current();
|
Thread* current = Scheduler::current();
|
||||||
|
|
||||||
|
TRY(check_pledge(current, Promise::p_rpath));
|
||||||
|
|
||||||
if (PathParser::is_absolute(path.view()))
|
if (PathParser::is_absolute(path.view()))
|
||||||
{
|
{
|
||||||
SharedPtr<VFS::Inode> inode = TRY(VFS::resolve_path(path.chars(), current->auth));
|
SharedPtr<VFS::Inode> inode = TRY(VFS::resolve_path(path.chars(), current->auth));
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
|
#include "Pledge.h"
|
||||||
#include "arch/Timer.h"
|
#include "arch/Timer.h"
|
||||||
#include "memory/MemoryManager.h"
|
#include "memory/MemoryManager.h"
|
||||||
#include "sys/Syscall.h"
|
#include "sys/Syscall.h"
|
||||||
|
#include "thread/Scheduler.h"
|
||||||
#include <bits/clockid.h>
|
#include <bits/clockid.h>
|
||||||
#include <bits/timespec.h>
|
#include <bits/timespec.h>
|
||||||
|
|
||||||
@ -9,6 +11,10 @@ Result<u64> sys_clock_gettime(Registers*, SyscallArgs args)
|
|||||||
clockid_t id = (clockid_t)args[0];
|
clockid_t id = (clockid_t)args[0];
|
||||||
struct timespec* ts = (struct timespec*)args[1];
|
struct timespec* ts = (struct timespec*)args[1];
|
||||||
|
|
||||||
|
auto* current = Scheduler::current();
|
||||||
|
|
||||||
|
TRY(check_pledge(current, Promise::p_stdio));
|
||||||
|
|
||||||
switch (id)
|
switch (id)
|
||||||
{
|
{
|
||||||
case CLOCK_MONOTONIC: {
|
case CLOCK_MONOTONIC: {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
|
#include "Pledge.h"
|
||||||
#include "binfmt/BinaryFormat.h"
|
#include "binfmt/BinaryFormat.h"
|
||||||
#include "fs/VFS.h"
|
#include "fs/VFS.h"
|
||||||
#include "memory/MemoryManager.h"
|
#include "memory/MemoryManager.h"
|
||||||
@ -63,6 +64,8 @@ Result<u64> sys_execve(Registers* regs, SyscallArgs args)
|
|||||||
|
|
||||||
auto current = Scheduler::current();
|
auto current = Scheduler::current();
|
||||||
|
|
||||||
|
TRY(check_pledge(current, Promise::p_exec));
|
||||||
|
|
||||||
auto inode = TRY(VFS::resolve_path(path.chars(), current->auth, current->current_directory));
|
auto inode = TRY(VFS::resolve_path(path.chars(), current->auth, current->current_directory));
|
||||||
|
|
||||||
if (!VFS::can_execute(inode, current->auth)) return err(EACCES);
|
if (!VFS::can_execute(inode, current->auth)) return err(EACCES);
|
||||||
@ -71,6 +74,11 @@ Result<u64> sys_execve(Registers* regs, SyscallArgs args)
|
|||||||
kdbgln("exec: attempting to replace current image with %s", path.chars());
|
kdbgln("exec: attempting to replace current image with %s", path.chars());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
bool is_setuid = VFS::is_setuid(inode);
|
||||||
|
bool is_setgid = VFS::is_setgid(inode);
|
||||||
|
bool is_secure_environment = is_setgid || is_setuid;
|
||||||
|
if (is_secure_environment && current->execpromises >= 0) return err(EACCES);
|
||||||
|
|
||||||
auto loader = TRY(BinaryFormat::create_loader(inode));
|
auto loader = TRY(BinaryFormat::create_loader(inode));
|
||||||
|
|
||||||
#ifdef EXEC_DEBUG
|
#ifdef EXEC_DEBUG
|
||||||
@ -104,8 +112,8 @@ Result<u64> sys_execve(Registers* regs, SyscallArgs args)
|
|||||||
if (descriptor->flags & O_CLOEXEC) { descriptor = {}; }
|
if (descriptor->flags & O_CLOEXEC) { descriptor = {}; }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (VFS::is_setuid(inode)) current->auth.euid = current->auth.suid = inode->metadata().uid;
|
if (is_setuid) current->auth.euid = current->auth.suid = inode->metadata().uid;
|
||||||
if (VFS::is_setgid(inode)) current->auth.egid = current->auth.sgid = inode->metadata().gid;
|
if (is_setgid) current->auth.egid = current->auth.sgid = inode->metadata().gid;
|
||||||
|
|
||||||
current->name = path.chars();
|
current->name = path.chars();
|
||||||
|
|
||||||
@ -115,6 +123,9 @@ Result<u64> sys_execve(Registers* regs, SyscallArgs args)
|
|||||||
|
|
||||||
current->set_arguments(user_argc, user_argv, user_envc, user_envp);
|
current->set_arguments(user_argc, user_argv, user_envc, user_envp);
|
||||||
|
|
||||||
|
current->promises = current->execpromises;
|
||||||
|
current->execpromises = -1;
|
||||||
|
|
||||||
memcpy(regs, ¤t->regs, sizeof(*regs));
|
memcpy(regs, ¤t->regs, sizeof(*regs));
|
||||||
|
|
||||||
for (int i = 0; i < NSIG; i++)
|
for (int i = 0; i < NSIG; i++)
|
||||||
@ -133,6 +144,8 @@ Result<u64> sys_fork(Registers* regs, SyscallArgs)
|
|||||||
{
|
{
|
||||||
auto current = Scheduler::current();
|
auto current = Scheduler::current();
|
||||||
|
|
||||||
|
TRY(check_pledge(current, Promise::p_proc));
|
||||||
|
|
||||||
auto guard = make_scope_guard([current] { MMU::switch_page_directory(current->self_directory()); });
|
auto guard = make_scope_guard([current] { MMU::switch_page_directory(current->self_directory()); });
|
||||||
|
|
||||||
memcpy(¤t->regs, regs, sizeof(*regs));
|
memcpy(¤t->regs, regs, sizeof(*regs));
|
||||||
@ -152,6 +165,8 @@ Result<u64> sys_fork(Registers* regs, SyscallArgs)
|
|||||||
thread->current_directory_path = move(current_directory_path);
|
thread->current_directory_path = move(current_directory_path);
|
||||||
thread->umask = current->umask;
|
thread->umask = current->umask;
|
||||||
thread->parent = current;
|
thread->parent = current;
|
||||||
|
thread->promises = current->promises;
|
||||||
|
thread->execpromises = current->execpromises;
|
||||||
|
|
||||||
for (int i = 0; i < FD_MAX; i++) { thread->fd_table[i] = current->fd_table[i]; }
|
for (int i = 0; i < FD_MAX; i++) { thread->fd_table[i] = current->fd_table[i]; }
|
||||||
|
|
||||||
@ -159,11 +174,7 @@ Result<u64> sys_fork(Registers* regs, SyscallArgs)
|
|||||||
|
|
||||||
memcpy(&thread->regs, regs, sizeof(*regs));
|
memcpy(&thread->regs, regs, sizeof(*regs));
|
||||||
|
|
||||||
for (int i = 0; i < NSIG; i++)
|
for (int i = 0; i < NSIG; i++) thread->signal_handlers[i] = current->signal_handlers[i];
|
||||||
{
|
|
||||||
auto sighandler = current->signal_handlers[i].sa_handler;
|
|
||||||
thread->signal_handlers[i] = { .sa_handler = sighandler, .sa_mask = 0, .sa_flags = 0 };
|
|
||||||
}
|
|
||||||
thread->signal_mask = current->signal_mask;
|
thread->signal_mask = current->signal_mask;
|
||||||
|
|
||||||
thread->set_return(0);
|
thread->set_return(0);
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
|
#include "Pledge.h"
|
||||||
#include "fs/Pipe.h"
|
#include "fs/Pipe.h"
|
||||||
#include "fs/VFS.h"
|
#include "fs/VFS.h"
|
||||||
#include "memory/MemoryManager.h"
|
#include "memory/MemoryManager.h"
|
||||||
@ -24,6 +25,8 @@ Result<u64> sys_read(Registers* regs, SyscallArgs args)
|
|||||||
|
|
||||||
Thread* current = Scheduler::current();
|
Thread* current = Scheduler::current();
|
||||||
|
|
||||||
|
TRY(check_pledge(current, Promise::p_stdio));
|
||||||
|
|
||||||
auto& descriptor = *TRY(current->resolve_fd(fd));
|
auto& descriptor = *TRY(current->resolve_fd(fd));
|
||||||
|
|
||||||
if (!descriptor.is_readable()) return err(EBADF);
|
if (!descriptor.is_readable()) return err(EBADF);
|
||||||
@ -65,6 +68,8 @@ Result<u64> sys_write(Registers*, SyscallArgs args)
|
|||||||
|
|
||||||
Thread* current = Scheduler::current();
|
Thread* current = Scheduler::current();
|
||||||
|
|
||||||
|
TRY(check_pledge(current, Promise::p_stdio));
|
||||||
|
|
||||||
auto& descriptor = *TRY(current->resolve_fd(fd));
|
auto& descriptor = *TRY(current->resolve_fd(fd));
|
||||||
|
|
||||||
if (!descriptor.is_writable()) return err(EBADF);
|
if (!descriptor.is_writable()) return err(EBADF);
|
||||||
@ -87,6 +92,8 @@ Result<u64> sys_lseek(Registers*, SyscallArgs args)
|
|||||||
|
|
||||||
Thread* current = Scheduler::current();
|
Thread* current = Scheduler::current();
|
||||||
|
|
||||||
|
TRY(check_pledge(current, Promise::p_stdio));
|
||||||
|
|
||||||
auto& descriptor = *TRY(current->resolve_fd(fd));
|
auto& descriptor = *TRY(current->resolve_fd(fd));
|
||||||
|
|
||||||
if (descriptor.inode()->type() == VFS::InodeType::FIFO) return err(ESPIPE);
|
if (descriptor.inode()->type() == VFS::InodeType::FIFO) return err(ESPIPE);
|
||||||
@ -117,6 +124,8 @@ Result<u64> sys_fcntl(Registers*, SyscallArgs args)
|
|||||||
|
|
||||||
Thread* current = Scheduler::current();
|
Thread* current = Scheduler::current();
|
||||||
|
|
||||||
|
TRY(check_pledge(current, Promise::p_stdio));
|
||||||
|
|
||||||
auto& descriptor = *TRY(current->resolve_fd(fd));
|
auto& descriptor = *TRY(current->resolve_fd(fd));
|
||||||
|
|
||||||
bool is_cloexec = true;
|
bool is_cloexec = true;
|
||||||
@ -176,6 +185,7 @@ Result<u64> sys_isatty(Registers*, SyscallArgs args)
|
|||||||
int fd = (int)args[0];
|
int fd = (int)args[0];
|
||||||
|
|
||||||
Thread* current = Scheduler::current();
|
Thread* current = Scheduler::current();
|
||||||
|
TRY(check_pledge(current, Promise::p_stdio));
|
||||||
auto& descriptor = *TRY(current->resolve_fd(fd));
|
auto& descriptor = *TRY(current->resolve_fd(fd));
|
||||||
|
|
||||||
return descriptor.inode()->isatty();
|
return descriptor.inode()->isatty();
|
||||||
@ -188,6 +198,8 @@ Result<u64> sys_dup2(Registers*, SyscallArgs args)
|
|||||||
|
|
||||||
Thread* current = Scheduler::current();
|
Thread* current = Scheduler::current();
|
||||||
|
|
||||||
|
TRY(check_pledge(current, Promise::p_stdio));
|
||||||
|
|
||||||
if (newfd < 0 || newfd >= FD_MAX) return err(EBADF);
|
if (newfd < 0 || newfd >= FD_MAX) return err(EBADF);
|
||||||
|
|
||||||
auto descriptor = *TRY(current->resolve_fd(oldfd));
|
auto descriptor = *TRY(current->resolve_fd(oldfd));
|
||||||
@ -206,6 +218,8 @@ Result<u64> sys_pipe(Registers*, SyscallArgs args)
|
|||||||
|
|
||||||
Thread* current = Scheduler::current();
|
Thread* current = Scheduler::current();
|
||||||
|
|
||||||
|
TRY(check_pledge(current, Promise::p_stdio));
|
||||||
|
|
||||||
int rfd = TRY(current->allocate_fd(0));
|
int rfd = TRY(current->allocate_fd(0));
|
||||||
int wfd = TRY(current->allocate_fd(rfd + 1));
|
int wfd = TRY(current->allocate_fd(rfd + 1));
|
||||||
|
|
||||||
@ -229,6 +243,8 @@ Result<u64> sys_umask(Registers*, SyscallArgs args)
|
|||||||
|
|
||||||
auto* current = Scheduler::current();
|
auto* current = Scheduler::current();
|
||||||
|
|
||||||
|
TRY(check_pledge(current, Promise::p_stdio));
|
||||||
|
|
||||||
mode_t old_umask = current->umask;
|
mode_t old_umask = current->umask;
|
||||||
|
|
||||||
current->umask = new_umask & 0777;
|
current->umask = new_umask & 0777;
|
||||||
@ -242,6 +258,7 @@ Result<u64> sys_truncate(Registers*, SyscallArgs args)
|
|||||||
size_t length = (size_t)args[1];
|
size_t length = (size_t)args[1];
|
||||||
|
|
||||||
auto* current = Scheduler::current();
|
auto* current = Scheduler::current();
|
||||||
|
TRY(check_pledge(current, Promise::p_wpath));
|
||||||
auto inode = TRY(VFS::resolve_path(path.chars(), current->auth, current->current_directory));
|
auto inode = TRY(VFS::resolve_path(path.chars(), current->auth, current->current_directory));
|
||||||
|
|
||||||
if (!VFS::can_write(inode, current->auth)) return err(EACCES);
|
if (!VFS::can_write(inode, current->auth)) return err(EACCES);
|
||||||
@ -257,6 +274,7 @@ Result<u64> sys_ftruncate(Registers*, SyscallArgs args)
|
|||||||
size_t length = (size_t)args[1];
|
size_t length = (size_t)args[1];
|
||||||
|
|
||||||
auto* current = Scheduler::current();
|
auto* current = Scheduler::current();
|
||||||
|
TRY(check_pledge(current, Promise::p_stdio));
|
||||||
auto description = TRY(current->resolve_fd(fd))->description;
|
auto description = TRY(current->resolve_fd(fd))->description;
|
||||||
if (!(description->flags & O_WRONLY)) return err(EBADF);
|
if (!(description->flags & O_WRONLY)) return err(EBADF);
|
||||||
|
|
||||||
@ -273,6 +291,7 @@ Result<u64> sys_utimensat(Registers*, SyscallArgs args)
|
|||||||
int flags = (int)args[3];
|
int flags = (int)args[3];
|
||||||
|
|
||||||
auto* current = Scheduler::current();
|
auto* current = Scheduler::current();
|
||||||
|
TRY(check_pledge(current, Promise::p_fattr));
|
||||||
auto inode = TRY(current->resolve_atfile(dirfd, path, flags & AT_EMPTY_PATH, !(flags & AT_SYMLINK_NOFOLLOW)));
|
auto inode = TRY(current->resolve_atfile(dirfd, path, flags & AT_EMPTY_PATH, !(flags & AT_SYMLINK_NOFOLLOW)));
|
||||||
|
|
||||||
struct timespec ktimes[2];
|
struct timespec ktimes[2];
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
#include "Pledge.h"
|
||||||
#include "fs/VFS.h"
|
#include "fs/VFS.h"
|
||||||
#include "memory/MemoryManager.h"
|
#include "memory/MemoryManager.h"
|
||||||
#include "sys/Syscall.h"
|
#include "sys/Syscall.h"
|
||||||
@ -11,6 +12,7 @@ Result<u64> sys_getdents(Registers*, SyscallArgs args)
|
|||||||
usize count = (usize)args[2];
|
usize count = (usize)args[2];
|
||||||
|
|
||||||
Thread* current = Scheduler::current();
|
Thread* current = Scheduler::current();
|
||||||
|
TRY(check_pledge(current, Promise::p_stdio));
|
||||||
|
|
||||||
auto& descriptor = *TRY(current->resolve_fd(fd));
|
auto& descriptor = *TRY(current->resolve_fd(fd));
|
||||||
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
#include "Pledge.h"
|
||||||
#include "memory/MemoryManager.h"
|
#include "memory/MemoryManager.h"
|
||||||
#include "sys/Syscall.h"
|
#include "sys/Syscall.h"
|
||||||
#include "thread/Scheduler.h"
|
#include "thread/Scheduler.h"
|
||||||
@ -5,41 +6,54 @@
|
|||||||
|
|
||||||
Result<u64> sys_getpid(Registers*, SyscallArgs)
|
Result<u64> sys_getpid(Registers*, SyscallArgs)
|
||||||
{
|
{
|
||||||
return Scheduler::current()->id;
|
auto* current = Scheduler::current();
|
||||||
|
TRY(check_pledge(current, Promise::p_stdio));
|
||||||
|
return current->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<u64> sys_getppid(Registers*, SyscallArgs)
|
Result<u64> sys_getppid(Registers*, SyscallArgs)
|
||||||
{
|
{
|
||||||
auto* parent = Scheduler::current()->parent;
|
auto* current = Scheduler::current();
|
||||||
|
TRY(check_pledge(current, Promise::p_stdio));
|
||||||
|
auto* parent = current->parent;
|
||||||
return parent ? parent->id : 0;
|
return parent ? parent->id : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<u64> sys_getuid(Registers*, SyscallArgs)
|
Result<u64> sys_getuid(Registers*, SyscallArgs)
|
||||||
{
|
{
|
||||||
return Scheduler::current()->auth.uid;
|
auto* current = Scheduler::current();
|
||||||
|
TRY(check_pledge(current, Promise::p_stdio));
|
||||||
|
return current->auth.uid;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<u64> sys_geteuid(Registers*, SyscallArgs)
|
Result<u64> sys_geteuid(Registers*, SyscallArgs)
|
||||||
{
|
{
|
||||||
return Scheduler::current()->auth.euid;
|
auto* current = Scheduler::current();
|
||||||
|
TRY(check_pledge(current, Promise::p_stdio));
|
||||||
|
return current->auth.euid;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<u64> sys_getgid(Registers*, SyscallArgs)
|
Result<u64> sys_getgid(Registers*, SyscallArgs)
|
||||||
{
|
{
|
||||||
return Scheduler::current()->auth.gid;
|
auto* current = Scheduler::current();
|
||||||
|
TRY(check_pledge(current, Promise::p_stdio));
|
||||||
|
return current->auth.gid;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<u64> sys_getegid(Registers*, SyscallArgs)
|
Result<u64> sys_getegid(Registers*, SyscallArgs)
|
||||||
{
|
{
|
||||||
return Scheduler::current()->auth.egid;
|
auto* current = Scheduler::current();
|
||||||
|
TRY(check_pledge(current, Promise::p_stdio));
|
||||||
|
return current->auth.egid;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<u64> sys_setuid(Registers*, SyscallArgs args)
|
Result<u64> sys_setuid(Registers*, SyscallArgs args)
|
||||||
{
|
{
|
||||||
u32 uid = (u32)args[0];
|
u32 uid = (u32)args[0];
|
||||||
|
|
||||||
Credentials& auth = Scheduler::current()->auth;
|
auto* current = Scheduler::current();
|
||||||
|
TRY(check_pledge(current, Promise::p_id));
|
||||||
|
Credentials& auth = current->auth;
|
||||||
|
|
||||||
if (auth.euid == 0)
|
if (auth.euid == 0)
|
||||||
{
|
{
|
||||||
@ -57,7 +71,9 @@ Result<u64> sys_seteuid(Registers*, SyscallArgs args)
|
|||||||
{
|
{
|
||||||
u32 uid = (u32)args[0];
|
u32 uid = (u32)args[0];
|
||||||
|
|
||||||
Credentials& auth = Scheduler::current()->auth;
|
auto* current = Scheduler::current();
|
||||||
|
TRY(check_pledge(current, Promise::p_id));
|
||||||
|
Credentials& auth = current->auth;
|
||||||
|
|
||||||
if (auth.euid != 0 && uid != auth.uid && uid != auth.suid) return err(EPERM);
|
if (auth.euid != 0 && uid != auth.uid && uid != auth.suid) return err(EPERM);
|
||||||
auth.euid = uid;
|
auth.euid = uid;
|
||||||
@ -69,7 +85,9 @@ Result<u64> sys_setgid(Registers*, SyscallArgs args)
|
|||||||
{
|
{
|
||||||
u32 gid = (u32)args[0];
|
u32 gid = (u32)args[0];
|
||||||
|
|
||||||
Credentials& auth = Scheduler::current()->auth;
|
auto* current = Scheduler::current();
|
||||||
|
TRY(check_pledge(current, Promise::p_id));
|
||||||
|
Credentials& auth = current->auth;
|
||||||
|
|
||||||
if (auth.euid == 0)
|
if (auth.euid == 0)
|
||||||
{
|
{
|
||||||
@ -87,7 +105,9 @@ Result<u64> sys_setegid(Registers*, SyscallArgs args)
|
|||||||
{
|
{
|
||||||
u32 gid = (u32)args[0];
|
u32 gid = (u32)args[0];
|
||||||
|
|
||||||
Credentials& auth = Scheduler::current()->auth;
|
auto* current = Scheduler::current();
|
||||||
|
TRY(check_pledge(current, Promise::p_id));
|
||||||
|
Credentials& auth = current->auth;
|
||||||
|
|
||||||
if (auth.euid != 0 && gid != auth.gid && gid != auth.sgid) return err(EPERM);
|
if (auth.euid != 0 && gid != auth.gid && gid != auth.sgid) return err(EPERM);
|
||||||
auth.egid = gid;
|
auth.egid = gid;
|
||||||
@ -101,6 +121,7 @@ Result<u64> sys_setpgid(Registers*, SyscallArgs args)
|
|||||||
pid_t pgid = (pid_t)args[1];
|
pid_t pgid = (pid_t)args[1];
|
||||||
|
|
||||||
auto* current = Scheduler::current();
|
auto* current = Scheduler::current();
|
||||||
|
TRY(check_pledge(current, Promise::p_proc));
|
||||||
if (pid == 0) pid = current->id;
|
if (pid == 0) pid = current->id;
|
||||||
if (pgid == 0) pgid = current->id;
|
if (pgid == 0) pgid = current->id;
|
||||||
|
|
||||||
@ -133,6 +154,7 @@ Result<u64> sys_getpgid(Registers*, SyscallArgs args)
|
|||||||
pid_t pid = (pid_t)args[0];
|
pid_t pid = (pid_t)args[0];
|
||||||
|
|
||||||
auto* current = Scheduler::current();
|
auto* current = Scheduler::current();
|
||||||
|
TRY(check_pledge(current, Promise::p_stdio));
|
||||||
if (pid == 0) pid = current->id;
|
if (pid == 0) pid = current->id;
|
||||||
|
|
||||||
if (pid < 0) return err(EINVAL);
|
if (pid < 0) return err(EINVAL);
|
||||||
@ -150,6 +172,7 @@ Result<u64> sys_fchmodat(Registers*, SyscallArgs args)
|
|||||||
int flags = (int)args[3];
|
int flags = (int)args[3];
|
||||||
|
|
||||||
auto* current = Scheduler::current();
|
auto* current = Scheduler::current();
|
||||||
|
TRY(check_pledge(current, Promise::p_wpath));
|
||||||
|
|
||||||
auto inode = TRY(current->resolve_atfile(dirfd, path, flags & AT_EMPTY_PATH, !(flags & AT_SYMLINK_NOFOLLOW)));
|
auto inode = TRY(current->resolve_atfile(dirfd, path, flags & AT_EMPTY_PATH, !(flags & AT_SYMLINK_NOFOLLOW)));
|
||||||
|
|
||||||
@ -171,6 +194,7 @@ Result<u64> sys_fchownat(Registers*, SyscallArgs args)
|
|||||||
int flags = (int)args[4];
|
int flags = (int)args[4];
|
||||||
|
|
||||||
auto* current = Scheduler::current();
|
auto* current = Scheduler::current();
|
||||||
|
TRY(check_pledge(current, Promise::p_chown));
|
||||||
|
|
||||||
auto inode = TRY(current->resolve_atfile(dirfd, path, flags & AT_EMPTY_PATH, !(flags & AT_SYMLINK_NOFOLLOW)));
|
auto inode = TRY(current->resolve_atfile(dirfd, path, flags & AT_EMPTY_PATH, !(flags & AT_SYMLINK_NOFOLLOW)));
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
|
#include "Pledge.h"
|
||||||
#include "memory/MemoryManager.h"
|
#include "memory/MemoryManager.h"
|
||||||
#include "sys/Syscall.h"
|
#include "sys/Syscall.h"
|
||||||
#include "thread/Scheduler.h"
|
#include "thread/Scheduler.h"
|
||||||
@ -12,6 +13,7 @@ Result<u64> sys_unlinkat(Registers*, SyscallArgs args)
|
|||||||
int flags = (int)args[2];
|
int flags = (int)args[2];
|
||||||
|
|
||||||
Thread* current = Scheduler::current();
|
Thread* current = Scheduler::current();
|
||||||
|
TRY(check_pledge(current, Promise::p_cpath));
|
||||||
|
|
||||||
auto dirname = TRY(PathParser::dirname(path.view()));
|
auto dirname = TRY(PathParser::dirname(path.view()));
|
||||||
auto basename = TRY(PathParser::basename(path.view()));
|
auto basename = TRY(PathParser::basename(path.view()));
|
||||||
@ -44,6 +46,7 @@ Result<u64> sys_symlinkat(Registers*, SyscallArgs args)
|
|||||||
if (target.is_empty()) return err(ENOENT);
|
if (target.is_empty()) return err(ENOENT);
|
||||||
|
|
||||||
auto* current = Scheduler::current();
|
auto* current = Scheduler::current();
|
||||||
|
TRY(check_pledge(current, Promise::p_cpath));
|
||||||
|
|
||||||
auto parent = TRY(PathParser::dirname(linkpath.view()));
|
auto parent = TRY(PathParser::dirname(linkpath.view()));
|
||||||
|
|
||||||
@ -73,6 +76,7 @@ Result<u64> sys_readlinkat(Registers*, SyscallArgs args)
|
|||||||
usize bufsiz = (usize)args[3];
|
usize bufsiz = (usize)args[3];
|
||||||
|
|
||||||
auto* current = Scheduler::current();
|
auto* current = Scheduler::current();
|
||||||
|
TRY(check_pledge(current, Promise::p_rpath));
|
||||||
|
|
||||||
auto symlink = TRY(current->resolve_atfile(dirfd, path, true, false));
|
auto symlink = TRY(current->resolve_atfile(dirfd, path, true, false));
|
||||||
|
|
||||||
@ -98,6 +102,7 @@ Result<u64> sys_linkat(Registers*, SyscallArgs args)
|
|||||||
int flags = (int)args[4];
|
int flags = (int)args[4];
|
||||||
|
|
||||||
auto* current = Scheduler::current();
|
auto* current = Scheduler::current();
|
||||||
|
TRY(check_pledge(current, Promise::p_cpath));
|
||||||
|
|
||||||
auto parent = TRY(PathParser::dirname(newpath.view()));
|
auto parent = TRY(PathParser::dirname(newpath.view()));
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
|
#include "Pledge.h"
|
||||||
#include "fs/VFS.h"
|
#include "fs/VFS.h"
|
||||||
#include "memory/MemoryManager.h"
|
#include "memory/MemoryManager.h"
|
||||||
#include "sys/Syscall.h"
|
#include "sys/Syscall.h"
|
||||||
@ -10,6 +11,7 @@ Result<u64> sys_mkdir(Registers*, SyscallArgs args)
|
|||||||
mode_t mode = (mode_t)args[1];
|
mode_t mode = (mode_t)args[1];
|
||||||
|
|
||||||
Thread* current = Scheduler::current();
|
Thread* current = Scheduler::current();
|
||||||
|
TRY(check_pledge(current, Promise::p_cpath));
|
||||||
|
|
||||||
auto inode =
|
auto inode =
|
||||||
TRY(VFS::create_directory(path.chars(), mode & ~current->umask, current->auth, current->current_directory));
|
TRY(VFS::create_directory(path.chars(), mode & ~current->umask, current->auth, current->current_directory));
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
|
#include "Pledge.h"
|
||||||
#include "arch/MMU.h"
|
#include "arch/MMU.h"
|
||||||
#include "memory/MemoryManager.h"
|
#include "memory/MemoryManager.h"
|
||||||
#include "memory/SharedMemory.h"
|
#include "memory/SharedMemory.h"
|
||||||
@ -22,6 +23,8 @@ Result<u64> sys_mmap(Registers*, SyscallArgs args)
|
|||||||
if (params.flags < 0) return err(EINVAL);
|
if (params.flags < 0) return err(EINVAL);
|
||||||
|
|
||||||
Thread* current = Scheduler::current();
|
Thread* current = Scheduler::current();
|
||||||
|
if (params.prot & PROT_EXEC) TRY(check_pledge(current, Promise::p_prot_exec));
|
||||||
|
TRY(check_pledge(current, Promise::p_stdio));
|
||||||
|
|
||||||
SharedPtr<OpenFileDescription> description;
|
SharedPtr<OpenFileDescription> description;
|
||||||
if ((params.flags & MAP_ANONYMOUS) != MAP_ANONYMOUS)
|
if ((params.flags & MAP_ANONYMOUS) != MAP_ANONYMOUS)
|
||||||
@ -94,6 +97,7 @@ Result<u64> sys_munmap(Registers*, SyscallArgs args)
|
|||||||
if (!is_aligned<ARCH_PAGE_SIZE>(address)) return err(EINVAL);
|
if (!is_aligned<ARCH_PAGE_SIZE>(address)) return err(EINVAL);
|
||||||
|
|
||||||
Thread* current = Scheduler::current();
|
Thread* current = Scheduler::current();
|
||||||
|
TRY(check_pledge(current, Promise::p_stdio));
|
||||||
|
|
||||||
bool ok = TRY(current->address_space->free_region(address, ceil_div(size, ARCH_PAGE_SIZE)));
|
bool ok = TRY(current->address_space->free_region(address, ceil_div(size, ARCH_PAGE_SIZE)));
|
||||||
|
|
||||||
@ -118,6 +122,7 @@ Result<u64> sys_msync(Registers*, SyscallArgs args)
|
|||||||
if (!is_aligned<ARCH_PAGE_SIZE>(address)) return err(EINVAL);
|
if (!is_aligned<ARCH_PAGE_SIZE>(address)) return err(EINVAL);
|
||||||
|
|
||||||
Thread* current = Scheduler::current();
|
Thread* current = Scheduler::current();
|
||||||
|
TRY(check_pledge(current, Promise::p_stdio));
|
||||||
|
|
||||||
TRY(current->address_space->sync_regions(address, ceil_div(size, ARCH_PAGE_SIZE)));
|
TRY(current->address_space->sync_regions(address, ceil_div(size, ARCH_PAGE_SIZE)));
|
||||||
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
#include "Pledge.h"
|
||||||
#include "fs/VFS.h"
|
#include "fs/VFS.h"
|
||||||
#include "fs/ext2/FileSystem.h"
|
#include "fs/ext2/FileSystem.h"
|
||||||
#include "fs/tmpfs/FileSystem.h"
|
#include "fs/tmpfs/FileSystem.h"
|
||||||
@ -12,6 +13,7 @@ Result<u64> sys_mount(Registers*, SyscallArgs args)
|
|||||||
auto source = TRY(MemoryManager::strdup_from_user(args[2]));
|
auto source = TRY(MemoryManager::strdup_from_user(args[2]));
|
||||||
|
|
||||||
auto* current = Scheduler::current();
|
auto* current = Scheduler::current();
|
||||||
|
TRY(check_pledge(current, Promise::p_mount));
|
||||||
if (current->auth.euid != 0) return err(EPERM);
|
if (current->auth.euid != 0) return err(EPERM);
|
||||||
|
|
||||||
auto get_source = [current, &source]() -> Result<SharedPtr<Device>> {
|
auto get_source = [current, &source]() -> Result<SharedPtr<Device>> {
|
||||||
@ -44,6 +46,7 @@ Result<u64> sys_umount(Registers*, SyscallArgs args)
|
|||||||
auto target = TRY(MemoryManager::strdup_from_user(args[0]));
|
auto target = TRY(MemoryManager::strdup_from_user(args[0]));
|
||||||
|
|
||||||
auto* current = Scheduler::current();
|
auto* current = Scheduler::current();
|
||||||
|
TRY(check_pledge(current, Promise::p_mount));
|
||||||
if (current->auth.euid != 0) return err(EPERM);
|
if (current->auth.euid != 0) return err(EPERM);
|
||||||
|
|
||||||
TRY(VFS::umount(target.chars(), current->auth, current->current_directory));
|
TRY(VFS::umount(target.chars(), current->auth, current->current_directory));
|
||||||
@ -57,6 +60,7 @@ Result<u64> sys_pivot_root(Registers*, SyscallArgs args)
|
|||||||
auto put_old = TRY(MemoryManager::strdup_from_user(args[1]));
|
auto put_old = TRY(MemoryManager::strdup_from_user(args[1]));
|
||||||
|
|
||||||
auto* current = Scheduler::current();
|
auto* current = Scheduler::current();
|
||||||
|
TRY(check_pledge(current, Promise::p_mount));
|
||||||
if (current->auth.euid != 0) return err(EPERM);
|
if (current->auth.euid != 0) return err(EPERM);
|
||||||
|
|
||||||
TRY(VFS::pivot_root(new_root.chars(), put_old.chars(), current->current_directory));
|
TRY(VFS::pivot_root(new_root.chars(), put_old.chars(), current->current_directory));
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
|
#include "Pledge.h"
|
||||||
#include "fs/VFS.h"
|
#include "fs/VFS.h"
|
||||||
#include "memory/MemoryManager.h"
|
#include "memory/MemoryManager.h"
|
||||||
#include "sys/Syscall.h"
|
#include "sys/Syscall.h"
|
||||||
@ -23,6 +24,12 @@ Result<u64> sys_openat(Registers*, SyscallArgs args)
|
|||||||
// Caller did not pass either O_RDONLY, O_WRONLY or O_RDWR
|
// Caller did not pass either O_RDONLY, O_WRONLY or O_RDWR
|
||||||
if ((flags & O_RDWR) == 0) { return err(EINVAL); }
|
if ((flags & O_RDWR) == 0) { return err(EINVAL); }
|
||||||
|
|
||||||
|
if (flags & O_RDONLY) TRY(check_pledge(current, Promise::p_rpath));
|
||||||
|
else if (flags & O_WRONLY)
|
||||||
|
TRY(check_pledge(current, Promise::p_wpath));
|
||||||
|
|
||||||
|
if (flags & O_CREAT) TRY(check_pledge(current, Promise::p_cpath));
|
||||||
|
|
||||||
if (flags & O_TMPFILE)
|
if (flags & O_TMPFILE)
|
||||||
{
|
{
|
||||||
if (!(flags & O_WRONLY)) return err(EINVAL);
|
if (!(flags & O_WRONLY)) return err(EINVAL);
|
||||||
@ -99,6 +106,7 @@ Result<u64> sys_close(Registers*, SyscallArgs args)
|
|||||||
if (fd < 0 || fd >= FD_MAX) return err(EBADF);
|
if (fd < 0 || fd >= FD_MAX) return err(EBADF);
|
||||||
|
|
||||||
Thread* current = Scheduler::current();
|
Thread* current = Scheduler::current();
|
||||||
|
TRY(check_pledge(current, Promise::p_stdio));
|
||||||
|
|
||||||
Option<FileDescriptor>& descriptor = current->fd_table[fd];
|
Option<FileDescriptor>& descriptor = current->fd_table[fd];
|
||||||
|
|
||||||
|
40
kernel/src/sys/pledge.cpp
Normal file
40
kernel/src/sys/pledge.cpp
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#include "Pledge.h"
|
||||||
|
#include "sys/Syscall.h"
|
||||||
|
#include "thread/Scheduler.h"
|
||||||
|
|
||||||
|
Result<u64> sys_pledge(Registers*, SyscallArgs args)
|
||||||
|
{
|
||||||
|
int promises = TRY(parse_promises(args[0]));
|
||||||
|
int execpromises = TRY(parse_promises(args[1]));
|
||||||
|
|
||||||
|
auto* current = Scheduler::current();
|
||||||
|
|
||||||
|
if (promises >= 0)
|
||||||
|
{
|
||||||
|
int actual_promises = promises & ~(1 << (int)Promise::p_error);
|
||||||
|
int old_promises = current->promises & ~(1 << (int)Promise::p_error);
|
||||||
|
|
||||||
|
if (actual_promises & ~old_promises)
|
||||||
|
{
|
||||||
|
if (current->promises & ~(1 << (int)Promise::p_error)) return 0;
|
||||||
|
return err(EPERM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (execpromises >= 0)
|
||||||
|
{
|
||||||
|
int actual_execpromises = execpromises & ~(1 << (int)Promise::p_error);
|
||||||
|
int old_execpromises = current->execpromises & ~(1 << (int)Promise::p_error);
|
||||||
|
|
||||||
|
if (actual_execpromises & ~old_execpromises)
|
||||||
|
{
|
||||||
|
if (current->execpromises & ~(1 << (int)Promise::p_error)) return 0;
|
||||||
|
return err(EPERM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (promises >= 0) current->promises = promises;
|
||||||
|
if (execpromises >= 0) current->execpromises = execpromises;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
@ -1,6 +1,8 @@
|
|||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
|
#include "Pledge.h"
|
||||||
#include "fs/VFS.h"
|
#include "fs/VFS.h"
|
||||||
#include "memory/MemoryManager.h"
|
#include "memory/MemoryManager.h"
|
||||||
|
#include "net/Socket.h"
|
||||||
#include "sys/Syscall.h"
|
#include "sys/Syscall.h"
|
||||||
#include "thread/Scheduler.h"
|
#include "thread/Scheduler.h"
|
||||||
#include <bits/poll.h>
|
#include <bits/poll.h>
|
||||||
@ -18,6 +20,7 @@ Result<u64> sys_poll(Registers*, SyscallArgs args)
|
|||||||
|
|
||||||
Vector<SharedPtr<VFS::Inode>> inodes;
|
Vector<SharedPtr<VFS::Inode>> inodes;
|
||||||
auto* current = Scheduler::current();
|
auto* current = Scheduler::current();
|
||||||
|
TRY(check_pledge(current, Promise::p_stdio));
|
||||||
|
|
||||||
for (nfds_t i = 0; i < nfds; i++)
|
for (nfds_t i = 0; i < nfds; i++)
|
||||||
{
|
{
|
||||||
@ -43,10 +46,25 @@ Result<u64> sys_poll(Registers*, SyscallArgs args)
|
|||||||
auto& inode = inodes[i];
|
auto& inode = inodes[i];
|
||||||
if (!inode) continue;
|
if (!inode) continue;
|
||||||
|
|
||||||
if (kfds[i].events & POLLIN && !inode->will_block_if_read())
|
if (kfds[i].events & POLLIN)
|
||||||
{
|
{
|
||||||
fds_with_events++;
|
if (inode->type() == VFS::InodeType::Socket)
|
||||||
kfds[i].revents |= POLLIN;
|
{
|
||||||
|
auto socket = (Socket*)inode.ptr();
|
||||||
|
if (socket->can_read_data() || socket->can_accept_connections())
|
||||||
|
{
|
||||||
|
fds_with_events++;
|
||||||
|
kfds[i].revents |= POLLIN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!inode->will_block_if_read())
|
||||||
|
{
|
||||||
|
fds_with_events++;
|
||||||
|
kfds[i].revents |= POLLIN;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
#include "Pledge.h"
|
||||||
#include "memory/MemoryManager.h"
|
#include "memory/MemoryManager.h"
|
||||||
#include "sys/Syscall.h"
|
#include "sys/Syscall.h"
|
||||||
#include "thread/Scheduler.h"
|
#include "thread/Scheduler.h"
|
||||||
@ -14,6 +15,9 @@ Result<u64> sys_pstat(Registers*, SyscallArgs args)
|
|||||||
pid_t pid = (pid_t)args[0];
|
pid_t pid = (pid_t)args[0];
|
||||||
struct process* ps = (struct process*)args[1];
|
struct process* ps = (struct process*)args[1];
|
||||||
|
|
||||||
|
auto* current = Scheduler::current();
|
||||||
|
TRY(check_pledge(current, Promise::p_proc));
|
||||||
|
|
||||||
// If pid == -1, return the PID of the last spawned thread.
|
// If pid == -1, return the PID of the last spawned thread.
|
||||||
if (pid == -1) return g_threads.expect_last()->id;
|
if (pid == -1) return g_threads.expect_last()->id;
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
|
#include "Pledge.h"
|
||||||
#include "memory/MemoryManager.h"
|
#include "memory/MemoryManager.h"
|
||||||
#include "sys/Syscall.h"
|
#include "sys/Syscall.h"
|
||||||
#include "thread/Scheduler.h"
|
#include "thread/Scheduler.h"
|
||||||
@ -18,6 +19,7 @@ Result<u64> sys_sigreturn(Registers* regs, SyscallArgs)
|
|||||||
Result<u64> sys_sigaction(Registers*, SyscallArgs args)
|
Result<u64> sys_sigaction(Registers*, SyscallArgs args)
|
||||||
{
|
{
|
||||||
auto* current = Scheduler::current();
|
auto* current = Scheduler::current();
|
||||||
|
TRY(check_pledge(current, Promise::p_signal));
|
||||||
|
|
||||||
int signo = (int)args[0];
|
int signo = (int)args[0];
|
||||||
const struct sigaction* act = (const struct sigaction*)args[1];
|
const struct sigaction* act = (const struct sigaction*)args[1];
|
||||||
@ -47,6 +49,7 @@ Result<u64> sys_sigaction(Registers*, SyscallArgs args)
|
|||||||
Result<u64> sys_kill(Registers*, SyscallArgs args)
|
Result<u64> sys_kill(Registers*, SyscallArgs args)
|
||||||
{
|
{
|
||||||
auto* current = Scheduler::current();
|
auto* current = Scheduler::current();
|
||||||
|
TRY(check_pledge(current, Promise::p_proc));
|
||||||
|
|
||||||
pid_t pid = (pid_t)args[0];
|
pid_t pid = (pid_t)args[0];
|
||||||
int signo = (int)args[1];
|
int signo = (int)args[1];
|
||||||
@ -68,6 +71,7 @@ Result<u64> sys_kill(Registers*, SyscallArgs args)
|
|||||||
Result<u64> sys_sigprocmask(Registers*, SyscallArgs args)
|
Result<u64> sys_sigprocmask(Registers*, SyscallArgs args)
|
||||||
{
|
{
|
||||||
auto* current = Scheduler::current();
|
auto* current = Scheduler::current();
|
||||||
|
TRY(check_pledge(current, Promise::p_signal));
|
||||||
|
|
||||||
int how = (int)args[0];
|
int how = (int)args[0];
|
||||||
const sigset_t* set = (const sigset_t*)args[1];
|
const sigset_t* set = (const sigset_t*)args[1];
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#include "net/Socket.h"
|
#include "net/Socket.h"
|
||||||
|
#include "Pledge.h"
|
||||||
#include "memory/MemoryManager.h"
|
#include "memory/MemoryManager.h"
|
||||||
#include "net/UnixSocket.h"
|
#include "net/UnixSocket.h"
|
||||||
#include "sys/Syscall.h"
|
#include "sys/Syscall.h"
|
||||||
@ -14,9 +15,10 @@ Result<u64> sys_socket(Registers*, SyscallArgs args)
|
|||||||
if (type != SOCK_STREAM) return err(EPROTOTYPE);
|
if (type != SOCK_STREAM) return err(EPROTOTYPE);
|
||||||
if (domain != AF_UNIX) return err(EAFNOSUPPORT);
|
if (domain != AF_UNIX) return err(EAFNOSUPPORT);
|
||||||
|
|
||||||
auto socket = TRY(make_shared<UnixSocket>());
|
|
||||||
|
|
||||||
auto* current = Scheduler::current();
|
auto* current = Scheduler::current();
|
||||||
|
TRY(check_pledge(current, Promise::p_unix));
|
||||||
|
|
||||||
|
auto socket = TRY(make_shared<UnixSocket>());
|
||||||
|
|
||||||
int fd = TRY(current->allocate_fd(0));
|
int fd = TRY(current->allocate_fd(0));
|
||||||
|
|
||||||
@ -36,6 +38,7 @@ Result<u64> sys_bind(Registers*, SyscallArgs args)
|
|||||||
if (!MemoryManager::copy_from_user(addr, &storage, addrlen)) return err(EFAULT);
|
if (!MemoryManager::copy_from_user(addr, &storage, addrlen)) return err(EFAULT);
|
||||||
|
|
||||||
auto* current = Scheduler::current();
|
auto* current = Scheduler::current();
|
||||||
|
TRY(check_pledge(current, Promise::p_unix));
|
||||||
|
|
||||||
auto inode = TRY(current->resolve_fd(sockfd))->inode();
|
auto inode = TRY(current->resolve_fd(sockfd))->inode();
|
||||||
|
|
||||||
@ -59,6 +62,7 @@ Result<u64> sys_connect(Registers* regs, SyscallArgs args)
|
|||||||
if (!MemoryManager::copy_from_user(addr, &storage, addrlen)) return err(EFAULT);
|
if (!MemoryManager::copy_from_user(addr, &storage, addrlen)) return err(EFAULT);
|
||||||
|
|
||||||
auto* current = Scheduler::current();
|
auto* current = Scheduler::current();
|
||||||
|
TRY(check_pledge(current, Promise::p_unix));
|
||||||
|
|
||||||
auto description = TRY(current->resolve_fd(sockfd))->description;
|
auto description = TRY(current->resolve_fd(sockfd))->description;
|
||||||
|
|
||||||
@ -77,6 +81,7 @@ Result<u64> sys_listen(Registers*, SyscallArgs args)
|
|||||||
int backlog = (int)args[1];
|
int backlog = (int)args[1];
|
||||||
|
|
||||||
auto* current = Scheduler::current();
|
auto* current = Scheduler::current();
|
||||||
|
TRY(check_pledge(current, Promise::p_unix));
|
||||||
|
|
||||||
auto inode = TRY(current->resolve_fd(sockfd))->inode();
|
auto inode = TRY(current->resolve_fd(sockfd))->inode();
|
||||||
|
|
||||||
@ -104,6 +109,7 @@ Result<u64> sys_accept(Registers* regs, SyscallArgs args)
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto* current = Scheduler::current();
|
auto* current = Scheduler::current();
|
||||||
|
TRY(check_pledge(current, Promise::p_unix));
|
||||||
|
|
||||||
auto description = TRY(current->resolve_fd(sockfd))->description;
|
auto description = TRY(current->resolve_fd(sockfd))->description;
|
||||||
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
#include "Pledge.h"
|
||||||
#include "memory/MemoryManager.h"
|
#include "memory/MemoryManager.h"
|
||||||
#include "sys/Syscall.h"
|
#include "sys/Syscall.h"
|
||||||
#include "thread/Scheduler.h"
|
#include "thread/Scheduler.h"
|
||||||
@ -33,6 +34,7 @@ Result<u64> sys_fstatat(Registers*, SyscallArgs args)
|
|||||||
int flags = (int)args[3];
|
int flags = (int)args[3];
|
||||||
|
|
||||||
Thread* current = Scheduler::current();
|
Thread* current = Scheduler::current();
|
||||||
|
TRY(check_pledge(current, Promise::p_rpath));
|
||||||
|
|
||||||
auto inode = TRY(current->resolve_atfile(dirfd, path, flags & AT_EMPTY_PATH, !(flags & AT_SYMLINK_NOFOLLOW)));
|
auto inode = TRY(current->resolve_atfile(dirfd, path, flags & AT_EMPTY_PATH, !(flags & AT_SYMLINK_NOFOLLOW)));
|
||||||
|
|
||||||
@ -67,6 +69,7 @@ Result<u64> sys_faccessat(Registers*, SyscallArgs args)
|
|||||||
Credentials creds;
|
Credentials creds;
|
||||||
|
|
||||||
auto* current = Scheduler::current();
|
auto* current = Scheduler::current();
|
||||||
|
TRY(check_pledge(current, Promise::p_rpath));
|
||||||
|
|
||||||
if (flags & AT_EACCESS) creds = current->auth;
|
if (flags & AT_EACCESS) creds = current->auth;
|
||||||
else
|
else
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
|
#include "Pledge.h"
|
||||||
#include "arch/CPU.h"
|
#include "arch/CPU.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "memory/MemoryManager.h"
|
#include "memory/MemoryManager.h"
|
||||||
@ -40,6 +41,7 @@ Result<u64> sys_sethostname(Registers*, SyscallArgs args)
|
|||||||
usize length = (usize)args[1];
|
usize length = (usize)args[1];
|
||||||
|
|
||||||
Thread* current = Scheduler::current();
|
Thread* current = Scheduler::current();
|
||||||
|
TRY(check_pledge(current, Promise::p_host));
|
||||||
if (current->auth.euid != 0) return err(EPERM);
|
if (current->auth.euid != 0) return err(EPERM);
|
||||||
|
|
||||||
if (length >= _UTSNAME_LENGTH) return err(EINVAL);
|
if (length >= _UTSNAME_LENGTH) return err(EINVAL);
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
#include "Pledge.h"
|
||||||
#include "sys/Syscall.h"
|
#include "sys/Syscall.h"
|
||||||
#include "thread/Scheduler.h"
|
#include "thread/Scheduler.h"
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
@ -6,12 +7,13 @@ Result<u64> sys_usleep(Registers*, SyscallArgs args)
|
|||||||
{
|
{
|
||||||
useconds_t us = (useconds_t)args[0];
|
useconds_t us = (useconds_t)args[0];
|
||||||
|
|
||||||
|
auto* current = Scheduler::current();
|
||||||
|
TRY(check_pledge(current, Promise::p_stdio));
|
||||||
|
|
||||||
// FIXME: Allow usleep() to use a more precise resolution.
|
// FIXME: Allow usleep() to use a more precise resolution.
|
||||||
if (us < 1000) return 0;
|
if (us < 1000) return 0;
|
||||||
|
|
||||||
kernel_sleep(us / 1000);
|
kernel_sleep(us / 1000);
|
||||||
|
|
||||||
auto* current = Scheduler::current();
|
|
||||||
|
|
||||||
return current->sleep_ticks_left;
|
return current->sleep_ticks_left;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
|
#include "Pledge.h"
|
||||||
#include "memory/MemoryManager.h"
|
#include "memory/MemoryManager.h"
|
||||||
#include "sys/Syscall.h"
|
#include "sys/Syscall.h"
|
||||||
#include "thread/Scheduler.h"
|
#include "thread/Scheduler.h"
|
||||||
@ -11,6 +12,7 @@ Result<u64> sys_waitpid(Registers* regs, SyscallArgs args)
|
|||||||
int options = (int)args[2];
|
int options = (int)args[2];
|
||||||
|
|
||||||
Thread* current = Scheduler::current();
|
Thread* current = Scheduler::current();
|
||||||
|
TRY(check_pledge(current, Promise::p_stdio));
|
||||||
|
|
||||||
Thread* thread;
|
Thread* thread;
|
||||||
|
|
||||||
|
@ -282,6 +282,8 @@ namespace Scheduler
|
|||||||
{
|
{
|
||||||
if (thread->sleep_ticks_left == 0 || --thread->sleep_ticks_left == 0) thread->wake_up();
|
if (thread->sleep_ticks_left == 0 || --thread->sleep_ticks_left == 0) thread->wake_up();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (thread->alarm_ticks_left && --thread->alarm_ticks_left == 0) thread->send_signal(SIGALRM);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!g_current->ticks_left) switch_task(regs);
|
if (!g_current->ticks_left) switch_task(regs);
|
||||||
|
@ -87,6 +87,10 @@ struct Thread : public LinkedListNode<Thread>
|
|||||||
|
|
||||||
u64 ticks_left;
|
u64 ticks_left;
|
||||||
u64 sleep_ticks_left;
|
u64 sleep_ticks_left;
|
||||||
|
u64 alarm_ticks_left { 0 };
|
||||||
|
|
||||||
|
int promises { -1 };
|
||||||
|
int execpromises { -1 };
|
||||||
|
|
||||||
Stack stack;
|
Stack stack;
|
||||||
Stack kernel_stack;
|
Stack kernel_stack;
|
||||||
|
@ -25,6 +25,7 @@ set(SOURCES
|
|||||||
src/termios.cpp
|
src/termios.cpp
|
||||||
src/utime.cpp
|
src/utime.cpp
|
||||||
src/strtod.cpp
|
src/strtod.cpp
|
||||||
|
src/math.cpp
|
||||||
src/sys/stat.cpp
|
src/sys/stat.cpp
|
||||||
src/sys/mman.cpp
|
src/sys/mman.cpp
|
||||||
src/sys/wait.cpp
|
src/sys/wait.cpp
|
||||||
|
0
libc/include/arpa/inet.h
Normal file
0
libc/include/arpa/inet.h
Normal file
@ -5,6 +5,28 @@
|
|||||||
|
|
||||||
#include <bits/locale-cat.h>
|
#include <bits/locale-cat.h>
|
||||||
|
|
||||||
|
struct lconv
|
||||||
|
{
|
||||||
|
char* decimal_point;
|
||||||
|
char* thousands_sep;
|
||||||
|
char* grouping;
|
||||||
|
char* int_curr_symbol;
|
||||||
|
char* currency_symbol;
|
||||||
|
char* mon_decimal_point;
|
||||||
|
char* mon_thousands_sep;
|
||||||
|
char* mon_grouping;
|
||||||
|
char* positive_sign;
|
||||||
|
char* negative_sign;
|
||||||
|
char int_frac_digits;
|
||||||
|
char frac_digits;
|
||||||
|
char p_cs_precedes;
|
||||||
|
char p_sep_by_space;
|
||||||
|
char n_cs_precedes;
|
||||||
|
char n_sep_by_space;
|
||||||
|
char p_sign_posn;
|
||||||
|
char n_sign_posn;
|
||||||
|
};
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C"
|
extern "C"
|
||||||
{
|
{
|
||||||
@ -13,6 +35,9 @@ extern "C"
|
|||||||
// Query or set the current locale.
|
// Query or set the current locale.
|
||||||
char* setlocale(int category, const char* locale);
|
char* setlocale(int category, const char* locale);
|
||||||
|
|
||||||
|
// Query formatting information for the current locale.
|
||||||
|
struct lconv* localeconv(void);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -0,0 +1,92 @@
|
|||||||
|
/* math.h: Floating-point arithmetic functions. */
|
||||||
|
|
||||||
|
#ifndef _MATH_H
|
||||||
|
#define _MATH_H
|
||||||
|
|
||||||
|
typedef float float_t;
|
||||||
|
typedef double double_t;
|
||||||
|
|
||||||
|
#define FP_NAN 0
|
||||||
|
#define FP_INFINITE 1
|
||||||
|
#define FP_ZERO 2
|
||||||
|
#define FP_SUBNORMAL 3
|
||||||
|
#define FP_NORMAL 4
|
||||||
|
#define fpclassify(x) __builtin_fpclassify(FP_NAN, FP_INFINITE, FP_ZERO, FP_SUBNORMAL, FP_ZERO, x)
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
double cos(double val);
|
||||||
|
float cosf(float val);
|
||||||
|
long double cosl(long double val);
|
||||||
|
double sin(double val);
|
||||||
|
float sinf(float val);
|
||||||
|
long double sinl(long double val);
|
||||||
|
double tan(double val);
|
||||||
|
float tanf(float val);
|
||||||
|
long double tanl(long double val);
|
||||||
|
double acos(double val);
|
||||||
|
float acosf(float val);
|
||||||
|
long double acosl(long double val);
|
||||||
|
double asin(double val);
|
||||||
|
float asinf(float val);
|
||||||
|
long double asinl(long double val);
|
||||||
|
double atan(double val);
|
||||||
|
float atanf(float val);
|
||||||
|
long double atanl(long double val);
|
||||||
|
double cosh(double val);
|
||||||
|
float coshf(float val);
|
||||||
|
long double coshl(long double val);
|
||||||
|
double sinh(double val);
|
||||||
|
float sinhf(float val);
|
||||||
|
long double sinhl(long double val);
|
||||||
|
double tanh(double val);
|
||||||
|
float tanhf(float val);
|
||||||
|
long double tanhl(long double val);
|
||||||
|
double log(double val);
|
||||||
|
float logf(float val);
|
||||||
|
long double logl(long double val);
|
||||||
|
double exp(double val);
|
||||||
|
float expf(float val);
|
||||||
|
long double expl(long double val);
|
||||||
|
double sqrt(double val);
|
||||||
|
float sqrtf(float val);
|
||||||
|
long double sqrtl(long double val);
|
||||||
|
double fabs(double val);
|
||||||
|
float fabsf(float val);
|
||||||
|
long double fabsl(long double val);
|
||||||
|
double floor(double val);
|
||||||
|
float floorf(float val);
|
||||||
|
long double floorl(long double val);
|
||||||
|
double ceil(double val);
|
||||||
|
float ceilf(float val);
|
||||||
|
long double ceill(long double val);
|
||||||
|
double log10(double val);
|
||||||
|
float log10f(float val);
|
||||||
|
long double log10l(long double val);
|
||||||
|
double fmod(double val1, double val2);
|
||||||
|
float fmodf(float val1, float val2);
|
||||||
|
long double fmodl(long double val1, long double val2);
|
||||||
|
double pow(double val1, double val2);
|
||||||
|
float powf(float val1, float val2);
|
||||||
|
long double powl(long double val1, long double val2);
|
||||||
|
double atan2(double val1, double val2);
|
||||||
|
float atan2f(float val1, float val2);
|
||||||
|
long double atan2l(long double val1, long double val2);
|
||||||
|
double frexp(double val1, int* val2);
|
||||||
|
float frexpf(float val1, int* val2);
|
||||||
|
long double frexpl(long double val1, int* val2);
|
||||||
|
double ldexp(double val1, int val2);
|
||||||
|
float ldexpf(float val1, int val2);
|
||||||
|
long double ldexpl(long double val1, int val2);
|
||||||
|
double modf(double val1, double* val2);
|
||||||
|
float modff(float val1, float* val2);
|
||||||
|
long double modfl(long double val1, long double* val2);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
0
libc/include/netdb.h
Normal file
0
libc/include/netdb.h
Normal file
0
libc/include/netinet/in.h
Normal file
0
libc/include/netinet/in.h
Normal file
@ -198,6 +198,9 @@ extern "C"
|
|||||||
/* Change a file's buffering mode to line buffered. */
|
/* Change a file's buffering mode to line buffered. */
|
||||||
void setlinebuf(FILE* stream);
|
void setlinebuf(FILE* stream);
|
||||||
|
|
||||||
|
/* Move a file's location across a file system. */
|
||||||
|
int rename(const char* oldpath, const char* newpath);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -128,6 +128,9 @@ extern "C"
|
|||||||
/* Clear all environment variables. */
|
/* Clear all environment variables. */
|
||||||
int clearenv(void);
|
int clearenv(void);
|
||||||
|
|
||||||
|
/* Add a new variable to the environment. */
|
||||||
|
int putenv(char* string);
|
||||||
|
|
||||||
/* Sort an array of arbitrary elements using a comparison function. */
|
/* Sort an array of arbitrary elements using a comparison function. */
|
||||||
void qsort(void* base, size_t nmemb, size_t size, int (*compar)(const void*, const void*));
|
void qsort(void* base, size_t nmemb, size_t size, int (*compar)(const void*, const void*));
|
||||||
|
|
||||||
|
@ -98,6 +98,9 @@ extern "C"
|
|||||||
/* Compare two null-terminated strings according to the current locale. */
|
/* Compare two null-terminated strings according to the current locale. */
|
||||||
int strcoll(const char* a, const char* b);
|
int strcoll(const char* a, const char* b);
|
||||||
|
|
||||||
|
/* Transform a string according to the current locale. */
|
||||||
|
size_t strxfrm(char* dest, const char* src, size_t n);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -14,10 +14,10 @@ extern "C"
|
|||||||
int socket(int domain, int type, int protocol);
|
int socket(int domain, int type, int protocol);
|
||||||
|
|
||||||
/* Bind a socket to an address. */
|
/* Bind a socket to an address. */
|
||||||
int bind(int sockfd, struct sockaddr* addr, socklen_t addrlen);
|
int bind(int sockfd, const struct sockaddr* addr, socklen_t addrlen);
|
||||||
|
|
||||||
/* Connect a socket to a remote address. */
|
/* Connect a socket to a remote address. */
|
||||||
int connect(int sockfd, struct sockaddr* addr, socklen_t addrlen);
|
int connect(int sockfd, const struct sockaddr* addr, socklen_t addrlen);
|
||||||
|
|
||||||
/* Start listening on a socket. */
|
/* Start listening on a socket. */
|
||||||
int listen(int sockfd, int backlog);
|
int listen(int sockfd, int backlog);
|
||||||
|
@ -7,6 +7,10 @@
|
|||||||
#include <bits/struct_tm.h>
|
#include <bits/struct_tm.h>
|
||||||
#include <bits/timespec.h>
|
#include <bits/timespec.h>
|
||||||
|
|
||||||
|
typedef long int clock_t;
|
||||||
|
|
||||||
|
#define CLOCKS_PER_SEC 1000000
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C"
|
extern "C"
|
||||||
{
|
{
|
||||||
@ -42,9 +46,18 @@ extern "C"
|
|||||||
/* Build a string representation of UNIX time. */
|
/* Build a string representation of UNIX time. */
|
||||||
char* ctime_r(const time_t* tp, char buf[26]);
|
char* ctime_r(const time_t* tp, char buf[26]);
|
||||||
|
|
||||||
|
/* Convert broken-down time back into UNIX time. */
|
||||||
|
time_t mktime(struct tm* tm);
|
||||||
|
|
||||||
/* Format a string representation of broken-down time using a format string. */
|
/* Format a string representation of broken-down time using a format string. */
|
||||||
size_t strftime(char* buf, size_t max, const char* format, const struct tm* tm);
|
size_t strftime(char* buf, size_t max, const char* format, const struct tm* tm);
|
||||||
|
|
||||||
|
/* Return the difference in seconds between two times. */
|
||||||
|
double difftime(time_t a, time_t b);
|
||||||
|
|
||||||
|
/* Estimate the CPU time used by a process. */
|
||||||
|
clock_t clock(void);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -190,6 +190,15 @@ extern "C"
|
|||||||
/* Truncate a file to a specific length. */
|
/* Truncate a file to a specific length. */
|
||||||
int ftruncate(int fd, size_t size);
|
int ftruncate(int fd, size_t size);
|
||||||
|
|
||||||
|
/* Return the system page size. */
|
||||||
|
int getpagesize(void);
|
||||||
|
|
||||||
|
/* Schedule an alarm signal. */
|
||||||
|
unsigned int alarm(unsigned int seconds);
|
||||||
|
|
||||||
|
/* Restrict system operations. */
|
||||||
|
int pledge(const char* promises, const char* execpromises);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -0,0 +1,25 @@
|
|||||||
|
/* wchar.h: Wide-character string manipulation functions. */
|
||||||
|
|
||||||
|
#ifndef _WCHAR_H
|
||||||
|
#define _WCHAR_H
|
||||||
|
|
||||||
|
typedef long int wint_t;
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Calculate the size of a null-terminated wide character string. */
|
||||||
|
size_t wcslen(const wchar_t* str);
|
||||||
|
|
||||||
|
/* Compare two null-terminated wide character strings. */
|
||||||
|
int wcscmp(const wchar_t* a, const wchar_t* b);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
@ -1,11 +1,13 @@
|
|||||||
#include <bits/errno-return.h>
|
#include <bits/errno-return.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <luna/HashTable.h>
|
||||||
#include <luna/ScopeGuard.h>
|
#include <luna/ScopeGuard.h>
|
||||||
#include <luna/Vector.h>
|
#include <luna/Vector.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
extern "C" char** environ;
|
extern "C" char** environ;
|
||||||
Vector<char*> g_dynamic_env = {};
|
Vector<char*> g_dynamic_env = {};
|
||||||
|
HashTable<char*> g_dynamic_vars = {};
|
||||||
bool env_is_dynamic { false };
|
bool env_is_dynamic { false };
|
||||||
|
|
||||||
/* If an environment variable matching key is found, stores its value in value and returns its index. Otherwise,
|
/* If an environment variable matching key is found, stores its value in value and returns its index. Otherwise,
|
||||||
@ -41,22 +43,24 @@ static isize _findenv(const char* key, char** value)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void free_if_needed(char* element)
|
||||||
|
{
|
||||||
|
if (g_dynamic_vars.try_find(element))
|
||||||
|
{
|
||||||
|
g_dynamic_vars.try_remove(element);
|
||||||
|
free(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Move environ to a heap-allocated array. */
|
/* Move environ to a heap-allocated array. */
|
||||||
static Result<void> _try_move_env()
|
static Result<void> _try_move_env()
|
||||||
{
|
{
|
||||||
char** env = environ;
|
char** env = environ;
|
||||||
g_dynamic_env.clear();
|
g_dynamic_env.clear();
|
||||||
auto guard = make_scope_guard([] {
|
|
||||||
for (auto element : g_dynamic_env)
|
|
||||||
{
|
|
||||||
if (element) free(element);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!env)
|
if (!env)
|
||||||
{
|
{
|
||||||
TRY(g_dynamic_env.try_append(nullptr));
|
TRY(g_dynamic_env.try_append(nullptr));
|
||||||
guard.deactivate();
|
|
||||||
env_is_dynamic = true;
|
env_is_dynamic = true;
|
||||||
environ = g_dynamic_env.data();
|
environ = g_dynamic_env.data();
|
||||||
return {};
|
return {};
|
||||||
@ -64,18 +68,12 @@ static Result<void> _try_move_env()
|
|||||||
|
|
||||||
while (*env)
|
while (*env)
|
||||||
{
|
{
|
||||||
char* ptr = strdup(*(env++));
|
char* ptr = *(env++);
|
||||||
if (!ptr) return err(errno);
|
|
||||||
|
|
||||||
auto ptr_guard = make_scope_guard([=] { free(ptr); });
|
|
||||||
TRY(g_dynamic_env.try_append(ptr));
|
TRY(g_dynamic_env.try_append(ptr));
|
||||||
ptr_guard.deactivate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TRY(g_dynamic_env.try_append(nullptr));
|
TRY(g_dynamic_env.try_append(nullptr));
|
||||||
|
|
||||||
guard.deactivate();
|
|
||||||
|
|
||||||
env_is_dynamic = true;
|
env_is_dynamic = true;
|
||||||
environ = g_dynamic_env.data();
|
environ = g_dynamic_env.data();
|
||||||
|
|
||||||
@ -105,7 +103,7 @@ static void _check_dynamic_env()
|
|||||||
{
|
{
|
||||||
for (auto element : g_dynamic_env)
|
for (auto element : g_dynamic_env)
|
||||||
{
|
{
|
||||||
if (element) free(element);
|
if (element) free_if_needed(element);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -122,7 +120,7 @@ extern "C"
|
|||||||
{
|
{
|
||||||
for (auto element : g_dynamic_env)
|
for (auto element : g_dynamic_env)
|
||||||
{
|
{
|
||||||
if (element) free(element);
|
if (element) free_if_needed(element);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_dynamic_env.clear();
|
g_dynamic_env.clear();
|
||||||
@ -152,9 +150,11 @@ extern "C"
|
|||||||
if (_move_env() < 0) return -1;
|
if (_move_env() < 0) return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_dynamic_env.remove_at(index);
|
char* p = g_dynamic_env.remove_at(index);
|
||||||
_update_env();
|
_update_env();
|
||||||
|
|
||||||
|
free_if_needed(p);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,12 +188,14 @@ extern "C"
|
|||||||
|
|
||||||
if (index >= 0)
|
if (index >= 0)
|
||||||
{
|
{
|
||||||
free(environ[index]);
|
free_if_needed(environ[index]);
|
||||||
environ[index] = str;
|
environ[index] = str;
|
||||||
guard.deactivate();
|
guard.deactivate();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TRY_OR_SET_ERRNO(g_dynamic_vars.try_set(str), int, -1);
|
||||||
|
|
||||||
// Add a new NULL at the end of the array and replace the previous one with our string.
|
// Add a new NULL at the end of the array and replace the previous one with our string.
|
||||||
index = g_dynamic_env.size() - 1;
|
index = g_dynamic_env.size() - 1;
|
||||||
|
|
||||||
@ -206,6 +208,43 @@ extern "C"
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int putenv(char* string)
|
||||||
|
{
|
||||||
|
char* p = strchr(string, '=');
|
||||||
|
if (!p) return unsetenv(string);
|
||||||
|
size_t key_len = p - string;
|
||||||
|
|
||||||
|
char* key = strndup(string, key_len);
|
||||||
|
auto guard = make_scope_guard([key] { free(key); });
|
||||||
|
|
||||||
|
auto index = _findenv(key, nullptr);
|
||||||
|
|
||||||
|
_check_dynamic_env();
|
||||||
|
|
||||||
|
if (!env_is_dynamic)
|
||||||
|
{
|
||||||
|
if (_move_env() < 0) return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index >= 0)
|
||||||
|
{
|
||||||
|
free_if_needed(environ[index]);
|
||||||
|
environ[index] = string;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a new NULL at the end of the array and replace the previous one with our string.
|
||||||
|
index = g_dynamic_env.size() - 1;
|
||||||
|
|
||||||
|
TRY_OR_SET_ERRNO(g_dynamic_env.try_append(nullptr), int, -1);
|
||||||
|
guard.deactivate();
|
||||||
|
_update_env();
|
||||||
|
|
||||||
|
environ[index] = string;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
char* getenv(const char* key)
|
char* getenv(const char* key)
|
||||||
{
|
{
|
||||||
char* result;
|
char* result;
|
||||||
|
@ -1,6 +1,30 @@
|
|||||||
|
#include <limits.h>
|
||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
|
|
||||||
static char s_default_locale[] = "C";
|
static char s_default_locale[] = "C";
|
||||||
|
static char s_empty_string[] = "";
|
||||||
|
static char s_decimal_point[] = ".";
|
||||||
|
|
||||||
|
static struct lconv s_lconv = {
|
||||||
|
.decimal_point = s_decimal_point,
|
||||||
|
.thousands_sep = s_empty_string,
|
||||||
|
.grouping = s_empty_string,
|
||||||
|
.int_curr_symbol = s_empty_string,
|
||||||
|
.currency_symbol = s_empty_string,
|
||||||
|
.mon_decimal_point = s_empty_string,
|
||||||
|
.mon_thousands_sep = s_empty_string,
|
||||||
|
.mon_grouping = s_empty_string,
|
||||||
|
.positive_sign = s_empty_string,
|
||||||
|
.negative_sign = s_empty_string,
|
||||||
|
.int_frac_digits = CHAR_MAX,
|
||||||
|
.frac_digits = CHAR_MAX,
|
||||||
|
.p_cs_precedes = CHAR_MAX,
|
||||||
|
.p_sep_by_space = CHAR_MAX,
|
||||||
|
.n_cs_precedes = CHAR_MAX,
|
||||||
|
.n_sep_by_space = CHAR_MAX,
|
||||||
|
.p_sign_posn = CHAR_MAX,
|
||||||
|
.n_sign_posn = CHAR_MAX,
|
||||||
|
};
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
{
|
{
|
||||||
@ -9,4 +33,9 @@ extern "C"
|
|||||||
// FIXME: Set the current locale if <locale> is not NULL.
|
// FIXME: Set the current locale if <locale> is not NULL.
|
||||||
return s_default_locale;
|
return s_default_locale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct lconv* localeconv(void)
|
||||||
|
{
|
||||||
|
return &s_lconv;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
106
libc/src/math.cpp
Normal file
106
libc/src/math.cpp
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
// FIXME: Provide our own definitions instead of relying on the compiler's builtins.
|
||||||
|
|
||||||
|
#define WRAP_AROUND_BUILTIN(name) \
|
||||||
|
double name(double val) \
|
||||||
|
{ \
|
||||||
|
return __builtin_##name(val); \
|
||||||
|
} \
|
||||||
|
float name##f(float val) \
|
||||||
|
{ \
|
||||||
|
return __builtin_##name##f(val); \
|
||||||
|
} \
|
||||||
|
long double name##l(long double val) \
|
||||||
|
{ \
|
||||||
|
return __builtin_##name##l(val); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define WRAP_AROUND_BUILTIN2(name) \
|
||||||
|
double name(double val1, double val2) \
|
||||||
|
{ \
|
||||||
|
return __builtin_##name(val1, val2); \
|
||||||
|
} \
|
||||||
|
float name##f(float val1, float val2) \
|
||||||
|
{ \
|
||||||
|
return __builtin_##name##f(val1, val2); \
|
||||||
|
} \
|
||||||
|
long double name##l(long double val1, long double val2) \
|
||||||
|
{ \
|
||||||
|
return __builtin_##name##l(val1, val2); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define WRAP_AROUND_BUILTIN_WITH_PARAMETER_TYPE(name, type) \
|
||||||
|
double name(double val1, type val2) \
|
||||||
|
{ \
|
||||||
|
return __builtin_##name(val1, val2); \
|
||||||
|
} \
|
||||||
|
float name##f(float val1, type val2) \
|
||||||
|
{ \
|
||||||
|
return __builtin_##name##f(val1, val2); \
|
||||||
|
} \
|
||||||
|
long double name##l(long double val1, type val2) \
|
||||||
|
{ \
|
||||||
|
return __builtin_##name##l(val1, val2); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define WRAP_AROUND_BUILTIN_WITH_POINTER(name) \
|
||||||
|
double name(double val1, double* val2) \
|
||||||
|
{ \
|
||||||
|
return __builtin_##name(val1, val2); \
|
||||||
|
} \
|
||||||
|
float name##f(float val1, float* val2) \
|
||||||
|
{ \
|
||||||
|
return __builtin_##name##f(val1, val2); \
|
||||||
|
} \
|
||||||
|
long double name##l(long double val1, long double* val2) \
|
||||||
|
{ \
|
||||||
|
return __builtin_##name##l(val1, val2); \
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
WRAP_AROUND_BUILTIN(cos);
|
||||||
|
|
||||||
|
WRAP_AROUND_BUILTIN(sin);
|
||||||
|
|
||||||
|
WRAP_AROUND_BUILTIN(tan);
|
||||||
|
|
||||||
|
WRAP_AROUND_BUILTIN(acos);
|
||||||
|
|
||||||
|
WRAP_AROUND_BUILTIN(asin);
|
||||||
|
|
||||||
|
WRAP_AROUND_BUILTIN(atan);
|
||||||
|
|
||||||
|
WRAP_AROUND_BUILTIN(cosh);
|
||||||
|
|
||||||
|
WRAP_AROUND_BUILTIN(sinh);
|
||||||
|
|
||||||
|
WRAP_AROUND_BUILTIN(tanh);
|
||||||
|
|
||||||
|
WRAP_AROUND_BUILTIN(log);
|
||||||
|
|
||||||
|
WRAP_AROUND_BUILTIN(exp);
|
||||||
|
|
||||||
|
WRAP_AROUND_BUILTIN(sqrt);
|
||||||
|
|
||||||
|
WRAP_AROUND_BUILTIN(fabs);
|
||||||
|
|
||||||
|
WRAP_AROUND_BUILTIN(floor);
|
||||||
|
|
||||||
|
WRAP_AROUND_BUILTIN(ceil);
|
||||||
|
|
||||||
|
WRAP_AROUND_BUILTIN(log10);
|
||||||
|
|
||||||
|
WRAP_AROUND_BUILTIN2(fmod);
|
||||||
|
|
||||||
|
WRAP_AROUND_BUILTIN2(pow);
|
||||||
|
|
||||||
|
WRAP_AROUND_BUILTIN2(atan2);
|
||||||
|
|
||||||
|
WRAP_AROUND_BUILTIN_WITH_PARAMETER_TYPE(frexp, int*);
|
||||||
|
|
||||||
|
WRAP_AROUND_BUILTIN_WITH_PARAMETER_TYPE(ldexp, int);
|
||||||
|
|
||||||
|
WRAP_AROUND_BUILTIN_WITH_POINTER(modf);
|
||||||
|
}
|
@ -752,4 +752,13 @@ extern "C"
|
|||||||
{
|
{
|
||||||
setvbuf(stream, NULL, _IOLBF, 0);
|
setvbuf(stream, NULL, _IOLBF, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int rename(const char* oldpath, const char* newpath)
|
||||||
|
{
|
||||||
|
// FIXME: Implement this atomically in-kernel.
|
||||||
|
unlink(newpath);
|
||||||
|
if (link(oldpath, newpath) < 0) return -1;
|
||||||
|
unlink(oldpath);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,12 @@ extern "C"
|
|||||||
return strcmp(a, b);
|
return strcmp(a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t strxfrm(char* dest, const char* src, size_t n)
|
||||||
|
{
|
||||||
|
strncpy(dest, src, n);
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
char* strerror(int errnum)
|
char* strerror(int errnum)
|
||||||
{
|
{
|
||||||
return const_cast<char*>(error_string(errnum));
|
return const_cast<char*>(error_string(errnum));
|
||||||
|
@ -11,13 +11,13 @@ extern "C"
|
|||||||
__errno_return(rc, int);
|
__errno_return(rc, int);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bind(int sockfd, struct sockaddr* addr, socklen_t addrlen)
|
int bind(int sockfd, const struct sockaddr* addr, socklen_t addrlen)
|
||||||
{
|
{
|
||||||
long rc = syscall(SYS_bind, sockfd, addr, addrlen);
|
long rc = syscall(SYS_bind, sockfd, addr, addrlen);
|
||||||
__errno_return(rc, int);
|
__errno_return(rc, int);
|
||||||
}
|
}
|
||||||
|
|
||||||
int connect(int sockfd, struct sockaddr* addr, socklen_t addrlen)
|
int connect(int sockfd, const struct sockaddr* addr, socklen_t addrlen)
|
||||||
{
|
{
|
||||||
long rc = syscall(SYS_connect, sockfd, addr, addrlen);
|
long rc = syscall(SYS_connect, sockfd, addr, addrlen);
|
||||||
__errno_return(rc, int);
|
__errno_return(rc, int);
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include <luna/Format.h>
|
#include <luna/Format.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <sys/resource.h>
|
||||||
#include <sys/syscall.h>
|
#include <sys/syscall.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@ -31,6 +32,13 @@ static int day_of_week(int year, int mon, int day)
|
|||||||
return (year + year / 4 - year / 100 + year / 400 + t[mon - 1] + day) % 7;
|
return (year + year / 4 - year / 100 + year / 400 + t[mon - 1] + day) % 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_16
|
||||||
|
static constexpr u64 broken_down_to_unix(u64 year, u64 yday, u64 hour, u64 min, u64 sec)
|
||||||
|
{
|
||||||
|
return sec + min * 60 + hour * 3600 + yday * 86400 + (year - 70) * 31536000 + ((year - 69) / 4) * 86400 -
|
||||||
|
((year - 1) / 100) * 86400 + ((year + 299) / 400) * 86400;
|
||||||
|
}
|
||||||
|
|
||||||
static void time_to_struct_tm(time_t time, struct tm* result)
|
static void time_to_struct_tm(time_t time, struct tm* result)
|
||||||
{
|
{
|
||||||
result->tm_isdst = 0; // No DST/timezone support for now.
|
result->tm_isdst = 0; // No DST/timezone support for now.
|
||||||
@ -167,4 +175,29 @@ extern "C"
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
time_t mktime(struct tm* tm)
|
||||||
|
{
|
||||||
|
// FIXME: Check if the tm structure is valid.
|
||||||
|
time_t result = broken_down_to_unix(tm->tm_year, make_yday(tm->tm_year, tm->tm_mon + 1) + (tm->tm_mday - 1),
|
||||||
|
tm->tm_hour, tm->tm_min, tm->tm_sec);
|
||||||
|
|
||||||
|
tm->tm_yday = make_yday(tm->tm_year + 1900, tm->tm_mon + 1) + (tm->tm_mday - 1);
|
||||||
|
tm->tm_wday = day_of_week(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
double difftime(time_t a, time_t b)
|
||||||
|
{
|
||||||
|
return (double)(a - b);
|
||||||
|
}
|
||||||
|
|
||||||
|
clock_t clock(void)
|
||||||
|
{
|
||||||
|
struct rusage ru;
|
||||||
|
if (getrusage(RUSAGE_SELF, &ru) < 0) return (clock_t)-1;
|
||||||
|
|
||||||
|
return ru.ru_utime.tv_sec * CLOCKS_PER_SEC + ru.ru_utime.tv_usec;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/syscall.h>
|
#include <sys/syscall.h>
|
||||||
#include <sys/utsname.h>
|
#include <sys/utsname.h>
|
||||||
@ -510,4 +511,20 @@ extern "C"
|
|||||||
long rc = syscall(SYS_ftruncate, fd, size);
|
long rc = syscall(SYS_ftruncate, fd, size);
|
||||||
__errno_return(rc, int);
|
__errno_return(rc, int);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int getpagesize(void)
|
||||||
|
{
|
||||||
|
return PAGE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int alarm(unsigned int seconds)
|
||||||
|
{
|
||||||
|
return (unsigned int)syscall(SYS_alarm, seconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
int pledge(const char* promises, const char* execpromises)
|
||||||
|
{
|
||||||
|
long rc = syscall(SYS_pledge, promises, execpromises);
|
||||||
|
__errno_return(rc, int);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,9 @@ class Buffer
|
|||||||
Buffer(Buffer&& other);
|
Buffer(Buffer&& other);
|
||||||
Buffer(const Buffer& other) = delete; // For now.
|
Buffer(const Buffer& other) = delete; // For now.
|
||||||
|
|
||||||
|
Buffer& operator=(Buffer&&);
|
||||||
|
Buffer& operator=(const Buffer&) = delete;
|
||||||
|
|
||||||
static Result<Buffer> create_sized(usize size);
|
static Result<Buffer> create_sized(usize size);
|
||||||
|
|
||||||
Result<void> try_resize(usize new_size);
|
Result<void> try_resize(usize new_size);
|
||||||
|
@ -16,7 +16,7 @@ template <typename T, usize Size> class CircularQueue
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_empty()
|
bool is_empty() const
|
||||||
{
|
{
|
||||||
return m_tail.load() == m_head.load();
|
return m_tail.load() == m_head.load();
|
||||||
}
|
}
|
||||||
@ -76,7 +76,7 @@ template <typename T> class DynamicCircularQueue
|
|||||||
if (m_data) free_impl(m_data);
|
if (m_data) free_impl(m_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_empty()
|
bool is_empty() const
|
||||||
{
|
{
|
||||||
return m_tail.load() == m_head.load();
|
return m_tail.load() == m_head.load();
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
_e(umount) _e(pstat) _e(getrusage) _e(symlinkat) _e(readlinkat) _e(umask) _e(linkat) _e(faccessat) \
|
_e(umount) _e(pstat) _e(getrusage) _e(symlinkat) _e(readlinkat) _e(umask) _e(linkat) _e(faccessat) \
|
||||||
_e(pivot_root) _e(sigreturn) _e(sigaction) _e(kill) _e(sigprocmask) _e(setpgid) _e(isatty) \
|
_e(pivot_root) _e(sigreturn) _e(sigaction) _e(kill) _e(sigprocmask) _e(setpgid) _e(isatty) \
|
||||||
_e(getpgid) _e(socket) _e(bind) _e(connect) _e(listen) _e(accept) _e(poll) _e(msync) \
|
_e(getpgid) _e(socket) _e(bind) _e(connect) _e(listen) _e(accept) _e(poll) _e(msync) \
|
||||||
_e(truncate) _e(ftruncate) _e(utimensat)
|
_e(truncate) _e(ftruncate) _e(utimensat) _e(alarm) _e(pledge)
|
||||||
|
|
||||||
enum Syscalls
|
enum Syscalls
|
||||||
{
|
{
|
||||||
|
@ -1,62 +1,70 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define EPERM 1 // Operation not permitted
|
#define EPERM 1 // Operation not permitted
|
||||||
#define ENOENT 2 // No such file or directory
|
#define ENOENT 2 // No such file or directory
|
||||||
#define ESRCH 3 // No such process
|
#define ESRCH 3 // No such process
|
||||||
#define EINTR 4 // Interrupted system call
|
#define EINTR 4 // Interrupted system call
|
||||||
#define EIO 5 // Input/output error
|
#define EIO 5 // Input/output error
|
||||||
#define ENXIO 6 // No such device or address
|
#define ENXIO 6 // No such device or address
|
||||||
#define E2BIG 7 // Argument list too long
|
#define E2BIG 7 // Argument list too long
|
||||||
#define ENOEXEC 8 // Exec format error
|
#define ENOEXEC 8 // Exec format error
|
||||||
#define EBADF 9 // Bad file descriptor
|
#define EBADF 9 // Bad file descriptor
|
||||||
#define ECHILD 10 // No child processes
|
#define ECHILD 10 // No child processes
|
||||||
#define EAGAIN 11 // Resource temporarily unavailable
|
#define EAGAIN 11 // Resource temporarily unavailable
|
||||||
#define EWOULDBLOCK 11 // Resource temporarily unavailable
|
#define EWOULDBLOCK 11 // Resource temporarily unavailable
|
||||||
#define ENOMEM 12 // Cannot allocate memory
|
#define ENOMEM 12 // Cannot allocate memory
|
||||||
#define EACCES 13 // Permission denied
|
#define EACCES 13 // Permission denied
|
||||||
#define EFAULT 14 // Bad address
|
#define EFAULT 14 // Bad address
|
||||||
#define ENOTBLK 15 // Block device required
|
#define ENOTBLK 15 // Block device required
|
||||||
#define EBUSY 16 // Device or resource busy
|
#define EBUSY 16 // Device or resource busy
|
||||||
#define EEXIST 17 // File exists
|
#define EEXIST 17 // File exists
|
||||||
#define EXDEV 18 // Invalid cross-device link
|
#define EXDEV 18 // Invalid cross-device link
|
||||||
#define ENODEV 19 // No such device
|
#define ENODEV 19 // No such device
|
||||||
#define ENOTDIR 20 // Not a directory
|
#define ENOTDIR 20 // Not a directory
|
||||||
#define EISDIR 21 // Is a directory
|
#define EISDIR 21 // Is a directory
|
||||||
#define EINVAL 22 // Invalid argument
|
#define EINVAL 22 // Invalid argument
|
||||||
#define ENFILE 23 // Too many open files in system
|
#define ENFILE 23 // Too many open files in system
|
||||||
#define EMFILE 24 // Too many open files
|
#define EMFILE 24 // Too many open files
|
||||||
#define ENOTTY 25 // Inappropriate ioctl for device
|
#define ENOTTY 25 // Inappropriate ioctl for device
|
||||||
#define ETXTBSY 26 // Text file busy
|
#define ETXTBSY 26 // Text file busy
|
||||||
#define EFBIG 27 // File too large
|
#define EFBIG 27 // File too large
|
||||||
#define ENOSPC 28 // No space left on device
|
#define ENOSPC 28 // No space left on device
|
||||||
#define ESPIPE 29 // Illegal seek
|
#define ESPIPE 29 // Illegal seek
|
||||||
#define EROFS 30 // Read-only file system
|
#define EROFS 30 // Read-only file system
|
||||||
#define EMLINK 31 // Too many links
|
#define EMLINK 31 // Too many links
|
||||||
#define EPIPE 32 // Broken pipe
|
#define EPIPE 32 // Broken pipe
|
||||||
#define EDOM 33 // Numerical argument out of domain
|
#define EDOM 33 // Numerical argument out of domain
|
||||||
#define ERANGE 34 // Numerical result out of range
|
#define ERANGE 34 // Numerical result out of range
|
||||||
#define EDEADLK 35 // Resource deadlock avoided
|
#define EDEADLK 35 // Resource deadlock avoided
|
||||||
#define ENAMETOOLONG 36 // File name too long
|
#define ENAMETOOLONG 36 // File name too long
|
||||||
#define ENOLCK 37 // No locks available
|
#define ENOLCK 37 // No locks available
|
||||||
#define ENOSYS 38 // Function not implemented
|
#define ENOSYS 38 // Function not implemented
|
||||||
#define ENOTEMPTY 39 // Directory not empty
|
#define ENOTEMPTY 39 // Directory not empty
|
||||||
#define ELOOP 40 // Too many levels of symbolic links
|
#define ELOOP 40 // Too many levels of symbolic links
|
||||||
#define ENOMSG 42 // No message of desired type
|
#define ENOMSG 42 // No message of desired type
|
||||||
#define EOVERFLOW 75 // Value too large for defined data type
|
#define EOVERFLOW 75 // Value too large for defined data type
|
||||||
#define EILSEQ 84 // Invalid or incomplete multibyte or wide character
|
#define EILSEQ 84 // Invalid or incomplete multibyte or wide character
|
||||||
#define ENOTSOCK 88 // Socket operation on non-socket
|
#define ENOTSOCK 88 // Socket operation on non-socket
|
||||||
#define EDESTADDRREQ 89 // Destination address required
|
#define EDESTADDRREQ 89 // Destination address required
|
||||||
#define EPROTOTYPE 91 // Protocol wrong type for socket
|
#define EMSGSIZE 90 // Message too long
|
||||||
#define ENOTSUP 95 // Operation not supported
|
#define EPROTOTYPE 91 // Protocol wrong type for socket
|
||||||
#define EOPNOTSUPP 95 // Operation not supported
|
#define ENOPROTOOPT 92 // Protocol not available
|
||||||
#define EAFNOSUPPORT 97 // Address family not supported by protocol
|
#define EPROTONOSUPPORT 93 // Protocol not supported
|
||||||
#define EADDRINUSE 98 // Address already in use
|
#define ENOTSUP 95 // Operation not supported
|
||||||
#define EADDRNOTAVAIL 99 // Cannot assign requested address
|
#define EOPNOTSUPP 95 // Operation not supported
|
||||||
#define ENETRESET 102 // Network dropped connection on reset
|
#define EAFNOSUPPORT 97 // Address family not supported by protocol
|
||||||
#define ECONNRESET 104 // Connection reset by peer
|
#define EADDRINUSE 98 // Address already in use
|
||||||
#define EISCONN 106 // Transport endpoint is already connected
|
#define EADDRNOTAVAIL 99 // Cannot assign requested address
|
||||||
#define ENOTCONN 107 // Transport endpoint is not connected
|
#define ENETDOWN 100 // Network is down
|
||||||
#define ETIMEDOUT 110 // Connection timed out
|
#define ENETUNREACH 101 // Network is unreachable
|
||||||
#define ECONNREFUSED 111 // Connection refused
|
#define ENETRESET 102 // Network dropped connection on reset
|
||||||
#define EALREADY 114 // Operation already in progress
|
#define ECONNABORTED 103 // Software caused connection abort
|
||||||
#define EINPROGRESS 115 // Operation now in progress
|
#define ECONNRESET 104 // Connection reset by peer
|
||||||
|
#define ENOBUFS 105 // No buffer space available
|
||||||
|
#define EISCONN 106 // Transport endpoint is already connected
|
||||||
|
#define ENOTCONN 107 // Transport endpoint is not connected
|
||||||
|
#define ETIMEDOUT 110 // Connection timed out
|
||||||
|
#define ECONNREFUSED 111 // Connection refused
|
||||||
|
#define EHOSTUNREACH 113 // No route to host
|
||||||
|
#define EALREADY 114 // Operation already in progress
|
||||||
|
#define EINPROGRESS 115 // Operation now in progress
|
||||||
|
@ -15,6 +15,16 @@ Buffer::Buffer(Buffer&& other) : m_data(other.data()), m_size(other.size())
|
|||||||
other.m_data = nullptr;
|
other.m_data = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Buffer& Buffer::operator=(Buffer&& other)
|
||||||
|
{
|
||||||
|
if (&other == this) return *this;
|
||||||
|
if (m_data) free_impl(m_data);
|
||||||
|
m_data = other.m_data;
|
||||||
|
m_size = other.m_size;
|
||||||
|
other.m_data = nullptr;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
Buffer::~Buffer()
|
Buffer::~Buffer()
|
||||||
{
|
{
|
||||||
if (m_data) free_impl(m_data);
|
if (m_data) free_impl(m_data);
|
||||||
|
@ -17,10 +17,14 @@
|
|||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Otherwise, this is defined in libstdc++.
|
||||||
|
#ifdef USE_FREESTANDING
|
||||||
|
|
||||||
namespace std
|
namespace std
|
||||||
{
|
{
|
||||||
const nothrow_t nothrow;
|
const nothrow_t nothrow;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static constexpr int BLOCK_USED = 1 << 0;
|
static constexpr int BLOCK_USED = 1 << 0;
|
||||||
static constexpr int BLOCK_START_MEM = 1 << 1;
|
static constexpr int BLOCK_START_MEM = 1 << 1;
|
||||||
@ -417,6 +421,8 @@ void dump_heap_usage()
|
|||||||
dbgln("-- Heap memory in use: %zu bytes", alloc_used);
|
dbgln("-- Heap memory in use: %zu bytes", alloc_used);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Otherwise, this is defined in libstdc++.
|
||||||
|
#ifdef USE_FREESTANDING
|
||||||
void* operator new(usize size, const std::nothrow_t&) noexcept
|
void* operator new(usize size, const std::nothrow_t&) noexcept
|
||||||
{
|
{
|
||||||
return malloc_impl(size).value_or(nullptr);
|
return malloc_impl(size).value_or(nullptr);
|
||||||
@ -446,3 +452,4 @@ void operator delete[](void* p, usize) noexcept
|
|||||||
{
|
{
|
||||||
free_impl(p);
|
free_impl(p);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
@ -63,6 +63,14 @@ const char* error_string(int error)
|
|||||||
case EADDRNOTAVAIL: return "Cannot assign requested address";
|
case EADDRNOTAVAIL: return "Cannot assign requested address";
|
||||||
case ECONNREFUSED: return "Connection refused";
|
case ECONNREFUSED: return "Connection refused";
|
||||||
case EINPROGRESS: return "Operation now in progress";
|
case EINPROGRESS: return "Operation now in progress";
|
||||||
|
case ECONNABORTED: return "Software caused connection abort";
|
||||||
|
case EHOSTUNREACH: return "No route to host";
|
||||||
|
case EMSGSIZE: return "Message too long";
|
||||||
|
case ENETDOWN: return "Network is down";
|
||||||
|
case ENETUNREACH: return "Network is unreachable";
|
||||||
|
case ENOBUFS: return "No buffer space available";
|
||||||
|
case ENOPROTOOPT: return "Protocol not available";
|
||||||
|
case EPROTONOSUPPORT: return "Protocol not supported";
|
||||||
default: return "Unknown error";
|
default: return "Unknown error";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -132,6 +140,14 @@ const char* error_name(int error)
|
|||||||
ERROR(EADDRNOTAVAIL);
|
ERROR(EADDRNOTAVAIL);
|
||||||
ERROR(ECONNREFUSED);
|
ERROR(ECONNREFUSED);
|
||||||
ERROR(EINPROGRESS);
|
ERROR(EINPROGRESS);
|
||||||
|
ERROR(ECONNABORTED);
|
||||||
|
ERROR(EHOSTUNREACH);
|
||||||
|
ERROR(EMSGSIZE);
|
||||||
|
ERROR(ENETDOWN);
|
||||||
|
ERROR(ENETUNREACH);
|
||||||
|
ERROR(ENOBUFS);
|
||||||
|
ERROR(ENOPROTOOPT);
|
||||||
|
ERROR(EPROTONOSUPPORT);
|
||||||
default: return nullptr;
|
default: return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,6 +13,9 @@ set(SOURCES
|
|||||||
src/Path.cpp
|
src/Path.cpp
|
||||||
src/Mode.cpp
|
src/Mode.cpp
|
||||||
src/Prompt.cpp
|
src/Prompt.cpp
|
||||||
|
src/Security.cpp
|
||||||
|
src/LocalServer.cpp
|
||||||
|
src/LocalClient.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
add_library(os ${SOURCES})
|
add_library(os ${SOURCES})
|
||||||
|
90
libos/include/os/LocalClient.h
Normal file
90
libos/include/os/LocalClient.h
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <luna/OwnedPtr.h>
|
||||||
|
#include <luna/StringView.h>
|
||||||
|
|
||||||
|
namespace os
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @brief A client used to connect to a local server socket.
|
||||||
|
*/
|
||||||
|
class LocalClient
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Create a new client object and connect it to a local server.
|
||||||
|
*
|
||||||
|
* @param path The path of the server socket to connect to.
|
||||||
|
* @param blocking Whether the client should block if no data is available and recv() is called.
|
||||||
|
* @return Result<OwnedPtr<LocalClient>> An error, or a new client object.
|
||||||
|
*/
|
||||||
|
static Result<OwnedPtr<LocalClient>> connect(StringView path, bool blocking);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return the underlying socket file descriptor used by this object.
|
||||||
|
*
|
||||||
|
* @return int The file descriptor.
|
||||||
|
*/
|
||||||
|
int fd() const
|
||||||
|
{
|
||||||
|
return m_fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read arbitrary data from the server. The call will block if there is no data and this object has not
|
||||||
|
* been created as non-blocking.
|
||||||
|
*
|
||||||
|
* @param buf The buffer to read data into.
|
||||||
|
* @param length The maximum amount of bytes to read.
|
||||||
|
* @return Result<usize> An error, or the number of bytes read.
|
||||||
|
*/
|
||||||
|
Result<usize> recv(u8* buf, usize length);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read an object from the server. The call will block if there is no data and this object has not been
|
||||||
|
* created as non-blocking.
|
||||||
|
*
|
||||||
|
* @tparam T The type of the object.
|
||||||
|
* @param out A reference to the object to read data into.
|
||||||
|
* @return Result<void> Whether the operation succeded.
|
||||||
|
*/
|
||||||
|
template <typename T> Result<void> recv_typed(T& out)
|
||||||
|
{
|
||||||
|
TRY(recv((u8*)&out, sizeof(T)));
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Send arbitrary data to the server.
|
||||||
|
*
|
||||||
|
* @param buf The buffer to send data from.
|
||||||
|
* @param length The amount of bytes to send.
|
||||||
|
* @return Result<usize> An error, or the number of bytes actually sent.
|
||||||
|
*/
|
||||||
|
Result<usize> send(const u8* buf, usize length);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Send an object to the server.
|
||||||
|
*
|
||||||
|
* @tparam T The type of the object.
|
||||||
|
* @param out A reference to the object to send data from.
|
||||||
|
* @return Result<void> Whether the operation succeded.
|
||||||
|
*/
|
||||||
|
template <typename T> Result<void> send_typed(const T& out)
|
||||||
|
{
|
||||||
|
TRY(send((const u8*)&out, sizeof(T)));
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Disconnect from the attached server.
|
||||||
|
*
|
||||||
|
* This will make any further reads on this connection return ECONNRESET, and will make this object invalid.
|
||||||
|
*/
|
||||||
|
void disconnect();
|
||||||
|
|
||||||
|
~LocalClient();
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_fd;
|
||||||
|
};
|
||||||
|
}
|
133
libos/include/os/LocalServer.h
Normal file
133
libos/include/os/LocalServer.h
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <luna/OwnedPtr.h>
|
||||||
|
#include <luna/Result.h>
|
||||||
|
#include <luna/StringView.h>
|
||||||
|
|
||||||
|
namespace os
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @brief A local domain server, used to communicate between processes on the same machine.
|
||||||
|
*/
|
||||||
|
class LocalServer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Create a new server object and bind it to a local address.
|
||||||
|
*
|
||||||
|
* @param path The path to use for the server socket.
|
||||||
|
* @param blocking Whether the server should block if no connections are available when calling accept().
|
||||||
|
* @return Result<OwnedPtr<LocalServer>> An error, or a new server object.
|
||||||
|
*/
|
||||||
|
static Result<OwnedPtr<LocalServer>> create(StringView path, bool blocking);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Activate the server and start listening for connections.
|
||||||
|
*
|
||||||
|
* @param backlog The number of unaccepted connections to keep.
|
||||||
|
* @return Result<void> Whether the operation succeded.
|
||||||
|
*/
|
||||||
|
Result<void> listen(int backlog);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return the underlying socket file descriptor used by this object.
|
||||||
|
*
|
||||||
|
* @return int The file descriptor.
|
||||||
|
*/
|
||||||
|
int fd() const
|
||||||
|
{
|
||||||
|
return m_fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief An interface to communicate with clients connected to a local server.
|
||||||
|
*/
|
||||||
|
class Client
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Read arbitrary data from the client. The call will block if there is no data and the parent server
|
||||||
|
* object has not been created as non-blocking.
|
||||||
|
*
|
||||||
|
* @param buf The buffer to read data into.
|
||||||
|
* @param length The maximum amount of bytes to read.
|
||||||
|
* @return Result<usize> An error, or the number of bytes read.
|
||||||
|
*/
|
||||||
|
Result<usize> recv(u8* buf, usize length);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read an object from the client. The call will block if there is no data and the parent server
|
||||||
|
* object has not been created as non-blocking.
|
||||||
|
*
|
||||||
|
* @tparam T The type of the object.
|
||||||
|
* @param out A reference to the object to read data into.
|
||||||
|
* @return Result<void> Whether the operation succeded.
|
||||||
|
*/
|
||||||
|
template <typename T> Result<void> recv_typed(T& out)
|
||||||
|
{
|
||||||
|
TRY(recv((u8*)&out, sizeof(T)));
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Send arbitrary data to the client.
|
||||||
|
*
|
||||||
|
* @param buf The buffer to send data from.
|
||||||
|
* @param length The amount of bytes to send.
|
||||||
|
* @return Result<usize> An error, or the number of bytes actually sent.
|
||||||
|
*/
|
||||||
|
Result<usize> send(const u8* buf, usize length);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Send an object to the client.
|
||||||
|
*
|
||||||
|
* @tparam T The type of the object.
|
||||||
|
* @param out A reference to the object to send data from.
|
||||||
|
* @return Result<void> Whether the operation succeded.
|
||||||
|
*/
|
||||||
|
template <typename T> Result<void> send_typed(const T& out)
|
||||||
|
{
|
||||||
|
TRY(send((const u8*)&out, sizeof(T)));
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Disconnect from the attached client.
|
||||||
|
*
|
||||||
|
* This will make any further reads on the client return ECONNRESET, and will make this object invalid.
|
||||||
|
*/
|
||||||
|
void disconnect();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return the underlying socket file descriptor used by this object.
|
||||||
|
*
|
||||||
|
* @return int The file descriptor.
|
||||||
|
*/
|
||||||
|
int fd() const
|
||||||
|
{
|
||||||
|
return m_fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
Client(Client&& other);
|
||||||
|
Client(int fd);
|
||||||
|
~Client();
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_fd;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Accept a new incoming connection and return a handle to it. If there are no incoming connections,
|
||||||
|
* accept() either blocks until there is one (if the object was created with blocking=true), or returns EAGAIN
|
||||||
|
* (if the object was created with blocking=false).
|
||||||
|
*
|
||||||
|
* @return Result<Client> An error, or a handle to the new connection.
|
||||||
|
*/
|
||||||
|
Result<Client> accept();
|
||||||
|
|
||||||
|
~LocalServer();
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_fd;
|
||||||
|
bool m_blocking;
|
||||||
|
};
|
||||||
|
}
|
48
libos/include/os/Security.h
Normal file
48
libos/include/os/Security.h
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
/**
|
||||||
|
* @file Security.h
|
||||||
|
* @author apio (cloudapio.eu)
|
||||||
|
* @brief Functions to restrict process operations.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2023, the Luna authors.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <luna/Result.h>
|
||||||
|
|
||||||
|
namespace os
|
||||||
|
{
|
||||||
|
namespace Security
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @brief Restrict system operations.
|
||||||
|
*
|
||||||
|
* The pledge() call, borrowed from OpenBSD, is a simple function to sandbox a process effectively.
|
||||||
|
*
|
||||||
|
* Syscalls are divided into a number of categories ("promises"), the following are the ones implemented on
|
||||||
|
* Luna: stdio rpath wpath cpath fattr chown unix tty proc exec prot_exec id mount signal host error
|
||||||
|
*
|
||||||
|
* The way pledge() works is: the process "tells" the kernel which subset of functions it will use, and if it
|
||||||
|
* suddenly uses something it has not promised (probably because the process was hacked, using ROP or something
|
||||||
|
* else) the kernel kills the process immediately with an uncatchable SIGABRT. Alternatively, if the process has
|
||||||
|
* pledged the "error" promise, the call will fail with ENOSYS.
|
||||||
|
*
|
||||||
|
* Pledges are not inherited across exec, although one may specify another set of promises to apply on the next
|
||||||
|
* execve() call. Thus, pledge() is not a way to restrict untrusted programs (unless the "exec" pledge is
|
||||||
|
* removed), but more of a way to protect trusted local programs from vulnerabilities.
|
||||||
|
*
|
||||||
|
* One may call pledge() several times, but only to remove promises, not to add them.
|
||||||
|
*
|
||||||
|
* A typical call to pledge would look like this:
|
||||||
|
*
|
||||||
|
* TRY(os::Security::pledge("stdio rpath wpath unix proc", nullptr));
|
||||||
|
*
|
||||||
|
* @param promises The promises to apply immediately, separated by spaces. If empty, the process may only call
|
||||||
|
* _exit(2). If NULL, the promises are not changed.
|
||||||
|
* @param execpromises The promises to apply on the next call to execve(2), separated by spaces. If empty, the
|
||||||
|
* process may only call _exit(2). If NULL, the execpromises are not changed.
|
||||||
|
* @return Result<void> Whether the operation succeded.
|
||||||
|
*/
|
||||||
|
Result<void> pledge(const char* promises, const char* execpromises);
|
||||||
|
}
|
||||||
|
}
|
59
libos/src/LocalClient.cpp
Normal file
59
libos/src/LocalClient.cpp
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <os/LocalClient.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
namespace os
|
||||||
|
{
|
||||||
|
Result<OwnedPtr<LocalClient>> LocalClient::connect(StringView path, bool blocking)
|
||||||
|
{
|
||||||
|
auto client = TRY(make_owned<LocalClient>());
|
||||||
|
|
||||||
|
int sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
|
if (sockfd < 0) return err(errno);
|
||||||
|
|
||||||
|
struct sockaddr_un un;
|
||||||
|
un.sun_family = AF_UNIX;
|
||||||
|
strncpy(un.sun_path, path.chars(), sizeof(un.sun_path));
|
||||||
|
|
||||||
|
if (::connect(sockfd, (struct sockaddr*)&un, sizeof(un)) < 0)
|
||||||
|
{
|
||||||
|
close(sockfd);
|
||||||
|
return err(errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!blocking) { fcntl(sockfd, F_SETFL, O_NONBLOCK); }
|
||||||
|
|
||||||
|
fcntl(sockfd, F_SETFD, FD_CLOEXEC);
|
||||||
|
|
||||||
|
client->m_fd = sockfd;
|
||||||
|
return client;
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalClient::~LocalClient()
|
||||||
|
{
|
||||||
|
close(m_fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<usize> LocalClient::recv(u8* buf, usize length)
|
||||||
|
{
|
||||||
|
ssize_t nread = read(m_fd, buf, length);
|
||||||
|
if (nread < 0) return err(errno);
|
||||||
|
return nread;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<usize> LocalClient::send(const u8* buf, usize length)
|
||||||
|
{
|
||||||
|
ssize_t nwrite = write(m_fd, buf, length);
|
||||||
|
if (nwrite < 0) return err(errno);
|
||||||
|
return nwrite;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LocalClient::disconnect()
|
||||||
|
{
|
||||||
|
close(m_fd);
|
||||||
|
m_fd = -1;
|
||||||
|
}
|
||||||
|
}
|
92
libos/src/LocalServer.cpp
Normal file
92
libos/src/LocalServer.cpp
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <os/FileSystem.h>
|
||||||
|
#include <os/LocalServer.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
namespace os
|
||||||
|
{
|
||||||
|
Result<OwnedPtr<LocalServer>> LocalServer::create(StringView path, bool blocking)
|
||||||
|
{
|
||||||
|
auto server = TRY(make_owned<LocalServer>());
|
||||||
|
|
||||||
|
(void)os::FileSystem::remove(path); // We explicitly ignore any error here, either it doesn't exist (which is
|
||||||
|
// fine), or it cannot be removed, which will make bind() fail later.
|
||||||
|
|
||||||
|
int sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
|
if (sockfd < 0) return err(errno);
|
||||||
|
|
||||||
|
struct sockaddr_un un;
|
||||||
|
un.sun_family = AF_UNIX;
|
||||||
|
strncpy(un.sun_path, path.chars(), sizeof(un.sun_path));
|
||||||
|
|
||||||
|
if (bind(sockfd, (struct sockaddr*)&un, sizeof(un)) < 0)
|
||||||
|
{
|
||||||
|
close(sockfd);
|
||||||
|
return err(errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!blocking) { fcntl(sockfd, F_SETFL, O_NONBLOCK); }
|
||||||
|
server->m_blocking = blocking;
|
||||||
|
|
||||||
|
fcntl(sockfd, F_SETFD, FD_CLOEXEC);
|
||||||
|
|
||||||
|
server->m_fd = sockfd;
|
||||||
|
return server;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void> LocalServer::listen(int backlog)
|
||||||
|
{
|
||||||
|
if (::listen(m_fd, backlog) < 0) return err(errno);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<LocalServer::Client> LocalServer::accept()
|
||||||
|
{
|
||||||
|
int fd = ::accept(m_fd, nullptr, nullptr);
|
||||||
|
if (fd < 0) return err(errno);
|
||||||
|
if (!m_blocking) fcntl(fd, F_SETFL, O_NONBLOCK);
|
||||||
|
return Client { fd };
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalServer::~LocalServer()
|
||||||
|
{
|
||||||
|
close(m_fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalServer::Client::Client(Client&& other) : m_fd(other.m_fd)
|
||||||
|
{
|
||||||
|
other.m_fd = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalServer::Client::Client(int fd) : m_fd(fd)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalServer::Client::~Client()
|
||||||
|
{
|
||||||
|
if (m_fd >= 0) close(m_fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<usize> LocalServer::Client::recv(u8* buf, usize length)
|
||||||
|
{
|
||||||
|
ssize_t nread = read(m_fd, buf, length);
|
||||||
|
if (nread < 0) return err(errno);
|
||||||
|
return nread;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<usize> LocalServer::Client::send(const u8* buf, usize length)
|
||||||
|
{
|
||||||
|
ssize_t nwrite = write(m_fd, buf, length);
|
||||||
|
if (nwrite < 0) return err(errno);
|
||||||
|
return nwrite;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LocalServer::Client::disconnect()
|
||||||
|
{
|
||||||
|
close(m_fd);
|
||||||
|
m_fd = -1;
|
||||||
|
}
|
||||||
|
}
|
22
libos/src/Security.cpp
Normal file
22
libos/src/Security.cpp
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
/**
|
||||||
|
* @file Security.cpp
|
||||||
|
* @author apio (cloudapio.eu)
|
||||||
|
* @brief Functions to restrict process operations.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2023, the Luna authors.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <os/Security.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
namespace os::Security
|
||||||
|
{
|
||||||
|
Result<void> pledge(const char* promises, const char* execpromises)
|
||||||
|
{
|
||||||
|
int rc = ::pledge(promises, execpromises);
|
||||||
|
if (rc < 0) return err(errno);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
17
libui/CMakeLists.txt
Normal file
17
libui/CMakeLists.txt
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
# The UI and graphics library for Luna.
|
||||||
|
|
||||||
|
file(GLOB HEADERS include/ui/*.h)
|
||||||
|
|
||||||
|
set(SOURCES
|
||||||
|
${HEADERS}
|
||||||
|
src/Canvas.cpp
|
||||||
|
src/Rect.cpp
|
||||||
|
src/Font.cpp
|
||||||
|
src/Image.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
add_library(ui ${SOURCES})
|
||||||
|
target_compile_options(ui PRIVATE ${COMMON_FLAGS} -fno-threadsafe-statics)
|
||||||
|
target_include_directories(ui PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include/)
|
||||||
|
target_include_directories(ui PUBLIC ${LUNA_BASE}/usr/include)
|
||||||
|
target_link_libraries(ui PUBLIC os)
|
64
libui/include/ui/Canvas.h
Normal file
64
libui/include/ui/Canvas.h
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <luna/Result.h>
|
||||||
|
#include <luna/Types.h>
|
||||||
|
#include <ui/Color.h>
|
||||||
|
#include <ui/Point.h>
|
||||||
|
#include <ui/Rect.h>
|
||||||
|
|
||||||
|
namespace ui
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @brief A drawable surface.
|
||||||
|
*/
|
||||||
|
struct Canvas
|
||||||
|
{
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
int stride;
|
||||||
|
u8* ptr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create a new Canvas object.
|
||||||
|
*
|
||||||
|
* @param ptr The memory to use for the canvas. It must be of at least width * height * 4 bytes of length.
|
||||||
|
* @param width The width of the canvas.
|
||||||
|
* @param height The height of the canvas.
|
||||||
|
* @return Canvas The new Canvas object.
|
||||||
|
*/
|
||||||
|
static Canvas create(u8* ptr, int width, int height);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return a new Canvas that represents a subsection of the current one.
|
||||||
|
*
|
||||||
|
* @param rect The dimensions of the new canvas. If these exceed the bounds of the current canvas, they will be
|
||||||
|
* clamped.
|
||||||
|
* @return Canvas The new Canvas object.
|
||||||
|
*/
|
||||||
|
Canvas subcanvas(Rect rect);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return the dimensions of the current canvas.
|
||||||
|
*
|
||||||
|
* @return Rect This canvas's dimensions, as a Rect object.
|
||||||
|
*/
|
||||||
|
Rect rect()
|
||||||
|
{
|
||||||
|
return Rect { .pos = { 0, 0 }, .width = width, .height = height };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Fill the entire canvas with one color.
|
||||||
|
*
|
||||||
|
* @param color The color to use.
|
||||||
|
*/
|
||||||
|
void fill(Color color);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Fill the canvas with pixels.
|
||||||
|
*
|
||||||
|
* @param pixels The array of pixels (must be at least width*height).
|
||||||
|
* @param stride The number of pixels to skip to go to the next line.
|
||||||
|
*/
|
||||||
|
void fill(u32* pixels, int stride);
|
||||||
|
};
|
||||||
|
};
|
104
libui/include/ui/Color.h
Normal file
104
libui/include/ui/Color.h
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <luna/Types.h>
|
||||||
|
|
||||||
|
namespace ui
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @brief A 32-bit ARGB color.
|
||||||
|
*/
|
||||||
|
struct Color
|
||||||
|
{
|
||||||
|
union {
|
||||||
|
u32 raw;
|
||||||
|
u8 colors[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return the blue value of this color.
|
||||||
|
*
|
||||||
|
* @return constexpr u8 The blue value.
|
||||||
|
*/
|
||||||
|
constexpr u8 red() const
|
||||||
|
{
|
||||||
|
return colors[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return the green value of this color.
|
||||||
|
*
|
||||||
|
* @return constexpr u8 The green value.
|
||||||
|
*/
|
||||||
|
constexpr u8 green() const
|
||||||
|
{
|
||||||
|
return colors[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return the blue value of this color.
|
||||||
|
*
|
||||||
|
* @return constexpr u8 The blue value.
|
||||||
|
*/
|
||||||
|
constexpr u8 blue() const
|
||||||
|
{
|
||||||
|
return colors[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return the alpha value of this color.
|
||||||
|
*
|
||||||
|
* @return constexpr u8 The alpha value.
|
||||||
|
*/
|
||||||
|
constexpr u8 alpha() const
|
||||||
|
{
|
||||||
|
return colors[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Construct a new color from a 32-bit ARGB integer.
|
||||||
|
*
|
||||||
|
* @param raw The integer representing the color.
|
||||||
|
* @return constexpr Color The new color.
|
||||||
|
*/
|
||||||
|
static constexpr Color from_u32(u32 raw)
|
||||||
|
{
|
||||||
|
return Color { .raw = raw };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Construct a new color from its separate RGBA values (from 0 to 255).
|
||||||
|
*
|
||||||
|
* @param red The red value.
|
||||||
|
* @param green The green value.
|
||||||
|
* @param blue The blue value.
|
||||||
|
* @param alpha The alpha value.
|
||||||
|
* @return constexpr Color The new color.
|
||||||
|
*/
|
||||||
|
static constexpr Color from_rgba(u8 red, u8 green, u8 blue, u8 alpha)
|
||||||
|
{
|
||||||
|
return Color { .colors = { blue, green, red, alpha } };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Construct a new color from its separate RGB values (from 0 to 255).
|
||||||
|
*
|
||||||
|
* @param red The red value.
|
||||||
|
* @param green The green value.
|
||||||
|
* @param blue The blue value.
|
||||||
|
* @return constexpr Color The new color.
|
||||||
|
*/
|
||||||
|
static constexpr Color from_rgb(u8 red, u8 green, u8 blue)
|
||||||
|
{
|
||||||
|
return from_rgba(red, green, blue, 0xff);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static constexpr Color WHITE = Color::from_rgb(0xff, 0xff, 0xff);
|
||||||
|
static constexpr Color BLACK = Color::from_rgb(0x00, 0x00, 0x00);
|
||||||
|
static constexpr Color GRAY = Color::from_rgb(0x80, 0x80, 0x80);
|
||||||
|
|
||||||
|
static constexpr Color BLUE = Color::from_rgb(0x00, 0x00, 0xff);
|
||||||
|
static constexpr Color GREEN = Color::from_rgb(0x00, 0xff, 0x00);
|
||||||
|
static constexpr Color RED = Color::from_rgb(0xff, 0x00, 0x00);
|
||||||
|
|
||||||
|
static constexpr Color CYAN = Color::from_rgb(0x00, 0xff, 0xff);
|
||||||
|
};
|
111
libui/include/ui/Font.h
Normal file
111
libui/include/ui/Font.h
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <luna/Buffer.h>
|
||||||
|
#include <luna/SharedPtr.h>
|
||||||
|
#include <os/Path.h>
|
||||||
|
#include <ui/Canvas.h>
|
||||||
|
|
||||||
|
#define PSF_FONT_MAGIC 0x864ab572
|
||||||
|
|
||||||
|
namespace ui
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @brief A class holding PSF font data, used for direct rendering of glyphs into a canvas.
|
||||||
|
*/
|
||||||
|
class Font : public Shareable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief An enum used to select a font weight when loading a font.
|
||||||
|
*/
|
||||||
|
enum FontWeight
|
||||||
|
{
|
||||||
|
Regular,
|
||||||
|
Bold,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Load a Font object from a font file.
|
||||||
|
*
|
||||||
|
* @param path The full path to the font file.
|
||||||
|
* @return Result<SharedPtr<Font>> An error, or the loaded Font object.
|
||||||
|
*/
|
||||||
|
static Result<SharedPtr<Font>> load(const os::Path& path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Load a system font by name.
|
||||||
|
*
|
||||||
|
* @param name The name of the font to load (the default system font is "Tamsyn").
|
||||||
|
* @param weight The weight of the font (regular or bold).
|
||||||
|
* @return Result<SharedPtr<Font>> An error, or the loaded Font object.
|
||||||
|
*/
|
||||||
|
static Result<SharedPtr<Font>> load_builtin(StringView name, FontWeight weight);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return a pointer to the system's default font.
|
||||||
|
*
|
||||||
|
* @return SharedPtr<Font> The default font.
|
||||||
|
*/
|
||||||
|
static SharedPtr<Font> default_font();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return a pointer to the system's default bold font.
|
||||||
|
*
|
||||||
|
* @return SharedPtr<Font> The default bold font.
|
||||||
|
*/
|
||||||
|
static SharedPtr<Font> default_bold_font();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Render a single Unicode code point onto a canvas, using this font's glyphs.
|
||||||
|
*
|
||||||
|
* @param codepoint The code point to render.
|
||||||
|
* @param color The color to draw the code point in.
|
||||||
|
* @param canvas The canvas to use.
|
||||||
|
*/
|
||||||
|
void render(wchar_t codepoint, ui::Color color, ui::Canvas& canvas);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Render a Unicode text string onto a canvas, using this font's glyphs.
|
||||||
|
*
|
||||||
|
* @param text The string to render (must be null-terminated).
|
||||||
|
* @param color The color to draw the code point in.
|
||||||
|
* @param canvas The canvas to use.
|
||||||
|
*/
|
||||||
|
void render(const wchar_t* text, ui::Color color, ui::Canvas& canvas);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return the width of this font's glyphs.
|
||||||
|
*
|
||||||
|
* @return int The width.
|
||||||
|
*/
|
||||||
|
int width() const
|
||||||
|
{
|
||||||
|
return m_psf_header.width;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return the height of this font's glyphs.
|
||||||
|
*
|
||||||
|
* @return int The height.
|
||||||
|
*/
|
||||||
|
int height() const
|
||||||
|
{
|
||||||
|
return m_psf_header.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct PSFHeader
|
||||||
|
{
|
||||||
|
u32 magic;
|
||||||
|
u32 version; // zero
|
||||||
|
u32 headersize;
|
||||||
|
u32 flags; // 0 if there's no unicode table
|
||||||
|
u32 numglyph;
|
||||||
|
u32 bytesperglyph;
|
||||||
|
int height;
|
||||||
|
int width;
|
||||||
|
};
|
||||||
|
|
||||||
|
PSFHeader m_psf_header;
|
||||||
|
Buffer m_font_data;
|
||||||
|
};
|
||||||
|
};
|
71
libui/include/ui/Image.h
Normal file
71
libui/include/ui/Image.h
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <luna/Buffer.h>
|
||||||
|
#include <luna/SharedPtr.h>
|
||||||
|
#include <os/Path.h>
|
||||||
|
|
||||||
|
namespace ui
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @brief An image in the TGA file format.
|
||||||
|
*/
|
||||||
|
class Image : public Shareable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Load a new TGA image from a file.
|
||||||
|
*
|
||||||
|
* @param path The path to open.
|
||||||
|
* @return Result<SharedPtr<Image>> An error, or a new Image object.
|
||||||
|
*/
|
||||||
|
static Result<SharedPtr<Image>> load(const os::Path& path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return the array of pixels contained in the image.
|
||||||
|
*
|
||||||
|
* @return u32* The array of pixels.
|
||||||
|
*/
|
||||||
|
u32* pixels()
|
||||||
|
{
|
||||||
|
return (u32*)m_image_data.data();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return the width of the image.
|
||||||
|
*
|
||||||
|
* @return u16 The width.
|
||||||
|
*/
|
||||||
|
u16 width()
|
||||||
|
{
|
||||||
|
return m_tga_header.w;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return the height of the image.
|
||||||
|
*
|
||||||
|
* @return u16 The height.
|
||||||
|
*/
|
||||||
|
u16 height()
|
||||||
|
{
|
||||||
|
return m_tga_header.h;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct [[gnu::packed]] TGAHeader
|
||||||
|
{
|
||||||
|
u8 idlen;
|
||||||
|
u8 colormap;
|
||||||
|
u8 encoding;
|
||||||
|
u16 cmaporig, cmaplen;
|
||||||
|
u8 cmapent;
|
||||||
|
u16 x;
|
||||||
|
u16 y;
|
||||||
|
u16 w;
|
||||||
|
u16 h;
|
||||||
|
u8 bpp;
|
||||||
|
u8 pixeltype;
|
||||||
|
};
|
||||||
|
|
||||||
|
TGAHeader m_tga_header;
|
||||||
|
Buffer m_image_data;
|
||||||
|
};
|
||||||
|
}
|
13
libui/include/ui/Point.h
Normal file
13
libui/include/ui/Point.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace ui
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @brief A point in 2D space.
|
||||||
|
*/
|
||||||
|
struct Point
|
||||||
|
{
|
||||||
|
int x { 0 };
|
||||||
|
int y { 0 };
|
||||||
|
};
|
||||||
|
}
|
72
libui/include/ui/Rect.h
Normal file
72
libui/include/ui/Rect.h
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <ui/Point.h>
|
||||||
|
|
||||||
|
namespace ui
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @brief A simple rectangle.
|
||||||
|
*/
|
||||||
|
struct Rect
|
||||||
|
{
|
||||||
|
Point pos;
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if a point is contained in this rectangle.
|
||||||
|
*
|
||||||
|
* @param point The point to check.
|
||||||
|
* @return true The point is contained inside the rectangle.
|
||||||
|
* @return false The point is not contained inside the rectangle.
|
||||||
|
*/
|
||||||
|
bool contains(Point point);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if another rectangle is contained in this one.
|
||||||
|
*
|
||||||
|
* @param point The rectangle to check.
|
||||||
|
* @return true The other rectangle is contained inside this one.
|
||||||
|
* @return false The other rectangle is not contained inside this one.
|
||||||
|
*/
|
||||||
|
bool contains(Rect rect);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Normalize a point to fit inside this rectangle.
|
||||||
|
*
|
||||||
|
* @param point The original point.
|
||||||
|
* @return Point The normalized point.
|
||||||
|
*/
|
||||||
|
Point normalize(Point point);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Transform an absolute position to a position relative to this rectangle.
|
||||||
|
*
|
||||||
|
* @param pos The original absolute position.
|
||||||
|
* @return Point The position relative to this rectangle.
|
||||||
|
*/
|
||||||
|
Point relative(Point pos);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Transform a position relative to this rectangle to an absolute position.
|
||||||
|
*
|
||||||
|
* @param pos The original relative position.
|
||||||
|
* @return Point The absolute position.
|
||||||
|
*/
|
||||||
|
Point absolute(Point pos);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Transform another rectangle relative to this one to an absolute rectangle.
|
||||||
|
*
|
||||||
|
* @param rect The original relative rectangle.
|
||||||
|
* @return Point The absolute rectangle.
|
||||||
|
*/
|
||||||
|
Rect absolute(Rect rect);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return a copy of this rectangle with no negative values (normalized to 0).
|
||||||
|
*
|
||||||
|
* @return Rect The new rectangle.
|
||||||
|
*/
|
||||||
|
Rect normalized();
|
||||||
|
};
|
||||||
|
}
|
53
libui/src/Canvas.cpp
Normal file
53
libui/src/Canvas.cpp
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
#include <ui/Canvas.h>
|
||||||
|
|
||||||
|
namespace ui
|
||||||
|
{
|
||||||
|
Canvas Canvas::create(u8* ptr, int width, int height)
|
||||||
|
{
|
||||||
|
return Canvas { .width = width, .height = height, .stride = width, .ptr = ptr };
|
||||||
|
}
|
||||||
|
|
||||||
|
Canvas Canvas::subcanvas(Rect rect)
|
||||||
|
{
|
||||||
|
if (rect.pos.x < 0) rect.pos.x = 0;
|
||||||
|
if (rect.pos.y < 0) rect.pos.y = 0;
|
||||||
|
if (rect.pos.x + rect.width > width) rect.width = width - rect.pos.x;
|
||||||
|
if (rect.pos.y + rect.height > height) rect.height = height - rect.pos.y;
|
||||||
|
|
||||||
|
u8* p = ptr + rect.pos.x * sizeof(Color) + (rect.pos.y * sizeof(Color) * stride);
|
||||||
|
|
||||||
|
return Canvas { .width = rect.width, .height = rect.height, .stride = stride, .ptr = p };
|
||||||
|
}
|
||||||
|
|
||||||
|
void Canvas::fill(Color color)
|
||||||
|
{
|
||||||
|
u8* p = ptr;
|
||||||
|
for (int i = 0; i < height; i++)
|
||||||
|
{
|
||||||
|
u32* colorp = (u32*)p;
|
||||||
|
for (int j = 0; j < width; j++)
|
||||||
|
{
|
||||||
|
*colorp = color.raw;
|
||||||
|
colorp++;
|
||||||
|
}
|
||||||
|
p += stride * sizeof(Color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Canvas::fill(u32* pixels, int _stride)
|
||||||
|
{
|
||||||
|
u8* p = ptr;
|
||||||
|
for (int i = 0; i < height; i++)
|
||||||
|
{
|
||||||
|
u32* colorp = (u32*)p;
|
||||||
|
for (int j = 0; j < width; j++)
|
||||||
|
{
|
||||||
|
u32 pix = pixels[j];
|
||||||
|
if (Color::from_u32(pix).alpha() == 0xff) *colorp = pix;
|
||||||
|
colorp++;
|
||||||
|
}
|
||||||
|
pixels += _stride;
|
||||||
|
p += stride * sizeof(Color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
112
libui/src/Font.cpp
Normal file
112
libui/src/Font.cpp
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
#include <luna/String.h>
|
||||||
|
#include <os/File.h>
|
||||||
|
#include <ui/Font.h>
|
||||||
|
|
||||||
|
constexpr static int BYTES_PER_PIXEL = (int)sizeof(ui::Color);
|
||||||
|
|
||||||
|
namespace ui
|
||||||
|
{
|
||||||
|
Result<SharedPtr<Font>> Font::load(const os::Path& path)
|
||||||
|
{
|
||||||
|
auto font = TRY(make_shared<Font>());
|
||||||
|
|
||||||
|
auto file = TRY(os::File::open(path, os::File::ReadOnly));
|
||||||
|
|
||||||
|
TRY(file->read_typed(font->m_psf_header));
|
||||||
|
|
||||||
|
if (font->m_psf_header.magic != PSF_FONT_MAGIC)
|
||||||
|
{
|
||||||
|
os::eprintln("ui::Font::load(%s) failed: font magic does not match PSF2 magic", path.name().chars());
|
||||||
|
return err(ENOTSUP);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (font->m_psf_header.version != 0)
|
||||||
|
{
|
||||||
|
os::eprintln("ui::Font::load(%s) failed: font version is unsupported", path.name().chars());
|
||||||
|
return err(ENOTSUP);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (font->m_psf_header.flags)
|
||||||
|
{
|
||||||
|
os::eprintln("ui::Font::load(%s) warning: font has a unicode table, which we're ignoring",
|
||||||
|
path.name().chars());
|
||||||
|
// todo(); // Font has a unicode table, oh no!
|
||||||
|
}
|
||||||
|
|
||||||
|
font->m_font_data = TRY(file->read_all()); // Read the rest of the file into the font data buffer.
|
||||||
|
|
||||||
|
return font;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<SharedPtr<Font>> Font::load_builtin(StringView name, FontWeight weight)
|
||||||
|
{
|
||||||
|
auto path = TRY(String::format("/usr/share/fonts/%s-%s.psf"_sv, name.chars(),
|
||||||
|
weight == FontWeight::Bold ? "Bold" : "Regular"));
|
||||||
|
|
||||||
|
return load(path.view());
|
||||||
|
}
|
||||||
|
|
||||||
|
SharedPtr<Font> Font::default_font()
|
||||||
|
{
|
||||||
|
static SharedPtr<ui::Font> s_default_font = {};
|
||||||
|
if (!s_default_font) s_default_font = load("/usr/share/fonts/Tamsyn-Regular.psf").release_value();
|
||||||
|
return s_default_font;
|
||||||
|
}
|
||||||
|
|
||||||
|
SharedPtr<Font> Font::default_bold_font()
|
||||||
|
{
|
||||||
|
static SharedPtr<ui::Font> s_default_bold_font = {};
|
||||||
|
if (!s_default_bold_font) s_default_bold_font = load("/usr/share/fonts/Tamsyn-Bold.psf").release_value();
|
||||||
|
return s_default_bold_font;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Font::render(wchar_t codepoint, ui::Color color, ui::Canvas& canvas)
|
||||||
|
{
|
||||||
|
const wchar_t str[] = { codepoint, 0 };
|
||||||
|
render(str, color, canvas);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Font::render(const wchar_t* text, ui::Color color, ui::Canvas& canvas)
|
||||||
|
{
|
||||||
|
usize len = wcslen(text);
|
||||||
|
|
||||||
|
int height = m_psf_header.height;
|
||||||
|
int width = m_psf_header.width;
|
||||||
|
int last_char_width = width;
|
||||||
|
|
||||||
|
if (canvas.width < (m_psf_header.width * static_cast<int>(len)))
|
||||||
|
{
|
||||||
|
len = (canvas.width / width) + 1;
|
||||||
|
last_char_width = canvas.width % width;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (canvas.height < height) height = canvas.height;
|
||||||
|
|
||||||
|
const int bytes_per_line = (m_psf_header.width + 7) / 8;
|
||||||
|
|
||||||
|
for (usize i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
if (i + 1 == len) width = last_char_width;
|
||||||
|
wchar_t codepoint = text[i];
|
||||||
|
|
||||||
|
u8* glyph =
|
||||||
|
m_font_data.data() + (codepoint > 0 && codepoint < (wchar_t)m_psf_header.numglyph ? codepoint : 0) *
|
||||||
|
m_psf_header.bytesperglyph;
|
||||||
|
|
||||||
|
u32 offset = (u32)i * m_psf_header.width * BYTES_PER_PIXEL;
|
||||||
|
for (int y = 0; y < height; y++)
|
||||||
|
{
|
||||||
|
u32 line = offset;
|
||||||
|
int mask = 1 << (m_psf_header.width - 1);
|
||||||
|
for (int x = 0; x < width; x++)
|
||||||
|
{
|
||||||
|
if (*((u32*)glyph) & mask) *(u32*)(canvas.ptr + line) = color.raw;
|
||||||
|
mask >>= 1;
|
||||||
|
line += BYTES_PER_PIXEL;
|
||||||
|
}
|
||||||
|
glyph += bytes_per_line;
|
||||||
|
offset += canvas.stride * BYTES_PER_PIXEL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
24
libui/src/Image.cpp
Normal file
24
libui/src/Image.cpp
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#include <os/File.h>
|
||||||
|
#include <ui/Image.h>
|
||||||
|
|
||||||
|
namespace ui
|
||||||
|
{
|
||||||
|
Result<SharedPtr<Image>> Image::load(const os::Path& path)
|
||||||
|
{
|
||||||
|
auto image = TRY(make_shared<Image>());
|
||||||
|
auto file = TRY(os::File::open(path, os::File::ReadOnly));
|
||||||
|
|
||||||
|
TRY(file->read_typed(image->m_tga_header));
|
||||||
|
|
||||||
|
if (image->m_tga_header.encoding != 2) todo();
|
||||||
|
if (image->m_tga_header.bpp != 32) todo();
|
||||||
|
|
||||||
|
Buffer image_id;
|
||||||
|
TRY(file->read(image_id, image->m_tga_header.idlen));
|
||||||
|
|
||||||
|
TRY(file->read(image->m_image_data,
|
||||||
|
image->m_tga_header.w * image->m_tga_header.h * (image->m_tga_header.bpp / 8)));
|
||||||
|
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
}
|
53
libui/src/Rect.cpp
Normal file
53
libui/src/Rect.cpp
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
#include <ui/Rect.h>
|
||||||
|
|
||||||
|
namespace ui
|
||||||
|
{
|
||||||
|
bool Rect::contains(Point point)
|
||||||
|
{
|
||||||
|
return (point.x >= pos.x) && (point.y >= pos.y) && (point.x <= (pos.x + width)) &&
|
||||||
|
(point.y <= (pos.y + height));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Rect::contains(Rect rect)
|
||||||
|
{
|
||||||
|
if (!contains(rect.pos)) return false;
|
||||||
|
Point rel = relative(rect.pos);
|
||||||
|
if ((rel.x + rect.width) > width) return false;
|
||||||
|
if ((rel.y + rect.height) > height) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Point Rect::normalize(Point point)
|
||||||
|
{
|
||||||
|
if (point.x < pos.x) point.x = pos.x;
|
||||||
|
if (point.y < pos.y) point.y = pos.y;
|
||||||
|
if (point.x > pos.x + width) point.x = pos.x + width;
|
||||||
|
if (point.y > pos.y + height) point.y = pos.y + height;
|
||||||
|
return point;
|
||||||
|
}
|
||||||
|
|
||||||
|
Point Rect::relative(Point point)
|
||||||
|
{
|
||||||
|
point = normalize(point);
|
||||||
|
point.x -= pos.x;
|
||||||
|
point.y -= pos.y;
|
||||||
|
return point;
|
||||||
|
}
|
||||||
|
|
||||||
|
Point Rect::absolute(Point point)
|
||||||
|
{
|
||||||
|
point.x += pos.x;
|
||||||
|
point.y += pos.y;
|
||||||
|
return point;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rect Rect::absolute(Rect rect)
|
||||||
|
{
|
||||||
|
return Rect { absolute(rect.pos), rect.width, rect.height };
|
||||||
|
}
|
||||||
|
|
||||||
|
Rect Rect::normalized()
|
||||||
|
{
|
||||||
|
return Rect { ui::Point { pos.x < 0 ? 0 : pos.x, pos.y < 0 ? 0 : pos.y }, width, height };
|
||||||
|
}
|
||||||
|
};
|
@ -13,7 +13,10 @@ Name | Version | Description | URL
|
|||||||
---|---|--- | ---
|
---|---|--- | ---
|
||||||
bc | 6.6.0 | An implementation of the POSIX bc calculator | https://github.com/gavinhoward/bc
|
bc | 6.6.0 | An implementation of the POSIX bc calculator | https://github.com/gavinhoward/bc
|
||||||
binutils | 2.39 | The GNU suite of binary utilities | https://www.gnu.org/software/binutils
|
binutils | 2.39 | The GNU suite of binary utilities | https://www.gnu.org/software/binutils
|
||||||
|
gmp | 6.3.0 | The GNU Multiple Precision Arithmetic Library | https://gmplib.org
|
||||||
minitar | 1.7.5 | Tiny and easy-to-use C library to read/write tar archives | https://git.cloudapio.eu/apio/minitar
|
minitar | 1.7.5 | Tiny and easy-to-use C library to read/write tar archives | https://git.cloudapio.eu/apio/minitar
|
||||||
|
mpc | 1.3.1 | The GNU Multiple Precision Complex Library | https://www.multiprecision.org
|
||||||
|
mpfr | 4.2.0 | The GNU Multiple Precision Floating-Point Reliable Library | https://mpfr.org
|
||||||
nasm | 2.16.01 | An assembler for the x86 CPU architecture | https://nasm.us
|
nasm | 2.16.01 | An assembler for the x86 CPU architecture | https://nasm.us
|
||||||
|
|
||||||
## Installing ports
|
## Installing ports
|
||||||
@ -48,10 +51,13 @@ The `name` variable should be set to the name of the ported program.
|
|||||||
|
|
||||||
The `version` variable should be set to the currently ported version of the program.
|
The `version` variable should be set to the currently ported version of the program.
|
||||||
|
|
||||||
|
If the program has dependencies on any other library/program, the `dependencies` field should be set to a list of those. Note that these dependencies must also be ported to Luna! Thus, when porting programs, you'll have to start with porting their dependencies (unless those have already been ported).
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```
|
```
|
||||||
name="example"
|
name="example"
|
||||||
version="1.0.0"
|
version="1.0.0"
|
||||||
|
dependencies=(foo bar)
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Download options
|
#### Download options
|
||||||
|
@ -10,6 +10,7 @@ sha256sum="d12ea6f239f1ffe3533ea11ad6e224ffcb89eb5d01bbea589e9158780fa11f10"
|
|||||||
|
|
||||||
# Build instructions
|
# Build instructions
|
||||||
default_build_make=true
|
default_build_make=true
|
||||||
|
default_install_make=true
|
||||||
|
|
||||||
do_patch()
|
do_patch()
|
||||||
{
|
{
|
||||||
@ -18,13 +19,5 @@ do_patch()
|
|||||||
|
|
||||||
do_configure()
|
do_configure()
|
||||||
{
|
{
|
||||||
$srcdir/configure --host=$LUNA_ARCH-luna --disable-nls --disable-werror --enable-warn-rwx-segments=no --prefix=/usr --enable-gold=no --enable-ld=yes --enable-gprofng=no
|
$srcdir/configure --host=$LUNA_ARCH-luna --with-build-sysroot=$LUNA_BASE --disable-nls --disable-werror --enable-warn-rwx-segments=no --prefix=/usr --enable-gold=no --enable-ld=yes --enable-gprofng=no
|
||||||
}
|
|
||||||
|
|
||||||
do_install()
|
|
||||||
{
|
|
||||||
make install
|
|
||||||
|
|
||||||
cd $installdir/usr/bin
|
|
||||||
$LUNA_ARCH-luna-strip size objdump ar strings ranlib objcopy addr2line readelf elfedit nm strip c++filt as gprof ld.bfd ld
|
|
||||||
}
|
}
|
||||||
|
18
ports/gmp/PACKAGE
Normal file
18
ports/gmp/PACKAGE
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# Basic information
|
||||||
|
name="gmp"
|
||||||
|
version="6.3.0"
|
||||||
|
|
||||||
|
# Download options
|
||||||
|
format="tar"
|
||||||
|
url="https://gmplib.org/download/gmp/gmp-$version.tar.xz"
|
||||||
|
output="gmp-$version.tar.xz"
|
||||||
|
sha256sum="a3c2b80201b89e68616f4ad30bc66aee4927c3ce50e33929ca819d5c43538898"
|
||||||
|
|
||||||
|
# Build instructions
|
||||||
|
default_build_make=true
|
||||||
|
default_install_make=true
|
||||||
|
|
||||||
|
do_configure()
|
||||||
|
{
|
||||||
|
$srcdir/configure --enable-shared=no --with-gnu-ld --host=$LUNA_ARCH-luna --prefix=/usr
|
||||||
|
}
|
19
ports/mpc/PACKAGE
Normal file
19
ports/mpc/PACKAGE
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# Basic information
|
||||||
|
name="mpc"
|
||||||
|
version="1.3.1"
|
||||||
|
dependencies=(gmp mpfr)
|
||||||
|
|
||||||
|
# Download options
|
||||||
|
format="tar"
|
||||||
|
url="https://ftp.gnu.org/gnu/mpc/mpc-$version.tar.gz"
|
||||||
|
output="mpc-$version.tar.gz"
|
||||||
|
sha256sum="ab642492f5cf882b74aa0cb730cd410a81edcdbec895183ce930e706c1c759b8"
|
||||||
|
|
||||||
|
# Build instructions
|
||||||
|
default_build_make=true
|
||||||
|
default_install_make=true
|
||||||
|
|
||||||
|
do_configure()
|
||||||
|
{
|
||||||
|
$srcdir/configure --enable-shared=no --with-gnu-ld --host=$LUNA_ARCH-luna --prefix=/usr
|
||||||
|
}
|
19
ports/mpfr/PACKAGE
Normal file
19
ports/mpfr/PACKAGE
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# Basic information
|
||||||
|
name="mpfr"
|
||||||
|
version="4.2.0"
|
||||||
|
dependencies=(gmp)
|
||||||
|
|
||||||
|
# Download options
|
||||||
|
format="tar"
|
||||||
|
url="https://www.mpfr.org/mpfr-current/mpfr-$version.tar.gz"
|
||||||
|
output="mpfr-$version.tar.gz"
|
||||||
|
sha256sum="f1cc1c6bb14d18f0c61cc416e083f5e697b6e0e3cf9630b9b33e8e483fc960f0"
|
||||||
|
|
||||||
|
# Build instructions
|
||||||
|
default_build_make=true
|
||||||
|
default_install_make=true
|
||||||
|
|
||||||
|
do_configure()
|
||||||
|
{
|
||||||
|
$srcdir/configure --enable-shared=no --with-gnu-ld --host=$LUNA_ARCH-luna --prefix=/usr
|
||||||
|
}
|
@ -72,6 +72,35 @@ TestResult test_setenv_before_and_after_manual_environ_modification()
|
|||||||
test_success;
|
test_success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TestResult test_putenv()
|
||||||
|
{
|
||||||
|
clearenv();
|
||||||
|
|
||||||
|
char lit[] = "NAME=VALUE";
|
||||||
|
|
||||||
|
validate(putenv(lit) == 0);
|
||||||
|
|
||||||
|
char* value = getenv("NAME");
|
||||||
|
validate(value && !strcmp(value, "VALUE"));
|
||||||
|
|
||||||
|
lit[0] = 'F';
|
||||||
|
|
||||||
|
value = getenv("NAME");
|
||||||
|
validate(!value);
|
||||||
|
|
||||||
|
value = getenv("FAME");
|
||||||
|
validate(value && !strcmp(value, "VALUE"));
|
||||||
|
|
||||||
|
validate(unsetenv("FAME") == 0);
|
||||||
|
|
||||||
|
value = getenv("FAME");
|
||||||
|
validate(!value);
|
||||||
|
|
||||||
|
validate(!strcmp(lit, "FAME=VALUE"));
|
||||||
|
|
||||||
|
test_success;
|
||||||
|
}
|
||||||
|
|
||||||
Result<void> test_main()
|
Result<void> test_main()
|
||||||
{
|
{
|
||||||
test_prelude;
|
test_prelude;
|
||||||
@ -80,6 +109,7 @@ Result<void> test_main()
|
|||||||
run_test(test_setenv_dont_overwrite);
|
run_test(test_setenv_dont_overwrite);
|
||||||
run_test(test_unsetenv);
|
run_test(test_unsetenv);
|
||||||
run_test(test_setenv_before_and_after_manual_environ_modification);
|
run_test(test_setenv_before_and_after_manual_environ_modification);
|
||||||
|
run_test(test_putenv);
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ export LUNA_BASE=${LUNA_BASE:-$LUNA_ROOT/base}
|
|||||||
[ -f "$LUNA_ROOT/env-local.sh" ] && source $LUNA_ROOT/env-local.sh
|
[ -f "$LUNA_ROOT/env-local.sh" ] && source $LUNA_ROOT/env-local.sh
|
||||||
|
|
||||||
export LUNA_ARCH=${LUNA_ARCH:-x86_64}
|
export LUNA_ARCH=${LUNA_ARCH:-x86_64}
|
||||||
export PATH=$LUNA_ROOT/toolchain/$LUNA_ARCH-luna/bin:$LUNA_ROOT/toolchain/dist:$PATH
|
export PATH=$LUNA_ROOT/toolchain/$LUNA_ARCH-luna/bin:$LUNA_ROOT/toolchain/dist:$LUNA_ROOT/tools/exec/:$PATH
|
||||||
|
|
||||||
if [ "$USE_MAKE" = "1" ]
|
if [ "$USE_MAKE" = "1" ]
|
||||||
then
|
then
|
||||||
|
10
tools/exec/luna-pkg-config
Normal file
10
tools/exec/luna-pkg-config
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Fill these in appropriately:
|
||||||
|
export PKG_CONFIG_SYSROOT_DIR=$LUNA_BASE
|
||||||
|
export PKG_CONFIG_LIBDIR=$LUNA_BASE/usr/lib/pkgconfig
|
||||||
|
# TODO: If it works this should probably just be set to the empty string.
|
||||||
|
export PKG_CONFIG_PATH=$PKG_CONFIG_LIBDIR
|
||||||
|
# Use --static here if your OS only has static linking.
|
||||||
|
# TODO: Perhaps it's a bug in the libraries if their pkg-config files doesn't
|
||||||
|
# record that only static libraries were built.
|
||||||
|
exec pkg-config --static "$@"
|
110
tools/gcc.patch
110
tools/gcc.patch
@ -1,6 +1,6 @@
|
|||||||
diff --color -rN -u gcc-12.2.0/config.sub build/gcc-12.2.0/config.sub
|
diff --color -rN -u vanilla/gcc-12.2.0/config.sub gcc-12.2.0/config.sub
|
||||||
--- a/gcc-12.2.0/config.sub 2022-08-19 10:09:52.128656687 +0200
|
--- a/gcc-12.2.0/config.sub 2022-08-19 10:09:52.128656687 +0200
|
||||||
+++ b/gcc-12.2.0/config.sub 2022-10-02 11:27:45.660055384 +0200
|
+++ b/gcc-12.2.0/config.sub 2023-08-08 20:42:05.032843544 +0200
|
||||||
@@ -1723,7 +1723,7 @@
|
@@ -1723,7 +1723,7 @@
|
||||||
| hpux* | unos* | osf* | luna* | dgux* | auroraux* | solaris* \
|
| hpux* | unos* | osf* | luna* | dgux* | auroraux* | solaris* \
|
||||||
| sym* | plan9* | psp* | sim* | xray* | os68k* | v88r* \
|
| sym* | plan9* | psp* | sim* | xray* | os68k* | v88r* \
|
||||||
@ -10,9 +10,9 @@ diff --color -rN -u gcc-12.2.0/config.sub build/gcc-12.2.0/config.sub
|
|||||||
| mpw* | magic* | mmixware* | mon960* | lnews* \
|
| mpw* | magic* | mmixware* | mon960* | lnews* \
|
||||||
| amigaos* | amigados* | msdos* | newsos* | unicos* | aof* \
|
| amigaos* | amigados* | msdos* | newsos* | unicos* | aof* \
|
||||||
| aos* | aros* | cloudabi* | sortix* | twizzler* \
|
| aos* | aros* | cloudabi* | sortix* | twizzler* \
|
||||||
diff --color -rN -u gcc-12.2.0/fixincludes/mkfixinc.sh build/gcc-12.2.0/fixincludes/mkfixinc.sh
|
diff --color -rN -u vanilla/gcc-12.2.0/fixincludes/mkfixinc.sh gcc-12.2.0/fixincludes/mkfixinc.sh
|
||||||
--- a/gcc-12.2.0/fixincludes/mkfixinc.sh 2022-08-19 10:09:52.160657095 +0200
|
--- a/gcc-12.2.0/fixincludes/mkfixinc.sh 2022-08-19 10:09:52.160657095 +0200
|
||||||
+++ b/gcc-12.2.0/fixincludes/mkfixinc.sh 2022-10-02 11:27:45.662055397 +0200
|
+++ b/gcc-12.2.0/fixincludes/mkfixinc.sh 2023-08-08 20:42:05.034843561 +0200
|
||||||
@@ -12,6 +12,8 @@
|
@@ -12,6 +12,8 @@
|
||||||
# Check for special fix rules for particular targets
|
# Check for special fix rules for particular targets
|
||||||
case $machine in
|
case $machine in
|
||||||
@ -22,18 +22,18 @@ diff --color -rN -u gcc-12.2.0/fixincludes/mkfixinc.sh build/gcc-12.2.0/fixinclu
|
|||||||
i?86-*-mingw32* | \
|
i?86-*-mingw32* | \
|
||||||
x86_64-*-mingw32* | \
|
x86_64-*-mingw32* | \
|
||||||
powerpc-*-eabisim* | \
|
powerpc-*-eabisim* | \
|
||||||
diff --color -rN -u gcc-12.2.0/gcc/config/i386/x86_64-luna-kernel build/gcc-12.2.0/gcc/config/i386/x86_64-luna-kernel
|
diff --color -rN -u vanilla/gcc-12.2.0/gcc/config/i386/x86_64-luna-kernel gcc-12.2.0/gcc/config/i386/x86_64-luna-kernel
|
||||||
--- a/dev/null 1970-01-01 01:00:00.000000000 +0100
|
--- a/gcc-12.2.0/gcc/config/i386/x86_64-luna-kernel 1970-01-01 01:00:00.000000000 +0100
|
||||||
+++ b/gcc-12.2.0/gcc/config/i386/x86_64-luna-kernel 2022-10-02 11:45:30.955856133 +0200
|
+++ b/gcc-12.2.0/gcc/config/i386/x86_64-luna-kernel 2023-08-08 20:42:05.038843594 +0200
|
||||||
@@ -0,0 +1,4 @@
|
@@ -0,0 +1,4 @@
|
||||||
+#Add libgcc multilib variant without red-zone requirement, for use in the kernel
|
+#Add libgcc multilib variant without red-zone requirement, for use in the kernel
|
||||||
+
|
+
|
||||||
+MULTILIB_OPTIONS += mno-red-zone
|
+MULTILIB_OPTIONS += mno-red-zone
|
||||||
+MULTILIB_DIRNAMES += no-red-zone
|
+MULTILIB_DIRNAMES += no-red-zone
|
||||||
\ No newline at end of file
|
\ No newline at end of file
|
||||||
diff --color -rN -u gcc-12.2.0/gcc/config/luna.h build/gcc-12.2.0/gcc/config/luna.h
|
diff --color -rN -u vanilla/gcc-12.2.0/gcc/config/luna.h gcc-12.2.0/gcc/config/luna.h
|
||||||
--- a/dev/null 1970-01-01 01:00:00.000000000 +0100
|
--- a/gcc-12.2.0/gcc/config/luna.h 1970-01-01 01:00:00.000000000 +0100
|
||||||
+++ b/gcc-12.2.0/gcc/config/luna.h 2022-10-02 11:27:45.663055404 +0200
|
+++ b/gcc-12.2.0/gcc/config/luna.h 2023-08-08 20:42:05.040843610 +0200
|
||||||
@@ -0,0 +1,36 @@
|
@@ -0,0 +1,36 @@
|
||||||
+#undef TARGET_LUNA
|
+#undef TARGET_LUNA
|
||||||
+#define TARGET_LUNA 1
|
+#define TARGET_LUNA 1
|
||||||
@ -71,11 +71,9 @@ diff --color -rN -u gcc-12.2.0/gcc/config/luna.h build/gcc-12.2.0/gcc/config/lun
|
|||||||
+ } while (0);
|
+ } while (0);
|
||||||
+
|
+
|
||||||
+#undef LINK_SPEC
|
+#undef LINK_SPEC
|
||||||
+#define LINK_SPEC "-z max-page-size=4096"
|
diff --color -rN -u vanilla/gcc-12.2.0/gcc/config.gcc gcc-12.2.0/gcc/config.gcc
|
||||||
\ No newline at end of file
|
|
||||||
diff --color -rN -u gcc-12.2.0/gcc/config.gcc build/gcc-12.2.0/gcc/config.gcc
|
|
||||||
--- a/gcc-12.2.0/gcc/config.gcc 2022-08-19 10:09:52.552662114 +0200
|
--- a/gcc-12.2.0/gcc/config.gcc 2022-08-19 10:09:52.552662114 +0200
|
||||||
+++ b/gcc-12.2.0/gcc/config.gcc 2022-10-02 11:45:18.311797546 +0200
|
+++ b/gcc-12.2.0/gcc/config.gcc 2023-08-08 20:42:05.044843643 +0200
|
||||||
@@ -895,6 +895,12 @@
|
@@ -895,6 +895,12 @@
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
@ -103,9 +101,9 @@ diff --color -rN -u gcc-12.2.0/gcc/config.gcc build/gcc-12.2.0/gcc/config.gcc
|
|||||||
x86_64-*-rtems*)
|
x86_64-*-rtems*)
|
||||||
tm_file="${tm_file} i386/unix.h i386/att.h dbxelf.h elfos.h newlib-stdint.h i386/i386elf.h i386/x86-64.h i386/rtemself.h rtems.h"
|
tm_file="${tm_file} i386/unix.h i386/att.h dbxelf.h elfos.h newlib-stdint.h i386/i386elf.h i386/x86-64.h i386/rtemself.h rtems.h"
|
||||||
;;
|
;;
|
||||||
diff --color -rN -u gcc-12.2.0/libgcc/config.host build/gcc-12.2.0/libgcc/config.host
|
diff --color -rN -u vanilla/gcc-12.2.0/libgcc/config.host gcc-12.2.0/libgcc/config.host
|
||||||
--- a/gcc-12.2.0/libgcc/config.host 2022-08-19 10:09:54.664689148 +0200
|
--- a/gcc-12.2.0/libgcc/config.host 2022-08-19 10:09:54.664689148 +0200
|
||||||
+++ b/gcc-12.2.0/libgcc/config.host 2022-10-02 11:27:45.671055461 +0200
|
+++ b/gcc-12.2.0/libgcc/config.host 2023-08-08 20:42:05.046843660 +0200
|
||||||
@@ -783,6 +783,14 @@
|
@@ -783,6 +783,14 @@
|
||||||
;;
|
;;
|
||||||
i[34567]86-*-lynxos*)
|
i[34567]86-*-lynxos*)
|
||||||
@ -121,9 +119,9 @@ diff --color -rN -u gcc-12.2.0/libgcc/config.host build/gcc-12.2.0/libgcc/config
|
|||||||
i[34567]86-*-nto-qnx*)
|
i[34567]86-*-nto-qnx*)
|
||||||
tmake_file="$tmake_file i386/t-nto t-libgcc-pic"
|
tmake_file="$tmake_file i386/t-nto t-libgcc-pic"
|
||||||
extra_parts=crtbegin.o
|
extra_parts=crtbegin.o
|
||||||
diff --color -rN -u gcc-12.2.0/libgcc/libgcov.h build/gcc-12.2.0/libgcc/libgcov.h
|
diff --color -rN -u vanilla/gcc-12.2.0/libgcc/libgcov.h gcc-12.2.0/libgcc/libgcov.h
|
||||||
--- a/gcc-12.2.0/libgcc/libgcov.h 2022-08-19 10:09:54.728689966 +0200
|
--- a/gcc-12.2.0/libgcc/libgcov.h 2022-08-19 10:09:54.728689966 +0200
|
||||||
+++ b/gcc-12.2.0/libgcc/libgcov.h 2022-10-02 11:41:48.571807335 +0200
|
+++ b/gcc-12.2.0/libgcc/libgcov.h 2023-08-08 20:42:05.048843677 +0200
|
||||||
@@ -194,6 +194,7 @@
|
@@ -194,6 +194,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -132,3 +130,79 @@ diff --color -rN -u gcc-12.2.0/libgcc/libgcov.h build/gcc-12.2.0/libgcc/libgcov.
|
|||||||
|
|
||||||
/* Structures embedded in coveraged program. The structures generated
|
/* Structures embedded in coveraged program. The structures generated
|
||||||
by write_profile must match these. */
|
by write_profile must match these. */
|
||||||
|
diff --color -rN -u vanilla/gcc-12.2.0/libstdc++-v3/acinclude.m4 gcc-12.2.0/libstdc++-v3/acinclude.m4
|
||||||
|
--- a/gcc-12.2.0/libstdc++-v3/acinclude.m4 2022-08-19 10:09:55.380698313 +0200
|
||||||
|
+++ b/gcc-12.2.0/libstdc++-v3/acinclude.m4 2023-08-08 21:08:00.777765701 +0200
|
||||||
|
@@ -1356,6 +1356,10 @@
|
||||||
|
ac_has_nanosleep=yes
|
||||||
|
ac_has_sched_yield=yes
|
||||||
|
;;
|
||||||
|
+ luna*)
|
||||||
|
+ ac_has_clock_monotonic=yes
|
||||||
|
+ ac_has_clock_realtime=yes
|
||||||
|
+ ;;
|
||||||
|
# VxWorks has nanosleep as soon as the kernel is configured with
|
||||||
|
# INCLUDE_POSIX_TIMERS, which is normally/most-often the case.
|
||||||
|
vxworks*)
|
||||||
|
@@ -2421,7 +2425,7 @@
|
||||||
|
dragonfly* | freebsd*)
|
||||||
|
enable_clocale_flag=dragonfly
|
||||||
|
;;
|
||||||
|
- openbsd*)
|
||||||
|
+ openbsd* | luna*)
|
||||||
|
enable_clocale_flag=newlib
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
diff --color -rN -u vanilla/gcc-12.2.0/libstdc++-v3/configure gcc-12.2.0/libstdc++-v3/configure
|
||||||
|
--- a/gcc-12.2.0/libstdc++-v3/configure 2022-08-19 10:09:55.416698774 +0200
|
||||||
|
+++ b/gcc-12.2.0/libstdc++-v3/configure 2023-08-09 11:34:54.810282202 +0200
|
||||||
|
@@ -16481,6 +16481,9 @@
|
||||||
|
openbsd*)
|
||||||
|
enable_clocale_flag=newlib
|
||||||
|
;;
|
||||||
|
+ luna*)
|
||||||
|
+ enable_clocale_flag=generic
|
||||||
|
+ ;;
|
||||||
|
*)
|
||||||
|
if test x"$with_newlib" = x"yes"; then
|
||||||
|
enable_clocale_flag=newlib
|
||||||
|
@@ -20493,6 +20496,10 @@
|
||||||
|
ac_has_nanosleep=yes
|
||||||
|
ac_has_sched_yield=yes
|
||||||
|
;;
|
||||||
|
+ luna*)
|
||||||
|
+ ac_has_clock_monotonic=yes
|
||||||
|
+ ac_has_clock_realtime=yes
|
||||||
|
+ ;;
|
||||||
|
# VxWorks has nanosleep as soon as the kernel is configured with
|
||||||
|
# INCLUDE_POSIX_TIMERS, which is normally/most-often the case.
|
||||||
|
vxworks*)
|
||||||
|
diff --color -rN -u vanilla/gcc-12.2.0/libstdc++-v3/configure.host gcc-12.2.0/libstdc++-v3/configure.host
|
||||||
|
--- a/gcc-12.2.0/libstdc++-v3/configure.host 2022-08-19 10:09:55.420698825 +0200
|
||||||
|
+++ b/gcc-12.2.0/libstdc++-v3/configure.host 2023-08-09 11:35:05.734185945 +0200
|
||||||
|
@@ -306,6 +306,9 @@
|
||||||
|
vxworks*)
|
||||||
|
os_include_dir="os/vxworks"
|
||||||
|
;;
|
||||||
|
+ luna*)
|
||||||
|
+ os_include_dir="os/generic"
|
||||||
|
+ ;;
|
||||||
|
*)
|
||||||
|
os_include_dir="os/generic"
|
||||||
|
;;
|
||||||
|
diff --color -rN -u vanilla/gcc-12.2.0/libstdc++-v3/crossconfig.m4 gcc-12.2.0/libstdc++-v3/crossconfig.m4
|
||||||
|
--- a/gcc-12.2.0/libstdc++-v3/crossconfig.m4 2022-08-19 10:09:55.420698825 +0200
|
||||||
|
+++ b/gcc-12.2.0/libstdc++-v3/crossconfig.m4 2023-08-08 21:16:12.897071194 +0200
|
||||||
|
@@ -277,6 +277,12 @@
|
||||||
|
GLIBCXX_CHECK_MATH_SUPPORT
|
||||||
|
GLIBCXX_CHECK_STDLIB_SUPPORT
|
||||||
|
;;
|
||||||
|
+ *-luna*)
|
||||||
|
+ GLIBCXX_CHECK_COMPILER_FEATURES
|
||||||
|
+ GLIBCXX_CHECK_LINKER_FEATURES
|
||||||
|
+ GLIBCXX_CHECK_MATH_SUPPORT
|
||||||
|
+ GLIBCXX_CHECK_STDLIB_SUPPORT
|
||||||
|
+ ;;
|
||||||
|
*-vxworks*)
|
||||||
|
AC_DEFINE(HAVE_ACOSF)
|
||||||
|
AC_DEFINE(HAVE_ASINF)
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user