summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Kernel/MemoryManager.cpp3
-rw-r--r--Kernel/Syscall.cpp8
-rw-r--r--Kernel/Syscall.h3
-rw-r--r--Kernel/Task.cpp41
-rw-r--r--Kernel/Task.h4
-rwxr-xr-xKernel/sync-local.sh7
-rwxr-xr-xKernel/sync-sh1
-rw-r--r--LibC/Makefile2
-rw-r--r--LibC/assert.h2
-rw-r--r--LibC/entry.cpp17
-rw-r--r--LibC/getopt.cpp109
-rw-r--r--LibC/getopt.h13
-rw-r--r--LibC/scanf.cpp255
-rw-r--r--LibC/stdio.cpp121
-rw-r--r--LibC/stdio.h16
-rw-r--r--LibC/stdlib.cpp78
-rw-r--r--LibC/stdlib.h3
-rw-r--r--LibC/string.cpp47
-rw-r--r--LibC/string.h4
-rw-r--r--LibC/unistd.cpp6
-rw-r--r--LibC/unistd.h3
-rw-r--r--VirtualFileSystem/FileHandle.cpp7
22 files changed, 714 insertions, 36 deletions
diff --git a/Kernel/MemoryManager.cpp b/Kernel/MemoryManager.cpp
index c22e8b3e0e..9a23f9da56 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<Zone> 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 67b0ff992c..d84c1642aa 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 9f0d8de243..1e952d8598 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 07f9f8cc77..8d26e9c02c 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<String> 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 c86b501792..8f7e77716c 100644
--- a/Kernel/Task.h
+++ b/Kernel/Task.h
@@ -94,7 +94,7 @@ public:
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 @@ public:
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 @@ private:
void murder();
Vector<String> m_arguments;
+ Vector<String> m_initialEnvironment;
};
extern void task_init();
diff --git a/Kernel/sync-local.sh b/Kernel/sync-local.sh
new file mode 100755
index 0000000000..ee67768785
--- /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 d455f52f31..99855924a2 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 88ab201b63..9ff40f9ff0 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 b56bd14d79..e0a297a12a 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<bool>(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 e4ea51f9bd..3d338dc0ac 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 0000000000..76b5e688de
--- /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 <getopt.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+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 0000000000..a55f06df52
--- /dev/null
+++ b/LibC/getopt.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#include <sys/cdefs.h>
+
+__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 0000000000..23c673c71a
--- /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 <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+
+#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 09f3a463b6..beea53547c 100644
--- a/LibC/stdio.cpp
+++ b/LibC/stdio.cpp
@@ -4,17 +4,115 @@
#include <string.h>
#include <errno.h>
#include <unistd.h>
+#include <assert.h>
+#include <stdlib.h>
#include <Kernel/Syscall.h>
#include <AK/printf.cpp>
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 6129ccd3da..8e61095d8f 100644
--- a/LibC/stdio.h
+++ b/LibC/stdio.h
@@ -1,6 +1,7 @@
#pragma once
#include <sys/cdefs.h>
+#include <sys/types.h>
__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 8f9758521b..f4482e9b11 100644
--- a/LibC/stdlib.cpp
+++ b/LibC/stdlib.cpp
@@ -1,32 +1,50 @@
-#include "stdlib.h"
-#include "mman.h"
-#include "stdio.h"
+#include <stdlib.h>
+#include <mman.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <alloca.h>
#include <Kernel/Syscall.h>
#include <AK/Assertions.h>
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 4b6b8c7765..0a6102719a 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 a7c8b2a5ea..0efe36a9eb 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 8d7f2a3f31..b16b5a733b 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 65e959edb3..53f6b2aab2 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 97b3f0df42..d9fa1da623 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 c114c2469e..7e795906e3 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();