diff --git a/ELFLoader/ELFLoader.cpp b/ELFLoader/ELFLoader.cpp index a14b3443f7..35e8020405 100644 --- a/ELFLoader/ELFLoader.cpp +++ b/ELFLoader/ELFLoader.cpp @@ -56,6 +56,22 @@ bool ELFLoader::layout() m_sections.set(section.name(), move(ptr)); return true; }); + m_image->forEachSectionOfType(SHT_NOBITS, [this, &failed] (const ELFImage::Section& section) { +#ifdef ELFLOADER_DEBUG + kprintf("[ELFLoader] Allocating nobits section: %s\n", section.name()); +#endif + if (!section.size()) + return true; + char* ptr = m_execSpace.allocateArea(section.name(), section.size()); + if (!ptr) { + kprintf("ELFLoader: failed to allocate section '%s'\n", section.name()); + failed = true; + return false; + } + memset(ptr, 0, section.size()); + m_sections.set(section.name(), move(ptr)); + return true; + }); return !failed; } diff --git a/Kernel/Task.cpp b/Kernel/Task.cpp index 4a534d479c..c8f5303133 100644 --- a/Kernel/Task.cpp +++ b/Kernel/Task.cpp @@ -9,6 +9,7 @@ #include #include #include "MemoryManager.h" +#include "errno.h" //#define DEBUG_IO //#define TASK_DEBUG @@ -166,25 +167,32 @@ int Task::sys$munmap(void* addr, size_t size) int Task::sys$spawn(const char* path) { - auto* child = Task::createUserTask(path, m_uid, m_gid, m_pid); + int error = 0; + auto* child = Task::createUserTask(path, m_uid, m_gid, m_pid, error); if (child) return child->pid(); - return -1; + return error; } -Task* Task::createUserTask(const String& path, uid_t uid, gid_t gid, pid_t parentPID) +Task* Task::createUserTask(const String& path, uid_t uid, gid_t gid, pid_t parentPID, int& error) { auto parts = path.split('/'); - if (parts.isEmpty()) + if (parts.isEmpty()) { + error = -ENOENT; return nullptr; + } auto handle = VirtualFileSystem::the().open(path); - if (!handle) + if (!handle) { + error = -ENOENT; // FIXME: Get a more detailed error from VFS. return nullptr; + } auto elfData = handle->readEntireFile(); - if (!elfData) + if (!elfData) { + error = -EIO; // FIXME: Get a more detailed error from VFS. return nullptr; + } InterruptDisabler disabler; // FIXME: Get rid of this, jesus christ. This "critical" section is HUGE. Task* t = new Task(parts.takeLast(), uid, gid, parentPID, Ring3); @@ -203,12 +211,14 @@ Task* Task::createUserTask(const String& path, uid_t uid, gid_t gid, pid_t paren if (!success) { delete t; kprintf("Failure loading ELF %s\n", path.characters()); + error = -ENOEXEC; return nullptr; } t->m_tss.eip = (dword)space.symbolPtr("_start"); if (!t->m_tss.eip) { delete t; + error = -ENOEXEC; return nullptr; } @@ -221,6 +231,7 @@ Task* Task::createUserTask(const String& path, uid_t uid, gid_t gid, pid_t paren kprintf("Task %u (%s) spawned @ %p\n", t->pid(), t->name().characters(), t->m_tss.eip); #endif + error = 0; return t; } @@ -758,11 +769,6 @@ Task* Task::kernelTask() return s_kernelTask; } -void Task::setError(int error) -{ - m_error = error; -} - Task::Region::Region(LinearAddress a, size_t s, RetainPtr&& z, String&& n) : linearAddress(a) , size(s) diff --git a/Kernel/Task.h b/Kernel/Task.h index 2a9e4532e0..f166df8c9b 100644 --- a/Kernel/Task.h +++ b/Kernel/Task.h @@ -16,7 +16,7 @@ class Task : public InlineLinkedListNode { friend class InlineLinkedListNode; public: static Task* createKernelTask(void (*entry)(), String&& name); - static Task* createUserTask(const String& path, uid_t, gid_t, pid_t parentPID); + static Task* createUserTask(const String& path, uid_t, gid_t, pid_t parentPID, int& error); ~Task(); static Vector allTasks(); @@ -100,7 +100,6 @@ public: int sys$getcwd(char*, size_t); static void initialize(); - void setError(int); static void taskDidCrash(Task*); diff --git a/Kernel/_fs_contents b/Kernel/_fs_contents index d3cf094bfb..182fabbb3f 100644 Binary files a/Kernel/_fs_contents and b/Kernel/_fs_contents differ diff --git a/Kernel/errno.h b/Kernel/errno.h new file mode 100644 index 0000000000..e01e73798a --- /dev/null +++ b/Kernel/errno.h @@ -0,0 +1,38 @@ +#pragma once + +#define EPERM 1 // Operation not permitted +#define ENOENT 2 // No such file or directory +#define ESRCH 3 // No such process +#define EINTR 4 // Interrupted system call +#define EIO 5 // I/O error +#define ENXIO 6 // No such device or address +#define E2BIG 7 // Argument list too long +#define ENOEXEC 8 // Exec format error +#define EBADF 9 // Bad file number +#define ECHILD 10 // No child processes +#define EAGAIN 11 // Try again +#define ENOMEM 12 // Out of memory +#define EACCES 13 // Permission denied +#define EFAULT 14 // Bad address +#define ENOTBLK 15 // Block device required +#define EBUSY 16 // Device or resource busy +#define EEXIST 17 // File exists +#define EXDEV 18 // Cross-device link +#define ENODEV 19 // No such device +#define ENOTDIR 20 // Not a directory +#define EISDIR 21 // Is a directory +#define EINVAL 22 // Invalid argument +#define ENFILE 23 // File table overflow +#define EMFILE 24 // Too many open files +#define ENOTTY 25 // Not a typewriter +#define ETXTBSY 26 // Text file busy +#define EFBIG 27 // File too large +#define ENOSPC 28 // No space left on device +#define ESPIPE 29 // Illegal seek +#define EROFS 30 // Read-only file system +#define EMLINK 31 // Too many links +#define EPIPE 32 // Broken pipe +#define EDOM 33 // Math argument out of domain of func +#define ERANGE 34 // Math result not representable + +#define EOVERFLOW 75 // Value too large for defined data type diff --git a/Kernel/init.cpp b/Kernel/init.cpp index 0dca290075..31cf17ba3e 100644 --- a/Kernel/init.cpp +++ b/Kernel/init.cpp @@ -140,7 +140,8 @@ static void init_stage2() dword lastAlloc = sum_alloc; for (unsigned i = 0; i < 100; ++i) { - auto* shTask = Task::createUserTask("/bin/id", (uid_t)100, (gid_t)100, (pid_t)0); + int error; + auto* shTask = Task::createUserTask("/bin/id", (uid_t)100, (gid_t)100, (pid_t)0, error); kprintf("malloc stats: alloc:%u free:%u\n", sum_alloc, sum_free); kprintf("sizeof(Task):%u\n", sizeof(Task)); kprintf("delta:%u\n",sum_alloc - lastAlloc); @@ -149,7 +150,8 @@ static void init_stage2() } #endif - auto* shTask = Task::createUserTask("/bin/sh", (uid_t)100, (gid_t)100, (pid_t)0); + int error; + auto* shTask = Task::createUserTask("/bin/sh", (uid_t)100, (gid_t)100, (pid_t)0, error); banner(); diff --git a/LibC/entry.cpp b/LibC/entry.cpp index 9a34577977..2308bc453c 100644 --- a/LibC/entry.cpp +++ b/LibC/entry.cpp @@ -2,8 +2,12 @@ extern "C" int main(int, char**); +int errno; + extern "C" int _start() { + errno = 0; + // FIXME: Pass appropriate argc/argv. int status = main(0, nullptr); diff --git a/LibC/errno.h b/LibC/errno.h new file mode 100644 index 0000000000..5f4a403f5a --- /dev/null +++ b/LibC/errno.h @@ -0,0 +1,57 @@ +#pragma once + +#define EPERM 1 // Operation not permitted +#define ENOENT 2 // No such file or directory +#define ESRCH 3 // No such process +#define EINTR 4 // Interrupted system call +#define EIO 5 // I/O error +#define ENXIO 6 // No such device or address +#define E2BIG 7 // Argument list too long +#define ENOEXEC 8 // Exec format error +#define EBADF 9 // Bad file number +#define ECHILD 10 // No child processes +#define EAGAIN 11 // Try again +#define ENOMEM 12 // Out of memory +#define EACCES 13 // Permission denied +#define EFAULT 14 // Bad address +#define ENOTBLK 15 // Block device required +#define EBUSY 16 // Device or resource busy +#define EEXIST 17 // File exists +#define EXDEV 18 // Cross-device link +#define ENODEV 19 // No such device +#define ENOTDIR 20 // Not a directory +#define EISDIR 21 // Is a directory +#define EINVAL 22 // Invalid argument +#define ENFILE 23 // File table overflow +#define EMFILE 24 // Too many open files +#define ENOTTY 25 // Not a typewriter +#define ETXTBSY 26 // Text file busy +#define EFBIG 27 // File too large +#define ENOSPC 28 // No space left on device +#define ESPIPE 29 // Illegal seek +#define EROFS 30 // Read-only file system +#define EMLINK 31 // Too many links +#define EPIPE 32 // Broken pipe +#define EDOM 33 // Math argument out of domain of func +#define ERANGE 34 // Math result not representable + +#define EOVERFLOW 75 // Value too large for defined data type + + +#define __RETURN_WITH_ERRNO(rc, good_ret, bad_ret) \ + do { \ + if (rc < 0) { \ + errno = -rc; \ + return (bad_ret); \ + } else { \ + errno = 0; \ + return (good_ret); \ + } \ + } while(0) + +extern "C" { + +extern int errno; + +}; + diff --git a/LibC/mman.cpp b/LibC/mman.cpp index ad8aae334c..604f3aaf05 100644 --- a/LibC/mman.cpp +++ b/LibC/mman.cpp @@ -1,16 +1,19 @@ #include "mman.h" +#include "errno.h" #include extern "C" { void* mmap(void* addr, size_t size) { - return (void*)Syscall::invoke(Syscall::PosixMmap, (dword)addr, (dword)size); + int rc = Syscall::invoke(Syscall::PosixMmap, (dword)addr, (dword)size); + __RETURN_WITH_ERRNO(rc, (void*)rc, (void*)-1); } int munmap(void* addr, size_t size) { - return Syscall::invoke(Syscall::PosixMunmap, (dword)addr, (dword)size); + int rc = Syscall::invoke(Syscall::PosixMunmap, (dword)addr, (dword)size); + __RETURN_WITH_ERRNO(rc, rc, -1); } } diff --git a/LibC/process.cpp b/LibC/process.cpp index 045b3e3eeb..223b6871d7 100644 --- a/LibC/process.cpp +++ b/LibC/process.cpp @@ -1,11 +1,13 @@ #include "process.h" +#include "errno.h" #include extern "C" { int spawn(const char* path) { - return Syscall::invoke(Syscall::Spawn, (dword)path); + int rc = Syscall::invoke(Syscall::Spawn, (dword)path); + __RETURN_WITH_ERRNO(rc, rc, -1); } } diff --git a/LibC/string.cpp b/LibC/string.cpp index 252dc65657..94b4450249 100644 --- a/LibC/string.cpp +++ b/LibC/string.cpp @@ -1,4 +1,6 @@ #include "string.h" +#include "errno.h" +#include "stdio.h" extern "C" { @@ -10,5 +12,49 @@ size_t strlen(const char* str) return len; } +const char* strerror(int errnum) +{ + switch (errnum) { + case 0: return "No error"; + case EPERM: return "Operation not permitted"; + case ENOENT: return "No such file or directory"; + case ESRCH: return "No such process"; + case EINTR: return "Interrupted syscall"; + case EIO: return "I/O error"; + case ENXIO: return "No such device/address"; + case E2BIG: return "Argument list too long"; + case ENOEXEC: return "Exec format error"; + case EBADF: return "Bad fd number"; + case ECHILD: return "No child processes"; + case EAGAIN: return "Try again"; + case ENOMEM: return "Out of memory"; + case EACCES: return "Access denied"; + case EFAULT: return "Bad address"; + case ENOTBLK: return "Not a block device"; + case EBUSY: return "Resource busy"; + case EEXIST: return "File already exists"; + case EXDEV: return "Cross-device link"; + case ENODEV: return "No such device"; + case ENOTDIR: return "Not a directory"; + case EISDIR: return "Is a directory"; + case EINVAL: return "Invalid argument"; + case ENFILE: return "File table overflow"; + case EMFILE: return "Too many open files"; + case ENOTTY: return "Not a TTY"; + case ETXTBSY: return "Text file busy"; + case EFBIG: return "File too big"; + case ENOSPC: return "No space left"; + case ESPIPE: return "Illegal seek"; + case EROFS: return "File system is read-only"; + case EMLINK: return "Too many links"; + case EPIPE: return "Broken pipe"; + case EDOM: return "Math argument out of domain"; + case ERANGE: return "Math result not representable"; + case EOVERFLOW: return "Value too large for data type"; + } + printf("strerror() missing string for errnum=%d\n", errnum); + return "Unknown error"; +} + } diff --git a/LibC/string.h b/LibC/string.h index 21e4ccf287..15d0dbf1bf 100644 --- a/LibC/string.h +++ b/LibC/string.h @@ -5,6 +5,7 @@ extern "C" { size_t strlen(const char*); +const char* strerror(int errnum); } diff --git a/LibC/unistd.cpp b/LibC/unistd.cpp index 814346e075..335645e91b 100644 --- a/LibC/unistd.cpp +++ b/LibC/unistd.cpp @@ -1,5 +1,6 @@ #include "unistd.h" #include "string.h" +#include "errno.h" #include extern "C" { @@ -22,35 +23,38 @@ pid_t getpid() int open(const char* path) { size_t length = strlen(path); - return Syscall::invoke(Syscall::PosixOpen, (dword)path, (dword)length); + int rc = Syscall::invoke(Syscall::PosixOpen, (dword)path, (dword)length); + __RETURN_WITH_ERRNO(rc, rc, -1); } ssize_t read(int fd, void* buf, size_t count) { - return Syscall::invoke(Syscall::PosixRead, (dword)fd, (dword)buf, (dword)count); + int rc = Syscall::invoke(Syscall::PosixRead, (dword)fd, (dword)buf, (dword)count); + __RETURN_WITH_ERRNO(rc, rc, -1); } int close(int fd) { - return Syscall::invoke(Syscall::PosixClose, fd); + int rc = Syscall::invoke(Syscall::PosixClose, fd); + __RETURN_WITH_ERRNO(rc, rc, -1); } pid_t waitpid(pid_t waitee) { - return Syscall::invoke(Syscall::PosixWaitpid, waitee); + int rc = Syscall::invoke(Syscall::PosixWaitpid, waitee); + __RETURN_WITH_ERRNO(rc, rc, -1); } int lstat(const char* path, stat* statbuf) { - return Syscall::invoke(Syscall::PosixLstat, (dword)path, (dword)statbuf); + int rc = Syscall::invoke(Syscall::PosixLstat, (dword)path, (dword)statbuf); + __RETURN_WITH_ERRNO(rc, rc, -1); } char* getcwd(char* buffer, size_t size) { int rc = Syscall::invoke(Syscall::PosixGetcwd, (dword)buffer, (dword)size); - if (rc != 0) - return nullptr; - return buffer; + __RETURN_WITH_ERRNO(rc, buffer, nullptr); } } diff --git a/Userland/sh.cpp b/Userland/sh.cpp index 68d4cc24b3..35905dc861 100644 --- a/Userland/sh.cpp +++ b/Userland/sh.cpp @@ -1,6 +1,8 @@ #include #include #include +#include +#include static void prompt() { @@ -12,12 +14,14 @@ static void prompt() static int runcmd(char* cmd) { + if (cmd[0] == 0) + return 0; //printf("command: '%s'\n", cmd); char buf[128]; sprintf(buf, "/bin/%s", cmd); int ret = spawn(buf); if (ret == -1) { - printf("spawn failed: %s\n", cmd); + printf("spawn failed: %s (%s)\n", cmd, strerror(errno)); return 1; } waitpid(ret);