diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp index 33463d9aeb..21de6a640c 100644 --- a/Kernel/Process.cpp +++ b/Kernel/Process.cpp @@ -359,7 +359,8 @@ int Process::exec(const String& path, Vector&& arguments, Vector } InterruptDisabler disabler; - loadTaskRegister(s_kernelProcess->selector()); + if (current == this) + loadTaskRegister(s_kernelProcess->selector()); m_name = parts.takeLast(); @@ -392,8 +393,9 @@ int Process::exec(const String& path, Vector&& arguments, Vector kprintf("Process %u (%s) exec'd %s @ %p\n", pid(), name().characters(), filename, m_tss.eip); #endif - yield(); - ASSERT(false); + if (current == this) + yield(); + 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 arguments; + if (argv) { + for (size_t i = 0; argv[i]; ++i) { + arguments.append(argv[i]); + } + } else { + arguments.append(parts.last()); + } + + Vector 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&& arguments, Vector&& 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 cwd; { InterruptDisabler disabler; - if (auto* parentProcess = Process::fromPID(parentPID)) - cwd = parentProcess->m_cwd.copyRef(); - if (!cwd) - cwd = VirtualFileSystem::the().root(); + 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 processArguments; - if (args) { - for (size_t i = 0; args[i]; ++i) { - processArguments.append(args[i]); - } - } else { - processArguments.append(parts.last()); - } - - Vector 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(*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) diff --git a/Kernel/Process.h b/Kernel/Process.h index 12fdf0c5c3..031dcf1a08 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -19,7 +19,7 @@ class Process : public InlineLinkedListNode { friend class InlineLinkedListNode; 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&& arguments = Vector(), Vector&& environment = Vector(), TTY* = nullptr); ~Process(); static Vector 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); diff --git a/Kernel/Syscall.cpp b/Kernel/Syscall.cpp index dd2ca9aeee..b9783e9a07 100644 --- a/Kernel/Syscall.cpp +++ b/Kernel/Syscall.cpp @@ -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: diff --git a/Kernel/TSS.h b/Kernel/TSS.h index 86d49d0fd8..676750e454 100644 --- a/Kernel/TSS.h +++ b/Kernel/TSS.h @@ -1,21 +1,23 @@ #pragma once +#include + 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; diff --git a/Kernel/init.cpp b/Kernel/init.cpp index 81a3fd84f0..d6e65978de 100644 --- a/Kernel/init.cpp +++ b/Kernel/init.cpp @@ -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(), Vector(), 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(), Vector(), 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(), Vector(), tty1); + auto* sh2 = Process::create_user_process("/bin/sh", (uid_t)100, (gid_t)100, (pid_t)0, error, Vector(), Vector(), tty2); + auto* sh3 = Process::create_user_process("/bin/sh", (uid_t)100, (gid_t)100, (pid_t)0, error, Vector(), Vector(), tty3); #endif #ifdef STRESS_TEST_SPAWNING diff --git a/LibC/process.cpp b/LibC/process.cpp index eb3040b80e..96c6a93540 100644 --- a/LibC/process.cpp +++ b/LibC/process.cpp @@ -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); } diff --git a/LibC/process.h b/LibC/process.h index 9b5bf828a9..aa2a1d9f5a 100644 --- a/LibC/process.h +++ b/LibC/process.h @@ -1,10 +1,11 @@ #pragma once #include +#include __BEGIN_DECLS -int spawn(const char* path, const char** args); +pid_t spawn(const char* path, const char** args, const char** envp); __END_DECLS