Compare commits

..

37 Commits

Author SHA1 Message Date
939f443e9b
wind: Spawn a new client process after startup
All checks were successful
continuous-integration/drone/pr Build is passing
Also, create the socket after dropping privileges.
2023-08-07 22:51:28 +02:00
b15ba11f90
apps: Add gclient 2023-08-07 22:50:50 +02:00
2204348a40
libos: Add os::LocalClient 2023-08-07 22:50:49 +02:00
54c3689cf7
libui: Change 'into' to 'onto' 2023-08-07 22:50:01 +02:00
a152623b01
libui: Document ui::Font 2023-08-07 22:50:01 +02:00
eef1fd24fb
libui+wind: Move some static variables inside functions 2023-08-07 22:50:01 +02:00
c83d4eafde
wind: Generate random windows on keypresses 2023-08-07 22:50:00 +02:00
f9abca1ffb
wind: Make sure windows have a minimum size to fit the titlebar 2023-08-07 22:50:00 +02:00
28dee21de5
libui: Properly cut off the last drawn character if necessary 2023-08-07 22:50:00 +02:00
0814e1edeb
libui: Add Rect::contains(Rect) 2023-08-07 22:49:59 +02:00
3f7ee75681
libui: Render font characters properly with no spacing, matching the width calculations 2023-08-07 22:49:59 +02:00
98e76b35d6
wind: Render an actual TGA mouse cursor 2023-08-07 22:49:58 +02:00
3785f7941e
wind: Add a close button to windows using a TGA icon 2023-08-07 22:49:58 +02:00
41b0ee094f
libui: Add support for TGA image loading 2023-08-07 22:49:58 +02:00
60542a42a5
libui: Add an interface to fill a Canvas with an array of pixels 2023-08-07 22:49:57 +02:00
ae8f6fbabd
wind: Add window titlebars using ui::Font 2023-08-07 22:49:57 +02:00
dfe8f6ed59
libui: Add PSF font loading and rendering 2023-08-07 22:49:57 +02:00
521208dd4b
libui: Add Color::GRAY 2023-08-07 22:49:56 +02:00
f174e286f2
libui: Rename Rect::absolute to normalized and add a new absolute function 2023-08-07 22:49:56 +02:00
40cc11bb1f
libluna: Add assignment operators to Buffer 2023-08-07 22:49:55 +02:00
2fc34fbc58
wind: Reorder drag sequence 2023-08-07 22:49:55 +02:00
9f71c0cc2a
libui: Add Rect::relative 2023-08-07 22:49:55 +02:00
cd30a32367
libui: Remove redundant statement 2023-08-07 22:49:54 +02:00
b448e7f206
libui: Add getters for separate color values 2023-08-07 22:49:54 +02:00
1be7866d49
libui: Remove unnecessary stuff 2023-08-07 22:49:53 +02:00
9291ad325c
base: Remove startup items not necessary for GUI startup 2023-08-07 22:49:53 +02:00
c8a490f927
libui+wind: (Draggable) windows 2023-08-07 22:49:53 +02:00
c7bef46c39
wind: Create a local server object 2023-08-07 22:49:52 +02:00
89f3e411c9
libos: Add a new LocalServer class for local domain sockets 2023-08-07 22:49:52 +02:00
d4bb9c61b6
kernel: Support listening sockets in poll() 2023-08-07 22:49:51 +02:00
e4ce41fc4c
base: Start wind on startup instead of the shell 2023-08-07 22:49:51 +02:00
acb26ad856
wind: Add a simple display server skeleton using libui
No client functionality yet, but it's a start.
2023-08-07 22:49:51 +02:00
6cc98b1dbc
libui: Add a GUI and graphics library 2023-08-07 22:49:50 +02:00
0b42018d8b
kernel: Fix negative movement in the PS/2 mouse driver 2023-08-07 22:49:50 +02:00
77ebdda2e0
libos: Add Process::spawn()
All checks were successful
continuous-integration/drone/push Build is passing
2023-08-07 22:49:12 +02:00
097353e779
kernel: Properly check memory bounds while touching user memory
Before this patch, one byte of each page was being accessed without checking the page's permissions.
2023-08-07 22:49:00 +02:00
10c892d606
kernel: Allow null envp in execve()
As far as I know, this is not standard, but I'm doing this as a convenience for programs using exec() right after clearenv().
2023-08-07 22:48:21 +02:00
10 changed files with 269 additions and 7 deletions

View File

@ -46,3 +46,4 @@ luna_app(socket-test.cpp socket-test)
luna_app(socket-client.cpp socket-client) 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(gclient.cpp gclient)

20
apps/gclient.cpp Normal file
View 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;
}

