Procházet zdrojové kódy

Rage hacking to get bash to run. It finally runs. So cool! :^)

Andreas Kling před 6 roky
rodič
revize
d5d45d1088

+ 2 - 2
AK/Vector.h

@@ -48,7 +48,7 @@ public:
         --m_size;
     }
 
-private:
+//private:
     friend class Vector<T, Allocator>;
 
     VectorImpl(size_t capacity) : m_capacity(capacity) { }
@@ -235,7 +235,7 @@ public:
     ConstIterator begin() const { return ConstIterator(*this, 0); }
     ConstIterator end() const { return ConstIterator(*this, size()); }
 
-private:
+//private:
     static size_t paddedCapacity(size_t capacity)
     {
         return max(size_t(4), capacity + (capacity / 4) + 4);

+ 4 - 0
Kernel/MemoryManager.cpp

@@ -289,7 +289,9 @@ bool MemoryManager::page_in_from_vnode(PageDirectory& page_directory, Region& re
     }
     remap_region_page(&page_directory, region, page_index_in_region, true);
     byte* dest_ptr = region.linearAddress.offset(page_index_in_region * PAGE_SIZE).asPtr();
+#ifdef MM_DEBUG
     dbgprintf("MM: page_in_from_vnode ready to read from vnode, will write to L%x!\n", dest_ptr);
+#endif
     sti(); // Oh god here we go...
     auto nread = vnode.fileSystem()->readInodeBytes(vnode.inode, vmo.vnode_offset() + ((region.first_page_index() + page_index_in_region) * PAGE_SIZE), PAGE_SIZE, dest_ptr, nullptr);
     if (nread < 0) {
@@ -444,7 +446,9 @@ void MemoryManager::map_region_at_address(PageDirectory* page_directory, Region&
 {
     InterruptDisabler disabler;
     auto& vmo = region.vmo();
+#ifdef MM_DEBUG
     dbgprintf("MM: map_region_at_address will map VMO pages %u - %u (VMO page count: %u)\n", region.first_page_index(), region.last_page_index(), vmo.page_count());
+#endif
     for (size_t i = region.first_page_index(); i <= region.last_page_index(); ++i) {
         auto page_laddr = laddr.offset(i * PAGE_SIZE);
         auto pte = ensurePTE(page_directory, page_laddr);

+ 60 - 34
Kernel/Process.cpp

@@ -431,11 +431,13 @@ int Process::sys$execve(const char* filename, const char** argv, const char** en
 {
     VALIDATE_USER_READ(filename, strlen(filename));
     if (argv) {
+        VALIDATE_USER_READ(argv, sizeof(const char**));
         for (size_t i = 0; argv[i]; ++i) {
             VALIDATE_USER_READ(argv[i], strlen(argv[i]));
         }
     }
     if (envp) {
+        VALIDATE_USER_READ(envp, sizeof(const char**));
         for (size_t i = 0; envp[i]; ++i) {
             VALIDATE_USER_READ(envp[i], strlen(envp[i]));
         }
@@ -455,9 +457,8 @@ int Process::sys$execve(const char* filename, const char** argv, const char** en
 
     Vector<String> environment;
     if (envp) {
-        for (size_t i = 0; envp[i]; ++i) {
+        for (size_t i = 0; envp[i]; ++i)
             environment.append(envp[i]);
-        }
     }
 
     int rc = exec(path, move(arguments), move(environment));
@@ -976,12 +977,9 @@ ssize_t Process::sys$write(int fd, const void* data, size_t size)
 {
     VALIDATE_USER_READ(data, size);
 #ifdef DEBUG_IO
-    kprintf("Process::sys$write: called(%d, %p, %u)\n", fd, data, size);
+    dbgprintf("%s(%u): sys$write(%d, %p, %u)\n", name().characters(), pid(), fd, data, size);
 #endif
     auto* descriptor = file_descriptor(fd);
-#ifdef DEBUG_IO
-    kprintf("Process::sys$write: handle=%p\n", descriptor);
-#endif
     if (!descriptor)
         return -EBADF;
     auto nwritten = descriptor->write((const byte*)data, size);
@@ -992,7 +990,7 @@ ssize_t Process::sys$write(int fd, const void* data, size_t size)
             return -EINTR;
     }
 #ifdef DEBUG_IO
-    kprintf("Process::sys$write: nwritten=%u\n", nwritten);
+    dbgprintf("%s(%u) sys$write: nwritten=%u\n", name().characters(), pid(), nwritten);
 #endif
     return nwritten;
 }
@@ -1001,12 +999,9 @@ ssize_t Process::sys$read(int fd, void* outbuf, size_t nread)
 {
     VALIDATE_USER_WRITE(outbuf, nread);
 #ifdef DEBUG_IO
-    kprintf("Process::sys$read: called(%d, %p, %u)\n", fd, outbuf, nread);
+    dbgprintf("%s(%u) sys$read(%d, %p, %u)\n", name().characters(), pid(), fd, outbuf, nread);
 #endif
     auto* descriptor = file_descriptor(fd);
-#ifdef DEBUG_IO
-    kprintf("Process::sys$read: handle=%p\n", descriptor);
-#endif
     if (!descriptor)
         return -EBADF;
     if (descriptor->isBlocking()) {
@@ -1020,7 +1015,7 @@ ssize_t Process::sys$read(int fd, void* outbuf, size_t nread)
     }
     nread = descriptor->read((byte*)outbuf, nread);
 #ifdef DEBUG_IO
-    kprintf("Process::sys$read: nread=%u\n", nread);
+    dbgprintf("%s(%u) Process::sys$read: nread=%u\n", name().characters(), pid(), nread);
 #endif
     return nread;
 }
@@ -1042,14 +1037,27 @@ int Process::sys$access(const char* pathname, int mode)
     ASSERT_NOT_REACHED();
 }
 
-int Process::sys$fcntl(int fd, int cmd, dword extra_arg)
+int Process::sys$fcntl(int fd, int cmd, dword arg)
 {
     (void) cmd;
-    (void) extra_arg;
+    (void) arg;
+    dbgprintf("sys$fcntl: fd=%d, cmd=%d, arg=%u\n", fd, cmd, arg);
     auto* descriptor = file_descriptor(fd);
     if (!descriptor)
         return -EBADF;
-    ASSERT_NOT_REACHED();
+    switch (cmd) {
+    case F_GETFD:
+        return descriptor->fd_flags();
+    case F_SETFD:
+        return descriptor->set_fd_flags(arg);
+    case F_GETFL:
+        return descriptor->file_flags();
+    case F_SETFL:
+        return descriptor->set_file_flags(arg);
+    default:
+        ASSERT_NOT_REACHED();
+    }
+    return 0;
 }
 
 int Process::sys$fstat(int fd, Unix::stat* statbuf)
@@ -1129,7 +1137,7 @@ int Process::sys$getcwd(char* buffer, size_t size)
     if (size < path.length() + 1)
         return -ERANGE;
     strcpy(buffer, path.characters());
-    return -ENOTIMPL;
+    return 0;
 }
 
 size_t Process::number_of_open_file_descriptors() const
@@ -1145,7 +1153,7 @@ size_t Process::number_of_open_file_descriptors() const
 int Process::sys$open(const char* path, int options)
 {
 #ifdef DEBUG_IO
-    kprintf("Process::sys$open(): PID=%u, path=%s {%u}\n", m_pid, path, pathLength);
+    dbgprintf("%s(%u) sys$open(\"%s\")\n", name().characters(), pid(), path);
 #endif
     VALIDATE_USER_READ(path, strlen(path));
     if (number_of_open_file_descriptors() >= m_max_open_file_descriptors)
@@ -1307,6 +1315,7 @@ void Process::reap(Process& process)
 
 pid_t Process::sys$waitpid(pid_t waitee, int* wstatus, int options)
 {
+    //kprintf("sys$waitpid(%d, %p, %d)\n", waitee, wstatus, options);
     // FIXME: Respect options
     (void) options;
     if (wstatus)
@@ -1314,7 +1323,7 @@ pid_t Process::sys$waitpid(pid_t waitee, int* wstatus, int options)
 
     {
         InterruptDisabler disabler;
-        if (!Process::from_pid(waitee))
+        if (waitee != -1 && !Process::from_pid(waitee))
             return -ECHILD;
     }
     m_waitee = waitee;
@@ -1326,7 +1335,9 @@ pid_t Process::sys$waitpid(pid_t waitee, int* wstatus, int options)
     Process* waitee_process;
     {
         InterruptDisabler disabler;
-        waitee_process = Process::from_pid(waitee);
+
+        // NOTE: If waitee was -1, m_waitee will have been filled in by the scheduler.
+        waitee_process = Process::from_pid(m_waitee);
     }
     ASSERT(waitee_process);
     reap(*waitee_process);
@@ -1471,7 +1482,12 @@ int Process::sys$tcgetattr(int fd, Unix::termios* tp)
         return -EBADF;
     if (!descriptor->isTTY())
         return -ENOTTY;
-    ASSERT_NOT_REACHED();
+    auto& tty = *descriptor->tty();
+#ifdef TERMIOS_DEBUG
+    kprintf("sys$tcgetattr(fd=%d, tp=%p)\n", fd, tp);
+#endif
+    memcpy(tp, &tty.termios(), sizeof(Unix::termios));
+    return 0;
 }
 
 int Process::sys$tcsetattr(int fd, int optional_actions, const Unix::termios* tp)
@@ -1483,7 +1499,12 @@ int Process::sys$tcsetattr(int fd, int optional_actions, const Unix::termios* tp
         return -EBADF;
     if (!descriptor->isTTY())
         return -ENOTTY;
-    ASSERT_NOT_REACHED();
+#ifdef TERMIOS_DEBUG
+    kprintf("sys$tcsetattr(fd=%d, tp=%p)\n", fd, tp);
+#endif
+    auto& tty = *descriptor->tty();
+    memcpy(&tty.termios(), tp, sizeof(Unix::termios));
+    return 0;
 }
 
 pid_t Process::sys$tcgetpgrp(int fd)
@@ -1560,20 +1581,25 @@ Unix::sighandler_t Process::sys$signal(int signum, Unix::sighandler_t handler)
 
 int Process::sys$sigprocmask(int how, const Unix::sigset_t* set, Unix::sigset_t* old_set)
 {
-    VALIDATE_USER_READ(set, sizeof(Unix::sigset_t));
-    if (old_set)
+    if (old_set) {
         VALIDATE_USER_READ(old_set, sizeof(Unix::sigset_t));
-    *old_set = m_signal_mask;
-    switch (how) {
-    case SIG_BLOCK:
-        m_signal_mask &= ~(*set);
-        break;
-    case SIG_UNBLOCK:
-        m_signal_mask |= *set;
-        break;
-    case SIG_SETMASK:
-        m_signal_mask = *set;
-        break;
+        *old_set = m_signal_mask;
+    }
+    if (set) {
+        VALIDATE_USER_READ(set, sizeof(Unix::sigset_t));
+        switch (how) {
+        case SIG_BLOCK:
+            m_signal_mask &= ~(*set);
+            break;
+        case SIG_UNBLOCK:
+            m_signal_mask |= *set;
+            break;
+        case SIG_SETMASK:
+            m_signal_mask = *set;
+            break;
+        default:
+            return -EINVAL;
+        }
     }
     return 0;
 }

+ 16 - 0
Kernel/Process.h

@@ -104,6 +104,7 @@ public:
     template<typename Callback> static void for_each_in_pgrp(pid_t, Callback);
     template<typename Callback> static void for_each_in_state(State, Callback);
     template<typename Callback> static void for_each_not_in_state(State, Callback);
+    template<typename Callback> void for_each_child(Callback);
 
     bool tick() { ++m_ticks; return --m_ticksLeft; }
     void set_ticks_left(dword t) { m_ticksLeft = t; }
@@ -360,6 +361,21 @@ inline void Process::for_each(Callback callback)
     }
 }
 
+template<typename Callback>
+inline void Process::for_each_child(Callback callback)
+{
+    ASSERT_INTERRUPTS_DISABLED();
+    pid_t my_pid = pid();
+    for (auto* process = g_processes->head(); process;) {
+        auto* next_process = process->next();
+        if (process->ppid() == my_pid) {
+            if (!callback(*process))
+                break;
+        }
+        process = next_process;
+    }
+}
+
 template<typename Callback>
 inline void Process::for_each_in_pgrp(pid_t pgid, Callback callback)
 {

+ 11 - 9
Kernel/Scheduler.cpp

@@ -35,15 +35,17 @@ bool Scheduler::pick_next()
         }
 
         if (process.state() == Process::BlockedWait) {
-            auto* waitee = Process::from_pid(process.waitee());
-            if (!waitee) {
-                kprintf("waitee %u of %s(%u) reaped before I could wait?\n", process.waitee(), process.name().characters(), process.pid());
-                ASSERT_NOT_REACHED();
-            }
-            if (waitee->state() == Process::Dead) {
-                process.m_waitee_status = (waitee->m_termination_status << 8) | waitee->m_termination_signal;
-                process.unblock();
-            }
+            process.for_each_child([&process] (Process& child) {
+                if (child.state() != Process::Dead)
+                    return true;
+                if (process.waitee() == -1 || process.waitee() == child.pid()) {
+                    process.m_waitee_status = (child.m_termination_status << 8) | child.m_termination_signal;
+                    process.m_waitee = child.pid();
+                    process.unblock();
+                    return false;
+                }
+                return true;
+            });
             return true;
         }
 

+ 4 - 0
Kernel/TTY.cpp

@@ -5,6 +5,8 @@
 TTY::TTY(unsigned major, unsigned minor)
     : CharacterDevice(major, minor)
 {
+    memset(&m_termios, 0, sizeof(m_termios));
+    m_termios.c_lflag |= ISIG | ECHO;
 }
 
 TTY::~TTY()
@@ -42,6 +44,8 @@ void TTY::emit(byte ch)
 
 void TTY::interrupt()
 {
+    if (!should_generate_signals())
+        return;
     dbgprintf("%s: Interrupt ^C pressed!\n", ttyName().characters());
     if (pgid()) {
         dbgprintf("%s: Send SIGINT to everyone in pgrp %d\n", ttyName().characters(), pgid());

+ 6 - 0
Kernel/TTY.h

@@ -1,6 +1,7 @@
 #pragma once
 
 #include <VirtualFileSystem/CharacterDevice.h>
+#include <VirtualFileSystem/UnixTypes.h>
 
 class TTY : public CharacterDevice {
 public:
@@ -15,6 +16,10 @@ public:
     void set_pgid(pid_t pgid) { m_pgid = pgid; }
     pid_t pgid() const { return m_pgid; }
 
+    Unix::termios& termios() { return m_termios; }
+    bool should_generate_signals() const { return m_termios.c_lflag & ISIG; }
+    bool should_echo_input() const { return m_termios.c_lflag & ECHO; }
+
 protected:
     virtual bool isTTY() const final override { return true; }
 
@@ -28,5 +33,6 @@ protected:
 private:
     Vector<byte> m_buffer;
     pid_t m_pgid { 0 };
+    Unix::termios m_termios;
 };
 

+ 11 - 0
Kernel/VirtualConsole.cpp

@@ -261,6 +261,17 @@ void VirtualConsole::escape$H(const Vector<unsigned>& params)
     set_cursor(row - 1, col - 1);
 }
 
+void VirtualConsole::escape$A(const Vector<unsigned>& params)
+{
+    int num = 1;
+    if (params.size() >= 1)
+        num = params[0];
+    int new_row = (int)m_cursor_row - num;
+    if (new_row < 0)
+        new_row = 0;
+    set_cursor(new_row, m_cursor_column);
+}
+
 void VirtualConsole::escape$J(const Vector<unsigned>& params)
 {
     int mode = 0;

+ 1 - 0
Kernel/VirtualConsole.h

@@ -40,6 +40,7 @@ private:
     void set_cursor(unsigned row, unsigned column);
     void put_character_at(unsigned row, unsigned column, byte ch);
 
+    void escape$A(const Vector<unsigned>&);
     void escape$H(const Vector<unsigned>&);
     void escape$J(const Vector<unsigned>&);
     void escape$m(const Vector<unsigned>&);

+ 4 - 1
Kernel/init.cpp

@@ -239,8 +239,11 @@ static void init_stage2()
     }
 #endif
 
+    Vector<String> environment;
+    environment.append("TERM=ansi");
+
     int error;
-    Process::create_user_process("/bin/sh", (uid_t)100, (gid_t)100, (pid_t)0, error, Vector<String>(), Vector<String>(), tty0);
+    Process::create_user_process("/bin/sh", (uid_t)100, (gid_t)100, (pid_t)0, error, Vector<String>(), move(environment), tty0);
 #ifdef SPAWN_MULTIPLE_SHELLS
     Process::create_user_process("/bin/sh", (uid_t)100, (gid_t)100, (pid_t)0, error, Vector<String>(), Vector<String>(), tty1);
     Process::create_user_process("/bin/sh", (uid_t)100, (gid_t)100, (pid_t)0, error, Vector<String>(), Vector<String>(), tty2);

+ 3 - 0
Kernel/sync-local.sh

@@ -5,3 +5,6 @@ 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
+
+cp ../../bash-1.14.7/bash2 mnt/bin/bash
+

+ 2 - 0
LibC/Makefile

@@ -28,6 +28,8 @@ LIBC_OBJS = \
        ctype.o \
        fcntl.o \
        termios.o \
+       ulimit.o \
+       qsort.o \
        entry.o
 
 OBJS = $(AK_OBJS) $(LIBC_OBJS)

+ 1 - 0
LibC/fcntl.cpp

@@ -1,6 +1,7 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <stdarg.h>
+#include <stdio.h>
 #include <Kernel/Syscall.h>
 
 extern "C" {

+ 77 - 0
LibC/qsort.cpp

@@ -0,0 +1,77 @@
+/*-
+ * Copyright (c) 1980, 1983, 1990 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)qsort.c	5.9 (Berkeley) 2/23/91";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+#include <stdlib.h>
+
+static void insertion_sort(void* bot, size_t nmemb, size_t size, int (*compar)(const void *, const void *));
+
+void qsort(void* bot, size_t nmemb, size_t size, int (*compar)(const void *, const void *))
+{
+	if (nmemb <= 1)
+		return;
+
+    insertion_sort(bot, nmemb, size, compar);
+}
+
+void insertion_sort(void* bot, size_t nmemb, size_t size, int (*compar)(const void *, const void *))
+{
+    int cnt;
+    unsigned char ch;
+    char *s1, *s2, *t1, *t2, *top;
+
+	/*
+	 * A simple insertion sort (see Knuth, Vol. 3, page 81, Algorithm
+	 * S).  Insertion sort has the same worst case as most simple sorts
+	 * (O N^2).  It gets used here because it is (O N) in the case of
+	 * sorted data.
+	 */
+    top = (char*)bot + nmemb * size;
+    for (t1 = (char*)bot + size; t1 < top;) {
+		for (t2 = t1; (t2 -= size) >= bot && compar(t1, t2) < 0;);
+		if (t1 != (t2 += size)) {
+			/* Bubble bytes up through each element. */
+			for (cnt = size; cnt--; ++t1) {
+				ch = *t1;
+				for (s1 = s2 = t1; (s2 -= size) >= t2; s1 = s2)
+					*s1 = *s2;
+				*s1 = ch;
+			}
+		} else
+			t1 += size;
+	}
+}

+ 2 - 1
LibC/setjmp.cpp

@@ -4,7 +4,8 @@
 
 int setjmp(jmp_buf)
 {
-    assert(false);
+    //assert(false);
+    return 0;
 }
 
 void longjmp(jmp_buf, int)

+ 1 - 0
LibC/signal.cpp

@@ -1,6 +1,7 @@
 #include <unistd.h>
 #include <errno.h>
 #include <signal.h>
+#include <stdio.h>
 #include <Kernel/Syscall.h>
 
 extern "C" {

+ 5 - 3
LibC/stdio.cpp

@@ -45,6 +45,7 @@ void __stdio_init()
 
 int setvbuf(FILE* stream, char* buf, int mode, size_t size)
 {
+    fprintf(stderr, "setvbuf(%p [fd=%d], %p, %d, %u)\n", stream, stream->fd, buf, mode, size);
     if (mode != _IONBF && mode != _IOLBF && mode != _IOFBF) {
         errno = EINVAL;
         return -1;
@@ -57,6 +58,7 @@ int setvbuf(FILE* stream, char* buf, int mode, size_t size)
         stream->buffer = stream->default_buffer;
         stream->buffer_size = BUFSIZ;
     }
+    stream->buffer_index = 0;
     return 0;
 }
 
@@ -65,9 +67,9 @@ void setbuf(FILE* stream, char* buf)
     setvbuf(stream, buf, buf ? _IOFBF : _IONBF, BUFSIZ);
 }
 
-void setlinebuf(FILE* stream, char* buf)
+void setlinebuf(FILE* stream)
 {
-    setvbuf(stream, buf, buf ? _IOLBF : _IONBF, BUFSIZ);
+    setvbuf(stream, nullptr, _IOLBF, 0);
 }
 
 int fileno(FILE* stream)
@@ -138,7 +140,7 @@ int fputc(int ch, FILE* stream)
     stream->buffer[stream->buffer_index++] = ch;
     if (stream->buffer_index >= stream->buffer_size)
         fflush(stream);
-    else if (stream->mode == _IOLBF && ch == '\n')
+    else if (stream->mode == _IONBF || (stream->mode == _IOLBF && ch == '\n'))
         fflush(stream);
     if (stream->eof)
         return EOF;

+ 1 - 1
LibC/stdio.h

@@ -61,7 +61,7 @@ int sscanf (const char* buf, const char* fmt, ...);
 int fscanf(FILE*, const char* fmt, ...);
 int setvbuf(FILE*, char* buf, int mode, size_t);
 void setbuf(FILE*, char* buf);
-void setlinebuf(FILE*, char* buf);
+void setlinebuf(FILE*);
 
 __END_DECLS
 

+ 16 - 5
LibC/stdlib.cpp

@@ -1,9 +1,10 @@
 #include <stdlib.h>
-#include <mman.h>
+#include <sys/mman.h>
 #include <stdio.h>
 #include <unistd.h>
 #include <string.h>
 #include <alloca.h>
+#include <assert.h>
 #include <Kernel/Syscall.h>
 #include <AK/Assertions.h>
 
@@ -54,11 +55,12 @@ void* calloc(size_t nmemb, size_t)
     return nullptr;
 }
 
-void* realloc(void *ptr, size_t)
+void* realloc(void *ptr, size_t size)
 {
-    (void) ptr;
-    ASSERT_NOT_REACHED();
-    return nullptr;
+    // FIXME: This is broken as shit.
+    auto* new_ptr = malloc(size);
+    memcpy(new_ptr, ptr, size);
+    return new_ptr;
 }
 
 void exit(int status)
@@ -116,4 +118,13 @@ long atol(const char* str)
     return atoi(str);
 }
 
+void __qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *))
+{
+    (void) base;
+    (void) nmemb;
+    (void) size;
+    (void) compar;
+    assert(false);
+}
+
 }

+ 1 - 1
LibC/stdlib.h

@@ -12,7 +12,7 @@ void* realloc(void *ptr, size_t);
 char* getenv(const char* name);
 int atoi(const char*);
 long atol(const char*);
-
+void qsort(void* base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));
 void exit(int status) __NORETURN;
 void abort() __NORETURN;
 

+ 9 - 0
LibC/string.cpp

@@ -2,6 +2,7 @@
 #include <errno.h>
 #include <stdio.h>
 #include <signal.h>
+#include <assert.h>
 
 extern "C" {
 
@@ -97,6 +98,14 @@ void memcpy(void* dest, const void* src, size_t n)
         *(bdest++) = *(bsrc++);
 }
 
+void memmove(void* dest, const void* src, size_t n)
+{
+    if (dest < src)
+        return memcpy(dest, src, n);
+    // FIXME: Implement backwards copy.
+    assert(false);
+}
+
 char* strcpy(char* dest, const char *src)
 {
     char* originalDest = dest;

+ 94 - 0
LibC/termcap.cpp

@@ -1,4 +1,9 @@
 #include <termcap.h>
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include <AK/HashMap.h>
+#include <AK/String.h>
 
 extern "C" {
 
@@ -6,5 +11,94 @@ char PC;
 char* UP;
 char* BC;
 
+int tgetent(char* bp, const char* name)
+{
+    fprintf(stderr, "tgetent: bp=%p, name='%s'\n", bp, name);
+    if (!strcmp(name, "ansi")) {
+        PC = '\0';
+        BC = const_cast<char*>("\033[D");
+        UP = const_cast<char*>("\033[A");
+        return 1;
+    }
+    assert(false);
+}
+
+static HashMap<String, String>* caps = nullptr;
+
+void ensure_caps()
+{
+    if (caps)
+        return;
+    caps = new HashMap<String, String>;
+    caps->set("DC", "\033[%p1%dP");
+    caps->set("IC", "\033[%p1%d@");
+    caps->set("ce", "\033[K");
+    caps->set("cl", "\033[H\033[J");
+    caps->set("cr", "\015");
+    caps->set("dc", "\033[P");
+    caps->set("ei", "");
+    caps->set("ic", "");
+    caps->set("im", "");
+    caps->set("kd", "\033[B");
+    caps->set("kl", "\033[D");
+    caps->set("kr", "\033[C");
+    caps->set("ku", "\033[A");
+    caps->set("ks", "");
+    caps->set("ke", "");
+    caps->set("le", "\033[D");
+    caps->set("mm", "");
+    caps->set("mo", "");
+    caps->set("pc", "");
+    caps->set("up", "\033[A");
+    caps->set("vb", "");
+    caps->set("am", "");
+
+    caps->set("co", "80");
+    caps->set("li", "25");
+}
+
+char* tgetstr(char* id, char** area)
+{
+    ensure_caps();
+    fprintf(stderr, "tgetstr: id='%s', area=%p\n", id, area);
+    auto it = caps->find(id);
+    if (it != caps->end()) {
+        char* ret = *area;
+        strcpy(*area, (*it).value.characters());
+        *area += (*it).value.length() + 1;
+        return ret;
+    }
+    assert(false);
+}
+
+int tgetflag(char* id)
+{
+    fprintf(stderr, "tgetflag: '%s'\n", id);
+    auto it = caps->find(id);
+    if (it != caps->end())
+        return 1;
+    return 0;
+}
+
+int tgetnum(char* id)
+{
+    fprintf(stderr, "tgetnum: '%s'\n", id);
+    auto it = caps->find(id);
+    if (it != caps->end()) {
+        return atoi((*it).value.characters());
+    }
+    assert(false);
+}
+
+char* tgoto(const char* cap, int col, int row)
+{
+    assert(false);
+}
+
+int tputs(const char* str, int affcnt, int (*putc)(int))
+{
+    assert(false);
+}
+
 }
 

+ 7 - 0
LibC/termcap.h

@@ -8,5 +8,12 @@ extern char PC;
 extern char* UP;
 extern char* BC;
 
+int tgetent(char* bp, const char* name);
+int tgetflag(char* id);
+int tgetnum(char* id);
+char* tgetstr(char* id, char** area);
+char* tgoto(const char* cap, int col, int row);
+int tputs(const char* str, int affcnt, int (*putc)(int));
+
 __END_DECLS
 

+ 8 - 0
LibC/termios.cpp

@@ -1,3 +1,4 @@
+#include <assert.h>
 #include <errno.h>
 #include <termios.h>
 #include <Kernel/Syscall.h>
@@ -16,5 +17,12 @@ int tcsetattr(int fd, int optional_actions, const struct termios* t)
     __RETURN_WITH_ERRNO(rc, rc, -1);
 }
 
+int tcflow(int fd, int action)
+{
+    (void) fd;
+    (void) action;
+    assert(false);
+}
+
 }
 

