OrionLibC
Barry Importing existing Orion LibC 03048a9 (2 years, 2 months ago)diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..dff8645 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +build/ +*.a diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..fe29407 --- /dev/null +++ b/Makefile @@ -0,0 +1,50 @@ +PRODUCT=libc.a + +CC=i686-orion-gcc +CFLAGS= + +AS=i686-orion-as +AFLAGS= + +AR=i686-orion-ar + +AS_SOURCES := $(shell find . -name '*.S') +OBJS += $(subst ./,build/,$(subst .S,.o,$(AS_SOURCES))) + +C_SOURCES := $(shell find . -name '*.c') +OBJS += $(subst ./,build/,$(subst .c,.o,$(C_SOURCES))) + +.PHONY: install-headers clean all install + +all: $(PRODUCT) + +clean: + @echo "REMOVING OBJECT FILES" + @mkdir -p build + @rm -rf build + @touch $(PRODUCT) + @rm $(PRODUCT) + +install-headers: + @echo "INSTALLING HEADERS" + @mkdir -p ${SYSROOT}/usr/include/ + @cp -r include/* ${SYSROOT}/usr/include/ + +install: $(PRODUCT) build/crt0.o build/crti.o build/crtn.o + @echo "INSTALLING $^" + @install -Dm 644 $^ -t ${SYSROOT}/usr/lib/ + +$(PRODUCT): $(OBJS) + @echo "LINKING $@" + @mkdir -p $(@D) + @$(AR) rcs $@ $^ + +build/%.o: %.c + @echo "COMPILING $<" + @mkdir -p $(@D) + @$(CC) -c $< -o $@ $(CFLAGS) + +build/%.o: %.S + @echo "ASSEMBLING $<" + @mkdir -p $(@D) + @$(AS) $< -o $@ $(AFLAGS) diff --git a/crt0.S b/crt0.S new file mode 100644 index 0000000..fb9f6b4 --- /dev/null +++ b/crt0.S @@ -0,0 +1,18 @@ +.section .text + +.global _start +_start: + movl 0(%esp), %eax # argc + leal 4(%esp), %edx # argv + leal 8(%esp, %eax, 4), %ecx # envp + + pushl %ecx # envp + pushl %edx # argv + pushl %eax # argc + xorl %ebp, %ebp # mark first stack frame + + call main + + pushl %eax + call exit +.size _start, . - _start diff --git a/crti.S b/crti.S new file mode 100644 index 0000000..df534de --- /dev/null +++ b/crti.S @@ -0,0 +1,13 @@ +.section .init +.global _init +.type _init, @function +_init: + push %ebp + movl %esp, %ebp + +.section .fini +.global _fini +.type _fini, @function +_fini: + push %ebp + movl %esp, %ebp diff --git a/crtn.S b/crtn.S new file mode 100644 index 0000000..4c72785 --- /dev/null +++ b/crtn.S @@ -0,0 +1,7 @@ +.section .init + popl %ebp + ret + +.section .fini + popl %ebp + ret diff --git a/dirent.c b/dirent.c new file mode 100644 index 0000000..e896020 --- /dev/null +++ b/dirent.c @@ -0,0 +1,16 @@ +#include <sys/syscall.h> +#include <dirent.h> +#include <errno.h> + +/* Get directory entries */ +size_t +getdents(int fd, void *buf, size_t count) +{ + int ret; + asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_GETDENTS), + "c" (3), "S" (&fd)); + if (ret >= 0) + return (size_t) ret; + errno = -ret; + return -1; +} diff --git a/exit.c b/exit.c new file mode 100644 index 0000000..ffd0620 --- /dev/null +++ b/exit.c @@ -0,0 +1,12 @@ +#include <sys/syscall.h> + +/* Exit the current program */ +void +exit(int status) +{ + int ret; + asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_EXIT), + "c" (1), "S" (&status)); + while (1); + /* UNREACHED */ +} diff --git a/grp/getgr.c b/grp/getgr.c new file mode 100644 index 0000000..e77d50c --- /dev/null +++ b/grp/getgr.c @@ -0,0 +1,142 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <grp.h> + +/* Parts of a /etc/group line */ +enum GroupParts { + GROUP_NAME, + GROUP_GID, + GROUP_USERS, +}; + +static Group entry; +static char entryName[33]; +static char *entryMembers[64]; +static char entryUsers[64 * 33]; + +/* Get part of a password line */ +static char * +get_part(char *line, int index, char *buf) +{ + int i, len = 0; + char *start; + for (i = 0; i < index; i++) + while (*line++ != ':'); + start = line; + while (*line != ':' && *line != '\n') { + line++; + len++; + } + memcpy(buf, start, len); + buf[len] = '\0'; + return buf; +} + +/* Convert a string to a number */ +static int +number(char *str) +{ + int num = 0, col = 1, len; + for (len = 0; str[len] >= '0' && str[len] <= '9'; len++); + while (len--) { + num += (str[len] - '0') * col; + col *= 10; + } + return num; +} + +/* Move to next line */ +static char * +next_line(char *line) +{ + while (*line++ != '\n'); + return line; +} + +/* Convert line to Grouop */ +static Group * +line_to_group(char *line) +{ + if (!*line) + return NULL; + + char gidstr[8]; + get_part(line, GROUP_NAME, entryName); + get_part(line, GROUP_GID, gidstr); + get_part(line, GROUP_USERS, entryUsers); + + int i, j = 0; + char *prev = entryUsers; + for (i = 0; entryUsers[i]; i++) { + if (entryUsers[i] != ' ') + continue; + entryUsers[i] = '\0'; + entryMembers[j] = prev; + prev = entryUsers + 1; + j++; + } + + entry.name = entryName; + entry.gid = number(gidstr); + entry.members = entryMembers; + + return &entry; +} + +/* Get group file entry by name */ +Group * +getgrname(const char *name) +{ + int fd = open("/etc/group", O_RDONLY); + if (fd < 0) + return (Group *) fd; + size_t sz = lseek(fd, 0, SEEK_END); + lseek(fd, 0, SEEK_SET); + char *buf = malloc(sz); + read(fd, buf, sz); + close(fd); + + char *line, tmp[33]; + for (line = buf; *line; line = next_line(line)) { + get_part(line, GROUP_NAME, tmp); + if (!strcmp(name, tmp)) + break; + } + + Group *res = line_to_group(line); + + free(buf); + return res; +} + +/* Get group file entry by ID */ +Group * +getgrgid(gid_t gid) +{ + int fd = open("/etc/group", O_RDONLY); + if (fd < 0) + return (Group *) fd; + size_t sz = lseek(fd, 0, SEEK_END); + lseek(fd, 0, SEEK_SET); + char *buf = malloc(sz); + read(fd, buf, sz); + close(fd); + + char *line, tmp[8]; + gid_t gidLine; + for (line = buf; *line; line = next_line(line)) { + get_part(line, GROUP_GID, tmp); + gidLine = number(tmp); + if (gid == gidLine) + break; + } + + Group *res = line_to_group(line); + + free(buf); + return res; +} diff --git a/include/arpa/inet.h b/include/arpa/inet.h new file mode 100644 index 0000000..4de8dc6 --- /dev/null +++ b/include/arpa/inet.h @@ -0,0 +1,15 @@ +#ifndef _ARPA_INET_H +#define _ARPA_INET_H + +typedef struct InAddr { + uint32_t addr; +} InAddr; + +typedef struct SockAddrIn { + int16_t family; + uint16_t port; + InAddr inAddr; + char zero[8]; +} SockAddrIn; + +#endif diff --git a/include/ctype.h b/include/ctype.h new file mode 100644 index 0000000..262a90d --- /dev/null +++ b/include/ctype.h @@ -0,0 +1,6 @@ +#ifndef _CTYPE_H +#define _CTYPE_H + + + +#endif diff --git a/include/dirent.h b/include/dirent.h new file mode 100644 index 0000000..abdad04 --- /dev/null +++ b/include/dirent.h @@ -0,0 +1,36 @@ +#ifndef _DIRENT_H +#define _DIRENT_H + +#include <stddef.h> +#include <sys/types.h> + +enum DirType { + DT_UNKNOWN, + DT_REG, + DT_DIR, + DT_CHR, + DT_BLK, + DT_FIFO, + DT_SOCK, + DT_LNK, +}; + +/* Structure for a Directory Entry */ +typedef struct dirent { + ino_t ino; + enum DirType type; + size_t namelen; + char name[]; +} DirEnt; + +#ifdef __cplusplus +extern "C" { +#endif + +size_t getdents(int fd, void *buf, size_t count); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/errno.h b/include/errno.h new file mode 100644 index 0000000..b47e18c --- /dev/null +++ b/include/errno.h @@ -0,0 +1,28 @@ +#ifndef _ERRNO_H +#define _ERRNO_H + +enum { + ENONE, + EPERM, + ENOENT, + ESRCH, + EINVAL, + EBADF, + ENOEXEC, + EMFILE, + EFAULT, + EISDIR, + ENOTDIR, + EACCES, + ENODEV, + EEXIST, + ENXIO, + ENOTBLK, + ENOMEM, + ECHILD, + ENOTTY, +}; + +extern int errno; + +#endif diff --git a/include/fcntl.h b/include/fcntl.h new file mode 100644 index 0000000..5274e33 --- /dev/null +++ b/include/fcntl.h @@ -0,0 +1,25 @@ +#ifndef _FCNTL_H +#define _FCNTL_H + +#include <sys/types.h> + +#define O_ACCMODE 0003 +#define O_RDONLY 00 +#define O_WRONLY 01 +#define O_RDWR 02 + +#define O_CREATE 0100 +#define O_TRUNC 0200 + +#ifdef __cplusplus +extern "C" { +#endif + +int open(const char *name, int flags, ...); /* mode_t mode */ +int create(const char *name, mode_t mode); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/grp.h b/include/grp.h new file mode 100644 index 0000000..a6e07d6 --- /dev/null +++ b/include/grp.h @@ -0,0 +1,14 @@ +#ifndef _GRP_H +#define _GRP_H + +/* Structure of a group entry */ +typedef struct group { + char *name; + gid_t gid; + char **members; +} Group; + +Group *getgrname(const char *name); +Group *getgrgid(gid_t gid); + +#endif diff --git a/include/inttypes.h b/include/inttypes.h new file mode 100644 index 0000000..855bf37 --- /dev/null +++ b/include/inttypes.h @@ -0,0 +1,13 @@ +#ifndef _INTTYPES_H +#define _INTTYPES_H + +#include <stdint.h> +#include <stddef.h> + +/* Structure for the imaxdiv() function */ +typedef struct { + __extension__ long long int quot; + __extension__ long long int rem; +} imaxdiv_t; + +#endif diff --git a/include/limits.h b/include/limits.h new file mode 100644 index 0000000..d165525 --- /dev/null +++ b/include/limits.h @@ -0,0 +1,6 @@ +#ifndef _LIMITS_H +#define _LIMITS_H + +#include <sys/limits.h> + +#endif diff --git a/include/pwd.h b/include/pwd.h new file mode 100644 index 0000000..df872d4 --- /dev/null +++ b/include/pwd.h @@ -0,0 +1,20 @@ +#ifndef _PWD_H +#define _PWD_H + +#include <sys/types.h> + +/* Structure of a password entry */ +typedef struct passwd { + char *username; + char *password; + uid_t uid; + gid_t gid; + char *info; + char *homedir; + char *shell; +} Passwd; + +Passwd *getpwname(const char *username); +Passwd *getpwuid(uid_t uid); + +#endif diff --git a/include/setjmp.h b/include/setjmp.h new file mode 100644 index 0000000..ded0ecd --- /dev/null +++ b/include/setjmp.h @@ -0,0 +1,19 @@ +#ifndef _SETJMP_H +#define _SETJMP_H + +#include <signal.h> + +#define setjmp __builtin_setjmp +#define longjmp __builtin_longjmp + +typedef int __jmp_buf[6]; + +struct __jmp_buf_tag { + __jmp_buf __jmpbuf; + int __saved; + __sigset_t __mask; +}; + +typedef struct __jmp_buf_tag jmp_buf[1]; + +#endif diff --git a/include/signal.h b/include/signal.h new file mode 100644 index 0000000..3999125 --- /dev/null +++ b/include/signal.h @@ -0,0 +1,39 @@ +#ifndef _SIGNAL_H +#define _SIGNAL_H + +#include <sys/types.h> + +typedef unsigned long int __sigset_t; +#ifndef sigset_t +typedef __sigset_t sigset_t; +#endif +#ifndef sig_atomic_t +typedef int sig_atomic_t; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +enum Signals { + SIGHUP = 1, + SIGINT, + SIGQUIT, + SIGILL, + SIGABRT, + SIGFPE, + SIGKILL, + SIGSEGV, + SIGPIPE, + +}; + +void (*signal(int sig, void (*func)(int)))(int); +int tgkill(pid_t tgid, pid_t tid, int sig); +int kill(pid_t pid, int sig); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/stdio.h b/include/stdio.h new file mode 100644 index 0000000..b38bba5 --- /dev/null +++ b/include/stdio.h @@ -0,0 +1,66 @@ +#ifndef _STDIO_H +#define _STDIO_H + +#include <stdarg.h> +#include <stddef.h> + +#define EOF ((int) -1) + +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 + +typedef struct { + size_t count; + char *buf, *ptr; + int flags; + int fd; +} FILE; + +enum FILEFlags { + FILE_READ = 1, + FILE_WRITE = 2, + FILE_UNBUF = 4, + FILE_EOF = 10, + FILE_ERR = 20, +}; + +#ifdef __cplusplus +extern "C" { +#endif + +extern FILE *stdin; +extern FILE *stdout; +extern FILE *stderr; +#define stdin stdin +#define stdout stdout +#define stderr stderr + +int fclose(FILE *); +int fflush(FILE *); +FILE *fopen(const char *, const char *); +int fprintf(FILE *, const char *, ...); +size_t fread(void *, size_t, size_t, FILE *); +int fseek(FILE *, long, int); +long ftell(FILE *); +size_t fwrite(const void *, size_t, size_t, FILE *); +void setbuf(FILE *stream, char *buf); +int vfprintf(FILE *stream, const char *fmt, va_list); +int sprintf(char *buf, const char *fmt, ...); +void dbgprintf(char *fmt, ...); +void dbgputs(char *str); +int printf(const char *fmt, ...); +void perror(const char *s); +int getc(FILE *stream); +int getchar(void); +int puts(const char *s); +int putc(int c, FILE *stream); +int putchar(int c); + +int rename(const char *oldpath, const char *newpath); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/stdlib.h b/include/stdlib.h new file mode 100644 index 0000000..b1265c2 --- /dev/null +++ b/include/stdlib.h @@ -0,0 +1,25 @@ +#ifndef _STDLIB_H +#define _STDLIB_H + +#define EXIT_SUCCESS 0 +#define EXIT_FAILURE 1 + +#ifdef __cplusplus +extern "C" { +#endif + +_Noreturn void abort(void); +int atexit(void (*)(void)); +int atoi(const char *); +void free(void *); +char *getenv(const char *); +void *malloc(size_t); +void *calloc(size_t, size_t); +_Noreturn void exit(int status); +int abs(int); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/string.h b/include/string.h new file mode 100644 index 0000000..470b759 --- /dev/null +++ b/include/string.h @@ -0,0 +1,26 @@ +#ifndef _STRING_H +#define _STRING_H + +#include <stddef.h> + +#ifdef __cplusplus +extern "C" { +#endif + +int memcmp(void *s1, void *s2, size_t n); +void *memcpy(void *dest, const void *src, size_t len); +void *memset(void *dest, int byte, size_t len); +int strcmp(const char *s1, const char *s2); +int strncmp(const char *s1, const char *s2, size_t n); +char *strcpy(char *dest, const char *src); +char *strncpy(char *dest, const char *src, size_t n); +size_t strlen(const char *str); +size_t strnlen(const char *str, size_t maxlen); +char *strcat(char *dest, const char *src); +char *strchr(char *s, int c); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/sys/fb.h b/include/sys/fb.h new file mode 100644 index 0000000..b56497e --- /dev/null +++ b/include/sys/fb.h @@ -0,0 +1,26 @@ +#ifndef _SYS_FB_H +#define _SYS_FB_H + +#include <stdint.h> +#include <stddef.h> + +/* ioctl() calls */ +enum FrameBufferIoctls { + FBIOGET_VSCREENINFO, + FBIOPUT_VSCREENINFO, + FBIOGET_FSCREENINFO, +}; + +/* Structure for fixed framebuffer info */ +typedef struct FBFixInfo { + uintptr_t fbmem; + size_t fbmemLen; +} FBFixInfo; + +/* Structure for variable framebuffer info */ +typedef struct FBVarInfo { + uint32_t xres, yres; + uint32_t bpp; +} FBVarInfo; + +#endif diff --git a/include/sys/ioctl.h b/include/sys/ioctl.h new file mode 100644 index 0000000..9c95275 --- /dev/null +++ b/include/sys/ioctl.h @@ -0,0 +1,6 @@ +#ifndef _SYS_IOCTL_H +#define _SYS_IOCTL_H + +int ioctl(int fd, unsigned long request, ...); + +#endif diff --git a/include/sys/ipc.h b/include/sys/ipc.h new file mode 100644 index 0000000..e81e077 --- /dev/null +++ b/include/sys/ipc.h @@ -0,0 +1,38 @@ +#ifndef _SYS_IPC_H +#define _SYS_IPC_H + +#include <stdint.h> +#include <sys/types.h> + +/* Processes */ +enum Process { + NO_PROCESS, + SYSTEM, + + ANY = 0xFFFFFFFF +}; + +/* Message encodings */ +typedef union MessageContent MessageContent; +union MessageContent { + /* Generics */ + char raw[16]; + void *ptr; + uint32_t num; +} __attribute__((__transparent_union__)); + +/* Structure for a message */ +typedef struct Message Message; +struct Message { + pid_t from; + uint16_t type; + MessageContent msg; + Message *next; +} __attribute__((packed)); + +Message *nb_send_msg(pid_t to, uint16_t type, MessageContent *msg); +Message *send_msg(pid_t to, uint16_t type, MessageContent *msg); +pid_t nb_recv_msg(Message *buf, pid_t from); +pid_t recv_msg(Message *buf, pid_t from); + +#endif diff --git a/include/sys/limits.h b/include/sys/limits.h new file mode 100644 index 0000000..835e765 --- /dev/null +++ b/include/sys/limits.h @@ -0,0 +1,9 @@ +#ifndef _SYS_LIMITS_H +#define _SYS_LIMITS_H + +#define NAME_MAX 255 +#define PATH_MAX 1024 + +#define HOST_NAME_MAX 64 + +#endif diff --git a/include/sys/mman.h b/include/sys/mman.h new file mode 100644 index 0000000..0e9518e --- /dev/null +++ b/include/sys/mman.h @@ -0,0 +1,35 @@ +#ifndef _SYS_MMAN_H +#define _SYS_MMAN_H + +#include <stddef.h> +#include <sys/types.h> + +/* Virtual Memory Region Protection */ +enum VMRegionProt { + PROT_NONE, + PROT_EXEC = (1 << 0), + PROT_WRITE = (1 << 1), + PROT_READ = (1 << 2), +}; + +/* Virtual Memory Region flags */ +enum VMRegionFlag { + MAP_SHARED, + MAP_PRIVATE = (1 << 0), + MAP_ANONYMOUS = (1 << 1), +}; + +#define MAP_ANON MAP_ANONYMOUS +#define MAP_FAILED ((void *) -1) + +#ifdef __cplusplus +extern "C" { +#endif + +void *mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/sys/mount.h b/include/sys/mount.h new file mode 100644 index 0000000..c5508ae --- /dev/null +++ b/include/sys/mount.h @@ -0,0 +1,20 @@ +#ifndef _SYS_MOUNT_H +#define _SYS_MOUNT_H + +#define MS_REMOUNT (1 << 0) +#define MS_BIND (1 << 1) +#define MS_MOVE (1 << 2) +#define MS_RDONLY (1 << 3) + +#ifdef __cplusplus +extern "C" { +#endif + +int mount(const char *src, const char *target, const char *type, + unsigned long flags, void *data); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/sys/param.h b/include/sys/param.h new file mode 100644 index 0000000..11ca58a --- /dev/null +++ b/include/sys/param.h @@ -0,0 +1,32 @@ +#ifndef _SYS_PARAM_H +#define _SYS_PARAM_H + +#include <stddef.h> +#include <sys/types.h> + +#define NBBY 8 + +/* Bit map related macros. */ +#define setbit(a,i) ((a)[(i)/NBBY] |= 1<<((i)%NBBY)) +#define clrbit(a,i) ((a)[(i)/NBBY] &= ~(1<<((i)%NBBY))) +#define isset(a,i) ((a)[(i)/NBBY] & (1<<((i)%NBBY))) +#define isclr(a,i) (((a)[(i)/NBBY] & (1<<((i)%NBBY))) == 0) + +/* Macros for counting and rounding. */ +#ifndef howmany +# define howmany(x, y) (((x) + ((y) - 1)) / (y)) +#endif +#ifdef __GNUC__ +# define roundup(x, y) (__builtin_constant_p (y) && powerof2 (y) \ + ? (((x) + (y) - 1) & ~((y) - 1)) \ + : ((((x) + ((y) - 1)) / (y)) * (y))) +#else +# define roundup(x, y) ((((x) + ((y) - 1)) / (y)) * (y)) +#endif +#define powerof2(x) ((((x) - 1) & (x)) == 0) + +/* Macros for min/max. */ +#define MIN(a,b) (((a)<(b))?(a):(b)) +#define MAX(a,b) (((a)>(b))?(a):(b)) + +#endif diff --git a/include/sys/sched.h b/include/sys/sched.h new file mode 100644 index 0000000..fe17753 --- /dev/null +++ b/include/sys/sched.h @@ -0,0 +1,19 @@ +#ifndef _SYS_SCHED_H +#define _SYS_SCHED_H + +#include <sys/types.h> + +/* Flags for clone syscall */ +enum CloneFlag { + CLONE_NONE = (1 << 0), + CLONE_PARENT = (1 << 1), + CLONE_THREAD = (1 << 2), + CLONE_FILES = (1 << 3), + CLONE_FS = (1 << 4), + CLONE_VM = (1 << 5), + CLONE_IPC = (1 << 6), // TODO: Add IPC namespace +}; + +pid_t clone(int flags); + +#endif diff --git a/include/sys/stat.h b/include/sys/stat.h new file mode 100644 index 0000000..b83cf2d --- /dev/null +++ b/include/sys/stat.h @@ -0,0 +1,67 @@ +#ifndef _SYS_STAT_H +#define _SYS_STAT_H + +#include <stddef.h> +#include <sys/types.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_ISREG(m) ((m & S_IFMT) == S_IFREG) +#define S_ISDIR(m) ((m & S_IFMT) == S_IFDIR) +#define S_ISCHR(m) ((m & S_IFMT) == S_IFCHR) +#define S_ISBLK(m) ((m & S_IFMT) == S_IFBLK) +#define S_ISFIFO(m) ((m & S_IFMT) == S_IFIFO) +#define S_ISLNK(m) ((m & S_IFMT) == S_IFLNK) +#define S_ISSOCK(m) ((m & S_IFMT) == S_IFSOCK) + +#define S_ISUID 04000 +#define S_ISGID 02000 +#define S_ISVTX 01000 + +#define S_IRWXU 00700 +#define S_IRUSR 00400 +#define S_IWUSR 00200 +#define S_IXUSR 00100 + +#define S_IRWXG 00070 +#define S_IRGRP 00040 +#define S_IWGRP 00020 +#define S_IXGRP 00010 + +#define S_IRWXO 00007 +#define S_IROTH 00004 +#define S_IWOTH 00002 +#define S_IXOTH 00001 + +/* Structure for a stat() call */ +typedef struct stat { + ino_t inode; + mode_t mode; + nlink_t nlink; + uid_t uid; + gid_t gid; + size_t size; +} Stat; + +#ifdef __cplusplus +extern "C" { +#endif + +int mkdir(const char *pathname, mode_t mode); +int mknod(const char *pathname, mode_t mode, dev_t dev); +int stat(const char *pathname, struct stat *statbuf); +int fstat(int fd, struct stat *statbuf); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/sys/syscall.h b/include/sys/syscall.h new file mode 100644 index 0000000..d732c59 --- /dev/null +++ b/include/sys/syscall.h @@ -0,0 +1,60 @@ +#ifndef _SYS_SYSCALL_H +#define _SYS_SYSCALL_H + +enum SystemCall { + /* Tasking */ + SYSCALL_DBGPRINTF, + SYSCALL_CLONE, + SYSCALL_EXIT, + SYSCALL_GETPID, + SYSCALL_GETUID, + SYSCALL_SETUID, + SYSCALL_GETEUID, + SYSCALL_SETEUID, + SYSCALL_GETGID, + SYSCALL_SETGID, + SYSCALL_GETEGID, + SYSCALL_SETEGID, + SYSCALL_EXECVE, + SYSCALL_WAITPID, + SYSCALL_TGKILL, + SYSCALL_KILL, + SYSCALL_TIME, + SYSCALL_TIMES, + SYSCALL_SLEEP, + + /* Files */ + SYSCALL_OPEN, + SYSCALL_CLOSE, + SYSCALL_READ, + SYSCALL_WRITE, + SYSCALL_IOCTL, + SYSCALL_LSEEK, + SYSCALL_STAT, + SYSCALL_FSTAT, + SYSCALL_GETDENTS, + SYSCALL_MKDIR, + SYSCALL_RMDIR, + SYSCALL_MKNOD, + SYSCALL_RENAME, + SYSCALL_DUP, + SYSCALL_DUP2, + SYSCALL_ISATTY, + + /* File System */ + SYSCALL_MOUNT, + SYSCALL_CHDIR, + SYSCALL_CHROOT, + SYSCALL_GETCWD, + + /* Memory */ + SYSCALL_MMAP, + + /* Messaging */ + SYSCALL_NB_SEND_MSG, + SYSCALL_SEND_MSG, + SYSCALL_NB_RECV_MSG, + SYSCALL_RECV_MSG, +}; + +#endif diff --git a/include/sys/times.h b/include/sys/times.h new file mode 100644 index 0000000..70d57f0 --- /dev/null +++ b/include/sys/times.h @@ -0,0 +1,18 @@ +#ifndef _SYS_TIMES_H +#define _SYS_TIMES_H + +#include <time.h> + +typedef uint64_t clock_t; + +/* Structure for a times call */ +typedef struct tms { + clock_t utime; + clock_t stime; + clock_t cutime; + clock_t cstime; +} Times; + +clock_t times(Times *buf); + +#endif diff --git a/include/sys/types.h b/include/sys/types.h new file mode 100644 index 0000000..f8d727a --- /dev/null +++ b/include/sys/types.h @@ -0,0 +1,14 @@ +#ifndef _SYS_TYPES_H +#define _SYS_TYPES_H + +typedef int pid_t; +typedef unsigned short uid_t; +typedef unsigned short gid_t; +typedef unsigned int dev_t; +typedef int ino_t; +typedef int off_t; +typedef int mode_t; +typedef int nlink_t; +typedef int refcount_t; + +#endif diff --git a/include/sys/wait.h b/include/sys/wait.h new file mode 100644 index 0000000..47ff26c --- /dev/null +++ b/include/sys/wait.h @@ -0,0 +1,22 @@ +#ifndef _SYS_INCLUDE_H +#define _SYS_INCLUDE_H + +#include <sys/types.h> + +#define WIFEXITED(status) (status & (1 << 31)) +#define WEXITSTATUS(status) (status & 0x0F) +#define WIFSIGNALED(status) (!(status & (1 << 31))) +#define WTERMSIG(status) (status & 0xFF) + +#ifdef __cplusplus +extern "C" { +#endif + +pid_t wait(int *wstatus); +pid_t waitpid(pid_t pid, int *wstatus, int options); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/termios.h b/include/termios.h new file mode 100644 index 0000000..259695b --- /dev/null +++ b/include/termios.h @@ -0,0 +1,33 @@ +#ifndef _TERMIOS_H +#define _TERMIOS_H + +/* ioctl() calls */ +enum TTYIoctls { + TCGETS, + TCSETS, + TCGWINSZ, +}; + +enum TTYLineDiscipline { + ISIG = (1 << 0), + ICANON = (1 << 1), + ECHO = (1 << 2), +}; + +typedef unsigned int tcflag_t; + +/* Terminal I/O Settings */ +typedef struct Termios { + tcflag_t iflag; + tcflag_t oflag; + tcflag_t cflag; + tcflag_t lflag; +} Termios; + +/* Terminal Window Size */ +typedef struct Winsize { + unsigned short rows, cols; + unsigned short xres, yres; +} Winsize; + +#endif diff --git a/include/time.h b/include/time.h new file mode 100644 index 0000000..24dee55 --- /dev/null +++ b/include/time.h @@ -0,0 +1,11 @@ +#ifndef _TIME_H +#define _TIME_H + +#include <stdint.h> + +typedef uint32_t time_t; + +int sleep(uint32_t ms); +time_t time(time_t *tloc); + +#endif diff --git a/include/unistd.h b/include/unistd.h new file mode 100644 index 0000000..c250e84 --- /dev/null +++ b/include/unistd.h @@ -0,0 +1,46 @@ +#ifndef _UNISTD_H +#define _UNISTD_H + +#include <sys/types.h> +#include <stddef.h> + +typedef int intptr_t; + +#define STDIN_FILENO 0 +#define STDOUT_FILENO 1 +#define STDERR_FILENO 2 + +#ifdef __cplusplus +extern "C" { +#endif + +int execv(const char *, char *[]); +int execve(const char *, char *[], char *[]); +int execvp(const char *, char *[]); +pid_t fork(void); +pid_t getpid(void); +uid_t getuid(void); +int setuid(uid_t uid); +uid_t geteuid(void); +int seteuid(uid_t euid); +gid_t getgid(void); +int setgid(gid_t gid); +gid_t getegid(void); +int setegid(gid_t egid); +int isatty(int fd); +int close(int fd); +int dup(int oldfd); +int dup2(int oldfd, int newfd); +size_t read(int fd, void *buf, size_t count); +size_t write(int fd, void *buf, size_t count); +off_t lseek(int fd, off_t offset, int whence); +int rmdir(const char *pathname); +int chroot(const char *path); +int chdir(const char *path); +char *getcwd(char *buf, size_t size); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/init.c b/init.c new file mode 100644 index 0000000..d0cbc60 --- /dev/null +++ b/init.c @@ -0,0 +1,5 @@ +void +init_std_lib(void) +{ + /* Do setup here */ +} diff --git a/pwd/getpw.c b/pwd/getpw.c new file mode 100644 index 0000000..116cf97 --- /dev/null +++ b/pwd/getpw.c @@ -0,0 +1,148 @@ +#include <sys/limits.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <pwd.h> + +#include <stdio.h> + +/* Parts of a /etc/passwd line */ +enum PasswordParts { + PASSWD_USERNAME, + PASSWD_PASSWORD, + PASSWD_UID, + PASSWD_GID, + PASSWD_INFO, + PASSWD_HOMEDIR, + PASSWD_SHELL, +}; + +static Passwd entry; +static char entryUsername[33]; +static char entryPassword[128]; +static char entryInfo[1024]; +static char entryHomeDir[PATH_MAX]; +static char entryShell[PATH_MAX]; + +/* Get part of a password line */ +static char * +get_part(char *line, int index, char *buf) +{ + int i, len = 0; + char *start; + for (i = 0; i < index; i++) + while (*line++ != ':'); + start = line; + while (*line != ':' && *line != '\n') { + line++; + len++; + } + memcpy(buf, start, len); + buf[len] = '\0'; + return buf; +} + +/* Convert a string to a number */ +static int +number(char *str) +{ + int num = 0, col = 1, len; + for (len = 0; str[len] >= '0' && str[len] <= '9'; len++); + while (len--) { + num += (str[len] - '0') * col; + col *= 10; + } + return num; +} + +/* Move to next line */ +static char * +next_line(char *line) +{ + while (*line++ != '\n'); + return line; +} + +/* Convert line to Passwd */ +static Passwd * +line_to_passwd(char *line) +{ + if (!*line) + return NULL; + + char uidstr[8], gidstr[8]; + get_part(line, PASSWD_USERNAME, entryUsername); + get_part(line, PASSWD_PASSWORD, entryPassword); + get_part(line, PASSWD_UID, uidstr); + get_part(line, PASSWD_GID, gidstr); + get_part(line, PASSWD_INFO, entryInfo); + get_part(line, PASSWD_HOMEDIR, entryHomeDir); + get_part(line, PASSWD_SHELL, entryShell); + + entry.username = entryUsername; + entry.password = entryPassword; + entry.uid = number(uidstr); + entry.gid = number(gidstr); + entry.info = entryInfo; + entry.homedir = entryHomeDir; + entry.shell = entryShell; + + return &entry; +} + +/* Get password file entry by name */ +Passwd * +getpwname(const char *username) +{ + + int fd = open("/etc/passwd", O_RDONLY); + if (fd < 0) + return (Passwd *) fd; + size_t sz = lseek(fd, 0, SEEK_END); + lseek(fd, 0, SEEK_SET); + char *buf = malloc(sz); + read(fd, buf, sz); + close(fd); + + char *line, tmp[33]; + for (line = buf; *line; line = next_line(line)) { + get_part(line, PASSWD_USERNAME, tmp); + if (!strcmp(username, tmp)) + break; + } + + Passwd *res = line_to_passwd(line); + + free(buf); + return res; +} + +/* Get password file entry by ID */ +Passwd * +getpwuid(uid_t uid) +{ + int fd = open("/etc/passwd", O_RDONLY); + if (fd < 0) + return (Passwd *) fd; + size_t sz = lseek(fd, 0, SEEK_END); + lseek(fd, 0, SEEK_SET); + char *buf = malloc(sz); + read(fd, buf, sz); + close(fd); + + char *line, tmp[8]; + uid_t uidLine; + for (line = buf; *line; line = next_line(line)) { + get_part(line, PASSWD_UID, tmp); + uidLine = number(tmp); + if (uid == uidLine) + break; + } + + Passwd *res = line_to_passwd(line); + + free(buf); + return res; +} diff --git a/signal/kill.c b/signal/kill.c new file mode 100644 index 0000000..34dc776 --- /dev/null +++ b/signal/kill.c @@ -0,0 +1,16 @@ +#include <sys/syscall.h> +#include <sys/types.h> +#include <errno.h> + +/* Send a signal to a process */ +int +kill(pid_t pid, int sig) +{ + int ret; + asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_KILL), + "c" (2), "S" (&pid)); + if (ret >= 0) + return ret; + errno = -ret; + return -1; +} diff --git a/signal/tgkill.c b/signal/tgkill.c new file mode 100644 index 0000000..760795b --- /dev/null +++ b/signal/tgkill.c @@ -0,0 +1,16 @@ +#include <sys/syscall.h> +#include <sys/types.h> +#include <errno.h> + +/* Send a signal to a thread */ +int +tgkill(pid_t tgid, pid_t tid, int sig) +{ + int ret; + asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_TGKILL), + "c" (3), "S" (&tgid)); + if (ret >= 0) + return ret; + errno = -ret; + return -1; +} diff --git a/stdio/dbgprintf.c b/stdio/dbgprintf.c new file mode 100644 index 0000000..c1f5729 --- /dev/null +++ b/stdio/dbgprintf.c @@ -0,0 +1,30 @@ +#include <stdarg.h> +#include <sys/syscall.h> + +int vsprintf(char *buf, const char *fmt, va_list args); + +/* Send message to Kernel Output */ +void +dbgprintf(char *fmt, ...) +{ + char buf[1024]; + va_list args; + va_start(args, fmt); + vsprintf(buf, fmt, args); + va_end(args); + + int ret; + char *p = buf; + asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_DBGPRINTF), + "c" (1), "S" (&p)); +} + +/* Send an unformatted message to Kernel Output */ +void +dbgputs(char *str) +{ + int ret; + asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_DBGPRINTF), + "c" (1), "S" (&str)); + +} diff --git a/stdio/fopen.c b/stdio/fopen.c new file mode 100644 index 0000000..69aecca --- /dev/null +++ b/stdio/fopen.c @@ -0,0 +1,39 @@ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> + +/* Open a file */ +FILE * +fopen(const char *name, const char *mode) +{ + int fd; + FILE *fp; + + if (*mode != 'r' && *mode != 'w' && *mode != 'a') + return NULL; + + fp = malloc(sizeof(FILE)); + if (!fp) + return NULL; + + if (*mode == 'w') + fd = create(name, 0666); + else if (*mode == 'a') + fd = open(name, O_CREATE | O_WRONLY, 0); + else + fd = open(name, O_RDONLY, 0); + if (fd < 0) { + free(fp); + return NULL; + } + if (*mode == 'a') + lseek(fd, 0, SEEK_END); + + fp->fd = fd; + fp->count = 0; + fp->buf = NULL; + fp->flags = (*mode == 'r') ? FILE_READ : FILE_WRITE; + + return fp; +} diff --git a/stdio/getc.c b/stdio/getc.c new file mode 100644 index 0000000..e1a8a8f --- /dev/null +++ b/stdio/getc.c @@ -0,0 +1,48 @@ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +/* Allocate and fill a file's buffer */ +static int +_fillbuf(FILE *fp) +{ + int bufsize; + + if ((fp->flags & (FILE_READ | FILE_EOF | FILE_ERR)) != FILE_READ) + return EOF; + bufsize = (fp->flags & FILE_UNBUF) ? 1 : 1024; + + /* Create buffer */ + if (fp->buf == NULL) { + fp->buf = malloc(bufsize); + if (!fp->buf) + return EOF; + } + fp->ptr = fp->buf; + fp->count = read(fp->fd, fp->ptr, bufsize); + if (--fp->count < 0) { + if (fp->count == -1) + fp->flags |= FILE_EOF; + else + fp->flags |= FILE_ERR; + fp->count = 0; + return EOF; + } + return (unsigned char) *fp->ptr++; +} + +/* Get a character from a stream */ +inline int +getc(FILE *stream) +{ + if (--stream->count >= 0) + return (unsigned char) *stream->ptr++; + return _fillbuf(stream); +} + +/* Get a character from standard input */ +int +getchar(void) +{ + getc(stdin); +} diff --git a/stdio/perror.c b/stdio/perror.c new file mode 100644 index 0000000..c852582 --- /dev/null +++ b/stdio/perror.c @@ -0,0 +1,39 @@ +#include <stdio.h> +#include <errno.h> + +int errno; +const char *errorList[] = { + [ENONE] = "No error", + [EPERM] = "Operation not permitted", + [ENOENT] = "No such file or directory", + [ESRCH] = "No such process", + [EINVAL] = "Invalid argument", + [EBADF] = "Bad file descriptor", + [ENOEXEC] = "Exec format error", + [EMFILE] = "Too many open files", + [EFAULT] = "Bad address", + [EISDIR] = "Is a directory", + [ENOTDIR] = "Not a directory", + [EACCES] = "Permission denied", + [ENODEV] = "No such device", + [EEXIST] = "File exists", + [ENXIO] = "No such device or address", + [ENOTBLK] = "Block device required", + [ENOMEM] = "Cannot allocate memory", + [ECHILD] = "No child processes", + [ENOTTY] = "Inappropriate ioctl for device", +}; + +/* Display an error message for errno */ +void +perror(const char *s) +{ + if (errno < 0 || errno >= (sizeof(errorList)/sizeof(errorList[0]))) + return; + if (!s) + printf("%s\n", errorList[errno]); + else if (!s[0]) + printf("%s\n", errorList[errno]); + else + printf("%s: %s\n", s, errorList[errno]); +} diff --git a/stdio/printf.c b/stdio/printf.c new file mode 100644 index 0000000..de0d9a4 --- /dev/null +++ b/stdio/printf.c @@ -0,0 +1,21 @@ +#include <unistd.h> +#include <stdarg.h> +#include <sys/syscall.h> +#include <stdio.h> + +int vsprintf(char *buf, const char *fmt, va_list args); + +/* Write a formatted string to stdout */ +int +printf(const char *fmt, ...) +{ + int len; + char buf[8196]; + va_list args; + va_start(args, fmt); + len = vsprintf(buf, fmt, args); + va_end(args); + + len = write(STDOUT_FILENO, buf, len); + return len; +} diff --git a/stdio/puts.c b/stdio/puts.c new file mode 100644 index 0000000..45113ef --- /dev/null +++ b/stdio/puts.c @@ -0,0 +1,21 @@ +#include <unistd.h> +#include <string.h> + +/* Write a string to stdout */ +int +puts(const char *str) +{ + char end[] = "\n"; + int len = strlen(str); + len = write(STDOUT_FILENO, (void *) str, len); + return len + write(STDOUT_FILENO, end, 1); +} + +/* Write a character to stdout */ +int +putchar(int c) +{ + char str[] = {(char) c, 0}; + write(STDOUT_FILENO, str, 1); + return c; +} diff --git a/stdio/vsprintf.c b/stdio/vsprintf.c new file mode 100644 index 0000000..88e2f9f --- /dev/null +++ b/stdio/vsprintf.c @@ -0,0 +1,244 @@ +#include <stdarg.h> +#include <string.h> + +#define is_digit(c) ((c) >= '0' && (c) <= '9') + +/* Do not convert */ +static int +skip_atoi(const char **s) +{ + int i = 0; + + while (is_digit(**s)) + i = i*10 + *((*s)++) - '0'; + + return i; +} + +#define ZEROPAD 1 /* pad with zero */ +#define SIGN 2 /* unsigned/signed long */ +#define PLUS 4 /* show plus */ +#define SPACE 8 /* space if plus */ +#define LEFT 16 /* left justified */ +#define SPECIAL 32 /* 0x */ +#define SMALL 64 /* use 'abcdef' instead of 'ABCDEF' */ + +#define do_div(n,base) ({ \ +int __res; \ +__asm__("divl %4":"=a" (n),"=d" (__res):"0" (n),"1" (0),"r" (base)); \ +__res; }) + +/* Convert a number to ASCII */ +static char * +number(char *str, int num, int base, int size, int precision, int type) +{ + char c, sign, tmp[36]; + const char *digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + int i; + + if (type & SMALL) + digits = "0123456789abcdefghijklmnopqrstuvwxyz"; + if (type & LEFT) + type &= ~ZEROPAD; + if (base < 2 || base > 36) + return 0; + c = (type & ZEROPAD) ? '0' : ' ' ; + if (type & SIGN && num < 0) { + sign = '-'; + num = -num; + } else { + sign = (type & PLUS) ? '+' : ((type & SPACE) ? ' ' : 0); + } + if (sign) + size--; + if (type & SPECIAL) + if (base == 16) + size -= 2; + else if (base == 8) + size--; + i = 0; + if (num == 0) + tmp[i++] = '0'; + else while (num != 0) + tmp[i++] = digits[do_div(num,base)]; + if (i > precision) + precision = i; + size -= precision; + if (!(type & (ZEROPAD + LEFT))) + while (size-- > 0) + *str++ = ' '; + if (sign) + *str++ = sign; + if (type & SPECIAL) + if (base == 8) { + *str++ = '0'; + } else if (base == 16) { + *str++ = '0'; + *str++ = digits[33]; + } + if (!(type & LEFT)) + while (size-- > 0) + *str++ = c; + while (i < precision--) + *str++ = '0'; + while (i-- > 0) + *str++ = tmp[i]; + while (size-- > 0) + *str++ = ' '; + return str; +} + +/* Print formatted to a buffer */ +int +vsprintf(char *buf, const char *fmt, va_list args) +{ + int len, i; + char *str, *s; + int *ip, flags; + int field_width, precision, qualifier; + + for (str = buf; *fmt; fmt++) { + if (*fmt != '%') { + *str++ = *fmt; + continue; + } + + /* Process flags */ + flags = 0; +repeat: + fmt++; + switch (*fmt) { + case '-': + flags |= LEFT; + goto repeat; + case '+': + flags |= PLUS; + goto repeat; + case ' ': + flags |= SPACE; + goto repeat; + case '#': + flags |= SPECIAL; + goto repeat; + case '0': + flags |= ZEROPAD; + goto repeat; + } + + /* Get field width */ + field_width = -1; + if (is_digit(*fmt)) { + field_width = skip_atoi(&fmt); + } else if (*fmt == '*') { + field_width = va_arg(args, int); + fmt++; + if (field_width < 0) { + field_width = -field_width; + flags |= LEFT; + } + } + + /* Get the precision */ + precision = -1; + if (*fmt == '.') { + fmt++; + if (is_digit(*fmt)) { + precision = skip_atoi(&fmt); + } else if (*fmt == '*') { + precision = va_arg(args, int); + fmt++; + } + if (precision < 0) + precision = 0; + } + + /* Get the conversion qualifier */ + qualifier = -1; + if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') { + qualifier = *fmt; + fmt++; + } + + switch (*fmt) { + case 'c': + if (!(flags & LEFT)) + while (--field_width > 0) + *str++ = ' '; + *str++ = (unsigned char) va_arg(args, int); + while (--field_width > 0) + *str++ = ' '; + break; + + case 's': + s = va_arg(args, char *); + len = strlen(s); + if (precision < 0) + precision = len; + else if (len > precision) + len = precision; + + if (!(flags & LEFT)) + while (len < field_width--) + *str++ = ' '; + for (i = 0; i < len; ++i) + *str++ = *s++; + while (len < field_width--) + *str++ = ' '; + break; + + case 'o': + str = number(str, va_arg(args, unsigned long), 8, + field_width, precision, flags); + break; + + case 'p': + if (field_width == -1) { + field_width = 8; + flags |= ZEROPAD; + } + str = number(str, + (unsigned long) va_arg(args, void *), 16, + field_width, precision, flags); + break; + + case 'x': + flags |= SMALL; + /* FALLTHROUGH */ + case 'X': + str = number(str, va_arg(args, unsigned long), 16, + field_width, precision, flags); + break; + + case 'd': /* FALLTHROUGH */ + case 'i': + flags |= SIGN; + /* FALLTHROUGH */ + case 'u': + str = number(str, va_arg(args, unsigned long), 10, + field_width, precision, flags); + break; + + case 'f': + str = number(str, + (unsigned long) va_arg(args, double), 10, + field_width, precision, flags); + break; + + case 'n': + ip = va_arg(args, int *); + *ip = (str - buf); + break; + + default: + if (*fmt != '%') + *str++ = '%'; + if (*fmt) + *str++ = *fmt; + else + --fmt; + break; + } + } + *str = '\0'; + return str-buf; +} diff --git a/stdlib/abort.c b/stdlib/abort.c new file mode 100644 index 0000000..a45a8fd --- /dev/null +++ b/stdlib/abort.c @@ -0,0 +1,9 @@ +#include <stdlib.h> + +/* Abnormally terminate the current process */ +_Noreturn void +abort(void) +{ + /* In future, this should raise the SIGABRT signal */ + exit(EXIT_FAILURE); +} diff --git a/stdlib/malloc.c b/stdlib/malloc.c new file mode 100644 index 0000000..cd19760 --- /dev/null +++ b/stdlib/malloc.c @@ -0,0 +1,157 @@ +#include <stdint.h> +#include <stdlib.h> +#include <stddef.h> +#include <stdio.h> +#include <string.h> +#include <sys/mman.h> +#include <errno.h> + +#define BLOCK_SIZE 16 + +typedef struct Header Header; +typedef struct Arena Arena; + +extern char _end[]; + +/* Structure for a Memory Header */ +struct Header { + Header *prev, *next; + size_t size; + char magic[4]; +}; + +/* Structure for a Memory Arena */ +struct Arena { + Arena *next; + void *start, *end; + size_t size; +}; + +Arena primaryArena = { + .next = NULL, + .start = NULL, + .end = NULL, + .size = 0 +}; + +/* Allocate a region of memory in an arena */ +static void * +arena_malloc(Arena *arena, size_t size) +{ + size_t blockSize, gapSize; + intptr_t blockEnd; + Header *prev, *head, *next; + head = prev = arena->start; + next = NULL; + + /* Minimum allocation */ + if (size % BLOCK_SIZE) + size += BLOCK_SIZE - (size % BLOCK_SIZE); + + /* Block does not exist, create heap */ + if (head->prev != head || memcmp(head->magic, "HEAP", 4)) { + head->prev = head; + head->next = NULL; + head->size = size; + memcpy(head->magic, "HEAP", 4); + memset((void *) (head + 1), 0, size); + return (void *) (head + 1); + } + + /* Find gap */ + while (head->next) { + next = head->next; + blockSize = sizeof(Header) + head->size; + blockEnd = (uintptr_t) head + blockSize; + gapSize = (size_t) next - blockEnd; + prev = head; + + /* Fit in gap */ + if (gapSize >= size + sizeof(Header)) { + head = (void *) blockEnd; + head->next = next; + head->prev = prev; + prev->next = head; + next->prev = head; + head->size = size; + memcpy(head->magic, "HEAP", 4); + memset((void *) (head + 1), 0, size); + return (void *) (head + 1); + } + + head = head->next; + } + + /* Add to end */ + blockSize = sizeof(Header) + head->size; + blockEnd = (uintptr_t) head + blockSize; + /* Ensure more arenas can be allocated */ + gapSize = (size_t) arena->end - blockEnd - sizeof(Arena); + /* Fit in gap */ + if (gapSize >= size + sizeof(Header)) { + prev = head; + head = (void *) blockEnd; + head->next = NULL; + head->prev = prev; + prev->next = head; + head->size = size; + memcpy(head->magic, "HEAP", 4); + memset((void *) (head + 1), 0, size); + return (void *) (head + 1); + } + + return NULL; +} + +/* Allocate a region of memory */ +void * +malloc(size_t size) +{ + void *addr = NULL; + Arena *arena; + size_t arenaSize = 64 * 1024; + while (arenaSize < size + sizeof(Arena)) + arenaSize += 64 * 1024; + + for (arena = &primaryArena; !addr; arena = arena->next) { + /* Allocate a new arena */ + if (!arena->size) { + arena->size = arenaSize; + arena->start = mmap(NULL, arena->size, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); + if (arena->start == MAP_FAILED) { + errno = ENOMEM; + return NULL; + } + arena->end = arena->start + arena->size; + } + + /* Attempt to use arena */ + addr = arena_malloc(arena, size); + if (!addr && !arena->next) + arena->next = arena_malloc(arena, sizeof(Arena)); + } + + return addr; +} + +/* Free an allocated region of memory */ +void +free(void *addr) +{ + Header *prev, *head, *next; + head = (Header *) addr - 1; + if (memcmp(head->magic, "HEAP", 4)) { + printf("free(): invalid pointer\n"); + abort(); + } + prev = head->prev; + next = head->next; + memset(head, 0, sizeof(Header)); + + if (prev != head) + prev->next = next; + if (next) + next->prev = prev; +} diff --git a/string/memcmp.c b/string/memcmp.c new file mode 100644 index 0000000..e4c18fc --- /dev/null +++ b/string/memcmp.c @@ -0,0 +1,13 @@ +#include <stddef.h> + +/* Copy one region of memory to another */ +int +memcmp(void *s1, void *s2, size_t n) +{ + unsigned char *a = (unsigned char *) s1, + *b = (unsigned char *) s2; + while (n-- > 0) + if (*a++ != *b++) + return a[-1] - b[-1]; + return 0; +} diff --git a/string/memcpy.c b/string/memcpy.c new file mode 100644 index 0000000..4988f38 --- /dev/null +++ b/string/memcpy.c @@ -0,0 +1,12 @@ +#include <stddef.h> + +/* Copy one region of memory to another */ +void * +memcpy(void *dest, void *src, size_t n) +{ + unsigned char *a = (unsigned char *) dest, + *b = (unsigned char *) src; + while (n-- > 0) + *a++ = *b++; + return dest; +} diff --git a/string/memset.c b/string/memset.c new file mode 100644 index 0000000..f9c0902 --- /dev/null +++ b/string/memset.c @@ -0,0 +1,13 @@ +#include <stddef.h> + +/* Fill a region of memory with specified byte */ +void * +memset(void *dest, int byte, size_t len) +{ + unsigned char *a = dest; + if (len > 0) { + while (len-- > 0) + *a++ = byte; + } + return dest; +} diff --git a/string/strcmp.c b/string/strcmp.c new file mode 100644 index 0000000..37b62a4 --- /dev/null +++ b/string/strcmp.c @@ -0,0 +1,18 @@ +#include <stddef.h> + +/* Compare two strings */ +int +strcmp(char *s1, char *s2) +{ + for (; *s1 == *s2 && *s1 && *s2; s1++, s2++); + return *(unsigned char *) s1 - *(unsigned char *) s2; +} + +/* Compare two limited strings */ +int +strncmp(char *s1, char *s2, size_t n) +{ + if (!n--) return 0; + for (; *s1 == *s2 && *s1 && *s2 && n; s1++, s2++, n--); + return *(unsigned char *) s1 - *(unsigned char *) s2; +} diff --git a/string/strcpy.c b/string/strcpy.c new file mode 100644 index 0000000..ce725a2 --- /dev/null +++ b/string/strcpy.c @@ -0,0 +1,23 @@ +#include <stddef.h> + +/* Copy a string */ +char * +strcpy(char *dest, const char *src) +{ + char *ret = dest; + while (*src) + *dest++ = *src++; + *dest = '\0'; + return ret; +} + +/* Copy a limited string */ +char * +strncpy(char *dest, const char *src, size_t n) +{ + char *ret = dest; + while (*src && n--) + *dest++ = *src++; + *dest = '\0'; + return ret; +} diff --git a/string/strlen.c b/string/strlen.c new file mode 100644 index 0000000..a8d506c --- /dev/null +++ b/string/strlen.c @@ -0,0 +1,12 @@ +#include <string.h> + +/* Find length of string */ +size_t +strlen(const char *str) +{ + if (!str) + return 0; + size_t i; + for (i = 0; str[i]; i++); + return i; +} diff --git a/sys/ioctl.c b/sys/ioctl.c new file mode 100644 index 0000000..db6d27d --- /dev/null +++ b/sys/ioctl.c @@ -0,0 +1,17 @@ +#include <sys/syscall.h> +#include <sys/ioctl.h> +#include <errno.h> + +/* Send an I/O Control request to a file descriptor */ +int +ioctl(int fd, unsigned long request, ...) +{ + int ret; + asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_IOCTL), + "c" (3), "S" (&fd)); + + if (ret >= 0) + return ret; + errno = -ret; + return -1; +} diff --git a/sys/ipc.c b/sys/ipc.c new file mode 100644 index 0000000..3a563fe --- /dev/null +++ b/sys/ipc.c @@ -0,0 +1,43 @@ +#include <stdint.h> +#include <sys/ipc.h> +#include <sys/syscall.h> + +/* Send a message without blocking */ +Message * +nb_send_msg(pid_t to, uint16_t type, MessageContent *msg) +{ + int ret; + asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_NB_SEND_MSG), + "c" (3), "S" (&to)); + return (Message *) ret; +} + +/* Send a message and block until delivery */ +Message * +send_msg(pid_t to, uint16_t type, MessageContent *msg) +{ + int ret; + asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_SEND_MSG), + "c" (3), "S" (&to)); + return (Message *) ret; +} + +/* Receive a message if available */ +pid_t +nb_recv_msg(Message *buf, pid_t from) +{ + int ret; + asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_NB_RECV_MSG), + "c" (2), "S" (&buf)); + return (pid_t) ret; +} + +/* Block until a message is received */ +pid_t +recv_msg(Message *buf, pid_t from) +{ + int ret; + asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_RECV_MSG), + "c" (2), "S" (&buf)); + return (pid_t) ret; +} diff --git a/sys/mkdir.c b/sys/mkdir.c new file mode 100644 index 0000000..0c6e7e4 --- /dev/null +++ b/sys/mkdir.c @@ -0,0 +1,16 @@ +#include <sys/stat.h> +#include <sys/syscall.h> +#include <errno.h> + +/* Make a directory */ +int +mkdir(const char *pathname, mode_t mode) +{ + int ret; + asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_MKDIR), + "c" (2), "S" (&pathname)); + if (ret >= 0) + return ret; + errno = -ret; + return -1; +} diff --git a/sys/mmap.c b/sys/mmap.c new file mode 100644 index 0000000..b80a2aa --- /dev/null +++ b/sys/mmap.c @@ -0,0 +1,16 @@ +#include <stdint.h> +#include <sys/mman.h> +#include <sys/syscall.h> +#include <errno.h> + +void * +mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off) +{ + int ret; + asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_MMAP), + "c" (6), "S" (&addr)); + if (ret >= 0) + return (void *) ret; + errno = -ret; + return MAP_FAILED; +} diff --git a/sys/mount.c b/sys/mount.c new file mode 100644 index 0000000..ec2f200 --- /dev/null +++ b/sys/mount.c @@ -0,0 +1,16 @@ +#include <sys/mount.h> +#include <sys/syscall.h> +#include <errno.h> + +int +mount(const char *src, const char *target, const char *type, + unsigned long flags, void *data) +{ + int ret; + asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_MOUNT), + "c" (6), "S" (&src)); + if (ret >= 0) + return ret; + errno = -ret; + return -1; +} diff --git a/sys/stat.c b/sys/stat.c new file mode 100644 index 0000000..3c42fd9 --- /dev/null +++ b/sys/stat.c @@ -0,0 +1,31 @@ +#include <sys/stat.h> +#include <sys/syscall.h> +#include <errno.h> + +/* Get file status */ +int +stat(const char *pathname, struct stat *statbuf) +{ + int ret; + asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_STAT), + "c" (2), "S" (&pathname)); + if (ret >= 0) + return ret; + errno = -ret; + return -1; + +} + +/* Get file status by file descriptor */ +int +fstat(int fd, struct stat *statbuf) +{ + int ret; + asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_FSTAT), + "c" (2), "S" (&fd)); + if (ret >= 0) + return ret; + errno = -ret; + return -1; + +} diff --git a/sys/wait.c b/sys/wait.c new file mode 100644 index 0000000..912712a --- /dev/null +++ b/sys/wait.c @@ -0,0 +1,23 @@ +#include <sys/syscall.h> +#include <sys/wait.h> +#include <errno.h> + +/* Wait for a process to change state */ +pid_t +wait(int *wstatus) +{ + return waitpid(-1, wstatus, 0); +} + +/* Wait for a specific process to change state */ +pid_t +waitpid(pid_t pid, int *wstatus, int options) +{ + int ret; + asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_WAITPID), + "c" (3), "S" (&pid)); + if (ret >= 0) + return ret; + errno = -ret; + return -1; +} diff --git a/time/sleep.c b/time/sleep.c new file mode 100644 index 0000000..dd01751 --- /dev/null +++ b/time/sleep.c @@ -0,0 +1,16 @@ +#include <sys/syscall.h> +#include <time.h> +#include <errno.h> + +/* Sleep for a specified time (milliseconds) */ +int +sleep(uint32_t ms) +{ + int ret; + asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_SLEEP), + "c" (1), "S" (&ms)); + if (ret >= 0) + return ret; + errno = -ret; + return -1; +} diff --git a/time/time.c b/time/time.c new file mode 100644 index 0000000..dd43c31 --- /dev/null +++ b/time/time.c @@ -0,0 +1,30 @@ +#include <sys/syscall.h> +#include <sys/times.h> +#include <time.h> +#include <errno.h> + +/* Get epoch time */ +time_t +time(time_t *tloc) +{ + int ret; + asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_TIME), + "c" (1), "S" (&tloc)); + if (ret >= 0) + return ret; + errno = -ret; + return -1; +} + +/* Get process times */ +clock_t +times(Times *buf) +{ + int ret; + asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_TIMES), + "c" (1), "S" (&buf)); + if (ret >= 0) + return ret; + errno = -ret; + return -1; +} diff --git a/unistd/chdir.c b/unistd/chdir.c new file mode 100644 index 0000000..c146c8c --- /dev/null +++ b/unistd/chdir.c @@ -0,0 +1,15 @@ +#include <sys/syscall.h> +#include <errno.h> + +/* Change the process' file system current working directory */ +int +chdir(const char *path) +{ + int ret; + asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_CHDIR), + "c" (1), "S" (&path)); + if (ret >= 0) + return ret; + errno = -ret; + return -1; +} diff --git a/unistd/chroot.c b/unistd/chroot.c new file mode 100644 index 0000000..e9fd64c --- /dev/null +++ b/unistd/chroot.c @@ -0,0 +1,15 @@ +#include <sys/syscall.h> +#include <errno.h> + +/* Change the process' file system root */ +int +chroot(const char *path) +{ + int ret; + asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_CHROOT), + "c" (1), "S" (&path)); + if (ret >= 0) + return ret; + errno = -ret; + return -1; +} diff --git a/unistd/clone.c b/unistd/clone.c new file mode 100644 index 0000000..f7f4b34 --- /dev/null +++ b/unistd/clone.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include <sys/syscall.h> +#include <sys/types.h> + +/* Fork the current process */ +pid_t +clone(int flags) +{ + int ret; + asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_CLONE), + "c" (1), "S" (&flags)); + return ret; +} diff --git a/unistd/close.c b/unistd/close.c new file mode 100644 index 0000000..d2cf9fc --- /dev/null +++ b/unistd/close.c @@ -0,0 +1,15 @@ +#include <sys/syscall.h> +#include <errno.h> + +/* Close a file */ +int +close(int fd) +{ + int ret; + asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_CLOSE), + "c" (1), "S" (&fd)); + if (ret >= 0) + return ret; + errno = -ret; + return -1; +} diff --git a/unistd/dup.c b/unistd/dup.c new file mode 100644 index 0000000..a4aabfc --- /dev/null +++ b/unistd/dup.c @@ -0,0 +1,28 @@ +#include <sys/syscall.h> +#include <errno.h> + +/* Duplicate an open file descriptor */ +int +dup(int oldfd) +{ + int ret; + asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_DUP), + "c" (1), "S" (&oldfd)); + if (ret >= 0) + return ret; + errno = -ret; + return -1; +} + +/* Duplicate an open file descriptor to a specified file descriptor */ +int +dup2(int oldfd, int newfd) +{ + int ret; + asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_DUP2), + "c" (2), "S" (&oldfd)); + if (ret >= 0) + return ret; + errno = -ret; + return -1; +} diff --git a/unistd/execve.c b/unistd/execve.c new file mode 100644 index 0000000..6fcf69f --- /dev/null +++ b/unistd/execve.c @@ -0,0 +1,32 @@ +#include <stddef.h> +#include <sys/syscall.h> +#include <errno.h> + +/* Execute a binary with the specified arguments and environment */ +int +execve(const char *path, char *argv[], char *envp[]) +{ + struct { + const char *path; + char **argv, **envp; + } args; + args.path = path; + args.argv = argv; + args.envp = envp; + + int ret; + asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_EXECVE), + "c" (3), "S" (&args)); + + if (ret >= 0) + return ret; + errno = -ret; + return -1; +} + +/* Execute a binary with the specified arguments */ +int +execv(const char *path, char *argv[]) +{ + return execve(path, argv, NULL); /* FIXME: environment */ +} diff --git a/unistd/fork.c b/unistd/fork.c new file mode 100644 index 0000000..f827758 --- /dev/null +++ b/unistd/fork.c @@ -0,0 +1,11 @@ +#include <stddef.h> +#include <sys/syscall.h> +#include <sys/types.h> +#include <sys/sched.h> + +/* Fork the current process */ +pid_t +fork(void) +{ + return clone(CLONE_NONE); +} diff --git a/unistd/getcwd.c b/unistd/getcwd.c new file mode 100644 index 0000000..0107f2f --- /dev/null +++ b/unistd/getcwd.c @@ -0,0 +1,16 @@ +#include <stddef.h> +#include <sys/syscall.h> +#include <errno.h> + +/* Get the current working directory's path */ +char * +getcwd(char *buf, size_t size) +{ + int ret; + asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_GETCWD), + "c" (2), "S" (&buf)); + if ((char *) ret == buf) + return (char *) ret; + errno = -ret; + return NULL; +} diff --git a/unistd/getpid.c b/unistd/getpid.c new file mode 100644 index 0000000..dc5d86a --- /dev/null +++ b/unistd/getpid.c @@ -0,0 +1,13 @@ +#include <stddef.h> +#include <sys/syscall.h> +#include <sys/types.h> + +/* Get the current process' id */ +pid_t +getpid(void) +{ + int ret; + asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_GETPID), + "c" (0), "S" (NULL)); + return ret; +} diff --git a/unistd/getuid.c b/unistd/getuid.c new file mode 100644 index 0000000..3e7174d --- /dev/null +++ b/unistd/getuid.c @@ -0,0 +1,43 @@ +#include <stddef.h> +#include <sys/syscall.h> +#include <sys/types.h> + +/* Get the current process' user id */ +uid_t +getuid(void) +{ + int ret; + asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_GETUID), + "c" (0), "S" (NULL)); + return ret; +} + +/* Get the current process' effective user id */ +uid_t +geteuid(void) +{ + int ret; + asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_GETEUID), + "c" (0), "S" (NULL)); + return ret; +} + +/* Get the current process' group id */ +gid_t +getgid(void) +{ + int ret; + asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_GETGID), + "c" (0), "S" (NULL)); + return ret; +} + +/* Get the current process' effective group id */ +gid_t +getegid(void) +{ + int ret; + asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_GETEGID), + "c" (0), "S" (NULL)); + return ret; +} diff --git a/unistd/isatty.c b/unistd/isatty.c new file mode 100644 index 0000000..823019a --- /dev/null +++ b/unistd/isatty.c @@ -0,0 +1,15 @@ +#include <sys/syscall.h> +#include <errno.h> + +/* Check if fd refers to a terminal */ +int +isatty(int fd) +{ + int ret; + asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_ISATTY), + "c" (1), "S" (&fd)); + if (ret >= 0) + return ret; + errno = -ret; + return 0; +} diff --git a/unistd/lseek.c b/unistd/lseek.c new file mode 100644 index 0000000..aa6510a --- /dev/null +++ b/unistd/lseek.c @@ -0,0 +1,15 @@ +#include <sys/syscall.h> +#include <sys/types.h> +#include <errno.h> + +off_t +lseek(int fd, off_t offset, int whence) +{ + int ret; + asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_LSEEK), + "c" (3), "S" (&fd)); + if (ret >= 0) + return ret; + errno = -ret; + return -1; +} diff --git a/unistd/open.c b/unistd/open.c new file mode 100644 index 0000000..02603d8 --- /dev/null +++ b/unistd/open.c @@ -0,0 +1,30 @@ +#include <fcntl.h> +#include <sys/syscall.h> +#include <sys/types.h> +#include <errno.h> + +/* Open a file */ +int +open(const char *name, int flags, ...) +{ + int ret; + if (flags & O_CREATE) { + asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_OPEN), + "c" (3), "S" (&name)); + } else { + asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_OPEN), + "c" (2), "S" (&name)); + } + + if (ret >= 0) + return ret; + errno = -ret; + return -1; +} + +/* Create a file */ +int +create(const char *name, mode_t mode) +{ + return open(name, O_CREATE | O_WRONLY | O_TRUNC, mode); +} diff --git a/unistd/read.c b/unistd/read.c new file mode 100644 index 0000000..f4d2d75 --- /dev/null +++ b/unistd/read.c @@ -0,0 +1,16 @@ +#include <stddef.h> +#include <sys/syscall.h> +#include <errno.h> + +/* Read from a file */ +int +read(int fd, void *buf, size_t count) +{ + int ret; + asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_READ), + "c" (3), "S" (&fd)); + if (ret >= 0) + return ret; + errno = -ret; + return -1; +} diff --git a/unistd/setuid.c b/unistd/setuid.c new file mode 100644 index 0000000..7dcca04 --- /dev/null +++ b/unistd/setuid.c @@ -0,0 +1,43 @@ +#include <stddef.h> +#include <sys/syscall.h> +#include <sys/types.h> + +/* Set the current process' user id */ +int +setuid(uid_t uid) +{ + int ret; + asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_SETUID), + "c" (1), "S" (&uid)); + return ret; +} + +/* Set the current process' effective user id */ +int +seteuid(uid_t euid) +{ + int ret; + asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_SETEUID), + "c" (1), "S" (&euid)); + return ret; +} + +/* Set the current process' group id */ +int +setgid(gid_t gid) +{ + int ret; + asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_SETGID), + "c" (1), "S" (&gid)); + return ret; +} + +/* Set the current process' effective group id */ +int +setegid(gid_t egid) +{ + int ret; + asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_SETEGID), + "c" (1), "S" (&egid)); + return ret; +} diff --git a/unistd/write.c b/unistd/write.c new file mode 100644 index 0000000..90862b2 --- /dev/null +++ b/unistd/write.c @@ -0,0 +1,16 @@ +#include <stddef.h> +#include <sys/syscall.h> +#include <errno.h> + +/* Write to a file */ +int +write(int fd, void *buf, size_t count) +{ + int ret; + asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_WRITE), + "c" (3), "S" (&fd)); + if (ret >= 0) + return ret; + errno = -ret; + return -1; +}