View File

@ -562,7 +562,7 @@ namespace MemoryManager
while (size--) while (size--)
{ {
// Crossed a page boundary, gotta check the page tables again before touching any memory!! // Crossed a page boundary, gotta check the page tables again before touching any memory!!
if (user_ptr % ARCH_PAGE_SIZE) if ((user_ptr % ARCH_PAGE_SIZE) == 0)
{ {
if (!validate_page_access(user_ptr, MMU::ReadWrite | MMU::User)) return false; if (!validate_page_access(user_ptr, MMU::ReadWrite | MMU::User)) return false;
} }
@ -590,7 +590,7 @@ namespace MemoryManager
while (size--) while (size--)
{ {
// Crossed a page boundary, gotta check the page tables again before touching any memory!! // Crossed a page boundary, gotta check the page tables again before touching any memory!!
if (user_ptr % ARCH_PAGE_SIZE) if ((user_ptr % ARCH_PAGE_SIZE) == 0)
{ {
if (!validate_page_access(user_ptr, MMU::User)) return false; if (!validate_page_access(user_ptr, MMU::User)) return false;
} }

View File

@ -55,7 +55,8 @@ Result<u64> sys_execve(Registers* regs, SyscallArgs args)
{ {
auto path = TRY(MemoryManager::strdup_from_user(args[0])); auto path = TRY(MemoryManager::strdup_from_user(args[0]));
auto argv = TRY(copy_string_vector_from_userspace(args[1])); auto argv = TRY(copy_string_vector_from_userspace(args[1]));
auto envp = TRY(copy_string_vector_from_userspace(args[2])); Vector<String> envp;
if (args[2]) envp = TRY(copy_string_vector_from_userspace(args[2]));
if ((calculate_userspace_stack_size(argv) + calculate_userspace_stack_size(envp)) > MAX_ARGV_STACK_SIZE) if ((calculate_userspace_stack_size(argv) + calculate_userspace_stack_size(envp)) > MAX_ARGV_STACK_SIZE)
return err(E2BIG); return err(E2BIG);

View File

@ -14,6 +14,7 @@ set(SOURCES
src/Mode.cpp src/Mode.cpp
src/Prompt.cpp src/Prompt.cpp
src/LocalServer.cpp src/LocalServer.cpp
src/LocalClient.cpp
) )
add_library(os ${SOURCES}) add_library(os ${SOURCES})

View File

@ -0,0 +1,90 @@
#pragma once
#include <luna/SharedPtr.h>
#include <luna/StringView.h>
namespace os
{
/**
* @brief A client used to connect to a local server socket.
*/
class LocalClient : public Shareable
{
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<SharedPtr<LocalClient>> An error, or a new client object.
*/
static Result<SharedPtr<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;
};
}

View File

@ -59,6 +59,37 @@ namespace os
*/ */
static Result<void> exec(StringView path, Slice<String> args, Slice<String> env, bool search_in_path = true); static Result<void> exec(StringView path, Slice<String> args, Slice<String> env, bool search_in_path = true);
/**
* @brief Spawn a new process from an executable file.
*
* @param path The new executable's path.
* @param args The argument list to pass to the new process.
* @param search_in_path Determines whether to search in the system binary directories if path is just a name.
* @return Result<pid_t> An error, or the process ID of the new process.
*/
static Result<pid_t> spawn(StringView path, Slice<String> args, bool search_in_path = true);
/**
* @brief Spawn a new process from an executable file.
*
* @param path The new executable's path.
* @param args The argument list to pass to the new process.
* @param search_in_path Determines whether to search in the system binary directories if path is just a name.
* @return Result<pid_t> An error, or the process ID of the new process.
*/
static Result<pid_t> spawn(StringView path, Slice<StringView> args, bool search_in_path = true);
/**
* @brief Spawn a new process from an executable file.
*
* @param path The new executable's path.
* @param args The argument list to pass to the new process.
* @param env The environment to pass to the new process, instead of the current environment.
* @param search_in_path Determines whether to search in the system binary directories if path is just a name.
* @return Result<pid_t> An error, or the process ID of the new process.
*/
static Result<pid_t> spawn(StringView path, Slice<String> args, Slice<String> env, bool search_in_path = true);
// To use as the child argument to wait() to wait for any child. // To use as the child argument to wait() to wait for any child.
static constexpr pid_t ANY_CHILD = -1; static constexpr pid_t ANY_CHILD = -1;

59
libos/src/LocalClient.cpp Normal file
View 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<SharedPtr<LocalClient>> LocalClient::connect(StringView path, bool blocking)
{
auto client = TRY(make_shared<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;
}
}

View File

@ -8,11 +8,14 @@
*/ */
#include <errno.h> #include <errno.h>
#include <luna/DebugLog.h>
#include <os/Process.h> #include <os/Process.h>
#include <stdlib.h> #include <stdlib.h>
#include <sys/syscall.h> #include <sys/syscall.h>
#include <unistd.h> #include <unistd.h>
extern char** environ;
namespace os namespace os
{ {
Result<pid_t> Process::fork() Result<pid_t> Process::fork()
@ -64,6 +67,58 @@ namespace os
return err(errno); return err(errno);
} }
static Result<pid_t> do_spawn(const char* path, char** argv, char** envp, bool use_path)
{
pid_t child = fork();
if (child < 0) return err(errno);
if (child == 0)
{
if (use_path) execvpe(path, argv, envp);
else
execve(path, argv, envp);
_exit(127);
}
return child;
}
Result<pid_t> Process::spawn(StringView path, Slice<String> args, bool search_in_path)
{
Vector<const char*> argv;
for (const auto& arg : args) { TRY(argv.try_append(arg.chars())); }
TRY(argv.try_append(nullptr));
return do_spawn(path.chars(), const_cast<char**>(argv.data()), environ, search_in_path);
}
Result<pid_t> Process::spawn(StringView path, Slice<StringView> args, bool search_in_path)
{
Vector<const char*> argv;
for (const auto& arg : args)
{
TRY(argv.try_append(arg.chars()));
dbgln("os::Process:spawn() adding new argument: %s", arg.chars());
}
TRY(argv.try_append(nullptr));
dbgln("os::Process:spawn() invoking do_spawn(): path=%s, argv=%p, envp=%p", path.chars(),
const_cast<char**>(argv.data()), environ);
return do_spawn(path.chars(), const_cast<char**>(argv.data()), environ, search_in_path);
}
Result<pid_t> Process::spawn(StringView path, Slice<String> args, Slice<String> env, bool search_in_path)
{
Vector<const char*> argv;
for (const auto& arg : args) { TRY(argv.try_append(arg.chars())); }
TRY(argv.try_append(nullptr));
Vector<const char*> envp;
for (const auto& arg : env) { TRY(envp.try_append(arg.chars())); }
TRY(envp.try_append(nullptr));
return do_spawn(path.chars(), const_cast<char**>(argv.data()), const_cast<char**>(envp.data()), search_in_path);
}
Result<pid_t> Process::wait(pid_t child, int* status, int options) Result<pid_t> Process::wait(pid_t child, int* status, int options)
{ {
long rc = syscall(SYS_waitpid, child, status, options); long rc = syscall(SYS_waitpid, child, status, options);

View File

@ -6,6 +6,7 @@
#include <os/ArgumentParser.h> #include <os/ArgumentParser.h>
#include <os/File.h> #include <os/File.h>
#include <os/LocalServer.h> #include <os/LocalServer.h>
#include <os/Process.h>
#include <pwd.h> #include <pwd.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -45,9 +46,6 @@ Result<int> luna_main(int argc, char** argv)
auto screen = TRY(Screen::open()); auto screen = TRY(Screen::open());
auto server = TRY(os::LocalServer::create(socket_path, false));
TRY(server->listen(20));
Mouse mouse_pointer { screen.canvas() }; Mouse mouse_pointer { screen.canvas() };
ioctl(STDIN_FILENO, TTYSETGFX, 1); ioctl(STDIN_FILENO, TTYSETGFX, 1);
@ -73,6 +71,12 @@ Result<int> luna_main(int argc, char** argv)
} }
} }
auto server = TRY(os::LocalServer::create(socket_path, false));
TRY(server->listen(20));
StringView args[] = { "/usr/bin/gclient"_sv };
TRY(os::Process::spawn("/usr/bin/gclient"_sv, Slice<StringView> { args, 1 }, false));
ui::Color background = ui::BLACK; ui::Color background = ui::BLACK;
TRY(make<Window>(ui::Rect { 200, 200, 600, 400 }, ui::GREEN, "Calculator"_sv)); TRY(make<Window>(ui::Rect { 200, 200, 600, 400 }, ui::GREEN, "Calculator"_sv));
@ -96,7 +100,7 @@ Result<int> luna_main(int argc, char** argv)
int rc = poll(fds, 3, 1000); int rc = poll(fds, 3, 1000);
if (!rc) continue; if (!rc) continue;
if (rc < 0) { os::println("poll: error: %s", strerror(errno)); } if (rc < 0 && errno != EINTR) { os::println("poll: error: %s", strerror(errno)); }
if (fds[0].revents & POLLIN) if (fds[0].revents & POLLIN)
{ {