mirror of
https://github.com/Fennix-Project/Kernel.git
synced 2025-07-11 15:29:18 +00:00
Restructured and rewritten entire codebase
This commit is contained in:
213
syscalls/native/execve.cpp
Normal file
213
syscalls/native/execve.cpp
Normal file
@ -0,0 +1,213 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <syscalls.hpp>
|
||||
|
||||
#include <memory.hpp>
|
||||
#include <lock.hpp>
|
||||
#include <exec.hpp>
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include "../../syscalls.h"
|
||||
#include "../../kernel.h"
|
||||
#include "../../ipc.h"
|
||||
|
||||
using InterProcessCommunication::IPC;
|
||||
using InterProcessCommunication::IPCID;
|
||||
using Tasking::PCB;
|
||||
using Tasking::TCB;
|
||||
using Tasking::TaskState::Ready;
|
||||
using Tasking::TaskState::Terminated;
|
||||
using vfs::RefNode;
|
||||
using namespace Memory;
|
||||
|
||||
#define SysFrm SyscallsFrame
|
||||
|
||||
#if defined(a64)
|
||||
typedef long arch_t;
|
||||
#elif defined(a32)
|
||||
typedef int arch_t;
|
||||
#endif
|
||||
|
||||
/* https://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html */
|
||||
int sys_execve(SysFrm *Frame, const char *path,
|
||||
char *const argv[], char *const envp[])
|
||||
{
|
||||
PCB *pcb = thisProcess;
|
||||
Memory::Virtual vmm(pcb->PageTable);
|
||||
|
||||
if (path == nullptr ||
|
||||
!vmm.Check((void *)path, Memory::US) ||
|
||||
!vmm.Check((void *)argv, Memory::US) ||
|
||||
!vmm.Check((void *)envp, Memory::US))
|
||||
return -ENOENT;
|
||||
|
||||
const char *safe_path;
|
||||
char **safe_argv;
|
||||
char **safe_envp;
|
||||
safe_path = (const char *)pcb->vma->RequestPages(1);
|
||||
safe_argv = (char **)pcb->vma->RequestPages(TO_PAGES(MAX_ARG));
|
||||
safe_envp = (char **)pcb->vma->RequestPages(TO_PAGES(MAX_ARG));
|
||||
{
|
||||
Memory::SwapPT swap(pcb->PageTable);
|
||||
size_t len = strlen(path);
|
||||
memset((void *)safe_path, 0, PAGE_SIZE);
|
||||
memcpy((void *)safe_path, path, len);
|
||||
|
||||
const char *arg;
|
||||
char *n_arg;
|
||||
for (int i = 0; argv[i] != nullptr; i++)
|
||||
{
|
||||
arg = argv[i];
|
||||
size_t len = strlen(arg);
|
||||
|
||||
n_arg = (char *)pcb->vma->RequestPages(TO_PAGES(len));
|
||||
memcpy((void *)n_arg, arg, len);
|
||||
n_arg[len] = '\0';
|
||||
|
||||
safe_argv[i] = n_arg;
|
||||
|
||||
if (likely(i < MAX_ARG - 1))
|
||||
safe_argv[i + 1] = nullptr;
|
||||
}
|
||||
|
||||
for (int i = 0; envp[i] != nullptr; i++)
|
||||
{
|
||||
arg = envp[i];
|
||||
size_t len = strlen(arg);
|
||||
|
||||
n_arg = (char *)pcb->vma->RequestPages(TO_PAGES(len));
|
||||
memcpy((void *)n_arg, arg, len);
|
||||
n_arg[len] = '\0';
|
||||
|
||||
safe_envp[i] = n_arg;
|
||||
|
||||
if (likely(i < MAX_ARG - 1))
|
||||
safe_envp[i + 1] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
function("%s %#lx %#lx", safe_path, safe_argv, safe_envp);
|
||||
|
||||
#ifdef DEBUG
|
||||
for (int i = 0; safe_argv[i] != nullptr; i++)
|
||||
debug("safe_argv[%d]: %s", i, safe_argv[i]);
|
||||
|
||||
for (int i = 0; safe_envp[i] != nullptr; i++)
|
||||
debug("safe_envp[%d]: %s", i, safe_envp[i]);
|
||||
#endif
|
||||
|
||||
RefNode *File = fs->Open(safe_path,
|
||||
pcb->CurrentWorkingDirectory);
|
||||
|
||||
if (!File)
|
||||
{
|
||||
error("File not found");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
char shebang_magic[2];
|
||||
File->read((uint8_t *)shebang_magic, 2);
|
||||
|
||||
if (shebang_magic[0] == '#' && shebang_magic[1] == '!')
|
||||
{
|
||||
char *orig_path = (char *)pcb->vma->RequestPages(TO_PAGES(strlen(path) + 1));
|
||||
memcpy(orig_path, path, strlen(path) + 1);
|
||||
|
||||
char *shebang = (char *)safe_path;
|
||||
size_t shebang_len = 0;
|
||||
constexpr int shebang_len_max = 255;
|
||||
File->seek(2, SEEK_SET);
|
||||
off_t shebang_off = 2;
|
||||
while (true)
|
||||
{
|
||||
char c;
|
||||
if (File->node->read((uint8_t *)&c, 1, shebang_off) == 0)
|
||||
break;
|
||||
if (c == '\n' || shebang_len == shebang_len_max)
|
||||
break;
|
||||
shebang[shebang_len++] = c;
|
||||
shebang_off++;
|
||||
}
|
||||
shebang[shebang_len] = '\0';
|
||||
debug("Shebang: %s", shebang);
|
||||
|
||||
char **c_safe_argv = (char **)pcb->vma->RequestPages(TO_PAGES(MAX_ARG));
|
||||
int i = 0;
|
||||
for (; safe_argv[i] != nullptr; i++)
|
||||
{
|
||||
size_t arg_len = strlen(safe_argv[i]);
|
||||
char *c_arg = (char *)pcb->vma->RequestPages(TO_PAGES(arg_len));
|
||||
memcpy((void *)c_arg, safe_argv[i], arg_len);
|
||||
c_arg[arg_len] = '\0';
|
||||
|
||||
c_safe_argv[i] = c_arg;
|
||||
debug("c_safe_argv[%d]: %s", i, c_safe_argv[i]);
|
||||
}
|
||||
c_safe_argv[i] = nullptr;
|
||||
|
||||
char *token = strtok(shebang, " ");
|
||||
i = 0;
|
||||
while (token != nullptr)
|
||||
{
|
||||
size_t len = strlen(token);
|
||||
char *t_arg = (char *)pcb->vma->RequestPages(TO_PAGES(len));
|
||||
memcpy((void *)t_arg, token, len);
|
||||
t_arg[len] = '\0';
|
||||
|
||||
safe_argv[i++] = t_arg;
|
||||
token = strtok(nullptr, " ");
|
||||
}
|
||||
|
||||
safe_argv[i++] = orig_path;
|
||||
for (int j = 1; c_safe_argv[j] != nullptr; j++)
|
||||
{
|
||||
safe_argv[i++] = c_safe_argv[j];
|
||||
debug("clone: safe_argv[%d]: %s",
|
||||
i, safe_argv[i - 1]);
|
||||
}
|
||||
safe_argv[i] = nullptr;
|
||||
|
||||
delete File;
|
||||
return sys_execve(Frame, safe_argv[0],
|
||||
(char *const *)safe_argv,
|
||||
(char *const *)safe_envp);
|
||||
}
|
||||
|
||||
int ret = Execute::Spawn((char *)safe_path,
|
||||
(const char **)safe_argv,
|
||||
(const char **)safe_envp,
|
||||
pcb->Parent, pcb->Info.Compatibility);
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
error("Failed to spawn");
|
||||
delete File;
|
||||
return ret;
|
||||
}
|
||||
|
||||
delete File;
|
||||
Tasking::Task *ctx = pcb->GetContext();
|
||||
ctx->Sleep(1000);
|
||||
pcb->State = Tasking::Zombie;
|
||||
pcb->ExitCode = 0;
|
||||
while (true)
|
||||
ctx->Yield();
|
||||
__builtin_unreachable();
|
||||
}
|
Reference in New Issue
Block a user