Jelajahi Sumber

Merge branch 'dev'

greatbridf 1 tahun lalu
induk
melakukan
5813062c00
60 mengubah file dengan 2018 tambahan dan 285 penghapusan
  1. 0 2
      CMakeLists.txt
  2. 13 1
      gblibc/CMakeLists.txt
  3. 16 0
      gblibc/include/alloca.h
  4. 33 0
      gblibc/include/bits/alltypes.h
  5. 8 12
      gblibc/include/errno.h
  6. 22 0
      gblibc/include/signal.h
  7. 59 0
      gblibc/include/stdio.h
  8. 37 0
      gblibc/include/stdlib.h
  9. 24 1
      gblibc/include/string.h
  10. 46 0
      gblibc/include/sys/stat.h
  11. 16 0
      gblibc/include/sys/time.h
  12. 5 0
      gblibc/include/sys/types.h
  13. 1 7
      gblibc/include/time.h
  14. 7 0
      gblibc/include/unistd.h
  15. 34 0
      gblibc/private-include/list.h
  16. 41 0
      gblibc/private-include/priv-vars.h
  17. 7 0
      gblibc/private-include/syscall.h
  18. 6 0
      gblibc/src/alloca.c
  19. 12 0
      gblibc/src/arithmetic.c
  20. 15 7
      gblibc/src/crt0.s
  21. 7 1
      gblibc/src/dirent.c
  22. 28 0
      gblibc/src/errno.c
  23. 7 1
      gblibc/src/fcntl.c
  24. 91 0
      gblibc/src/init.c
  25. 20 0
      gblibc/src/internal.c
  26. 5 0
      gblibc/src/platform-independent.s
  27. 23 0
      gblibc/src/signal.c
  28. 29 0
      gblibc/src/stat.c
  29. 492 0
      gblibc/src/stdio.c
  30. 268 0
      gblibc/src/stdlib.c
  31. 228 1
      gblibc/src/string.c
  32. 20 0
      gblibc/src/time.c
  33. 140 15
      gblibc/src/unistd.c
  34. 0 38
      gblibstdc++/include/bits/alltypes.h
  35. 1 0
      gblibstdc++/include/memory
  36. 2 1
      include/fs/fat.hpp
  37. 2 0
      include/kernel/mm.hpp
  38. 2 1
      include/kernel/process.hpp
  39. 18 4
      include/kernel/signal.hpp
  40. 2 0
      include/kernel/tty.hpp
  41. 15 15
      include/kernel/vfs.hpp
  42. 6 0
      include/types/buffer.hpp
  43. 1 1
      include/types/elf.hpp
  44. 5 4
      src/asm/interrupt.s
  45. 16 1
      src/fs/fat.cpp
  46. 0 2
      src/kernel.ld
  47. 0 8
      src/kernel/errno.c
  48. 3 3
      src/kernel/hw/ahci.cc
  49. 4 2
      src/kernel/hw/pci.cc
  50. 3 0
      src/kernel/interrupt.cpp
  51. 6 1
      src/kernel/mem.cpp
  52. 9 3
      src/kernel/process.cpp
  53. 93 5
      src/kernel/syscall.cpp
  54. 5 0
      src/kernel/tty.cpp
  55. 39 39
      src/kernel/vfs.cpp
  56. 1 1
      src/types/elf.cpp
  57. 1 1
      user-space-program/CMakeLists.txt
  58. 6 4
      user-space-program/init.c
  59. 14 44
      user-space-program/lazybox.c
  60. 4 59
      user-space-program/sh.c

+ 0 - 2
CMakeLists.txt

@@ -37,7 +37,6 @@ set(BOOTLOADER_SOURCES src/boot.s
 
 set(KERNEL_MAIN_SOURCES src/fs/fat.cpp
                         src/kinit.cpp
-                        src/kernel/errno.c
                         src/kernel/interrupt.cpp
                         src/kernel/process.cpp
                         src/kernel/tty.cpp
@@ -61,7 +60,6 @@ set(KERNEL_MAIN_SOURCES src/fs/fat.cpp
                         include/fs/fat.hpp
                         include/kernel/event/event.h
                         include/kernel/event/evtqueue.hpp
-                        include/kernel/errno.h
                         include/kernel/tty.hpp
                         include/kernel/interrupt.h
                         include/kernel/irq.hpp

+ 13 - 1
gblibc/CMakeLists.txt

@@ -5,13 +5,25 @@ add_library(gblibc STATIC
     src/stdio.c
     src/arithmetic.c
     src/string.c
-    src/crt0.s
     src/fcntl.c
     src/unistd.c
     src/wait.c
     src/assert.c
     src/dirent.c
     src/ctype.c
+    src/stdlib.c
+    src/errno.c
+    src/init.c
+    src/internal.c
+    src/alloca.c
+    src/stat.c
+    src/time.c
+    src/signal.c
+    src/platform-independent.s
+)
+
+add_library(crt0 OBJECT
+    src/crt0.s
 )
 
 file(GLOB_RECURSE GBLIBC_PUBLIC_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/include)

+ 16 - 0
gblibc/include/alloca.h

@@ -0,0 +1,16 @@
+#ifndef __GBLIBC_ALLOCA_H_
+#define __GBLIBC_ALLOCA_H_
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void* alloca(size_t size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 33 - 0
gblibc/include/bits/alltypes.h

@@ -0,0 +1,33 @@
+#ifndef __GBLIBC_BITS_ALLTYPES_H_
+#define __GBLIBC_BITS_ALLTYPES_H_
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef size_t blksize_t;
+typedef size_t blkcnt_t;
+
+struct timespec {
+    time_t tv_sec;
+    long tv_nsec;
+    int : 32; // padding
+};
+
+struct timeval {
+    time_t tv_sec;
+    size_t tv_usec;
+};
+
+struct timezone {
+    int tz_minuteswest;
+    int tz_dsttime;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 8 - 12
include/kernel/errno.h → gblibc/include/errno.h

@@ -1,19 +1,14 @@
-#ifndef __GBOS_ERRNO_H
-#define __GBOS_ERRNO_H
-
-#include <types/types.h>
+#ifndef __GBLIBC_ERRNO_H_
+#define __GBLIBC_ERRNO_H_
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-extern uint32_t* _get_errno(void);
-
-#define errno (*_get_errno())
+extern int* __errno_location(void);
 
-#ifdef __cplusplus
-}
-#endif
+#undef errno
+#define errno (*__errno_location())
 
 #define EPERM 1
 #define ENOENT 2
@@ -31,7 +26,8 @@ extern uint32_t* _get_errno(void);
 #define ENOTTY 25
 #define EPIPE 32
 
-// non-standard errors
-#define ENOTFOUND 200
+#ifdef __cplusplus
+}
+#endif
 
 #endif

+ 22 - 0
gblibc/include/signal.h

@@ -0,0 +1,22 @@
+#ifndef __GBLIBC_SIGNAL_H_
+#define __GBLIBC_SIGNAL_H_
+
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SIGINT 2
+#define SIGQUIT 3
+#define SIGPIPE 13
+#define SIGSTOP 19
+
+int kill(pid_t pid, int sig);
+int raise(int sig);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 59 - 0
gblibc/include/stdio.h

@@ -7,12 +7,71 @@
 #undef EOF
 #define EOF (-1)
 
+#undef BUFSIZ
+#define BUFSIZ (1024)
+
 #ifdef __cplusplus
 extern "C" {
 #endif
 
+typedef struct __io_file {
+    int fd;
+    uint32_t flags;
+
+    char* rbuf;
+    size_t rpos;
+    size_t rcnt;
+    size_t rbsz;
+
+    char* wbuf;
+    size_t wpos;
+    size_t wbsz;
+} FILE;
+
+int putchar(int character);
+int getchar(void);
+
+int puts(const char* str);
+char* gets(char* str);
+
 int vsnprintf(char* buf, size_t bufsize, const char* fmt, va_list args);
 int snprintf(char* buf, size_t bufsize, const char* fmt, ...);
+int sprintf(char* buf, const char* fmt, ...);
+int vasprintf(char** strp, const char* fmt, va_list args);
+int asprintf(char** strp, const char* fmt, ...);
+
+int vfprintf(FILE* stream, const char* fmt, va_list args);
+int fprintf(FILE* stream, const char* fmt, ...);
+
+int vprintf(const char* fmt, va_list args);
+int printf(const char* fmt, ...);
+
+FILE* fopen(const char* path, const char* mode);
+int fflush(FILE* stream);
+int fclose(FILE* stream);
+
+int getc_unlocked(FILE* stream);
+int putc_unlocked(int character, FILE* stream);
+int fputs_unlocked(const char* s, FILE* stream);
+int fputc_unlocked(int character, FILE* stream);
+int fputs(const char* s, FILE* stream);
+int fgetc(FILE* stream);
+int fputc(int character, FILE* stream);
+
+int ferror(FILE* stream);
+int ferror_unlocked(FILE* stream);
+int feof(FILE* stream);
+void clearerr(FILE* stream);
+
+extern FILE* stdout;
+extern FILE* stdin;
+extern FILE* stderr;
+#undef stdout
+#undef stdin
+#undef stderr
+#define stdout (stdout)
+#define stdin (stdin)
+#define stderr (stderr)
 
 #ifdef __cplusplus
 }

+ 37 - 0
gblibc/include/stdlib.h

@@ -0,0 +1,37 @@
+#ifndef __GBLIBC_STDLIB_H_
+#define __GBLIBC_STDLIB_H_
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int atoi(const char* str);
+
+void __attribute__((noreturn)) exit(int status);
+
+void* malloc(size_t size);
+void* realloc(void* ptr, size_t newsize);
+void free(void* ptr);
+
+typedef int (*comparator_t)(const void* a, const void* b);
+void qsort(void* base, size_t num, size_t size, comparator_t comparator);
+void* bsearch(
+    const void* key,
+    const void* base,
+    size_t num,
+    size_t size,
+    comparator_t comparator);
+
+int rand(void);
+int rand_r(unsigned int* seedp);
+void srand(unsigned int seed);
+
+int setenv(const char* name, const char* value, int overwrite);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 24 - 1
gblibc/include/string.h

@@ -12,13 +12,36 @@
 extern "C" {
 #endif
 
+int memcmp(const void* ptr1, const void* ptr2, size_t num);
+
+void* memmove(void* dst, const void* src, size_t n);
 void* memcpy(void* dst, const void* src, size_t n);
+void* mempcpy(void* dst, const void* src, size_t n);
 void* memset(void* dst, int c, size_t n);
 
+char* strerror(int errnum);
+
 int strcmp(const char* s1, const char* s2);
+int strncmp(const char* s1, const char* s2, size_t n);
+int strcasecmp(const char* s1, const char* s2);
+int strncasecmp(const char* s1, const char* s2, size_t n);
 size_t strlen(const char* str);
-
+char* strchr(const char* str, int character);
+char* strrchr(const char* str, int character);
+char* strchrnul(const char* str, int character);
+size_t strcspn(const char* str1, const char* str2);
+char* strstr(const char* str1, const char* str2);
+char* strpbrk(const char* str1, const char* str2);
+
+char* strcpy(char* dst, const char* src);
 char* strncpy(char* dst, const char* src, size_t n);
+char* stpcpy(char* dst, const char* src);
+char* stpncpy(char* dst, const char* src, size_t n);
+
+char* strdup(const char* str);
+char* strndup(const char* str, size_t n);
+
+char* strsignal(int sig);
 
 #ifdef __cplusplus
 }

+ 46 - 0
gblibc/include/sys/stat.h

@@ -2,6 +2,8 @@
 #define __GBLIBC_SYS_STAT_H
 
 #include <stdint.h>
+#include <bits/alltypes.h>
+#include <sys/types.h>
 
 #define STATX_TYPE (1 << 0)
 #define STATX_MODE (1 << 1)
@@ -17,6 +19,24 @@
 #define STATX_BASIC_STATS (0x7ff)
 #define STATX_BTIME (1 << 11)
 
+#define S_IFMT 0170000
+
+#define S_IFSOCK 0140000
+#define S_IFLNK 0120000
+#define S_IFREG 0100000
+#define S_IFBLK 0060000
+#define S_IFDIR 0040000
+#define S_IFCHR 0020000
+#define S_IFIFO 0010000
+
+#define S_ISSOCK(m) (((m)&S_IFMT) == S_IFSOCK)
+#define S_ISLNK(m) (((m)&S_IFMT) == S_IFLNK)
+#define S_ISREG(m) (((m)&S_IFMT) == S_IFREG)
+#define S_ISBLK(m) (((m)&S_IFMT) == S_IFBLK)
+#define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR)
+#define S_ISCHR(m) (((m)&S_IFMT) == S_IFCHR)
+#define S_ISFIFO(m) (((m)&S_IFMT) == S_IFIFO)
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -52,6 +72,32 @@ struct statx {
     uint64_t stx_dio_alignment[13];
 };
 
+struct stat {
+    dev_t st_dev;
+    ino_t st_ino;
+    nlink_t st_nlink;
+
+    mode_t st_mode;
+    uid_t st_uid;
+    gid_t st_gid;
+
+    dev_t st_rdev;
+    off_t st_size;
+    blksize_t st_blksize;
+    blkcnt_t st_blocks;
+
+    struct timespec st_atim;
+    struct timespec st_mtim;
+    struct timespec st_ctim;
+
+    long __padding[3];
+};
+
+int stat(const char* pathname, struct stat* statbuf);
+int fstat(int fd, struct stat* statbuf);
+
+mode_t umask(mode_t mask);
+
 #ifdef __cplusplus
 }
 #endif

+ 16 - 0
gblibc/include/sys/time.h

@@ -0,0 +1,16 @@
+#ifndef __GBLIBC_SYS_TIME_H_
+#define __GBLIBC_SYS_TIME_H_
+
+#include <bits/alltypes.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int gettimeofday(struct timeval* tv, struct timezone* tz);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 5 - 0
gblibc/include/sys/types.h

@@ -10,6 +10,11 @@ extern "C" {
 typedef int pid_t;
 typedef uint32_t ino_t;
 typedef int32_t off_t;
+typedef uint32_t dev_t;
+typedef unsigned uid_t;
+typedef unsigned gid_t;
+typedef unsigned mode_t;
+typedef unsigned long nlink_t;
 
 typedef uint64_t ino64_t;
 typedef int64_t off64_t;

+ 1 - 7
gblibc/include/time.h

@@ -2,21 +2,15 @@
 #define __GBLIBC_TIME_H_
 
 #include <stdint.h>
+#include <bits/alltypes.h>
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
 #define CLOCK_REALTIME 0
-
 typedef int clockid_t;
 
-struct timespec {
-    time_t tv_sec;
-    long tv_nsec;
-    int : 32; // padding
-};
-
 #ifdef __cplusplus
 }
 #endif

+ 7 - 0
gblibc/include/unistd.h

@@ -44,6 +44,13 @@ pid_t getsid(pid_t pid);
 pid_t tcgetpgrp(int fd);
 int tcsetpgrp(int fd, pid_t pgrp);
 
+int brk(void* addr);
+void* sbrk(ssize_t increment);
+
+int isatty(int fd);
+
+extern char** environ;
+
 #ifdef __cplusplus
 }
 #endif

+ 34 - 0
gblibc/private-include/list.h

@@ -0,0 +1,34 @@
+#ifndef __GBLIBC_LIST_H_
+#define __GBLIBC_LIST_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct list_node {
+    struct list_node* prev;
+    struct list_node* next;
+    char data[];
+};
+
+typedef struct list_node list_node;
+typedef list_node list_head;
+
+#define NDDATA(node, type) (*((type*)((node).data)))
+#define NDPREV(node) ((node).prev)
+#define NDNEXT(node) ((node).next)
+#define NDISEND(node) (!((node).next))
+#define NEWNODE(type) ((struct list_node*)malloc(sizeof(list_node) + sizeof(type)))
+#define NDPTR(p_data) ((list_node*)((char*)p_data - sizeof(list_node)))
+
+void __node_insert(list_node* node, list_node* new_node);
+void __node_erase(list_node* node);
+
+#define NDINSERT(node, newnode) __node_insert(node, newnode)
+#define NDERASE(p_node) __node_erase(p_node)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 41 - 0
gblibc/private-include/priv-vars.h

