mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-12-12 09:20:36 +00:00
Share code between spawn() and exec() implementations.
Okay, now there's only one ELF loading client in the process launch code.
This commit is contained in:
parent
c5eec9cbfc
commit
dd060d0fa8
Notes:
sideshowbarker
2024-07-19 18:34:07 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/dd060d0fa89
7 changed files with 86 additions and 128 deletions
|
@ -359,6 +359,7 @@ int Process::exec(const String& path, Vector<String>&& arguments, Vector<String>
|
|||
}
|
||||
|
||||
InterruptDisabler disabler;
|
||||
if (current == this)
|
||||
loadTaskRegister(s_kernelProcess->selector());
|
||||
|
||||
m_name = parts.takeLast();
|
||||
|
@ -392,8 +393,9 @@ int Process::exec(const String& path, Vector<String>&& arguments, Vector<String>
|
|||
kprintf("Process %u (%s) exec'd %s @ %p\n", pid(), name().characters(), filename, m_tss.eip);
|
||||
#endif
|
||||
|
||||
if (current == this)
|
||||
yield();
|
||||
ASSERT(false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -430,129 +432,82 @@ int Process::sys$execve(const char* filename, const char** argv, const char** en
|
|||
}
|
||||
}
|
||||
|
||||
return exec(path, move(arguments), move(environment));
|
||||
int rc = exec(path, move(arguments), move(environment));
|
||||
ASSERT(rc < 0);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int Process::sys$spawn(const char* path, const char** args)
|
||||
pid_t Process::sys$spawn(const char* filename, const char** argv, const char** envp)
|
||||
{
|
||||
if (args) {
|
||||
for (size_t i = 0; args[i]; ++i) {
|
||||
VALIDATE_USER_READ(args[i], strlen(args[i]));
|
||||
VALIDATE_USER_READ(filename, strlen(filename));
|
||||
if (argv) {
|
||||
for (size_t i = 0; argv[i]; ++i) {
|
||||
VALIDATE_USER_READ(argv[i], strlen(argv[i]));
|
||||
}
|
||||
}
|
||||
if (envp) {
|
||||
for (size_t i = 0; envp[i]; ++i) {
|
||||
VALIDATE_USER_READ(envp[i], strlen(envp[i]));
|
||||
}
|
||||
}
|
||||
|
||||
int error = 0;
|
||||
auto* child = Process::createUserProcess(path, m_uid, m_gid, m_pid, error, args, m_tty);
|
||||
String path(filename);
|
||||
auto parts = path.split('/');
|
||||
|
||||
Vector<String> arguments;
|
||||
if (argv) {
|
||||
for (size_t i = 0; argv[i]; ++i) {
|
||||
arguments.append(argv[i]);
|
||||
}
|
||||
} else {
|
||||
arguments.append(parts.last());
|
||||
}
|
||||
|
||||
Vector<String> environment;
|
||||
if (envp) {
|
||||
for (size_t i = 0; envp[i]; ++i) {
|
||||
environment.append(envp[i]);
|
||||
}
|
||||
}
|
||||
|
||||
int error;
|
||||
auto* child = create_user_process(path, m_uid, m_gid, m_pid, error, move(arguments), move(environment), m_tty);
|
||||
if (child)
|
||||
return child->pid();
|
||||
return error;
|
||||
}
|
||||
|
||||
Process* Process::createUserProcess(const String& path, uid_t uid, gid_t gid, pid_t parentPID, int& error, const char** args, TTY* tty)
|
||||
Process* Process::create_user_process(const String& path, uid_t uid, gid_t gid, pid_t parent_pid, int& error, Vector<String>&& arguments, Vector<String>&& environment, TTY* tty)
|
||||
{
|
||||
// FIXME: Don't split() the path twice (sys$spawn also does it...)
|
||||
auto parts = path.split('/');
|
||||
if (parts.isEmpty()) {
|
||||
error = -ENOENT;
|
||||
return nullptr;
|
||||
if (arguments.isEmpty()) {
|
||||
arguments.append(parts.last());
|
||||
}
|
||||
|
||||
RetainPtr<VirtualFileSystem::Node> cwd;
|
||||
{
|
||||
InterruptDisabler disabler;
|
||||
if (auto* parentProcess = Process::fromPID(parentPID))
|
||||
cwd = parentProcess->m_cwd.copyRef();
|
||||
if (auto* parent = Process::fromPID(parent_pid))
|
||||
cwd = parent->m_cwd.copyRef();
|
||||
}
|
||||
if (!cwd)
|
||||
cwd = VirtualFileSystem::the().root();
|
||||
}
|
||||
|
||||
auto handle = VirtualFileSystem::the().open(path, error, 0, cwd ? cwd->inode : InodeIdentifier());
|
||||
if (!handle)
|
||||
auto* process = new Process(parts.takeLast(), uid, gid, parent_pid, Ring3, move(cwd), nullptr, tty);
|
||||
|
||||
error = process->exec(path, move(arguments), move(environment));
|
||||
if (error != 0)
|
||||
return nullptr;
|
||||
|
||||
if (!handle->metadata().mayExecute(uid, gid)) {
|
||||
error = -EACCES;
|
||||
return nullptr;
|
||||
}
|
||||
ProcFileSystem::the().addProcess(*process);
|
||||
|
||||
auto elfData = handle->readEntireFile();
|
||||
if (!elfData) {
|
||||
error = -EIO; // FIXME: Get a more detailed error from VFS.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Vector<String> processArguments;
|
||||
if (args) {
|
||||
for (size_t i = 0; args[i]; ++i) {
|
||||
processArguments.append(args[i]);
|
||||
}
|
||||
} else {
|
||||
processArguments.append(parts.last());
|
||||
}
|
||||
|
||||
Vector<String> processEnvironment;
|
||||
processEnvironment.append("PATH=/bin");
|
||||
processEnvironment.append("SHELL=/bin/sh");
|
||||
processEnvironment.append("TERM=console");
|
||||
processEnvironment.append("HOME=/");
|
||||
|
||||
auto* t = new Process(parts.takeLast(), uid, gid, parentPID, Ring3, move(cwd), handle->vnode(), tty);
|
||||
|
||||
t->m_arguments = move(processArguments);
|
||||
t->m_initialEnvironment = move(processEnvironment);
|
||||
|
||||
ExecSpace space;
|
||||
Region* region = nullptr;
|
||||
|
||||
ProcessPagingScope pagingScope(*t);
|
||||
space.hookableAlloc = [&] (const String& name, size_t size) {
|
||||
if (!size)
|
||||
return (void*)nullptr;
|
||||
size = ((size / 4096) + 1) * 4096; // FIXME: Use ceil_div?
|
||||
region = t->allocateRegion(size, String(name));
|
||||
return (void*)region->linearAddress.get();
|
||||
};
|
||||
bool success = space.loadELF(move(elfData));
|
||||
if (!success) {
|
||||
delete t;
|
||||
kprintf("Failure loading ELF %s\n", path.characters());
|
||||
error = -ENOEXEC;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
space.forEachArea([&] (const String& name, dword offset, size_t size, LinearAddress laddr) {
|
||||
if (laddr.isNull())
|
||||
return;
|
||||
dword roundedOffset = offset & 0xfffff000;
|
||||
size_t roundedSize = 4096 * ceilDiv((offset - roundedOffset) + size, 4096u);
|
||||
LinearAddress roundedLaddr = laddr;
|
||||
roundedLaddr.mask(0xfffff000);
|
||||
t->m_subregions.append(make<Subregion>(*region, roundedOffset, roundedSize, roundedLaddr, String(name)));
|
||||
#ifdef SUBREGION_DEBUG
|
||||
kprintf(" req subregion %s (offset: %u, size: %u) @ %p\n", name.characters(), offset, size, laddr.get());
|
||||
kprintf("actual subregion %s (offset: %u, size: %u) @ %p\n", name.characters(), roundedOffset, roundedSize, roundedLaddr.get());
|
||||
#endif
|
||||
MM.mapSubregion(*t, *t->m_subregions.last());
|
||||
});
|
||||
|
||||
t->m_tss.eip = (dword)space.symbolPtr("_start");
|
||||
if (!t->m_tss.eip) {
|
||||
// FIXME: This is ugly. If we need to do this, it should be at a different level.
|
||||
delete t;
|
||||
error = -ENOEXEC;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ASSERT(region);
|
||||
|
||||
ProcFileSystem::the().addProcess(*t);
|
||||
|
||||
s_processes->prepend(t);
|
||||
s_processes->prepend(process);
|
||||
system.nprocess++;
|
||||
#ifdef TASK_DEBUG
|
||||
kprintf("Process %u (%s) spawned @ %p\n", t->pid(), t->name().characters(), t->m_tss.eip);
|
||||
kprintf("Process %u (%s) spawned @ %p\n", process->pid(), process->name().characters(), process->m_tss.eip);
|
||||
#endif
|
||||
error = 0;
|
||||
return t;
|
||||
return process;
|
||||
}
|
||||
|
||||
int Process::sys$get_environment(char*** environ)
|
||||
|
|
|
@ -19,7 +19,7 @@ class Process : public InlineLinkedListNode<Process> {
|
|||
friend class InlineLinkedListNode<Process>;
|
||||
public:
|
||||
static Process* createKernelProcess(void (*entry)(), String&& name);
|
||||
static Process* createUserProcess(const String& path, uid_t, gid_t, pid_t parentPID, int& error, const char** args = nullptr, TTY* = nullptr);
|
||||
static Process* create_user_process(const String& path, uid_t, gid_t, pid_t parentPID, int& error, Vector<String>&& arguments = Vector<String>(), Vector<String>&& environment = Vector<String>(), TTY* = nullptr);
|
||||
~Process();
|
||||
|
||||
static Vector<Process*> allProcesses();
|
||||
|
@ -103,7 +103,7 @@ public:
|
|||
int sys$kill(pid_t pid, int sig);
|
||||
int sys$geterror() { return m_error; }
|
||||
void sys$exit(int status);
|
||||
int sys$spawn(const char* path, const char** args);
|
||||
pid_t sys$spawn(const char* path, const char** args, const char** envp);
|
||||
pid_t sys$waitpid(pid_t, int* wstatus, int options);
|
||||
void* sys$mmap(void*, size_t size);
|
||||
int sys$munmap(void*, size_t size);
|
||||
|
|
|
@ -58,7 +58,7 @@ static DWORD handle(RegisterDump& regs, DWORD function, DWORD arg1, DWORD arg2,
|
|||
case Syscall::PosixGettimeofday:
|
||||
return current->sys$gettimeofday((timeval*)arg1);
|
||||
case Syscall::Spawn:
|
||||
return current->sys$spawn((const char*)arg1, (const char**)arg2);
|
||||
return current->sys$spawn((const char*)arg1, (const char**)arg2, (const char**)arg3);
|
||||
case Syscall::GetDirEntries:
|
||||
return current->sys$get_dir_entries((int)arg1, (void*)arg2, (size_t)arg3);
|
||||
case Syscall::PosixLstat:
|
||||
|
|
36
Kernel/TSS.h
36
Kernel/TSS.h
|
@ -1,21 +1,23 @@
|
|||
#pragma once
|
||||
|
||||
#include <AK/Types.h>
|
||||
|
||||
struct TSS32 {
|
||||
unsigned short backlink, __blh;
|
||||
unsigned long esp0;
|
||||
unsigned short ss0, __ss0h;
|
||||
unsigned long esp1;
|
||||
unsigned short ss1, __ss1h;
|
||||
unsigned long esp2;
|
||||
unsigned short ss2, __ss2h;
|
||||
unsigned long cr3, eip, eflags;
|
||||
unsigned long eax,ecx,edx,ebx,esp,ebp,esi,edi;
|
||||
unsigned short es, __esh;
|
||||
unsigned short cs, __csh;
|
||||
unsigned short ss, __ssh;
|
||||
unsigned short ds, __dsh;
|
||||
unsigned short fs, __fsh;
|
||||
unsigned short gs, __gsh;
|
||||
unsigned short ldt, __ldth;
|
||||
unsigned short trace, iomapbase;
|
||||
word backlink, __blh;
|
||||
dword esp0;
|
||||
word ss0, __ss0h;
|
||||
dword esp1;
|
||||
word ss1, __ss1h;
|
||||
dword esp2;
|
||||
word ss2, __ss2h;
|
||||
dword cr3, eip, eflags;
|
||||
dword eax,ecx,edx,ebx,esp,ebp,esi,edi;
|
||||
word es, __esh;
|
||||
word cs, __csh;
|
||||
word ss, __ssh;
|
||||
word ds, __dsh;
|
||||
word fs, __fsh;
|
||||
word gs, __gsh;
|
||||
word ldt, __ldth;
|
||||
word trace, iomapbase;
|
||||
} PACKED;
|
||||
|
|
|
@ -145,7 +145,7 @@ static void spawn_stress()
|
|||
|
||||
for (unsigned i = 0; i < 10000; ++i) {
|
||||
int error;
|
||||
Process::createUserProcess("/bin/id", (uid_t)100, (gid_t)100, (pid_t)0, error, nullptr, tty0);
|
||||
Process::create_user_process("/bin/id", (uid_t)100, (gid_t)100, (pid_t)0, error, Vector<String>(), Vector<String>(), tty0);
|
||||
// kprintf("malloc stats: alloc:%u free:%u page_aligned:%u eternal:%u\n", sum_alloc, sum_free, kmalloc_page_aligned, kmalloc_sum_eternal);
|
||||
// kprintf("delta:%u\n", sum_alloc - lastAlloc);
|
||||
lastAlloc = sum_alloc;
|
||||
|
@ -230,11 +230,11 @@ static void init_stage2()
|
|||
#endif
|
||||
|
||||
int error;
|
||||
auto* sh0 = Process::createUserProcess("/bin/sh", (uid_t)100, (gid_t)100, (pid_t)0, error, nullptr, tty0);
|
||||
auto* sh0 = Process::create_user_process("/bin/sh", (uid_t)100, (gid_t)100, (pid_t)0, error, Vector<String>(), Vector<String>(), tty0);
|
||||
#ifdef SPAWN_MULTIPLE_SHELLS
|
||||
auto* sh1 = Process::createUserProcess("/bin/sh", (uid_t)100, (gid_t)100, (pid_t)0, error, nullptr, tty1);
|
||||
auto* sh2 = Process::createUserProcess("/bin/sh", (uid_t)100, (gid_t)100, (pid_t)0, error, nullptr, tty2);
|
||||
auto* sh3 = Process::createUserProcess("/bin/sh", (uid_t)100, (gid_t)100, (pid_t)0, error, nullptr, tty3);
|
||||
auto* sh1 = Process::create_user_process("/bin/sh", (uid_t)100, (gid_t)100, (pid_t)0, error, Vector<String>(), Vector<String>(), tty1);
|
||||
auto* sh2 = Process::create_user_process("/bin/sh", (uid_t)100, (gid_t)100, (pid_t)0, error, Vector<String>(), Vector<String>(), tty2);
|
||||
auto* sh3 = Process::create_user_process("/bin/sh", (uid_t)100, (gid_t)100, (pid_t)0, error, Vector<String>(), Vector<String>(), tty3);
|
||||
#endif
|
||||
|
||||
#ifdef STRESS_TEST_SPAWNING
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
|
||||
extern "C" {
|
||||
|
||||
int spawn(const char* path, const char** args)
|
||||
int spawn(const char* path, const char** args, const char** envp)
|
||||
{
|
||||
int rc = Syscall::invoke(Syscall::Spawn, (dword)path, (dword)args);
|
||||
int rc = Syscall::invoke(Syscall::Spawn, (dword)path, (dword)args, (dword)envp);
|
||||
__RETURN_WITH_ERRNO(rc, rc, -1);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
#pragma once
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
int spawn(const char* path, const char** args);
|
||||
pid_t spawn(const char* path, const char** args, const char** envp);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
|
|
Loading…
Reference in a new issue