From 819ce91395804d4ae9ac07d0080d3cfbed4ea258 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Wed, 31 Oct 2018 17:50:43 +0100 Subject: [PATCH] Enough compatibility work to make figlet build and run! I ran out of steam writing library routines and imported two BSD-licensed libc routines: sscanf() and getopt(). I will most likely rewrite them sooner or later. For now I just wanted to see figlet running. --- Kernel/MemoryManager.cpp | 3 +- Kernel/Syscall.cpp | 8 +- Kernel/Syscall.h | 3 +- Kernel/Task.cpp | 41 ++++- Kernel/Task.h | 4 +- Kernel/sync-local.sh | 7 + Kernel/sync-sh | 1 + LibC/Makefile | 2 + LibC/assert.h | 2 +- LibC/entry.cpp | 17 ++- LibC/getopt.cpp | 109 +++++++++++++ LibC/getopt.h | 13 ++ LibC/scanf.cpp | 255 +++++++++++++++++++++++++++++++ LibC/stdio.cpp | 121 ++++++++++++++- LibC/stdio.h | 16 ++ LibC/stdlib.cpp | 78 ++++++++-- LibC/stdlib.h | 3 +- LibC/string.cpp | 47 +++++- LibC/string.h | 4 + LibC/unistd.cpp | 6 + LibC/unistd.h | 3 + VirtualFileSystem/FileHandle.cpp | 7 +- 22 files changed, 714 insertions(+), 36 deletions(-) create mode 100755 Kernel/sync-local.sh create mode 100644 LibC/getopt.cpp create mode 100644 LibC/getopt.h create mode 100644 LibC/scanf.cpp diff --git a/Kernel/MemoryManager.cpp b/Kernel/MemoryManager.cpp index c22e8b3e0e4830..9a23f9da5628c1 100644 --- a/Kernel/MemoryManager.cpp +++ b/Kernel/MemoryManager.cpp @@ -41,7 +41,6 @@ void MemoryManager::initializePaging() identityMap(LinearAddress(4096), 4 * MB); - // Put pages between 4MB and 8MB in the page freelist. for (size_t i = (4 * MB) + PAGE_SIZE; i < (8 * MB); i += PAGE_SIZE) { m_freePages.append(PhysicalAddress(i)); } @@ -170,7 +169,7 @@ RetainPtr MemoryManager::createZone(size_t size) InterruptDisabler disabler; auto pages = allocatePhysicalPages(ceilDiv(size, PAGE_SIZE)); if (pages.isEmpty()) { - kprintf("[MM] createZone: no physical pages for size %u", size); + kprintf("[MM] createZone: no physical pages for size %u\n", size); return nullptr; } return adopt(*new Zone(move(pages))); diff --git a/Kernel/Syscall.cpp b/Kernel/Syscall.cpp index 67b0ff992cbf59..d84c1642aa2c63 100644 --- a/Kernel/Syscall.cpp +++ b/Kernel/Syscall.cpp @@ -77,10 +77,8 @@ DWORD handle(DWORD function, DWORD arg1, DWORD arg2, DWORD arg3) case Syscall::PosixRead: //kprintf("syscall: read(%d, %p, %u)\n", arg1, arg2, arg3); return current->sys$read((int)arg1, (void*)arg2, (size_t)arg3); - case Syscall::PosixSeek: - // FIXME: This has the wrong signature, should be like lseek() - kprintf("syscall: seek(%d, %d)\n", arg1, arg2); - return current->sys$seek((int)arg1, (int)arg2); + case Syscall::PosixLseek: + return current->sys$lseek((int)arg1, (off_t)arg2, (int)arg3); case Syscall::PosixKill: return current->sys$kill((pid_t)arg1, (int)arg2); case Syscall::PosixGetuid: @@ -104,6 +102,8 @@ DWORD handle(DWORD function, DWORD arg1, DWORD arg2, DWORD arg3) return 0; case Syscall::GetArguments: return current->sys$get_arguments((int*)arg1, (char***)arg2); + case Syscall::GetEnvironment: + return current->sys$get_environment((char***)arg1); case Syscall::PosixChdir: return current->sys$chdir((const char*)arg1); case Syscall::PosixUname: diff --git a/Kernel/Syscall.h b/Kernel/Syscall.h index 9f0d8de243f285..1e952d859891c0 100644 --- a/Kernel/Syscall.h +++ b/Kernel/Syscall.h @@ -17,7 +17,7 @@ enum Function { PosixOpen = 0x1985, PosixClose = 0x1986, PosixRead = 0x1987, - PosixSeek = 0x1988, + PosixLseek = 0x1988, PosixKill = 0x1989, PosixGetuid = 0x1990, PosixExit = 0x1991, @@ -39,6 +39,7 @@ enum Function { PosixWrite = 0x2007, PosixTtynameR = 0x2008, PosixStat = 0x2009, + GetEnvironment = 0x2010, }; void initialize(); diff --git a/Kernel/Task.cpp b/Kernel/Task.cpp index 07f9f8cc7707b8..8d26e9c02c9644 100644 --- a/Kernel/Task.cpp +++ b/Kernel/Task.cpp @@ -182,6 +182,7 @@ int Task::sys$set_mmap_name(void* addr, size_t size, const char* name) void* Task::sys$mmap(void* addr, size_t size) { + InterruptDisabler disabler; // FIXME: Implement mapping at a client-preferred address. ASSERT(addr == nullptr); auto* region = allocateRegion(size, "mmap"); @@ -193,6 +194,7 @@ void* Task::sys$mmap(void* addr, size_t size) int Task::sys$munmap(void* addr, size_t size) { + InterruptDisabler disabler; auto* region = regionFromRange(LinearAddress((dword)addr), size); if (!region) return -1; @@ -213,6 +215,12 @@ int Task::sys$gethostname(char* buffer, size_t size) int Task::sys$spawn(const char* path, const char** args) { + if (args) { + for (size_t i = 0; args[i]; ++i) { + VALIDATE_USER_BUFFER(args[i], strlen(args[i])); + } + } + int error = 0; auto* child = Task::createUserTask(path, m_uid, m_gid, m_pid, error, args, m_tty); if (child) @@ -261,10 +269,17 @@ Task* Task::createUserTask(const String& path, uid_t uid, gid_t gid, pid_t paren taskArguments.append(parts.last()); } + Vector taskEnvironment; + taskEnvironment.append("PATH=/bin"); + taskEnvironment.append("SHELL=/bin/sh"); + taskEnvironment.append("TERM=console"); + taskEnvironment.append("HOME=/"); + InterruptDisabler disabler; // FIXME: Get rid of this, jesus christ. This "critical" section is HUGE. Task* t = new Task(parts.takeLast(), uid, gid, parentPID, Ring3, move(cwd), handle->vnode(), tty); t->m_arguments = move(taskArguments); + t->m_initialEnvironment = move(taskEnvironment); ExecSpace space; Region* region = nullptr; @@ -322,11 +337,29 @@ Task* Task::createUserTask(const String& path, uid_t uid, gid_t gid, pid_t paren #ifdef TASK_DEBUG kprintf("Task %u (%s) spawned @ %p\n", t->pid(), t->name().characters(), t->m_tss.eip); #endif - error = 0; return t; } +int Task::sys$get_environment(char*** environ) +{ + auto* region = allocateRegion(4096, "environ"); + if (!region) + return -ENOMEM; + MM.mapRegion(*this, *region); + char* envpage = (char*)region->linearAddress.get(); + *environ = (char**)envpage; + char* bufptr = envpage + (sizeof(char*) * (m_initialEnvironment.size() + 1)); + for (size_t i = 0; i < m_initialEnvironment.size(); ++i) { + (*environ)[i] = bufptr; + memcpy(bufptr, m_initialEnvironment[i].characters(), m_initialEnvironment[i].length()); + bufptr += m_initialEnvironment[i].length(); + *(bufptr++) = '\0'; + } + (*environ)[m_initialEnvironment.size()] = nullptr; + return 0; +} + int Task::sys$get_arguments(int* argc, char*** argv) { auto* region = allocateRegion(4096, "argv"); @@ -763,12 +796,12 @@ ssize_t Task::sys$get_dir_entries(int fd, void* buffer, size_t size) return handle->get_dir_entries((byte*)buffer, size); } -int Task::sys$seek(int fd, int offset) +int Task::sys$lseek(int fd, off_t offset, int whence) { auto* handle = fileHandleIfExists(fd); if (!handle) - return -1; - return handle->seek(offset, SEEK_SET); + return -EBADF; + return handle->seek(offset, whence); } int Task::sys$ttyname_r(int fd, char* buffer, size_t size) diff --git a/Kernel/Task.h b/Kernel/Task.h index c86b501792320f..8f7e77716c0de5 100644 --- a/Kernel/Task.h +++ b/Kernel/Task.h @@ -94,7 +94,7 @@ class Task : public InlineLinkedListNode { ssize_t sys$write(int fd, const void*, size_t); int sys$lstat(const char*, Unix::stat*); int sys$stat(const char*, Unix::stat*); - int sys$seek(int fd, int offset); + int sys$lseek(int fd, off_t, int whence); int sys$kill(pid_t pid, int sig); int sys$geterror() { return m_error; } void sys$exit(int status); @@ -110,6 +110,7 @@ class Task : public InlineLinkedListNode { int sys$gettimeofday(timeval*); int sys$gethostname(char* name, size_t length); int sys$get_arguments(int* argc, char*** argv); + int sys$get_environment(char*** environ); int sys$uname(utsname*); int sys$readlink(const char*, char*, size_t); int sys$ttyname_r(int fd, char*, size_t); @@ -220,6 +221,7 @@ class Task : public InlineLinkedListNode { void murder(); Vector m_arguments; + Vector m_initialEnvironment; }; extern void task_init(); diff --git a/Kernel/sync-local.sh b/Kernel/sync-local.sh new file mode 100755 index 00000000000000..ee67768785f867 --- /dev/null +++ b/Kernel/sync-local.sh @@ -0,0 +1,7 @@ +cp ../../figlet-2.2.5/figlet mnt/bin/ +mkdir -p mnt/usr/local/share/figlet +FIGLET_FONTDIR=/ +cp ../../figlet-2.2.5/fonts/standard.flf mnt/$FIGLET_FONTDIR +cp ../../figlet-2.2.5/fonts/big.flf mnt/$FIGLET_FONTDIR +cp ../../figlet-2.2.5/fonts/slant.flf mnt/$FIGLET_FONTDIR +cp ../../figlet-2.2.5/fonts/lean.flf mnt/$FIGLET_FONTDIR diff --git a/Kernel/sync-sh b/Kernel/sync-sh index d455f52f31dc38..99855924a2733f 100755 --- a/Kernel/sync-sh +++ b/Kernel/sync-sh @@ -17,6 +17,7 @@ cp ../Userland/clear mnt/bin/clear cp ../Userland/tst mnt/bin/tst cp ../Userland/mm mnt/bin/mm cp ../Userland/kill mnt/bin/kill +sh sync-local.sh cp kernel.map mnt/ umount mnt sync diff --git a/LibC/Makefile b/LibC/Makefile index 88ab201b6321f6..9ff40f9ff0640b 100644 --- a/LibC/Makefile +++ b/LibC/Makefile @@ -17,6 +17,8 @@ LIBC_OBJS = \ utsname.o \ assert.o \ signal.o \ + getopt.o \ + scanf.o \ entry.o OBJS = $(AK_OBJS) $(LIBC_OBJS) diff --git a/LibC/assert.h b/LibC/assert.h index b56bd14d79abf5..e0a297a12a8dfb 100644 --- a/LibC/assert.h +++ b/LibC/assert.h @@ -6,7 +6,7 @@ __BEGIN_DECLS void __assertion_failed(const char* msg, const char* file, unsigned line, const char* func); -#define assert(expr) (static_cast(expr) ? (void)0 : __assertion_failed(#expr, __FILE__, __LINE__, __PRETTY_FUNCTION__)) +#define assert(expr) ((expr) ? (void)0 : __assertion_failed(#expr, __FILE__, __LINE__, __PRETTY_FUNCTION__)) #define CRASH() do { asm volatile("ud2"); } while(0) #define ASSERT assert #define RELEASE_ASSERT assert diff --git a/LibC/entry.cpp b/LibC/entry.cpp index e4ea51f9bd1a99..3d338dc0acd2bd 100644 --- a/LibC/entry.cpp +++ b/LibC/entry.cpp @@ -10,9 +10,14 @@ int errno; FILE* stdin; FILE* stdout; FILE* stderr; +char** environ; + +extern "C" void __malloc_init(); extern "C" int _start() { + __malloc_init(); + errno = 0; __default_streams[0].fd = 0; @@ -26,12 +31,18 @@ extern "C" int _start() StringImpl::initializeGlobals(); + int status = 254; int argc; char** argv; int rc = Syscall::invoke(Syscall::GetArguments, (dword)&argc, (dword)&argv); - int status = 254; - if (rc == 0) - status = main(argc, argv); + if (rc < 0) + goto epilogue; + rc = Syscall::invoke(Syscall::GetEnvironment, (dword)&environ); + if (rc < 0) + goto epilogue; + status = main(argc, argv); + +epilogue: Syscall::invoke(Syscall::PosixExit, status); // Birger's birthday <3 diff --git a/LibC/getopt.cpp b/LibC/getopt.cpp new file mode 100644 index 00000000000000..76b5e688de51df --- /dev/null +++ b/LibC/getopt.cpp @@ -0,0 +1,109 @@ +/* + * Copyright (c) 1987, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include +#include +#include +#include +#include + +int opterr = 1; /* if error message should be printed */ +int optind = 1; /* index into parent argv vector */ +int optopt; /* character checked for validity */ +int optreset; /* reset getopt */ +char *optarg; /* argument associated with option */ + +#define BADCH (int)'?' +#define BADARG (int)':' +#define EMSG "" + +int getopt(int nargc, char* const nargv[], const char* ostr) +{ + static const char* place = EMSG; /* option letter processing */ + char *oli; /* option letter list index */ + + ASSERT(nargv != NULL); + ASSERT(ostr != NULL); + + if (optreset || !*place) { /* update scanning pointer */ + optreset = 0; + if (optind >= nargc || *(place = nargv[optind]) != '-') { + place = EMSG; + return (-1); + } + if (place[1] && *++place == '-' /* found "--" */ + && place[1] == '\0') { + ++optind; + place = EMSG; + return -1; + } + } /* option letter okay? */ + if ((optopt = (int)*place++) == (int)':' || !(oli = strchr(ostr, optopt))) { + /* + * if the user didn't specify '-' as an option, + * assume it means -1. + */ + if (optopt == (int)'-') + return -1; + if (!*place) + ++optind; + if (opterr && *ostr != ':') + fprintf(stderr, "unknown option -- %c\n", optopt); + return BADCH; + } + if (*++oli != ':') { /* don't need argument */ + optarg = NULL; + if (!*place) + ++optind; + } + else { /* need an argument */ + if (*place) /* no white space */ + optarg = (char*)place; + else if (nargc <= ++optind) { /* no arg */ + place = EMSG; + if (*ostr == ':') + return BADARG; + if (opterr) + fprintf(stderr, "option requires an argument -- %c\n", optopt); + return BADCH; + } + else /* white space */ + optarg = nargv[optind]; + place = EMSG; + ++optind; + } + return optopt; /* dump back option letter */ +} diff --git a/LibC/getopt.h b/LibC/getopt.h new file mode 100644 index 00000000000000..a55f06df526a1c --- /dev/null +++ b/LibC/getopt.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +__BEGIN_DECLS + +int getopt(int argc, char* const argv[], const char* optstring); +extern char* optarg; +extern int optind; +extern int opterr; +extern int optopt; + +__END_DECLS diff --git a/LibC/scanf.cpp b/LibC/scanf.cpp new file mode 100644 index 00000000000000..23c673c71a73d3 --- /dev/null +++ b/LibC/scanf.cpp @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2000-2002 Opsycon AB (www.opsycon.se) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Opsycon AB. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ +#include +#include +#include +#include + +#define MAXLN 512 + +static const char* determineBase(const char* p, int& base) +{ + if (p[0] == '0') { + switch (p[1]) { + case 'x': + base = 16; + break; + case 't': + case 'n': + base = 10; + break; + case 'o': + base = 8; + break; + default: + base = 10; + return p; + } + return p + 2; + } + base = 10; + return p; +} + +static int _atob(unsigned long* vp, const char* p, int base) +{ + unsigned long value, v1, v2; + char *q, tmp[20]; + int digit; + + if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) { + base = 16; + p += 2; + } + + if (base == 16 && (q = strchr(p, '.')) != 0) { + if (q - p > sizeof(tmp) - 1) + return 0; + strncpy(tmp, p, q - p); + tmp[q - p] = '\0'; + if (!_atob(&v1, tmp, 16)) + return 0; + ++q; + if (strchr(q, '.')) + return 0; + if (!_atob(&v2, q, 16)) + return 0; + *vp = (v1 << 16) + v2; + return 1; + } + + value = *vp = 0; + for (; *p; p++) { + if (*p >= '0' && *p <= '9') + digit = *p - '0'; + else if (*p >= 'a' && *p <= 'f') + digit = *p - 'a' + 10; + else if (*p >= 'A' && *p <= 'F') + digit = *p - 'A' + 10; + else + return 0; + + if (digit >= base) + return 0; + value *= base; + value += digit; + } + *vp = value; + return 1; +} + +int atob(unsigned int* vp, const char* p, int base) +{ + unsigned long v; + + if (base == 0) + p = determineBase(p, base); + if (_atob(&v, p, base)) { + *vp = v; + return 1; + } + return 0; +} + +static int vfscanf(FILE*, const char*, va_list); +static int vsscanf(const char*, const char*, va_list); + +#define ISSPACE " \t\n\r\f\v" + +int scanf(const char* fmt, ...) +{ + int count; + va_list ap; + + va_start(ap, fmt); + count = vfscanf(stdin, fmt, ap); + va_end(ap); + return count; +} + +int fscanf(FILE *fp, const char* fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + int count = vfscanf(fp, fmt, ap); + va_end(ap); + return count; +} + +int sscanf(const char *buf, const char* fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + int count = vsscanf(buf, fmt, ap); + va_end(ap); + return count; +} + +static int vfscanf(FILE *fp, const char* fmt, va_list ap) +{ + char buf[MAXLN + 1]; + if (!fgets(buf, MAXLN, fp)) + return -1; + int count = vsscanf(buf, fmt, ap); + return count; +} + +static int vsscanf(const char *buf, const char *s, va_list ap) +{ + int base; + char *t; + char tmp[MAXLN]; + bool noassign = false; + bool lflag = false; + int count = 0; + int width = 0; + + while (*s && *buf) { + while (isspace (*s)) + s++; + if (*s == '%') { + s++; + for (; *s; s++) { + if (strchr ("dibouxcsefg%", *s)) + break; + if (*s == '*') + noassign = true; + else if (*s == 'l' || *s == 'L') + lflag = true; + else if (*s >= '1' && *s <= '9') { + const char* tc; + for (tc = s; isdigit(*s); s++); + strncpy (tmp, tc, s - tc); + tmp[s - tc] = '\0'; + atob ((dword*)&width, tmp, 10); + s--; + } + } + if (*s == 's') { + while (isspace(*buf)) + buf++; + if (!width) + width = strcspn(buf, ISSPACE); + if (!noassign) { + strncpy(t = va_arg(ap, char*), buf, width); + t[width] = '\0'; + } + buf += width; + } else if (*s == 'c') { + if (!width) + width = 1; + if (!noassign) { + strncpy(t = va_arg(ap, char*), buf, width); + t[width] = '\0'; + } + buf += width; + } else if (strchr("dobxu", *s)) { + while (isspace(*buf)) + buf++; + if (*s == 'd' || *s == 'u') + base = 10; + else if (*s == 'x') + base = 16; + else if (*s == 'o') + base = 8; + else if (*s == 'b') + base = 2; + if (!width) { + if (isspace(*(s + 1)) || *(s + 1) == 0) + width = strcspn(buf, ISSPACE); + else + width = strchr(buf, *(s + 1)) - buf; + } + strncpy(tmp, buf, width); + tmp[width] = '\0'; + buf += width; + if (!noassign) + atob(va_arg(ap, dword*), tmp, base); + } + if (!noassign) + ++count; + width = 0; + noassign = false; + lflag = false; + ++s; + } else { + while (isspace(*buf)) + buf++; + if (*s != *buf) + break; + else { + ++s; + ++buf; + } + } + } + return count; +} diff --git a/LibC/stdio.cpp b/LibC/stdio.cpp index 09f3a463b6f382..beea53547cfc43 100644 --- a/LibC/stdio.cpp +++ b/LibC/stdio.cpp @@ -4,17 +4,115 @@ #include #include #include +#include +#include #include #include extern "C" { -int putchar(int ch) +int fileno(FILE* stream) +{ + return stream->fd; +} + +int feof(FILE* stream) +{ + return stream->eof; +} + +char* fgets(char* buffer, int size, FILE* stream) +{ + ssize_t nread = 0; + for (;;) { + if (nread >= size) + break; + char ch = fgetc(stream); + if (feof(stream)) + break; + buffer[nread++] = ch; + if (!ch || ch == '\n') + break; + } + if (nread < size) + buffer[nread] = '\0'; + return buffer; +} + +int fgetc(FILE* stream) +{ + char ch; + read(stream->fd, &ch, 1); + return ch; +} + +int getc(FILE* stream) { - write(0, &ch, 1); + return fgetc(stream); +} + +int getchar() +{ + return getc(stdin); +} + +int fputc(int ch, FILE* stream) +{ + write(stream->fd, &ch, 1); return (byte)ch; } +int putc(int ch, FILE* stream) +{ + return fputc(ch, stream); +} + +int putchar(int ch) +{ + return putc(ch, stdout); +} + +void clearerr(FILE* stream) +{ + stream->eof = false; +} + +size_t fread(void* ptr, size_t size, size_t nmemb, FILE* stream) +{ + ssize_t nread = read(stream->fd, ptr, nmemb * size); + if (nread < 0) + return 0; + if (nread == 0) + stream->eof = true; + return nread; +} + +size_t fwrite(const void* ptr, size_t size, size_t nmemb, FILE* stream) +{ + ssize_t nwritten = write(stream->fd, ptr, nmemb * size); + if (nwritten < 0) + return 0; + return nwritten; +} + +int fseek(FILE* stream, long offset, int whence) +{ + off_t off = lseek(stream->fd, offset, whence); + if (off < 0) + return off; + return 0; +} + +long ftell(FILE* stream) +{ + return lseek(stream->fd, 0, SEEK_CUR); +} + +void rewind(FILE* stream) +{ + fseek(stream, 0, SEEK_SET); +} + static void sys_putch(char*&, char ch) { putchar(ch); @@ -65,5 +163,24 @@ void perror(const char* s) printf("%s: %s\n", s, strerror(errno)); } +FILE* fopen(const char* pathname, const char* mode) +{ + assert(!strcmp(mode, "r") || !strcmp(mode, "rb")); + int fd = open(pathname, O_RDONLY); + if (fd < 0) + return nullptr; + auto* fp = (FILE*)malloc(sizeof(FILE)); + fp->fd = fd; + fp->eof = false; + return fp; +} + +int fclose(FILE* stream) +{ + int rc = close(stream->fd); + free(stream); + return rc; +} + } diff --git a/LibC/stdio.h b/LibC/stdio.h index 6129ccd3da5ce1..8e61095d8fc81e 100644 --- a/LibC/stdio.h +++ b/LibC/stdio.h @@ -1,6 +1,7 @@ #pragma once #include +#include __BEGIN_DECLS @@ -8,8 +9,13 @@ __BEGIN_DECLS #define EOF (-1) #endif +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 + struct __STDIO_FILE { int fd; + int eof; }; typedef struct __STDIO_FILE FILE; @@ -18,11 +24,21 @@ extern FILE* stdin; extern FILE* stdout; extern FILE* stderr; +char* fgets(char* buffer, int size, FILE*); +int fileno(FILE*); +int fgetc(FILE*); +int getc(FILE*); +int getchar(); +FILE* fopen(const char* pathname, const char* mode); +int fclose(FILE*); +size_t fread(void* ptr, size_t size, size_t nmemb, FILE*); +size_t fwrite(const void* ptr, size_t size, size_t nmemb, FILE*); int fprintf(FILE*, const char* fmt, ...); int printf(const char* fmt, ...); int sprintf(char* buffer, const char* fmt, ...); int putchar(int ch); void perror(const char*); +int sscanf (const char* buf, const char* fmt, ...); __END_DECLS diff --git a/LibC/stdlib.cpp b/LibC/stdlib.cpp index 8f9758521bf2e1..f4482e9b117028 100644 --- a/LibC/stdlib.cpp +++ b/LibC/stdlib.cpp @@ -1,32 +1,50 @@ -#include "stdlib.h" -#include "mman.h" -#include "stdio.h" +#include +#include +#include +#include +#include +#include #include #include extern "C" { +// FIXME: This is a temporary malloc() implementation. It never frees anything, +// and you can't allocate more than 128 kB total. +static const size_t mallocBudget = 131072; + +static byte* nextptr = nullptr; +static byte* endptr = nullptr; + +void __malloc_init() +{ + nextptr = (byte*)mmap(nullptr, mallocBudget); + endptr = nextptr + mallocBudget; + int rc = set_mmap_name(nextptr, mallocBudget, "malloc"); + if (rc < 0) + perror("set_mmap_name failed"); +} + void* malloc(size_t size) { - if (size > 4096) { + if ((nextptr + size) > endptr) { volatile char* crashme = (char*)0xc007d00d; *crashme = 0; } - void* ptr = mmap(nullptr, 4096); - if (ptr) { - int rc = set_mmap_name(ptr, 4096, "malloc"); - if (rc < 0) { - perror("set_mmap_name failed"); - } - } - return ptr; + byte* ret = nextptr; + nextptr += size; + nextptr += 16; + nextptr = (byte*)((dword)nextptr & 0xfffffff0); + return ret; } void free(void* ptr) { if (!ptr) return; +#if 0 munmap(ptr, 4096); +#endif } void* calloc(size_t nmemb, size_t) @@ -52,5 +70,41 @@ void abort() exit(253); } +char* getenv(const char* name) +{ + for (size_t i = 0; environ[i]; ++i) { + const char* decl = environ[i]; + char* eq = strchr(decl, '='); + if (!eq) + continue; + size_t varLength = eq - decl; + char* var = (char*)alloca(varLength + 1); + memcpy(var, decl, varLength); + var[varLength] = '\0'; + if (!strcmp(var, name)) { + char* value = eq + 1; + return value; + } + } + return nullptr; +} + +int atoi(const char* str) +{ + ssize_t len = strlen(str); + int value = 0; + bool isNegative = false; + for (size_t i = 0; i < len; ++i) { + if (i == 0 && str[0] == '-') { + isNegative = true; + continue; + } + if (str[i] < '0' || str[i] > '9') + return 0; + value = value * 10; + value += str[i] - '0'; + } + return isNegative ? -value : value; } +} diff --git a/LibC/stdlib.h b/LibC/stdlib.h index 4b6b8c7765cf4c..0a6102719a5321 100644 --- a/LibC/stdlib.h +++ b/LibC/stdlib.h @@ -9,7 +9,8 @@ void* malloc(size_t); void free(void*); void* calloc(size_t nmemb, size_t); void* realloc(void *ptr, size_t); - +char* getenv(const char* name); +int atoi(const char*); void exit(int status); void abort(); diff --git a/LibC/string.cpp b/LibC/string.cpp index a7c8b2a5ea7b06..0efe36a9eba2c2 100644 --- a/LibC/string.cpp +++ b/LibC/string.cpp @@ -4,6 +4,40 @@ extern "C" { +void* memset(void* dest, int c, size_t n) +{ + byte* bdest = (byte*)dest; + for (; n; --n) + *(bdest++) = c; + return dest; +} + +size_t strspn(const char* s, const char* accept) +{ + const char* p = s; +cont: + char ch = *p++; + char ac; + for (const char* ap = accept; (ac = *ap++) != '\0';) { + if (ac == ch) + goto cont; + } + return p - 1 - s; +} + +size_t strcspn(const char* s, const char* reject) +{ + for (auto* p = s;;) { + char c = *p++; + auto* rp = reject; + char rc; + do { + if ((rc = *rp++) == c) + return p - 1 - s; + } while(rc); + } +} + size_t strlen(const char* str) { size_t len = 0; @@ -62,11 +96,22 @@ char* strchr(const char* str, int c) if (!str) return nullptr; char* ptr = (char*)str; - while (*ptr != c) + while (*ptr && *ptr != c) ++ptr; return ptr; } +char* strrchr(const char* str, int ch) +{ + char *last = nullptr; + char c; + for (; (c = *str); ++str) { + if (c == ch) + last = (char*)str; + } + return last; +} + char* strcat(char *dest, const char *src) { size_t destLength = strlen(dest); diff --git a/LibC/string.h b/LibC/string.h index 8d7f2a3f31c928..b16b5a733ba9e5 100644 --- a/LibC/string.h +++ b/LibC/string.h @@ -9,11 +9,15 @@ size_t strlen(const char*); int strcmp(const char*, const char*); int memcmp(const void*, const void*, size_t); void memcpy(void*, const void*, size_t); +void* memset(void*, int, size_t); char* strcpy(char* dest, const char* src); char* strncpy(char* dest, const char* src, size_t); char* strchr(const char*, int c); +char* strrchr(const char*, int c); char* strcat(char *dest, const char *src); char* strncat(char *dest, const char *src, size_t); +size_t strspn(const char*, const char* accept); +size_t strcspn(const char*, const char* reject); const char* strerror(int errnum); __END_DECLS diff --git a/LibC/unistd.cpp b/LibC/unistd.cpp index 65e959edb3cfea..53f6b2aab23ab7 100644 --- a/LibC/unistd.cpp +++ b/LibC/unistd.cpp @@ -105,5 +105,11 @@ ssize_t readlink(const char* path, char* buffer, size_t size) __RETURN_WITH_ERRNO(rc, rc, -1); } +off_t lseek(int fd, off_t offset, int whence) +{ + int rc = Syscall::invoke(Syscall::PosixLseek, (dword)fd, (dword)offset, (dword)whence); + __RETURN_WITH_ERRNO(rc, rc, -1); +} + } diff --git a/LibC/unistd.h b/LibC/unistd.h index 97b3f0df429440..d9fa1da623a408 100644 --- a/LibC/unistd.h +++ b/LibC/unistd.h @@ -5,6 +5,8 @@ __BEGIN_DECLS +extern char** environ; + uid_t getuid(); gid_t getgid(); pid_t getpid(); @@ -22,6 +24,7 @@ int gethostname(char*, size_t); ssize_t readlink(const char* path, char* buffer, size_t); char* ttyname(int fd); int ttyname_r(int fd, char* buffer, size_t); +off_t lseek(int fd, off_t, int whence); #define WEXITSTATUS(status) (((status) & 0xff00) >> 8) #define WTERMSIG(status) ((status) & 0x7f) diff --git a/VirtualFileSystem/FileHandle.cpp b/VirtualFileSystem/FileHandle.cpp index c114c2469eba48..7e795906e31a16 100644 --- a/VirtualFileSystem/FileHandle.cpp +++ b/VirtualFileSystem/FileHandle.cpp @@ -79,9 +79,8 @@ Unix::off_t FileHandle::seek(Unix::off_t offset, int whence) return -EINVAL; break; case SEEK_END: - // FIXME: Implement! - notImplemented(); - newOffset = 0; + ASSERT(metadata.size); // FIXME: What do I do? + newOffset = metadata.size; break; default: return -EINVAL; @@ -148,7 +147,7 @@ ssize_t FileHandle::get_dir_entries(byte* buffer, Unix::size_t size) // FIXME: Compute the actual size needed. auto tempBuffer = ByteBuffer::createUninitialized(2048); BufferStream stream(tempBuffer); - m_vnode->vfs()->enumerateDirectoryInode(m_vnode->inode, [&stream] (const FileSystem::DirectoryEntry& entry) { + m_vnode->vfs()->enumerateDirectoryInode(m_vnode->inode, [&stream] (auto& entry) { stream << (dword)entry.inode.index(); stream << (byte)entry.fileType; stream << (dword)entry.name.length();