@@ -0,0 +1,41 @@
+#ifndef __GBLIBC_PRIV_VARS_H_
+#define __GBLIBC_PRIV_VARS_H_
+
+#include <list.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct mem {
+    uint32_t sz;
+    uint32_t flag;
+};
+
+#define FILE_READ (1 << 0)
+#define FILE_WRITE (1 << 1)
+#define FILE_ERROR (1 << 2)
+#define FILE_EOF (1 << 3)
+
+void** __start_brk_location(void);
+void** __curr_brk_location(void);
+list_head* __io_files_location(void);
+size_t* __environ_size_location(void);
+
+#undef start_brk
+#define start_brk (*__start_brk_location())
+#undef curr_brk
+#define curr_brk (*__curr_brk_location())
+
+#undef iofiles
+#define iofiles (*__io_files_location())
+
+#undef environ_size
+#define environ_size (*__environ_size_location())
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 7 - 0
gblibc/private-include/syscall.h

@@ -12,17 +12,24 @@
 #define SYS_waitpid (0x07)
 #define SYS_execve (0x0b)
 #define SYS_chdir (0x0c)
+#define SYS_stat (0x12)
 #define SYS_getpid (0x14)
+#define SYS_fstat (0x1c)
+#define SYS_kill (0x25)
 #define SYS_dup (0x29)
 #define SYS_pipe (0x2a)
+#define SYS_brk (0x2d)
 #define SYS_ioctl (0x36)
 #define SYS_setpgid (0x39)
 #define SYS_dup2 (0x3f)
+#define SYS_umask (0x3c)
 #define SYS_getppid (0x40)
 #define SYS_setsid (0x42)
+#define SYS_gettimeofday (0x4e)
 #define SYS_getdents (0x84)
 #define SYS_writev (0x92)
 #define SYS_getsid (0x93)
+#define SYS_nanosleep (0xa2)
 #define SYS_getcwd (0xb7)
 #define SYS_set_thread_area (0xf3)
 #define SYS_exit_group (0xfc)

+ 6 - 0
gblibc/src/alloca.c

@@ -0,0 +1,6 @@
+#include <alloca.h>
+
+void* alloca(size_t size)
+{
+    return __builtin_alloca(size);
+}

+ 12 - 0
gblibc/src/arithmetic.c

@@ -51,3 +51,15 @@ int64_t __moddi3(int64_t a, int64_t b)
     do_div_s(a, b, &remainder);
     return remainder;
 }
+
+uint64_t __udivdi3(uint64_t a, uint64_t b)
+{
+    return do_div(a, b, NULL);
+}
+
+uint64_t __umoddi3(uint64_t a, uint64_t b)
+{
+    uint64_t rem = 0;
+    do_div(a, b, &rem);
+    return rem;
+}

+ 15 - 7
gblibc/src/crt0.s

@@ -6,20 +6,28 @@
 .globl _start
 .type  _start @function
 _start:
-    movl (%esp), %eax   # argc
-    leal 4(%esp), %ecx  # argv
-    movl %esp, %edx
-
+    movl %esp, %ebx     # initial stack
     andl $0xfffffff0, %esp
-
-    pushl %edx
     pushl $0
-
     movl %esp, %ebp
 
+    movl (%ebx), %eax           # %eax = argc
+
+    leal 8(%ebx, %eax, 4), %ecx # %ecx = envp
     pushl %ecx
+
+    leal 4(%ebx), %ecx          # %ecx = argv
+    pushl %ecx
+
     pushl %eax
 
+    call __init_gblibc
+
+    movl (%ebx), %eax # %eax = argc
+    movl %eax, (%esp)
+    leal 4(%ebx), %eax
+    movl %eax, 4(%esp)
+
     call main
 
     movl %eax, %ebx  # code

+ 7 - 1
gblibc/src/dirent.c

@@ -1,3 +1,4 @@
+#include <errno.h>
 #include <fcntl.h>
 #include <dirent.h>
 #include <string.h>
@@ -62,8 +63,13 @@ struct dirent* readdir(DIR* dirp)
         sizeof(dirp->buffer)
     );
 
-    if (dirp->blen <= 0)
+    if (dirp->blen <= 0) {
+        if (dirp->blen < 0) {
+            errno = -dirp->blen;
+            dirp->blen = 0;
+        }
         return NULL;
+    }
 
 fill:
     dirp->bpos = fill_dirent(&dirp->dent, dirp->buffer, dirp->bpos);

+ 28 - 0
gblibc/src/errno.c

@@ -0,0 +1,28 @@
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+int* __errno_location(void)
+{
+    static int __errno = 0;
+    return &__errno;
+}
+
+void
+__attribute__((noreturn))
+__attribute__((weak))
+__stack_chk_fail(void)
+{
+    const char* msg = "***** stack overflow detected *****\n"
+                      "quiting...\n";
+    write(STDERR_FILENO, msg, strlen(msg));
+    exit(-1);
+}
+
+void
+__attribute__((noreturn))
+__attribute__((weak))
+__stack_chk_fail_local(void)
+{
+    __stack_chk_fail();
+}

+ 7 - 1
gblibc/src/fcntl.c

@@ -1,7 +1,13 @@
+#include <errno.h>
 #include <fcntl.h>
 #include <syscall.h>
 
 int open(const char* filename, int flags, ...)
 {
-    return syscall2(SYS_open, (uint32_t)filename, flags);
+    int ret = syscall2(SYS_open, (uint32_t)filename, flags);
+    if (ret < 0) {
+        errno = -ret;
+        return -1;
+    }
+    return ret;
 }

+ 91 - 0
gblibc/src/init.c

@@ -0,0 +1,91 @@
+#include <assert.h>
+#include <priv-vars.h>
+#include <stdlib.h>
+#include <syscall.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <list.h>
+
+FILE* stdout;
+FILE* stdin;
+FILE* stderr;
+
+list_head* __io_files_location(void)
+{
+    static list_head __io_files;
+    return &__io_files;
+}
+
+size_t* __environ_size_location(void)
+{
+    static size_t __environ_size;
+    return &__environ_size;
+}
+
+void __init_gblibc(int argc, char** argv, char** envp)
+{
+    (void)argc, (void)argv;
+    // initialize program break position and heap
+    start_brk = curr_brk = (void*)syscall1(SYS_brk, (uint32_t)NULL);
+
+    sbrk(128 * 1024);
+    struct mem* first = start_brk;
+    first->sz = 0;
+    first->flag = 0;
+
+    // save environ vector
+    environ_size = 4;
+    environ = malloc(environ_size * sizeof(char*));
+    assert(environ);
+
+    while (*envp) {
+        char* eqp = strchr(*envp, '=');
+        if (!eqp || eqp == *envp)
+            goto next;
+
+        *eqp = 0;
+        char* value = eqp + 1;
+        setenv(*envp, value, 1);
+
+    next:;
+        ++envp;
+    }
+
+    // stdout, stdin, stderr objects
+    list_node* node = NULL;
+
+    // stdout
+    node = NEWNODE(FILE);
+    stdout = &NDDATA(*node, FILE);
+    memset(stdout, 0x00, sizeof(FILE));
+
+    stdout->fd = STDOUT_FILENO;
+    stdout->flags = FILE_WRITE;
+    stdout->wbuf = malloc(BUFSIZ);
+    stdout->wbsz = BUFSIZ;
+
+    NDINSERT(&iofiles, node);
+
+    // stdin
+    node = NEWNODE(FILE);
+    stdin = &NDDATA(*node, FILE);
+    memset(stdin, 0x00, sizeof(FILE));
+
+    stdin->fd = STDIN_FILENO;
+    stdin->flags = FILE_READ;
+    stdin->rbuf = malloc(BUFSIZ);
+    stdin->rbsz = BUFSIZ;
+
+    NDINSERT(&iofiles, node);
+
+    // stderr
+    node = NEWNODE(FILE);
+    stderr = &NDDATA(*node, FILE);
+    memset(stderr, 0x00, sizeof(FILE));
+
+    stderr->fd = STDERR_FILENO;
+    stderr->flags = FILE_WRITE;
+
+    NDINSERT(&iofiles, node);
+}

+ 20 - 0
gblibc/src/internal.c

@@ -0,0 +1,20 @@
+#include <list.h>
+#include <stdlib.h>
+
+void __node_insert(list_node* node, list_node* newnode)
+{
+    NDNEXT(*newnode) = NDNEXT(*node);
+    if (NDNEXT(*node))
+        NDPREV(*NDNEXT(*node)) = newnode;
+    NDNEXT(*node) = newnode;
+    NDPREV(*newnode) = node;
+}
+
+void __node_erase(list_node* node)
+{
+    if (NDPREV(*node))
+        NDNEXT(*NDPREV(*node)) = NDNEXT(*node);
+    if (NDNEXT(*node))
+        NDPREV(*NDNEXT(*node)) = NDPREV(*node);
+    free(node);
+}