+ 1 - 0
LibC/termios.h

@@ -20,6 +20,7 @@ struct termios {
 
 int tcgetattr(int fd, struct termios*);
 int tcsetattr(int fd, int optional_actions, const struct termios*);
+int tcflow(int fd, int action);
 
 /* c_cc characters */
 #define VINTR 0

+ 14 - 0
LibC/ulimit.cpp

@@ -0,0 +1,14 @@
+#include <ulimit.h>
+#include <assert.h>
+
+extern "C" {
+
+long ulimit(int cmd, long newlimit)
+{
+    (void) cmd;
+    (void) newlimit;
+    assert(false);
+}
+
+}
+

+ 10 - 0
LibC/ulimit.h

@@ -0,0 +1,10 @@
+#pragma once
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+long ulimit(int cmd, long newlimit);
+
+__END_DECLS
+

+ 2 - 1
LibC/unistd.cpp

@@ -167,7 +167,8 @@ char* getcwd(char* buffer, size_t size)
 
 char* getwd(char* buf)
 {
-    return getcwd(buf, PATH_MAX);
+    auto* p = getcwd(buf, PATH_MAX);
+    return p;
 }
 
 int sleep(unsigned seconds)

+ 4 - 3
Userland/sh.cpp

@@ -253,13 +253,13 @@ static bool handle_builtin(int argc, const char** argv, int& retval)
 
 static int try_exec(const char* path, const char** argv)
 {
-    int ret = execve(path, argv, nullptr);
+    int ret = execve(path, argv, const_cast<const char**>(environ));
     assert(ret < 0);
 
     const char* search_path = "/bin";
     char pathbuf[128];
     sprintf(pathbuf, "%s/%s", search_path, argv[0]);
-    ret = execve(pathbuf, argv, nullptr);
+    ret = execve(pathbuf, argv, const_cast<const char**>(environ));
     if (ret == -1)
         return -1;
     return ret;
@@ -317,7 +317,8 @@ static int runcmd(char* cmd)
     tcsetpgrp(0, getpid());
 
     if (WIFEXITED(wstatus)) {
-        //printf("Exited normally with status %d\n", WEXITSTATUS(wstatus));
+        if (WEXITSTATUS(wstatus) != 0)
+            printf("Exited with status %d\n", WEXITSTATUS(wstatus));
     } else {
         if (WIFSIGNALED(wstatus)) {
             switch (WTERMSIG(wstatus)) {

+ 8 - 0
VirtualFileSystem/FileDescriptor.h

@@ -46,6 +46,12 @@ public:
 #ifdef SERENITY
     bool isBlocking() const { return m_isBlocking; }
     void setBlocking(bool b) { m_isBlocking = b; }
+
+    dword file_flags() const { return m_file_flags; }
+    int set_file_flags(dword flags) { m_file_flags = flags; return 0; }
+
+    dword fd_flags() const { return m_fd_flags; }
+    int set_fd_flags(dword flags) { m_fd_flags = flags; return 0; }
 #endif
 
     ByteBuffer& generatorCache() { return m_generatorCache; }
@@ -62,6 +68,8 @@ private:
 
 #ifdef SERENITY
     bool m_isBlocking { true };
+    dword m_fd_flags { 0 };
+    dword m_file_flags { 0 };
 #endif
 };
 

+ 182 - 0
VirtualFileSystem/UnixTypes.h

@@ -19,6 +19,188 @@ namespace Unix {
 #define PROT_EXEC 0x4
 #define PROT_NONE 0x0
 
+#define F_DUPFD 0
+#define F_GETFD 1
+#define F_SETFD 2
+#define F_GETFL 3
+#define F_SETFL 4
+
+/* c_cc characters */
+#define VINTR 0
+#define VQUIT 1
+#define VERASE 2
+#define VKILL 3
+#define VEOF 4
+#define VTIME 5
+#define VMIN 6
+#define VSWTC 7
+#define VSTART 8
+#define VSTOP 9
+#define VSUSP 10
+#define VEOL 11
+#define VREPRINT 12
+#define VDISCARD 13
+#define VWERASE 14
+#define VLNEXT 15
+#define VEOL2 16
+
+/* c_iflag bits */
+#define IGNBRK	0000001
+#define BRKINT	0000002
+#define IGNPAR	0000004
+#define PARMRK	0000010
+#define INPCK	0000020
+#define ISTRIP	0000040
+#define INLCR	0000100
+#define IGNCR	0000200
+#define ICRNL	0000400
+#define IUCLC	0001000
+#define IXON	0002000
+#define IXANY	0004000
+#define IXOFF	0010000
+#define IMAXBEL	0020000
+#define IUTF8	0040000
+
+/* c_oflag bits */
+#define OPOST	0000001
+#define OLCUC	0000002
+#define ONLCR	0000004
+#define OCRNL	0000010
+#define ONOCR	0000020
+#define ONLRET	0000040
+#define OFILL	0000100
+#define OFDEL	0000200
+#if defined __USE_MISC || defined __USE_XOPEN
+# define NLDLY	0000400
+# define   NL0	0000000
+# define   NL1	0000400
+# define CRDLY	0003000
+# define   CR0	0000000
+# define   CR1	0001000
+# define   CR2	0002000
+# define   CR3	0003000
+# define TABDLY	0014000
+# define   TAB0	0000000
+# define   TAB1	0004000
+# define   TAB2	0010000
+# define   TAB3	0014000
+# define BSDLY	0020000
+# define   BS0	0000000
+# define   BS1	0020000
+# define FFDLY	0100000
+# define   FF0	0000000
+# define   FF1	0100000
+#endif
+
+#define VTDLY	0040000
+#define   VT0	0000000
+#define   VT1	0040000
+
+#ifdef __USE_MISC
+# define XTABS	0014000
+#endif
+
+/* c_cflag bit meaning */
+#ifdef __USE_MISC
+# define CBAUD	0010017
+#endif
+#define  B0	0000000		/* hang up */
+#define  B50	0000001
+#define  B75	0000002
+#define  B110	0000003
+#define  B134	0000004
+#define  B150	0000005
+#define  B200	0000006
+#define  B300	0000007
+#define  B600	0000010
+#define  B1200	0000011
+#define  B1800	0000012
+#define  B2400	0000013
+#define  B4800	0000014
+#define  B9600	0000015
+#define  B19200	0000016
+#define  B38400	0000017
+#ifdef __USE_MISC
+# define EXTA B19200
+# define EXTB B38400
+#endif
+#define CSIZE	0000060
+#define   CS5	0000000
+#define   CS6	0000020
+#define   CS7	0000040
+#define   CS8	0000060
+#define CSTOPB	0000100
+#define CREAD	0000200
+#define PARENB	0000400
+#define PARODD	0001000
+#define HUPCL	0002000
+#define CLOCAL	0004000
+#ifdef __USE_MISC
+# define CBAUDEX 0010000
+#endif
+#define  B57600   0010001
+#define  B115200  0010002
+#define  B230400  0010003
+#define  B460800  0010004
+#define  B500000  0010005
+#define  B576000  0010006
+#define  B921600  0010007
+#define  B1000000 0010010
+#define  B1152000 0010011
+#define  B1500000 0010012
+#define  B2000000 0010013
+#define  B2500000 0010014
+#define  B3000000 0010015
+#define  B3500000 0010016
+#define  B4000000 0010017
+#define __MAX_BAUD B4000000
+#ifdef __USE_MISC
+# define CIBAUD	  002003600000		/* input baud rate (not used) */
+# define CMSPAR   010000000000		/* mark or space (stick) parity */
+# define CRTSCTS  020000000000		/* flow control */
+#endif
+
+/* c_lflag bits */
+#define ISIG	0000001
+#define ICANON	0000002
+#if defined __USE_MISC || (defined __USE_XOPEN && !defined __USE_XOPEN2K)
+# define XCASE	0000004
+#endif
+#define ECHO	0000010
+#define ECHOE	0000020
+#define ECHOK	0000040
+#define ECHONL	0000100
+#define NOFLSH	0000200
+#define TOSTOP	0000400
+#ifdef __USE_MISC
+# define ECHOCTL 0001000
+# define ECHOPRT 0002000
+# define ECHOKE	 0004000
+# define FLUSHO	 0010000
+# define PENDIN	 0040000
+#endif
+#define IEXTEN	0100000
+#ifdef __USE_MISC
+# define EXTPROC 0200000
+#endif
+
+/* tcflow() and TCXONC use these */
+#define	TCOOFF		0
+#define	TCOON		1
+#define	TCIOFF		2
+#define	TCION		3
+
+/* tcflush() and TCFLSH use these */
+#define	TCIFLUSH	0
+#define	TCOFLUSH	1
+#define	TCIOFLUSH	2
+
+/* tcsetattr uses these */
+#define	TCSANOW		0
+#define	TCSADRAIN	1
+#define	TCSAFLUSH	2
+
+
 typedef dword dev_t;
 typedef dword ino_t;
 typedef dword mode_t;