+ 5 - 0
gblibc/src/platform-independent.s

@@ -0,0 +1,5 @@
+.section .rodata
+
+.globl __stack_chk_guard
+__stack_chk_guard:
+    .long 0x19198101

+ 23 - 0
gblibc/src/signal.c

@@ -0,0 +1,23 @@
+#include <syscall.h>
+#include <errno.h>
+#include <unistd.h>
+#include <signal.h>
+
+int kill(pid_t pid, int sig)
+{
+    int ret = syscall2(SYS_kill, pid, sig);
+    if (ret < 0) {
+        errno = -ret;
+        return -1;
+    }
+    return ret;
+}
+
+int raise(int sig)
+{
+    pid_t pid = getpid();
+    if (pid < 0)
+        return -1;
+
+    return kill(pid, sig);
+}

+ 29 - 0
gblibc/src/stat.c

@@ -0,0 +1,29 @@
+#include <stdint.h>
+#include <errno.h>
+#include <syscall.h>
+#include <sys/stat.h>
+
+int stat(const char* pathname, struct stat* statbuf)
+{
+    int ret = syscall2(SYS_stat, (uint32_t)pathname, (uint32_t)statbuf);
+    if (ret < 0) {
+        errno = -ret;
+        return -1;
+    }
+    return ret;
+}
+
+int fstat(int fd, struct stat* statbuf)
+{
+    int ret = syscall2(SYS_fstat, fd, (uint32_t)statbuf);
+    if (ret < 0) {
+        errno = -ret;
+        return -1;
+    }
+    return ret;
+}
+
+mode_t umask(mode_t mask)
+{
+    return syscall1(SYS_umask, mask);
+}

+ 492 - 0
gblibc/src/stdio.c

@@ -1,7 +1,19 @@
+#include <assert.h>
 #include <devutil.h>
+#include <fcntl.h>
+#include <list.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <priv-vars.h>
+
+static inline int __feof_or_error(FILE* stream)
+{
+    return !!(stream->flags & (FILE_ERROR | FILE_EOF));
+}
 
 // where n is in the range of [0, 9]
 static inline char d_to_c(int32_t n)
@@ -351,3 +363,483 @@ int vsnprintf(char* buf, size_t buf_size, const char* fmt, va_list arg)
 
     return n_write;
 }
+
+int sprintf(char* buf, const char* fmt, ...)
+{
+    va_list lst;
+    va_start(lst, fmt);
+
+    int ret = vsnprintf(buf, __SIZE_MAX__, fmt, lst);
+
+    va_end(lst);
+
+    return ret;
+}
+
+int puts(const char* str)
+{
+    return fputs(str, stdout);
+}
+
+char* gets(char* buf)
+{
+    int c, num = 0;
+    while ((c = getchar()) != EOF && c != '\n')
+        buf[num++] = c;
+    buf[num] = 0;
+
+    if (c == EOF)
+        return NULL;
+    return buf;
+}
+
+int vfprintf_u32(uint32_t num, FILE* stream)
+{
+    if (num <= 9) {
+        fputc(d_to_c(num), stream);
+        return 1;
+    }
+
+    int ret = vfprintf_u32(num / 10, stream);
+    fputc(d_to_c(num % 10), stream);
+    return ret + 1;
+}
+
+int vfprintf_d32(int32_t num, FILE* stream)
+{
+    if (num < 0) {
+        fputc('-', stream);
+        return vfprintf_u32(-num, stream) + 1;
+    }
+    return vfprintf_u32(num, stream);
+}
+
+int vfprintf_u64(uint64_t num, FILE* stream)
+{
+    if (num <= 9) {
+        fputc(d_to_c(num), stream);
+        return 1;
+    }
+
+    int ret = vfprintf_u64(num / 10, stream);
+    fputc(d_to_c(num % 10), stream);
+    return ret + 1;
+}
+
+int vfprintf_d64(int64_t num, FILE* stream)
+{
+    if (num < 0) {
+        fputc('-', stream);
+        return vfprintf_u64(-num, stream) + 1;
+    }
+    return vfprintf_u64(num, stream);
+}
+
+int vfprintf_x32(uint32_t num, int off, FILE* stream)
+{
+    // print leading 0x
+    if (off & 1) {
+        --off;
+        fputc('0', stream);
+        fputc('X' + off, stream);
+        return vfprintf_x32(num, off, stream) + 2;
+    }
+
+    if (num <= 15) {
+        fputc(X_to_c(num) + off, stream);
+        return 1;
+    }
+
+    int ret = vfprintf_x32(num >> 4, off, stream);
+    fputc(X_to_c(num & 0xf) + off, stream);
+    return ret + 1;
+}
+
+int vfprintf_x64(uint64_t num, int off, FILE* stream)
+{
+    // print leading 0x
+    if (off & 1) {
+        --off;
+        fputc('0', stream);
+        fputc('X' + off, stream);
+        return vfprintf_x64(num, off, stream) + 2;
+    }
+
+    if (num <= 15) {
+        fputc(X_to_c(num) + off, stream);
+        return 1;
+    }
+
+    int ret = vfprintf_x64(num >> 4, off, stream);
+    fputc(X_to_c(num & 0xf) + off, stream);
+    return ret + 1;
+}
+
+int vfprintf(FILE* stream, const char* fmt, va_list args)
+{
+    int n = 0;
+
+    for (char c = 0; (c = *fmt) != 0x00; ++fmt) {
+        if (c == '%') {
+            switch (*(++fmt)) {
+
+            // int
+            case 'd':
+                n += vfprintf_d32(va_arg(args, int), stream);
+                break;
+
+            case 'x':
+                n += vfprintf_x32(va_arg(args, unsigned int), 'a' - 'A' + 1, stream);
+                break;
+
+            case 'X':
+                n += vfprintf_x32(va_arg(args, unsigned int), 1, stream);
+                break;
+
+            // long decimal
+            case 'l':
+                switch (*(++fmt)) {
+                // long long aka int64
+                case 'l':
+                    switch (*(++fmt)) {
+                    case 'd':
+                        n += vfprintf_d64(va_arg(args, long long), stream);
+                        break;
+                    case 'x':
+                        n += vfprintf_x64(va_arg(args, unsigned long long), 'a' - 'A' + 1, stream);
+                        break;
+                    case 'X':
+                        n += vfprintf_x64(va_arg(args, unsigned long long), 'a' - 'A' + 1, stream);
+                        break;
+                    }
+                    break;
+                // long int aka int32
+                case 'd':
+                    n += vfprintf_d32(va_arg(args, int), stream);
+                    break;
+                case 'x':
+                    n += vfprintf_x32(va_arg(args, unsigned int), 'a' - 'A' + 1, stream);
+                    break;
+
+                case 'X':
+                    n += vfprintf_x32(va_arg(args, unsigned int), 1, stream);
+                    break;
+                }
+                break;
+
+            // c string
+            case 's':
+                n += fprintf(stream, va_arg(args, const char*));
+                break;
+
+            // int8 char
+            case 'c':
+                ++n;
+                fputc(va_arg(args, int), stream);
+                break;
+
+            // pointer
+            case 'p':
+#ifdef __32bit_system
+                n += vfprintf_x32(va_arg(args, size_t), 'a' - 'A' + 1, stream);
+#else
+                n += vfprintf_x64(va_arg(args, size_t), 'a' - 'A' + 1, stream);
+#endif
+                break;
+
+            default:
+                ++n;
+                fputc(*(fmt - 1), stream);
+                break;
+            }
+        } else {
+            ++n;
+            fputc(c, stream);
+        }
+    }
+
+    return n;
+}
+
+int fprintf(FILE* stream, const char* fmt, ...)
+{
+    va_list args;
+    va_start(args, fmt);
+
+    int ret = vfprintf(stream, fmt, args);
+
+    va_end(args);
+    return ret;
+}
+
+int vprintf(const char* fmt, va_list args)
+{
+    return vfprintf(stdout, fmt, args);
+}
+
+int printf(const char* fmt, ...)
+{
+    va_list args;
+    va_start(args, fmt);
+
+    int ret = vprintf(fmt, args);
+
+    va_end(args);
+    return ret;
+}
+
+int putchar(int c)
+{
+    fputc(c, stdout);
+    return c;
+}
+
+FILE* fopen(const char* path, const char* mode)
+{
+    uint32_t flags = 0, file_flags = 0;
+
+    if (strcmp(mode, "r") == 0)
+        flags = O_RDONLY, file_flags = FILE_READ;
+
+    if (strcmp(mode, "r+") == 0)
+        flags = O_RDWR, file_flags = FILE_READ | FILE_WRITE;
+
+    if (strcmp(mode, "w") == 0)
+        flags = O_WRONLY | O_CREAT | O_TRUNC, file_flags = FILE_WRITE;
+
+    if (strcmp(mode, "w+") == 0)
+        flags = O_RDWR | O_CREAT | O_TRUNC, file_flags = FILE_READ | FILE_WRITE;
+    
+    assert(flags);
+
+    int fd = open(path, flags, 0644);
+    if (fd < 0)
+        goto open_fail;
+    
+    FILE* file = malloc(sizeof(FILE));
+    if (!file)
+        goto file_malloc_fail;
+    
+    file->fd = fd;
+    file->flags = file_flags;
+
+    if (file_flags & FILE_READ) {
+        file->rbuf = malloc(BUFSIZ);
+        if (!file->rbuf)
+            goto rbuf_malloc_fail;
+        file->rbsz = BUFSIZ;
+    }
+
+    if (file_flags & FILE_WRITE) {
+        file->wbuf = malloc(BUFSIZ);
+        if (!file->wbuf)
+            goto wbuf_malloc_fail;
+        file->wbsz = BUFSIZ;
+    }
+
+    return file;
+
+wbuf_malloc_fail:
+    free(file->rbuf);
+
+rbuf_malloc_fail:
+    free(file);
+
+file_malloc_fail:
+    close(fd);
+
+open_fail:
+    return NULL;
+}
+
+int fflush(FILE* stream)
+{
+    if (__feof_or_error(stream))
+        return EOF;
+
+    if (stream->wbuf && stream->wpos) {
+        int ret = write(stream->fd, stream->wbuf, stream->wpos);
+        if (ret < 0) {
+            stream->flags |= FILE_ERROR;
+            return EOF;
+        }
+        if (ret == 0) {
+            stream->flags |= FILE_EOF;
+            return EOF;
+        }
+        stream->wpos = 0;
+    }
+
+    // TODO: call flush()
+
+    return 0;
+}
+
+int fclose(FILE* stream)
+{
+    if (fflush(stream) == EOF)
+        return EOF;
+    
+    free(stream->rbuf);
+    free(stream->wbuf);
+    stream->rbsz = 0;
+    stream->wbsz = 0;
+    
+    if (close(stream->fd) < 0)
+        return EOF;
+    
+    NDERASE(NDPTR(stream));
+    
+    return 0;
+}
+
+int fputc_unlocked(int c, FILE* stream)
+{
+    return putc_unlocked(c, stream);
+}
+
+int fputs_unlocked(const char* s, FILE* stream)
+{
+    // 1 is for the trailing '\n'
+    int len = 1;
+    for (const char* p = s; *p; ++p, ++len)
+        fputc_unlocked(*p, stream);
+    fputc_unlocked('\n', stream);
+    return len;
+}
+
+int fputc(int c, FILE* stream)
+{
+    // TODO: lock the stream
+    return putc_unlocked(c, stream);
+}
+
+int fputs(const char* s, FILE* stream)
+{
+    // TODO: lock the stream
+    return fputs_unlocked(s, stream);
+}
+
+static inline int __fillbuf(FILE* stream)
+{
+    if ((stream->rcnt = read(stream->fd, stream->rbuf, stream->rbsz)) >= 2147483648U) {
+        stream->rcnt = 0;
+        stream->flags |= FILE_ERROR;
+        return EOF;
+    }
+    if (stream->rcnt == 0) {
+        stream->flags |= FILE_EOF;
+        return EOF;
+    }
+    stream->rpos = 0;
+    return 0;
+}
+
+int getc_unlocked(FILE* stream)
+{
+    if (__feof_or_error(stream))
+        return EOF;
+
+    if (stream->rbuf) {
+        if (stream->rpos == stream->rcnt) {
+            if (__fillbuf(stream) < 0)
+                return EOF;
+        }
+        return stream->rbuf[stream->rpos++];
+    } else {
+        int c;
+        int ret = read(stream->fd, &c, 1);
+        if (ret < 0) {
+            stream->flags |= FILE_ERROR;
+            return EOF;
+        }
+        if (ret == 0) {
+            stream->flags |= FILE_EOF;
+            return EOF;
+        }
+        return c;
+    }
+}
+
+int putc_unlocked(int c, FILE* stream)
+{
+    if (__feof_or_error(stream))
+        return EOF;
+
+    if (stream->wbuf) {
+        stream->wbuf[stream->wpos++] = c;
+        if (stream->wpos == stream->wbsz || c == '\n')
+            if (fflush(stream) == EOF)
+                return EOF;
+    } else {
+        if (write(stream->fd, &c, 1) < 0) {
+            stream->flags |= FILE_ERROR;
+            return EOF;
+        }
+    }
+
+    return c;
+}
+
+int getchar(void)
+{
+    return fgetc(stdin);
+}
+
+int fgetc(FILE* stream)
+{
+    return getc_unlocked(stream);
+}
+
+int ferror(FILE* stream)
+{
+    // TODO: lock the stream
+    return ferror_unlocked(stream);
+}
+
+int ferror_unlocked(FILE* stream)
+{
+    return stream->flags & FILE_ERROR;
+}
+
+int feof(FILE* stream)
+{
+    return stream->flags & FILE_EOF;
+}
+
+void clearerr(FILE* stream)
+{
+    stream->flags &= ~FILE_ERROR;
+}
+
+int vasprintf(char** strp, const char* fmt, va_list args)
+{
+    // TODO: this is WAY TOO SLOWWWWWWWWW
+    int sz = 8, n;
+    char* buf = NULL;
+
+    do {
+        buf = realloc(buf, sz *= 2);
+        if (!buf)
+            return -1;
+        
+        n = vsnprintf(buf, sz, fmt, args);
+        if (sz > n)
+            break;
+    } while (1);
+    
+    *strp = buf;
+    return n;
+}
+
+int asprintf(char** strp, const char* fmt, ...)
+{
+    va_list lst;
+    va_start(lst, fmt);
+
+    int ret = vasprintf(strp, fmt, lst);
+
+    va_end(lst);
+
+    return ret;
+}

+ 268 - 0
gblibc/src/stdlib.c

@@ -0,0 +1,268 @@
+#include <alloca.h>
+#include <priv-vars.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <syscall.h>
+#include <unistd.h>
+#include <string.h>
+
+int atoi(const char* str)
+{
+    int ret = 0;
+    while (*str) {
+        ret *= 10;
+        ret += *str - '0';
+    }
+    return ret;
+}
+
+void __attribute__((noreturn)) exit(int status)
+{
+    syscall1(SYS_exit, status);
+    for (;;)
+        ;
+}
+
+#define MINIMUM_ALLOCATION_SIZE (8)
+#define MEM_ALLOCATED (1)
+
+static inline int _is_end(struct mem* p)
+{
+    return p->sz == 0;
+}
+
+static inline int _is_allocated(struct mem* p)
+{
+    return !!(p->flag & MEM_ALLOCATED);
+}
+
+static inline size_t _max(size_t a, size_t b)
+{
+    return a > b ? a : b;
+}
+
+static inline size_t _size(struct mem* from)
+{
+    if (!_is_end(from))
+        return from->sz;
+    
+    size_t sz = curr_brk - (void*)from;
+    if (sz < sizeof(struct mem))
+        return 0;
+
+    return sz - sizeof(struct mem);
+}
+
+static inline struct mem* _next(struct mem* p, size_t sz)
+{
+    return (void*)p + sizeof(struct mem) + sz;
+}
+
+static inline void _union(struct mem* p)
+{
+    if (_is_end(p))
+        return;
+
+    for (struct mem* next = _next(p, p->sz);
+        !(next->flag & MEM_ALLOCATED);
+        next = _next(p, p->sz)) {
+
+        if (_is_end(next)) {
+            p->sz = 0;
+            break;
+        }
+
+        p->sz += sizeof(struct mem);
+        p->sz += next->sz;
+    }
+}
+
+static inline void _cut_block(struct mem* p, size_t mem_size, size_t block_size)
+{
+    if (block_size >= mem_size + sizeof(struct mem) + MINIMUM_ALLOCATION_SIZE) {
+        p->sz = mem_size;
+
+        struct mem* next = _next(p, mem_size);
+        next->flag = 0;
+        next->sz = block_size - mem_size - sizeof(struct mem);
+    }
+}
+
+void* malloc(size_t size)
+{
+    if (size < MINIMUM_ALLOCATION_SIZE)
+        size = MINIMUM_ALLOCATION_SIZE;
+
+    struct mem* p = start_brk;
+    size_t sz = 0;
+    for (;; p = _next(p, p->sz)) {
+        if (_is_allocated(p))
+            continue;
+
+        _union(p);
+
+        sz = _size(p);
+        if (_is_end(p)) {
+            if (sz < size + sizeof(struct mem))
+                sbrk(_max(128 * 1024, size + sizeof(struct mem)));
+
+            sz = p->sz = size;
+            struct mem* next = _next(p, size);
+            next->flag = 0;
+            next->sz = 0;
+
+            break;
+        }
+
+        if (sz >= size)
+            break;
+    }
+
+    p->flag |= MEM_ALLOCATED;
+    _cut_block(p, size, sz);
+
+    return _next(p, 0);
+}
+
+void* realloc(void* ptr, size_t newsize)
+{
+    if (!ptr)
+        return malloc(newsize);
+
+    struct mem* p = ptr - sizeof(struct mem);
+    size_t oldsize = p->sz;
+
+    _union(p);
+    if (_is_end(p)) {
+        if (_size(p) < newsize + sizeof(struct mem))
+            sbrk(_max(128 * 1024, newsize + sizeof(struct mem)));
+
+        p->sz = newsize;
+        struct mem* next = _next(p, newsize);
+        next->flag = 0;
+        next->sz = 0;
+
+        return ptr;
+    }
+
+    if (p->sz >= newsize) {
+        _cut_block(p, newsize, p->sz);
+        return ptr;
+    }
+
+    void* newptr = malloc(newsize);
+    if (!newptr)
+        return NULL;
+    
+    memcpy(newptr, ptr, oldsize);
+    free(ptr);
+    return newptr;
+}
+
+void free(void* ptr)
+{
+    struct mem* p = ptr - sizeof(struct mem);
+    p->flag &= ~MEM_ALLOCATED;
+    _union(p);
+}
+
+static inline void _swap(void* a, void* b, size_t sz)
+{
+    void* tmp = alloca(sz);
+    memcpy(tmp, a, sz);
+    memcpy(a, b, sz);
+    memcpy(b, tmp, sz);
+}
+
+void qsort(void* arr, size_t len, size_t sz, comparator_t cmp) {
+    if (len <= 1)
+        return;
+
+    char* pivot = alloca(sz);
+    memcpy(pivot, arr + sz * (rand() % len), sz);
+
+    int i = 0, j = 0, k = len;
+    while (i < k) {
+        int res = cmp(arr + sz * i, pivot);
+        if (res < 0)
+            _swap(arr + sz * i++, arr + sz * j++, sz);
+        else if (res > 0)
+            _swap(arr + sz * i, arr + sz * --k, sz);
+        else
+            i++;
+    }
+
+    qsort(arr, j, sz, cmp);
+    qsort(arr + sz * k, len - k, sz, cmp);
+}
+
+static unsigned int __next_rand;
+int rand(void)
+{
+    return rand_r(&__next_rand);
+}
+
+int rand_r(unsigned int* seedp)
+{
+    *seedp = *seedp * 1103515245 + 12345;
+    return (unsigned int) (*seedp / 65536) % 32768;
+}
+
+void srand(unsigned int seed)
+{
+    __next_rand = seed;
+    rand();
+}
+
+void* bsearch(const void* key, const void* base, size_t num, size_t size, comparator_t cmp)
+{
+    if (num == 0)
+        return NULL;
+
+    size_t mid = num / 2;
+    int result = cmp(key, base + size * mid);
+
+    if (result == 0)
+        return (void*)base + size * mid;
+    
+    if (result > 0) {
+        ++mid;
+        return bsearch(key, base + size * mid, num - mid, size, cmp);
+    }
+    
+    return bsearch(key, base, mid, size, cmp);
+}
+
+int setenv(const char* name, const char* value, int overwrite)
+{
+    size_t i = 0;
+    for (; environ[i]; ++i) {
+        char* eqpos = strchr(environ[i], '=');
+        if (strncmp(name, environ[i], eqpos - environ[i]) == 0) {
+            if (overwrite)
+                goto fill_p;
+            return 0;
+        }
+    }
+
+    if (i + 2 == environ_size) {
+        environ_size *= 2;
+        char** newarr = malloc(environ_size * sizeof(char*));
+        if (!newarr)
+            return -1;
+        
+        memcpy(newarr, environ, sizeof(char*) * environ_size / 2);
+        free(environ);
+        environ = newarr;
+    }
+    environ[i + 1] = NULL;
+
+fill_p:;
+    char* newenv = NULL;
+    if (asprintf(&newenv, "%s=%s", name, value) < 0)
+        return -1;
+
+    environ[i] = newenv;
+    return 0;
+}

+ 228 - 1
gblibc/src/string.c

@@ -1,7 +1,30 @@
+#include <ctype.h>
+#include <errno.h>
+#include <signal.h>
 #include <stdint.h>
+#include <stdlib.h>
 
 #define BYTES_PER_MAX_COPY_UNIT (sizeof(uint32_t) / sizeof(uint8_t))
 
+int memcmp(const void* ptr1, const void* ptr2, size_t num)
+{
+    while (num--) {
+        if (*(const char*)ptr1 < *(const char*)ptr2)
+            return -1;
+        else if (*(const char*)ptr1 > *(const char*)ptr2)
+            return 1;
+    }
+    return 0;
+}
+
+void* memmove(void* dst, const void* src, size_t n)
+{
+    void* orig_dst = dst;
+    while (n--)
+        *(char*)(dst++) = *(const char*)(src++);
+    return orig_dst;
+}
+
 void* memcpy(void* _dst, const void* _src, size_t n)
 {
     void* orig_dst = _dst;
@@ -18,6 +41,11 @@ void* memcpy(void* _dst, const void* _src, size_t n)
     return orig_dst;
 }
 
+void* mempcpy(void* dst, const void* src, size_t n)
+{
+    return memcpy(dst, src, n) + n;
+}
+
 void* memset(void* _dst, int c, size_t n)
 {
     uint8_t* dst = (uint8_t*)_dst;
@@ -41,6 +69,41 @@ size_t strlen(const char* str)
     return n;
 }
 
+char* strchr(const char* str, int c)
+{
+    const char* p = str;
+    while (*p) {
+        if (*p == c)
+            return (char*)p;
+        ++p;
+    }
+    return NULL;
+}
+
+char* strrchr(const char* str, int c)
+{
+    const char* p = str + strlen(str) - 1;
+    while (p >= str) {
+        if (*p == c)
+            return (char*)p;
+        --p;
+    }
+    return NULL;
+}
+
+char* strchrnul(const char* str, int c)
+{
+    char* ret = strchr(str, c);
+    if (ret)
+        return ret;
+    return (char*)str + strlen(str);
+}
+
+char* strcpy(char* dst, const char* src)
+{
+    return memcpy(dst, src, strlen(src) + 1);
+}
+
 char* strncpy(char* dst, const char* src, size_t n)
 {
     size_t len = strlen(src);
@@ -55,12 +118,176 @@ char* strncpy(char* dst, const char* src, size_t n)
     return dst;
 }
 
+char* stpcpy(char* restrict dst, const char* restrict src)
+{
+    return memcpy(dst, src, strlen(src) + 1) + strlen(src);
+}
+
+char* stpncpy(char* restrict dst, const char* restrict src, size_t n)
+{
+    size_t len = strlen(src);
+
+    if (len < n) {
+        memset(dst + len, 0x00, n - len);
+        memcpy(dst, src, len);
+    } else {
+        memcpy(dst, src, n);
+    }
+
+    return dst + len;
+}
+
+int strncmp(const char* s1, const char* s2, size_t n)
+{
+    if (n == 0)
+        return 0;
+
+    int c;
+    while (n-- && (c = *s1 - *s2) == 0 && *s1) {
+        ++s1;
+        ++s2;
+    }
+    return c;
+}
+
 int strcmp(const char* s1, const char* s2)
 {
+    return strncmp(s1, s2, __SIZE_MAX__);
+}
+
+int strncasecmp(const char* s1, const char* s2, size_t n)
+{
+    if (n == 0)
+        return 0;
+
     int c;
-    while ((c = *s1 - *s2) == 0 && *s1 != 0) {
+    while (n-- && (c = tolower(*s1) - tolower(*s2)) == 0 && *s1) {
         ++s1;
         ++s2;
     }
     return c;
 }
+
+int strcasecmp(const char* s1, const char* s2)
+{
+    return strncasecmp(s1, s2, __SIZE_MAX__);
+}
+
+size_t strcspn(const char* str1, const char* str2)
+{
+    size_t ret = 0;
+    while (*str1) {
+        ++ret;
+        for (const char* p = str2; *p; ++p) {
+            if (*str1 == *p)
+                return ret;
+        }
+        ++str1;
+    }
+    return ret;
+}
+
+char* strstr(const char* str1, const char* str2)
+{
+    const char* p = str1;
+
+    while (*p) {
+        if (*p != *str2) {
+            ++p;
+            continue;
+        }
+
+        const char* p1 = p;
+        const char* q = str2;
+        while (*q) {
+            if (*p1 != *q)
+                break;
+            ++p1;
+            ++q;
+        }
+        if (!*q)
+            break;
+        p = p1;
+    }
+
+    if (*p)
+        return (char*)p;
+    return NULL;
+}
+
+char* strpbrk(const char* str1, const char* str2)
+{
+    size_t n = strcspn(str1, str2);
+    if (str1[n])
+        return (char*)str1 + n;
+    return NULL;
+}
+
+char* strerror(int errnum)
+{
+    switch (errnum) {
+    case EPERM:
+        return "Operation not permitted";
+    case ENOENT:
+        return "No such file or directory";
+    case ESRCH:
+        return "No such process";
+    case EINTR:
+        return "Interrupted system call";
+    case EBADF:
+        return "Bad file descriptor";
+    case ECHILD:
+        return "No child process";
+    case ENOMEM:
+        return "Out of memory";
+    case EEXIST:
+        return "File exists";
+    case ENOTDIR:
+        return "Not a directory";
+    case EISDIR:
+        return "Is a directory";
+    case EINVAL:
+        return "Invalid argument";
+    case ENOTTY:
+        return "Not a tty";
+    case EPIPE:
+        return "Broken pipe";
+    default:
+        return "No error information";
+    }
+}
+
+char* strndup(const char* str, size_t n)
+{
+    size_t len = strlen(str);
+    if (len > n)
+        len = n;
+    char* ret = malloc(len + 1);
+    if (!ret)
+        return NULL;
+    
+    memcpy(ret, str, len);
+    ret[len] = 0;
+    return ret;
+}
+
+char* strdup(const char* str)
+{
+    return strndup(str, __SIZE_MAX__);
+}
+
+char* strsignal(int sig)
+{
+    switch (sig) {
+    default:
+        return "Unknown signal";
+    case SIGINT:
+        return "Interrupt";
+    case SIGQUIT:
+        return "Quit";
+    case SIGSTOP:
+        return "Stopped (signal)";
+    case SIGPIPE:
+        return "Broken pipe";
+    }
+}

+ 20 - 0
gblibc/src/time.c

@@ -0,0 +1,20 @@
+#include <errno.h>
+#include <sys/time.h>
+#include <syscall.h>
+
+int gettimeofday(struct timeval* tv, struct timezone* tz)
+{
+    if (tz) {
+        errno = -EINVAL;
+        return -1;
+    }
+
+    int ret = syscall2(SYS_gettimeofday, (uint32_t)tv, 0);
+
+    if (ret < 0) {
+        errno = -ret;
+        return -1;
+    }
+
+    return ret;
+}

+ 140 - 15
gblibc/src/unistd.c

@@ -1,36 +1,69 @@
+#include <errno.h>
+#include <priv-vars.h>
 #include <stdarg.h>
+#include <stdint.h>
 #include <sys/ioctl.h>
 #include <unistd.h>
 #include <syscall.h>
 
 ssize_t read(int fd, void* buf, size_t count)
 {
-    return syscall3(SYS_read, fd, (uint32_t)buf, count);
+    ssize_t ret = syscall3(SYS_read, fd, (uint32_t)buf, count);
+    if (ret < 0) {
+        errno = -ret;
+        return -1;
+    }
+    return ret;
 }
 
 ssize_t write(int fd, const void* buf, size_t count)
 {
-    return syscall3(SYS_write, fd, (uint32_t)buf, count);
+    ssize_t ret = syscall3(SYS_write, fd, (uint32_t)buf, count);
+    if (ret < 0) {
+        errno = -ret;
+        return -1;
+    }
+    return ret;
 }
 
 int dup(int oldfd)
 {
-    return syscall1(SYS_dup, oldfd);
+    int ret = syscall1(SYS_dup, oldfd);
+    if (ret < 0) {
+        errno = -ret;
+        return -1;
+    }
+    return ret;
 }
 
 int dup2(int oldfd, int newfd)
 {
-    return syscall2(SYS_dup2, oldfd, newfd);
+    int ret = syscall2(SYS_dup2, oldfd, newfd);
+    if (ret < 0) {
+        errno = -ret;
+        return -1;
+    }
+    return ret;
 }
 
 int pipe(int pipefd[2])
 {
-    return syscall1(SYS_pipe, (uint32_t)pipefd);
+    int ret = syscall1(SYS_pipe, (uint32_t)pipefd);
+    if (ret < 0) {
+        errno = -ret;
+        return -1;
+    }
+    return ret;
 }
 
 int close(int fd)
 {
-    return syscall1(SYS_close, fd);
+    int ret = syscall1(SYS_close, fd);
+    if (ret < 0) {
+        errno = -ret;
+        return -1;
+    }
+    return ret;
 }
 
 _Noreturn void _exit(int code)
@@ -42,12 +75,22 @@ _Noreturn void _exit(int code)
 
 pid_t fork(void)
 {
-    return syscall0(SYS_fork);
+    pid_t ret = syscall0(SYS_fork);
+    if (ret < 0) {
+        errno = -ret;
+        return -1;
+    }
+    return ret;
 }
 
 int execve(const char* pathname, char* const argv[], char* const envp[])
 {
-    return syscall3(SYS_execve, (uint32_t)pathname, (uint32_t)argv, (uint32_t)envp);
+    int ret = syscall3(SYS_execve, (uint32_t)pathname, (uint32_t)argv, (uint32_t)envp);
+    if (ret < 0) {
+        errno = -ret;
+        return -1;
+    }
+    return ret;
 }
 
 // unsigned int sleep(unsigned int seconds)
@@ -57,7 +100,12 @@ int execve(const char* pathname, char* const argv[], char* const envp[])
 
 int chdir(const char* path)
 {
-    return syscall1(SYS_chdir, (uint32_t)path);
+    int ret = syscall1(SYS_chdir, (uint32_t)path);
+    if (ret < 0) {
+        errno = -ret;
+        return -1;
+    }
+    return ret;
 }
 
 char* getcwd(char* buf, size_t bufsize)
@@ -67,27 +115,52 @@ char* getcwd(char* buf, size_t bufsize)
 
 pid_t getpid(void)
 {
-    return syscall0(SYS_getpid);
+    pid_t ret = syscall0(SYS_getpid);
+    if (ret < 0) {
+        errno = -ret;
+        return -1;
+    }
+    return ret;
 }
 
 pid_t getppid(void)
 {
-    return syscall0(SYS_getppid);
+    pid_t ret = syscall0(SYS_getppid);
+    if (ret < 0) {
+        errno = -ret;
+        return -1;
+    }
+    return ret;
 }
 
 int setpgid(pid_t pid, pid_t pgid)
 {
-    return syscall2(SYS_setpgid, pid, pgid);
+    int ret = syscall2(SYS_setpgid, pid, pgid);
+    if (ret < 0) {
+        errno = -ret;
+        return -1;
+    }
+    return ret;
 }
 
 pid_t setsid(void)
 {
-    return syscall0(SYS_setsid);
+    pid_t ret = syscall0(SYS_setsid);
+    if (ret < 0) {
+        errno = -ret;
+        return -1;
+    }
+    return ret;
 }
 
 pid_t getsid(pid_t pid)
 {
-    return syscall1(SYS_getsid, pid);
+    pid_t ret = syscall1(SYS_getsid, pid);
+    if (ret < 0) {
+        errno = -ret;
+        return -1;
+    }
+    return ret;
 }
 
 pid_t tcgetpgrp(int fd)
@@ -103,7 +176,7 @@ int tcsetpgrp(int fd, pid_t pgrp)
 
 int ioctl(int fd, unsigned long request, ...)
 {
-    int ret = -1;
+    int ret = -EINVAL;
 
     va_list args;
     va_start(args, request);
@@ -120,5 +193,57 @@ int ioctl(int fd, unsigned long request, ...)
     }
 
     va_end(args);
+
+    if (ret < 0) {
+        errno = -ret;
+        return -1;
+    }
+
     return ret;
 }
+
+static inline void* _sys_brk(void* addr)
+{
+    return (void*)syscall1(SYS_brk, (uint32_t)addr);
+}
+
+void** __start_brk_location(void)
+{
+    static void* __start_brk = NULL;
+    return &__start_brk;
+}
+void** __curr_brk_location(void)
+{
+    static void* __curr_brk = NULL;
+    return &__curr_brk;
+}
+
+int brk(void* addr)
+{
+    void* new_brk = _sys_brk(addr);
+    if (new_brk == curr_brk) {
+        errno = 0;
+        return -1;
+    }
+
+    if (new_brk != addr) {
+        errno = ENOMEM;
+        return -1;
+    }
+
+    return 0;
+}
+
+void* sbrk(ssize_t increment)
+{
+    if (brk(curr_brk + increment) == 0)
+        return curr_brk += increment;
+    return (void*)-1;
+}
+
+int isatty(int fd)
+{
+    return tcgetpgrp(fd) != -1;
+}
+
+char** environ;

+ 0 - 38
gblibstdc++/include/bits/alltypes.h

@@ -1,38 +0,0 @@
-#ifndef __GBLIBC_BITS_ALLTYPES_H
-#define __GBLIBC_BITS_ALLTYPES_H
-
-
-#define S_IFMT 0170000
-
-#define S_IFSOCK 0140000
-#define S_IFLNK 0120000
-#define S_IFREG 0100000
-#define S_IFBLK 0060000
-#define S_IFDIR 0040000
-#define S_IFCHR 0020000
-#define S_IFIFO 0010000
-
-#define S_ISSOCK(m) (((m)&S_IFMT) == S_IFSOCK)
-#define S_ISLNK(m) (((m)&S_IFMT) == S_IFLNK)
-#define S_ISREG(m) (((m)&S_IFMT) == S_IFREG)
-#define S_ISBLK(m) (((m)&S_IFMT) == S_IFBLK)
-#define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR)
-#define S_ISCHR(m) (((m)&S_IFMT) == S_IFCHR)
-#define S_ISFIFO(m) (((m)&S_IFMT) == S_IFIFO)
-
-// gblibc extension
-#define S_ISBLKCHR(m) (S_ISBLK(m) || S_ISCHR(m))
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef unsigned uid_t;
-typedef unsigned gid_t;
-typedef unsigned mode_t;
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif

+ 1 - 0
gblibstdc++/include/memory

@@ -4,6 +4,7 @@
 #include <cstddef>
 #include <type_traits>
 #include <utility>
+#include <new>
 
 namespace std {
 

+ 2 - 1
include/fs/fat.hpp

@@ -167,7 +167,8 @@ public:
     ~fat32();
 
     virtual size_t inode_read(inode* file, char* buf, size_t buf_size, size_t offset, size_t n) override;
-    virtual int inode_stat(dentry* ent, statx* st, unsigned int mask) override;
+    virtual int inode_statx(dentry* ent, statx* st, unsigned int mask) override;
+    virtual int inode_stat(dentry* ent, struct stat* st) override;
     virtual int inode_readdir(fs::inode* dir, size_t offset, const fs::vfs::filldir_func& callback) override;
 };
 

+ 2 - 0
include/kernel/mm.hpp

@@ -20,6 +20,8 @@
                                  : "r"(addr)   \
                                  : "memory")
 
+#define memory_fence asm volatile("" ::: "memory")
+
 constexpr size_t THREAD_KERNEL_STACK_SIZE = 2 * PAGE_SIZE;
 
 constexpr uint32_t PAGE_COW = (1 << 0);

+ 2 - 1
include/kernel/process.hpp

@@ -8,8 +8,8 @@
 #include <tuple>
 #include <utility>
 
+#include <errno.h>
 #include <fcntl.h>
-#include <kernel/errno.h>
 #include <kernel/event/evtqueue.hpp>
 #include <kernel/interrupt.h>
 #include <kernel/mm.hpp>
@@ -253,6 +253,7 @@ public:
     filearr files;
     types::path pwd;
     kernel::signal_list signals;
+    mode_t umask { 0022 };
 
     pid_t pid {};
     pid_t ppid {};

+ 18 - 4
include/kernel/signal.hpp

@@ -9,10 +9,10 @@ namespace kernel {
 
 using sig_t = uint32_t;
 
-constexpr sig_t SIGINT = 1 << 0;
-constexpr sig_t SIGQUIT = 1 << 1;
-constexpr sig_t SIGSTOP = 1 << 2;
-constexpr sig_t SIGPIPE = 1 << 3;
+constexpr sig_t SIGINT = 2;
+constexpr sig_t SIGQUIT = 3;
+constexpr sig_t SIGSTOP = 13;
+constexpr sig_t SIGPIPE = 19;
 
 class signal_list {
 public:
@@ -22,6 +22,20 @@ private:
     list_type m_list;
     sig_t m_mask;
 
+public:
+    static constexpr bool check_valid(sig_t sig)
+    {
+        switch (sig) {
+        case SIGINT:
+        case SIGQUIT:
+        case SIGSTOP:
+        case SIGPIPE:
+            return true;
+        default:
+            return false;
+        }
+    }
+
 public:
     constexpr signal_list(void)
         : m_mask(0)

+ 2 - 0
include/kernel/tty.hpp

@@ -18,6 +18,8 @@ public:
     void print(const char* str);
     size_t read(char* buf, size_t buf_size, size_t n);
 
+    void clear_read_buf(void);
+
     constexpr void set_pgrp(pid_t pgid)
     {
         fg_pgroup = pgid;

+ 15 - 15
include/kernel/vfs.hpp

@@ -7,12 +7,13 @@
 
 #include <sys/stat.h>
 #include <sys/types.h>
-#include <kernel/errno.h>
+#include <errno.h>
 #include <bits/alltypes.h>
 
 #include <assert.h>
 #include <kernel/event/evtqueue.hpp>
 #include <stdint.h>
+#include <sys/types.h>
 #include <types/allocator.hpp>
 #include <types/buffer.hpp>
 #include <types/cplusplus.hpp>
@@ -55,13 +56,11 @@ struct inode {
     gid_t gid;
 };
 
-using node_t = uint32_t;
-
 #define NODE_MAJOR(node) ((node) >> 16)
 #define NODE_MINOR(node) ((node) & 0xffff)
-constexpr node_t NODE_INVALID = -1U;
+constexpr dev_t NODE_INVALID = -1U;
 
-constexpr node_t make_node(uint32_t major, uint32_t minor)
+constexpr dev_t make_device(uint32_t major, uint32_t minor)
 {
     return (major << 16) | (minor & 0xffff);
 }
@@ -211,11 +210,12 @@ public:
     virtual size_t inode_read(inode* file, char* buf, size_t buf_size, size_t offset, size_t n);
     virtual size_t inode_write(inode* file, const char* buf, size_t offset, size_t n);
     virtual int inode_mkfile(dentry* dir, const char* filename, mode_t mode);
-    virtual int inode_mknode(dentry* dir, const char* filename, mode_t mode, node_t sn);
+    virtual int inode_mknode(dentry* dir, const char* filename, mode_t mode, dev_t sn);
     virtual int inode_rmfile(dentry* dir, const char* filename);
     virtual int inode_mkdir(dentry* dir, const char* dirname);
-    virtual int inode_stat(dentry* dent, statx* buf, unsigned int mask);
-    virtual uint32_t inode_getnode(inode* file);
+    virtual int inode_statx(dentry* dent, statx* buf, unsigned int mask);
+    virtual int inode_stat(dentry* dent, struct stat* stat);
+    virtual dev_t inode_devid(inode* file);
 
     // parameter 'length' in callback:
     // if 0, 'name' should be null terminated
@@ -316,23 +316,23 @@ struct fifo_file : public virtual file {
 
 inline fs::vfs::dentry* fs_root;
 
-int register_block_device(node_t node, blkdev_ops ops);
-int register_char_device(node_t node, chrdev_ops ops);
+int register_block_device(dev_t node, blkdev_ops ops);
+int register_char_device(dev_t node, chrdev_ops ops);
 
 void partprobe();
 
-ssize_t block_device_read(node_t node, char* buf, size_t buf_size, size_t offset, size_t n);
-ssize_t block_device_write(node_t node, const char* buf, size_t offset, size_t n);
+ssize_t block_device_read(dev_t node, char* buf, size_t buf_size, size_t offset, size_t n);
+ssize_t block_device_write(dev_t node, const char* buf, size_t offset, size_t n);
 
-ssize_t char_device_read(node_t node, char* buf, size_t buf_size, size_t n);
-ssize_t char_device_write(node_t node, const char* buf, size_t n);
+ssize_t char_device_read(dev_t node, char* buf, size_t buf_size, size_t n);
+ssize_t char_device_write(dev_t node, const char* buf, size_t n);
 
 vfs* register_fs(vfs* fs);
 
 size_t vfs_read(inode* file, char* buf, size_t buf_size, size_t offset, size_t n);
 size_t vfs_write(inode* file, const char* buf, size_t offset, size_t n);
 int vfs_mkfile(fs::vfs::dentry* dir, const char* filename, mode_t mode);
-int vfs_mknode(fs::vfs::dentry* dir, const char* filename, mode_t mode, node_t sn);
+int vfs_mknode(fs::vfs::dentry* dir, const char* filename, mode_t mode, dev_t sn);
 int vfs_rmfile(fs::vfs::dentry* dir, const char* filename);
 int vfs_mkdir(fs::vfs::dentry* dir, const char* dirname);
 int vfs_stat(fs::vfs::dentry* dent, statx* stat, unsigned int mask);

+ 6 - 0
include/types/buffer.hpp

@@ -144,6 +144,12 @@ public:
     {
         return end - start + 1 - count;
     }
+
+    constexpr void clear(void)
+    {
+        count = 0;
+        head = base;
+    }
 };
 
 } // namespace types

+ 1 - 1
include/types/elf.hpp

@@ -1,5 +1,5 @@
 #pragma once
-#include <kernel/errno.h>
+#include <errno.h>
 #include <kernel/interrupt.h>
 #include <kernel/process.hpp>
 #include <kernel/vfs.hpp>

+ 5 - 4
src/asm/interrupt.s

@@ -44,15 +44,16 @@ int14:
     # save current esp (also pointer to struct int14_data)
     mov %esp, %ebx
 
+    # allocate space for mmx registers and argument
+    subl $0x210, %esp
+
     # align stack to 16byte boundary
     and $0xfffffff0, %esp
 
     # save mmx registers
-    subl $512, %esp
-    fxsave (%esp)
+    fxsave 16(%esp)
 
-    # push *data
-    sub $16, %esp
+    # push (interrupt_stack*)data
     mov %ebx, (%esp)
 
     call int14_handler

+ 16 - 1
src/fs/fat.cpp

@@ -234,7 +234,7 @@ size_t fat32::inode_read(inode* file, char* buf, size_t buf_size, size_t offset,
     return orig_n - n;
 }
 
-int fat32::inode_stat(dentry* ent, statx* st, unsigned int mask)
+int fat32::inode_statx(dentry* ent, statx* st, unsigned int mask)
 {
     st->stx_mask = 0;
     if (mask & STATX_SIZE) {
@@ -277,4 +277,19 @@ int fat32::inode_stat(dentry* ent, statx* st, unsigned int mask)
     return GB_OK;
 }
 
+int fat32::inode_stat(dentry* dent, struct stat* st)
+{
+    auto* ind = dent->ind;
+
+    memset(st, 0x00, sizeof(struct stat));
+    st->st_mode = ind->mode;
+    st->st_dev = device->fs->inode_devid(device);
+    st->st_nlink = S_ISDIR(ind->mode) ? 2 : 1;
+    st->st_size = ind->size;
+    st->st_blksize = 4096;
+    st->st_blocks = (ind->size + 511) / 512;
+    st->st_ino = ind->ino;
+    return GB_OK;
+}
+
 } // namespace fs::fat

+ 0 - 2
src/kernel.ld

@@ -91,8 +91,6 @@ SECTIONS
         LONG(__bss_end - __bss_start);
         kernel_size = .;
         LONG(__data_end - __kinit_start);
-        __stack_chk_guard = .;
-        LONG(0x19198101);
 
         . = ALIGN(0x1000);
         __rodata_end = .;

+ 0 - 8
src/kernel/errno.c

@@ -1,8 +0,0 @@
-#include <kernel/errno.h>
-#include <types/types.h>
-
-uint32_t* _get_errno(void)
-{
-    static uint32_t _errno = 0;
-    return &_errno;
-}

+ 3 - 3
src/kernel/hw/ahci.cc

@@ -1,18 +1,18 @@
-#include "kernel/vfs.hpp"
 #include <vector>
 #include <cstddef>
 #include <algorithm>
 
+#include <kernel/vfs.hpp>
 #include <kernel/log.hpp>
 #include <kernel/mm.hpp>
 #include <kernel/module.hpp>
 #include <kernel/hw/pci.hpp>
 #include <kernel/irq.hpp>
-#include <kernel/errno.h>
 
 #include <types/size.h>
 
 #include <stdint.h>
+#include <errno.h>
 
 #define SPIN(cond, spin) \
     (spin) = 0; \
@@ -484,7 +484,7 @@ public:
 
             this->ports[n] = port;
 
-            fs::register_block_device(fs::make_node(8, n * 8), {
+            fs::register_block_device(fs::make_device(8, n * 8), {
                 [port](char* buf, std::size_t buf_size, std::size_t offset, std::size_t cnt) {
                     return port->read(buf, buf_size, offset, cnt);
                 }, nullptr

+ 4 - 2
src/kernel/hw/pci.cc

@@ -1,10 +1,12 @@
+#include <map>
+
 #include <kernel/hw/pci.hpp>
 #include <kernel/hw/port.hpp>
-#include <kernel/errno.h>
 
-#include <map>
+#include <types/types.h>
 
 #include <assert.h>
+#include <errno.h>
 #include <stdint.h>
 
 using kernel::hw::p32;

+ 3 - 0
src/kernel/interrupt.cpp

@@ -259,6 +259,7 @@ extern "C" void int14_handler(int14_data* d)
             pte->in.p = 1;
             pte->in.a = 0;
             pte->in.rw = mm_area->attr.write;
+            memory_fence;
             return;
         }
         // duplicate the page
@@ -275,6 +276,7 @@ extern "C" void int14_handler(int14_data* d)
         pte->in.page = new_page;
         pte->in.rw = mm_area->attr.write;
         pte->in.a = 0;
+        memory_fence;
 
         --*page->ref_count;
 
@@ -285,6 +287,7 @@ extern "C" void int14_handler(int14_data* d)
 
     if (page->attr & PAGE_MMAP) {
         pte->in.p = 1;
+        memory_fence;
 
         size_t offset = align_down<12>((uint32_t)d->l_addr);
         offset -= (uint32_t)mm_area->start;

+ 6 - 1
src/kernel/mem.cpp

@@ -3,7 +3,7 @@
 #include <asm/port_io.h>
 #include <asm/sys.h>
 #include <assert.h>
-#include <kernel/errno.h>
+#include <errno.h>
 #include <kernel/mem.h>
 #include <kernel/mm.hpp>
 #include <kernel/process.hpp>
@@ -405,6 +405,7 @@ void mm::append_page(pd_t pd, const page& pg, uint32_t attr, bool priv)
         assert(pt);
         pte = *pt;
     }
+    memory_fence;
 
     // map the page in the page table
     int pti = v_to_pti(addr);
@@ -417,6 +418,7 @@ void mm::append_page(pd_t pd, const page& pg, uint32_t attr, bool priv)
         false,
         priv);
 
+    memory_fence;
     kernel::pfree(pt_pg);
 
     if (unlikely((attr & PAGE_COW) && !(pg.attr & PAGE_COW))) {
@@ -429,7 +431,10 @@ void mm::append_page(pd_t pd, const page& pg, uint32_t attr, bool priv)
         pg_pte->in.a = 0;
         invalidate_tlb(addr);
     }
+
+    memory_fence;
     ++*pg.ref_count;
+    memory_fence;
 
     this->pgs->emplace_back(pg);
     auto& emplaced = this->pgs->back();

+ 9 - 3
src/kernel/process.cpp

@@ -153,7 +153,7 @@ int filearr::open(const process &current,
 
 process::process(const process& parent, pid_t pid)
     : mms { parent.mms }, attr { parent.attr } , pwd { parent.pwd }
-    , signals { parent.signals } , pid { pid }
+    , signals { parent.signals } , umask { parent.umask }, pid { pid }
     , ppid { parent.pid } , pgid { parent.pgid } , sid { parent.sid }
     , control_tty { parent.control_tty }, root { parent.root }
 {
@@ -348,7 +348,7 @@ void NORETURN _kernel_init(void)
     current_thread->attr.system = 0;
 
     const char* argv[] = { "/mnt/init", "/mnt/sh", nullptr };
-    const char* envp[] = { nullptr };
+    const char* envp[] = { "LANG=C", "HOME=/", nullptr };
 
     types::elf::elf32_load_data d;
     d.argv = argv;
@@ -502,8 +502,14 @@ void check_signal()
     switch (current_process->signals.pop()) {
     case kernel::SIGINT:
     case kernel::SIGQUIT:
+    case kernel::SIGSTOP: {
+        tty* ctrl_tty = current_process->control_tty;
+        if (ctrl_tty)
+            ctrl_tty->clear_read_buf();
+        kill_current(-1);
+        break;
+    }
     case kernel::SIGPIPE:
-    case kernel::SIGSTOP:
         kill_current(-1);
         break;
     case 0:

+ 93 - 5
src/kernel/syscall.cpp

@@ -1,30 +1,38 @@
 #include <asm/port_io.h>
 #include <asm/sys.h>
+
 #include <assert.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <bits/alltypes.h>
 #include <bits/ioctl.h>
+#include <sys/types.h>
 #include <sys/prctl.h>
 #include <sys/mman.h>
 #include <sys/stat.h>
-#include <time.h>
+
 #include <kernel/user/thread_local.hpp>
-#include <kernel/errno.h>
 #include <kernel/interrupt.h>
 #include <kernel/log.hpp>
 #include <kernel/mem.h>
 #include <kernel/mm.hpp>
 #include <kernel/process.hpp>
+#include <kernel/signal.hpp>
 #include <kernel/syscall.hpp>
 #include <kernel/tty.hpp>
 #include <kernel/vfs.hpp>
 #include <kernel/hw/timer.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <string.h>
+
 #include <types/allocator.hpp>
 #include <types/elf.hpp>
 #include <types/path.hpp>
 #include <types/lock.hpp>
 #include <types/status.h>
+#include <types/string.hpp>
+#include <types/types.h>
 
 #define SYSCALL_NO ((data)->s_regs.eax)
 #define SYSCALL_RETVAL ((data)->s_regs.eax)
@@ -248,6 +256,8 @@ int _syscall_open(interrupt_stack* data)
     SYSCALL_ARG2(int, flags);
     SYSCALL_ARG3(mode_t, mode);
 
+    mode &= ~current_process->umask;
+
     return current_process->files.open(*current_process,
         types::make_path(path, current_process->pwd), flags, mode);
 }
@@ -658,6 +668,81 @@ int _syscall_getdents64(interrupt_stack* data)
     return dir->getdents64(buf, cnt);
 }
 
+/* TODO: implement vfs_stat(stat*)
+int _syscall_stat(interrupt_stack* data)
+{
+    SYSCALL_ARG1(const char* __user, pathname);
+    SYSCALL_ARG2(struct stat* __user, buf);
+
+    auto* dent = fs::vfs_open(*current_process->root,
+        types::make_path(pathname, current_process->pwd));
+
+    if (!dent)
+        return -ENOENT;
+
+    return fs::vfs_stat(dent, buf);
+}
+*/
+
+/* TODO: implement vfs_stat(stat*)
+int _syscall_fstat(interrupt_stack* data)
+{
+    SYSCALL_ARG1(int, fd);
+    SYSCALL_ARG2(struct stat* __user, buf);
+
+    auto* file = current_process->files[fd];
+    if (!file)
+        return -EBADF;
+
+    return fs::vfs_stat(file, buf);
+}
+*/
+
+int _syscall_gettimeofday(interrupt_stack* data)
+{
+    SYSCALL_ARG1(timeval* __user, tv);
+    SYSCALL_ARG2(void* __user, tz);
+    // TODO: return time of the day, not time from this boot
+
+    if (unlikely(tz))
+        return -EINVAL;
+
+    if (likely(tv)) {
+        // TODO: use copy_to_user
+        tv->tv_sec = current_ticks() / 100;
+        tv->tv_usec = current_ticks() * 10 * 1000;
+    }
+
+    return 0;
+}
+
+int _syscall_umask(interrupt_stack* data)
+{
+    SYSCALL_ARG1(mode_t, mask);
+
+    mode_t old = current_process->umask;
+    current_process->umask = mask;
+
+    return old;
+}
+
+int _syscall_kill(interrupt_stack* data)
+{
+    SYSCALL_ARG1(pid_t, pid);
+    SYSCALL_ARG2(int, sig);
+
+    if (!procs->try_find(pid))
+        return -ESRCH;
+
+    if (!kernel::signal_list::check_valid(sig))
+        return -EINVAL;
+
+    // TODO: check permission
+    procs->send_signal(pid, sig);
+
+    return 0;
+}
+
 extern "C" void syscall_entry(interrupt_stack* data)
 {
     int syscall_no = SYSCALL_NO;
@@ -693,14 +778,17 @@ void init_syscall(void)
     syscall_handlers[0x0b] = _syscall_execve;
     syscall_handlers[0x0c] = _syscall_chdir;
     syscall_handlers[0x14] = _syscall_getpid;
+    syscall_handlers[0x25] = _syscall_kill;
     syscall_handlers[0x29] = _syscall_dup;
     syscall_handlers[0x2a] = _syscall_pipe;
     syscall_handlers[0x2d] = _syscall_brk;
     syscall_handlers[0x36] = _syscall_ioctl;
     syscall_handlers[0x39] = _syscall_setpgid;
+    syscall_handlers[0x3c] = _syscall_umask;
     syscall_handlers[0x3f] = _syscall_dup2;
     syscall_handlers[0x40] = _syscall_getppid;
     syscall_handlers[0x42] = _syscall_setsid;
+    syscall_handlers[0x4e] = _syscall_gettimeofday;
     syscall_handlers[0x5b] = _syscall_munmap;
     syscall_handlers[0x84] = _syscall_getdents;
     syscall_handlers[0x92] = _syscall_writev;

+ 5 - 0
src/kernel/tty.cpp

@@ -150,3 +150,8 @@ void serial_tty::recvchar(char c)
         break;
     }
 }
+
+void tty::clear_read_buf(void)
+{
+    this->buf.clear();
+}

+ 39 - 39
src/kernel/vfs.cpp

@@ -1,20 +1,21 @@
 #include <cstddef>
 #include <map>
+#include <sys/types.h>
 #include <vector>
 #include <bit>
 #include <utility>
 
 #include <bits/alltypes.h>
-
 #include <assert.h>
-#include <kernel/errno.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+
 #include <kernel/log.hpp>
 #include <kernel/mem.h>
 #include <kernel/process.hpp>
 #include <kernel/tty.hpp>
 #include <kernel/vfs.hpp>
-#include <stdint.h>
-#include <stdio.h>
 #include <types/allocator.hpp>
 #include <types/status.h>
 #include <types/path.hpp>
@@ -70,7 +71,7 @@ fs::vfs::dentry* fs::vfs::dentry::find(const name_type& name)
 
     auto iter = idx_children->find(name);
     if (!iter) {
-        errno = ENOTFOUND;
+        errno = ENOENT;
         return nullptr;
     }
 
@@ -184,19 +185,18 @@ size_t fs::vfs::inode_write(inode*, const char*, size_t, size_t)
 { return -EINVAL; }
 int fs::vfs::inode_mkfile(dentry*, const char*, mode_t)
 { return -EINVAL; }
-int fs::vfs::inode_mknode(dentry*, const char*, mode_t, node_t)
+int fs::vfs::inode_mknode(dentry*, const char*, mode_t, dev_t)
 { return -EINVAL; }
 int fs::vfs::inode_rmfile(dentry*, const char*)
 { return -EINVAL; }
 int fs::vfs::inode_mkdir(dentry*, const char*)
 { return -EINVAL; }
-int fs::vfs::inode_stat(dentry*, statx*, unsigned int)
+int fs::vfs::inode_statx(dentry*, statx*, unsigned int)
+{ return -EINVAL; }
+int fs::vfs::inode_stat(dentry*, struct stat*)
+{ return -EINVAL; }
+dev_t fs::vfs::inode_devid(fs::inode*)
 { return -EINVAL; }
-uint32_t fs::vfs::inode_getnode(fs::inode*)
-{
-    assert(false);
-    return 0xffffffff;
-}
 
 class tmpfs : public virtual fs::vfs {
 private:
@@ -308,12 +308,12 @@ public:
         return GB_OK;
     }
 
-    virtual int inode_mknode(dentry* dir, const char* filename, mode_t mode, fs::node_t sn) override
+    virtual int inode_mknode(dentry* dir, const char* filename, mode_t mode, dev_t dev) override
     {
         if (!S_ISBLK(mode) && !S_ISCHR(mode))
             return -EINVAL;
 
-        auto& node = *cache_inode(0, _savedata(sn), mode, 0, 0);
+        auto& node = *cache_inode(0, _savedata(dev), mode, 0, 0);
         mklink(dir->ind, &node, filename);
         dir->append(get_inode(node.ino), filename, true);
         return GB_OK;
@@ -367,7 +367,7 @@ public:
         return n;
     }
 
-    virtual int inode_stat(dentry* dent, statx* st, unsigned int mask) override
+    virtual int inode_statx(dentry* dent, statx* st, unsigned int mask) override
     {
         auto* ind = dent->ind;
         const mode_t mode = ind->mode;
@@ -386,7 +386,7 @@ public:
         if (mask & STATX_TYPE) {
             st->stx_mode |= ind->mode & S_IFMT;
             if (S_ISBLK(mode) || S_ISCHR(mode)) {
-                auto nd = (fs::node_t)as_val(_getdata(ind->ino));
+                auto nd = (dev_t)as_val(_getdata(ind->ino));
                 st->stx_rdev_major = NODE_MAJOR(nd);
                 st->stx_rdev_minor = NODE_MINOR(nd);
             }
@@ -417,7 +417,7 @@ public:
         return GB_OK;
     }
 
-    virtual uint32_t inode_getnode(fs::inode* file) override
+    virtual dev_t inode_devid(fs::inode* file) override
     {
         return as_val(_getdata(file->ino));
     }
@@ -563,8 +563,8 @@ void fs::fifo_file::close(void)
     ppipe.reset();
 }
 
-static std::map<fs::node_t, fs::blkdev_ops> blkdevs;
-static std::map<fs::node_t, fs::chrdev_ops> chrdevs;
+static std::map<dev_t, fs::blkdev_ops> blkdevs;
+static std::map<dev_t, fs::chrdev_ops> chrdevs;
 
 size_t fs::vfs_read(fs::inode* file, char* buf, size_t buf_size, size_t offset, size_t n)
 {
@@ -577,13 +577,13 @@ size_t fs::vfs_read(fs::inode* file, char* buf, size_t buf_size, size_t offset,
         return file->fs->inode_read(file, buf, buf_size, offset, n);
 
     if (S_ISBLK(file->mode) || S_ISCHR(file->mode)) {
-        node_t sn = file->fs->inode_getnode(file);
+        dev_t dev = file->fs->inode_devid(file);
 
         ssize_t ret;
         if (S_ISBLK(file->mode))
-            ret = block_device_read(sn, buf, buf_size, offset, n);
+            ret = block_device_read(dev, buf, buf_size, offset, n);
         else
-            ret = char_device_read(sn, buf, buf_size, n);
+            ret = char_device_read(dev, buf, buf_size, n);
 
         if (ret < 0) {
             errno = -ret;
@@ -607,13 +607,13 @@ size_t fs::vfs_write(fs::inode* file, const char* buf, size_t offset, size_t n)
         return file->fs->inode_write(file, buf, offset, n);
 
     if (S_ISBLK(file->mode) || S_ISCHR(file->mode)) {
-        node_t sn = file->fs->inode_getnode(file);
+        dev_t dev = file->fs->inode_devid(file);
 
         ssize_t ret;
         if (S_ISBLK(file->mode))
-            ret = block_device_write(sn, buf, offset, n);
+            ret = block_device_write(dev, buf, offset, n);
         else
-            ret = char_device_write(sn, buf, n);
+            ret = char_device_write(dev, buf, n);
 
         if (ret < 0) {
             errno = -ret;
@@ -630,9 +630,9 @@ int fs::vfs_mkfile(fs::vfs::dentry* dir, const char* filename, mode_t mode)
 {
     return dir->ind->fs->inode_mkfile(dir, filename, mode);
 }
-int fs::vfs_mknode(fs::vfs::dentry* dir, const char* filename, mode_t mode, fs::node_t sn)
+int fs::vfs_mknode(fs::vfs::dentry* dir, const char* filename, mode_t mode, dev_t dev)
 {
-    return dir->ind->fs->inode_mknode(dir, filename, mode, sn);
+    return dir->ind->fs->inode_mknode(dir, filename, mode, dev);
 }
 int fs::vfs_rmfile(fs::vfs::dentry* dir, const char* filename)
 {
@@ -660,12 +660,12 @@ fs::vfs::dentry* fs::vfs_open(fs::vfs::dentry& root, const types::path& path)
 
 int fs::vfs_stat(fs::vfs::dentry* ent, statx* stat, unsigned int mask)
 {
-    return ent->ind->fs->inode_stat(ent, stat, mask);
+    return ent->ind->fs->inode_statx(ent, stat, mask);
 }
 
 static std::list<fs::vfs*>* fs_es;
 
-int fs::register_block_device(fs::node_t node, fs::blkdev_ops ops)
+int fs::register_block_device(dev_t node, fs::blkdev_ops ops)
 {
     auto iter = blkdevs.find(node);
     if (iter)
@@ -675,7 +675,7 @@ int fs::register_block_device(fs::node_t node, fs::blkdev_ops ops)
     return 0;
 }
 
-int fs::register_char_device(fs::node_t node, fs::chrdev_ops ops)
+int fs::register_char_device(dev_t node, fs::chrdev_ops ops)
 {
     auto iter = chrdevs.find(node);
     if (iter)
@@ -704,7 +704,7 @@ struct PACKED mbr {
     uint16_t magic;
 };
 
-static inline void mbr_part_probe(fs::node_t node, char ch)
+static inline void mbr_part_probe(dev_t node, char ch)
 {
     mbr buf_mbr;
     // TODO: devtmpfs
@@ -776,7 +776,7 @@ void fs::partprobe()
     }
 }
 
-ssize_t fs::block_device_read(fs::node_t node, char* buf, size_t buf_size, size_t offset, size_t n)
+ssize_t fs::block_device_read(dev_t node, char* buf, size_t buf_size, size_t offset, size_t n)
 {
     if (node == fs::NODE_INVALID)
         return -EINVAL;
@@ -788,7 +788,7 @@ ssize_t fs::block_device_read(fs::node_t node, char* buf, size_t buf_size, size_
     return iter->second.read(buf, buf_size, offset, n);
 }
 
-ssize_t fs::block_device_write(fs::node_t node, const char* buf, size_t offset, size_t n)
+ssize_t fs::block_device_write(dev_t node, const char* buf, size_t offset, size_t n)
 {
     if (node == fs::NODE_INVALID)
         return -EINVAL;
@@ -800,7 +800,7 @@ ssize_t fs::block_device_write(fs::node_t node, const char* buf, size_t offset,
     return iter->second.write(buf, offset, n);
 }
 
-ssize_t fs::char_device_read(fs::node_t node, char* buf, size_t buf_size, size_t n)
+ssize_t fs::char_device_read(dev_t node, char* buf, size_t buf_size, size_t n)
 {
     if (node == fs::NODE_INVALID)
         return -EINVAL;
@@ -812,7 +812,7 @@ ssize_t fs::char_device_read(fs::node_t node, char* buf, size_t buf_size, size_t
     return iter->second.read(buf, buf_size, n);
 }
 
-ssize_t fs::char_device_write(fs::node_t node, const char* buf, size_t n)
+ssize_t fs::char_device_write(dev_t node, const char* buf, size_t n)
 {
     if (node == fs::NODE_INVALID)
         return -EINVAL;
@@ -950,10 +950,10 @@ void init_vfs(void)
 {
     using namespace fs;
     // null
-    register_char_device(make_node(1, 0), { b_null_read, b_null_write });
+    register_char_device(make_device(1, 0), { b_null_read, b_null_write });
     // console (supports serial console only for now)
     // TODO: add interface to bind console device to other devices
-    register_char_device(make_node(2, 0), { console_read, console_write });
+    register_char_device(make_device(2, 0), { console_read, console_write });
 
     fs_es = types::pnew<types::kernel_ident_allocator>(fs_es);
 
@@ -973,6 +973,6 @@ void init_vfs(void)
 
     auto* dev = vfs_open(*fs_root, "/dev");
     assert(dev);
-    vfs_mknode(dev, "null", 0666 | S_IFCHR, make_node(1, 0));
-    vfs_mknode(dev, "console", 0666 | S_IFCHR, make_node(2, 0));
+    vfs_mknode(dev, "null", 0666 | S_IFCHR, make_device(1, 0));
+    vfs_mknode(dev, "console", 0666 | S_IFCHR, make_device(2, 0));
 }

+ 1 - 1
src/types/elf.cpp

@@ -1,7 +1,7 @@
 #include <vector>
 
 #include <assert.h>
-#include <kernel/errno.h>
+#include <errno.h>
 #include <kernel/mem.h>
 #include <kernel/process.hpp>
 #include <kernel/vfs.hpp>

+ 1 - 1
user-space-program/CMakeLists.txt

@@ -4,7 +4,7 @@ project(user_space_program C ASM)
 set(CMAKE_C_FLAGS "-nostdlib -nostdinc -static -m32 -W -Wall -Wextra -Werror -mstack-protector-guard=global")
 set(CMAKE_ASM_FLAGS "-nostdlib -m32 -static -mstack-protector-guard=global -g0")
 
-link_libraries(gblibc)
+link_libraries(gblibc crt0)
 
 set(CMAKE_C_IMPLICIT_LINK_DIRECTORIES "")
 set(CMAKE_C_IMPLICIT_LINK_LIBRARIES "")

+ 6 - 4
user-space-program/init.c

@@ -1,4 +1,6 @@
+#include <assert.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 #include <fcntl.h>
@@ -35,7 +37,6 @@ _run_sh:;
         }
 
         char* shell_argv[128] = {};
-        char* envp[1] = { NULL };
 
         if (argc < 2)
             shell_argv[0] = "/bin/sh";
@@ -45,18 +46,19 @@ _run_sh:;
         for (int i = 2; i < argc; ++i)
             shell_argv[i - 1] = argv[i];
         
-        execve(shell_argv[0], shell_argv, envp);
+        execve(shell_argv[0], shell_argv, environ);
 
         print("[init] unable to run sh, exiting...\n");
         return -1;
     }
 
     int ret, pid;
-    char buf[512] = {};
     for (;;) {
         pid = wait(&ret);
-        snprintf(buf, sizeof(buf), "[init] pid%d has exited with code %d\n", pid, ret);
+        char* buf = NULL;
+        assert(asprintf(&buf, "[init] pid%d has exited with code %d\n", pid, ret) >= 0);
         print(buf);
+        free(buf);
         // sh
         if (pid == sh_pid)
             goto _run_sh;

+ 14 - 44
user-space-program/lazybox.c

@@ -10,35 +10,8 @@ struct applet {
     int (*func)(const char** args);
 };
 
-int putchar(int c)
+int lazybox_version(void)
 {
-    write(STDOUT_FILENO, &c, 1);
-    return c;
-}
-
-int puts(const char* str)
-{
-    size_t ret = write(STDOUT_FILENO, str, strlen(str));
-    ret += write(STDOUT_FILENO, "\n", 1);
-    return ret;
-}
-
-int printf(const char* fmt, ...)
-{
-    va_list args;
-    va_start(args, fmt);
-
-    char buf[128];
-    int n = vsnprintf(buf, sizeof(buf), fmt, args);
-    n = write(STDOUT_FILENO, buf, n);
-
-    va_end(args);
-    return n;
-}
-
-int lazybox_version(const char** _)
-{
-    (void)_;
     printf("lazybox by greatbridf\n");
     return 0;
 }
@@ -86,7 +59,7 @@ int ls(const char** args)
 struct applet applets[] = {
     {
         "lazybox",
-        lazybox_version,
+        NULL,
     },
     {
         "pwd",
@@ -130,7 +103,7 @@ const char* find_file_name(const char* path)
             break;
         }
     }
-    return last;
+    return last == path ? path : last + 1;
 }
 
 int parse_applet(const char* name)
@@ -149,22 +122,19 @@ int parse_applet(const char* name)
 
 int main(int argc, const char** argv)
 {
-    (void)argc;
-    int offset = 0;
-    const char* name = find_file_name(argv[offset++]);
-    int type = -1;
-
-run:
-    type = parse_applet(name);
-    if (type == -1) {
+    if (argc == 0)
+        return lazybox_version();
+
+    const char* name = find_file_name(*argv);
+    int type = parse_applet(find_file_name(*argv));
+
+    if (type < 0) {
         printf("applet not found: %s\n", name);
         return -1;
     }
 
-    if (type == 0 && offset == 1) {
-        name = argv[offset++];
-        goto run;
-    }
-
-    return applets[type].func(argv + offset);
+    if (type == 0)
+        return main(argc - 1, argv + 1);
+    
+    return applets[type].func(argv + 1);
 }

+ 4 - 59
user-space-program/sh.c

@@ -5,61 +5,7 @@
 #include <string.h>
 #include <fcntl.h>
 #include <unistd.h>
-
-int printf(const char* fmt, ...)
-{
-    va_list args;
-    va_start(args, fmt);
-
-    char buf[256] = {};
-    int len = vsnprintf(buf, sizeof(buf), fmt, args);
-
-    len = write(STDOUT_FILENO, buf, len);
-
-    va_end(args);
-
-    return len;
-}
-
-char* strchr(const char* str, int c)
-{
-    const char* p = str;
-    while (*p) {
-        if (*p == c)
-            return (char*)p;
-        ++p;
-    }
-    return NULL;
-}
-
-char* gets(char* buf, int bufsize)
-{
-    int n = read(STDIN_FILENO, buf, bufsize);
-    if (n > 0) {
-      if (buf[n-1] == '\n')
-        buf[n-1] = 0;
-      else
-        buf[n] = 0;
-      return buf;
-    }
-    return NULL;
-}
-
-int puts(const char* str)
-{
-    int len = strlen(str);
-    write(STDOUT_FILENO, str, len);
-    return len + 1;
-}
-
-void* malloc(size_t n)
-{
-    static char mems[1024];
-    static int pos;
-    int orig_pos = pos;
-    pos += n;
-    return mems + orig_pos;
-}
+#include <stdlib.h>
 
 // Parsed command representation
 #define EXEC  1
@@ -133,8 +79,7 @@ runcmd(struct cmd *cmd)
     ecmd = (struct execcmd*)cmd;
     if(ecmd->argv[0] == 0)
       _exit(-1);
-    char* const envp[1] = { NULL };
-    execve(ecmd->argv[0], ecmd->argv, envp);
+    execve(ecmd->argv[0], ecmd->argv, environ);
     printf("exec %s failed\n", ecmd->argv[0]);
     break;
 
@@ -192,9 +137,9 @@ runcmd(struct cmd *cmd)
 int
 getcmd(char *buf, int nbuf)
 {
-  printf("$ ");
+  printf("[root@localhost] #\n");
   memset(buf, 0, nbuf);
-  gets(buf, nbuf);
+  gets(buf);
   if(buf[0] == 0) // EOF
     return -1;
   return 0;