commit d63e3c43527f6e14a000e17efb458f38e839e12e Author: Mark Date: Thu Jul 16 22:49:00 2020 +0300 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..378eac2 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +build diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..348519c --- /dev/null +++ b/Makefile @@ -0,0 +1,72 @@ +# Files +HEADERS=$(shell find include -type f -name "*.h") +INSTALL_HEADERS=$(filter-out include/_libc/%,$(HEADERS)) +OBJ_CRT=$(O)/obj/crt0.o +SRC_LIBC=$(shell find src -type f -name "*.c") +OBJ_LIBC=$(SRC_LIBC:src/%.c=$(O)/libc/%.o) +SRC_DIR_LIBC=$(shell find src/* -type d) +DIR_LIBC=$(SRC_DIR_LIBC:src/%=$(O)/libc/%) +STATIC_LIBS=$(O)/lib/libc.a +SHARED_LIBS= + +# Build +CFLAGS=-mno-sse \ + -mno-sse2 \ + -mno-mmx \ + -I include \ + -ffreestanding \ + -Wall \ + -Wextra \ + -Werror \ + -zmax-page-size=4096 +LDFLAGS=-nostdlib +CC=$(CROSS_COMPILE)gcc + +O=build +DESTDIR?=/usr/local +LIBS=$(STATIC_LIBS) $(SHARED_LIBS) + +### General rules + +all: mkdirs $(LIBS) $(OBJ_CRT) + +mkdirs: + mkdir -p $(O)/obj $(O)/lib $(DIR_LIBC) + +clean: + rm -rf $(O) + +### Install rules + +install-crt: mkdirs $(OBJ_CRT) + $(foreach obj,$(OBJ_CRT), \ + install -Dm 0644 $(obj) $(obj:$(O)/obj/%.o=$(DESTDIR)/lib/%.o); \ + ) + +install-static-libs: mkdirs $(STATIC_LIBS) + $(foreach lib,$(STATIC_LIBS), \ + install -Dm 0644 $(lib) $(DESTDIR)/$(lib:$(O)/%=%); \ + ) + +install-headers: mkdirs $(INSTALL_HEADERS) + $(foreach hdr,$(INSTALL_HEADERS), \ + install -Dm 0644 $(hdr) $(DESTDIR)/$(hdr:$(O)/%=%); \ + ) + +install: install-crt install-static-libs install-headers + +### CRT objects + +$(O)/obj/crt%.o: crt/crt%.c $(HEADERS) + $(CC) $(CFLAGS) -c -o $@ $< + +### lib + +$(O)/lib/libc.a: $(OBJ_LIBC) + $(CROSS_COMPILE)ar rcs $@ + $(foreach obj,$(OBJ_LIBC), \ + $(CROSS_COMPILE)ar rs $@ $(obj); \ + ) + +$(O)/libc/%.o: src/%.c $(HEADERS) + $(CC) $(CFLAGS) -c -o $@ $< diff --git a/crt/crt0.c b/crt/crt0.c new file mode 100644 index 0000000..3411ef5 --- /dev/null +++ b/crt/crt0.c @@ -0,0 +1,28 @@ +#include +#include +#include +#include +#include <_libc/stdio.h> +#include <_libc/signal.h> + +// XXX: envp +extern int main(int argc, char **argv); + +extern char **environ; + +void _start(void *_arg) { + uintptr_t arg = (uintptr_t) _arg; + // arg: argp page number << 24 | 12 bit page count << 12 | 12 bit argc + char **argp = (char **) ((arg >> 12) & ~0xFFF); + int argc = arg & 0xFFF; + //__libc_vecp_pages = (arg >> 12) & 0xFFF; + + // TODO: better handling for this + environ = &argp[argc + 1]; + + __libc_signal_init(); + + fwrite("Test\n", 1, 5, stdout); + + exit(main(argc, argp)); +} diff --git a/include/_libc/abort.h b/include/_libc/abort.h new file mode 100644 index 0000000..0305630 --- /dev/null +++ b/include/_libc/abort.h @@ -0,0 +1,3 @@ +#pragma once + +_Noreturn void __libc_abort_init(const char *reason); diff --git a/include/_libc/list.h b/include/_libc/list.h new file mode 100644 index 0000000..41d3c58 --- /dev/null +++ b/include/_libc/list.h @@ -0,0 +1,72 @@ +#pragma once + +struct list_head { + struct list_head *prev, *next; +}; + +#define LIST_HEAD(name) \ + struct list_head name = { &name, &name } + +#define list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +#define list_for_each_entry(pos, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +#define list_entry(link, type, member) ({ \ + const typeof (((type *) 0)->member) *__memb = (link); \ + (type *) ((char *) __memb - offsetof(type, member)); \ + }) + +#define list_next_entry(pos, member) \ + list_entry((pos)->member.next, typeof(*(pos)), member) + +#define list_first_entry(ptr, type, member) \ + list_entry((ptr)->next, type, member) + +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + +static inline void list_head_init(struct list_head *list) { + list->next = list; + list->prev = list; +} + +static inline void __list_add(struct list_head *new, + struct list_head *prev, + struct list_head *next) { + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} + +static inline void list_add(struct list_head *new, struct list_head *head) { + __list_add(new, head, head->next); +} + +static inline void list_add_tail(struct list_head *new, struct list_head *head) { + __list_add(new, head->prev, head); +} + +static inline void __list_del(struct list_head *prev, struct list_head *next) { + next->prev = prev; + prev->next = next; +} + +static inline void list_del(struct list_head *entry) { + __list_del(entry->prev, entry->next); +} + +static inline int list_empty(const struct list_head *head) { + return head->next == head; +} + +static inline void list_del_init(struct list_head *entry) { + __list_del(entry->prev, entry->next); + list_head_init(entry); +} + diff --git a/include/_libc/malloc.h b/include/_libc/malloc.h new file mode 100644 index 0000000..504ae29 --- /dev/null +++ b/include/_libc/malloc.h @@ -0,0 +1,35 @@ +#pragma once +#include <_libc/list.h> +#include +#include + +#define BLOCK_ALLOC 1 +#define BLOCK_MMAP 2 +#define BLOCK_MAGIC_MASK 0xFFFFFFC +#define BLOCK_MAGIC 0xBAD8EA0 + +// Fits ~56 blocks of 256 +#define SMALL_ZONE_ELEM 256 +#define SMALL_ZONE_SIZE (4 * 0x1000) +// Fits ~31 block of 2K +#define MID_ZONE_ELEM 2048 +#define MID_ZONE_SIZE (16 * 0x1000) +// Fits ~15 blocks of 8K +#define LARGE_ZONE_ELEM 8192 +#define LARGE_ZONE_SIZE (32 * 0x1000) +// Larger objects are allocated directly using mmap() + +struct block { + struct block *prev, *next; + uint32_t flags, size; +}; + +struct zone { + size_t size; + struct list_head list; +}; + +extern struct list_head small_zone_list, mid_zone_list, large_zone_list; + +struct zone *zone_create(size_t size); +void zone_destroy(struct zone *zone); diff --git a/include/_libc/signal.h b/include/_libc/signal.h new file mode 100644 index 0000000..c6258bd --- /dev/null +++ b/include/_libc/signal.h @@ -0,0 +1,4 @@ +#pragma once +#define __LIBC_SIGNAL_STACK_SIZE 4096 + +void __libc_signal_init(void); diff --git a/include/_libc/stdio.h b/include/_libc/stdio.h new file mode 100644 index 0000000..f21924b --- /dev/null +++ b/include/_libc/stdio.h @@ -0,0 +1,33 @@ +#pragma once +#include + +#define FILE_MODE_READ (1 << 0) +#define FILE_MODE_WRITE (1 << 1) +#define FILE_MODE_APPEND (1 << 2) +#define FILE_MODE_TRUNC (1 << 3) +#define FILE_MODE_CREAT (1 << 4) + +#define FILE_FLAG_ERROR (1 << 16) +#define FILE_FLAG_EOF (1 << 17) + +struct __FILE { + void *ctx; + void *buf; + + ssize_t (*write)(void *ctx, const void *data, size_t len); + ssize_t (*read) (void *ctx, void *data, size_t len); + off_t (*seek) (void *ctx, off_t offset, int whence); + int (*close)(void *ctx); + + void (*free) (void *ctx, struct __FILE *fp); + + int fd, flags, buf_mode; + size_t wrbuf, rdbuf, rdbufpos; +}; + +struct __FILE *__libc_file_create(void); +int __libc_file_open_path(struct __FILE *fp, const char *pathname, const char *mode); +int __libc_file_open_fd(struct __FILE *fp, int fd, int flags); +int __libc_file_mode(const char *mode); +int __libc_file_flush_read(struct __FILE *fp); +int __libc_file_flush_write(struct __FILE *fp); diff --git a/include/_libc/syscalls.h b/include/_libc/syscalls.h new file mode 100644 index 0000000..1f8ad1b --- /dev/null +++ b/include/_libc/syscalls.h @@ -0,0 +1,57 @@ +#pragma once + +static inline long __syscall0(long n) { + unsigned long ret; + asm volatile ("syscall" + :"=a"(ret) + :"a"(n) + :"rcx","r11","memory"); + return ret; +} + +static inline long __syscall1(long n, long a1) { + unsigned long ret; + asm volatile ("syscall" + :"=a"(ret) + :"a"(n),"D"(a1) + :"rcx","r11","memory"); + return ret; +} + +static inline long __syscall2(long n, long a1, long a2) { + unsigned long ret; + asm volatile ("syscall" + :"=a"(ret) + :"a"(n),"D"(a1),"S"(a2) + :"rcx","r11","memory"); + return ret; +} + +static inline long __syscall3(long n, long a1, long a2, long a3) { + unsigned long ret; + asm volatile ("syscall" + :"=a"(ret) + :"a"(n),"D"(a1),"S"(a2),"d"(a3) + :"rcx","r11","memory"); + return ret; +} + +static inline long __syscall6(long n, long a1, long a2, long a3, long a4, long a5, long a6) { + unsigned long ret; + register long r10 __asm__("r10") = a4; + register long r8 __asm__("r8") = a5; + register long r9 __asm__("r9") = a6; + asm volatile ("syscall" + :"=a"(ret) + :"a"(n),"D"(a1),"S"(a2),"d"(a3),"r"(r10),"r"(r8),"r"(r9) + :"rcx","r11","memory"); + return ret; +} + +#define SET_ERRNO(t, r) ({ \ + t res = (t) r; \ + if (res < 0) { \ + errno = -res; \ + } \ + ((int) res) < 0 ? (t) -1 : res; \ + }) diff --git a/include/assert.h b/include/assert.h new file mode 100644 index 0000000..54be437 --- /dev/null +++ b/include/assert.h @@ -0,0 +1,12 @@ +#pragma once + +#define _assert_stringify_line(x) #x +#define _assert_line(x) _assert_stringify_line(x) +#if !defined(NDEBUG) +#define assert(c) \ + if (!(c)) { _assert_fail(__func__, __FILE__ ":" _assert_line(__LINE__) ": Assertion `" #c "' failed." ); } +#else +#define assert(c) +#endif + +_Noreturn void _assert_fail(const char *func, const char *msg); diff --git a/include/bits/attr.h b/include/bits/attr.h new file mode 100644 index 0000000..92e4ccb --- /dev/null +++ b/include/bits/attr.h @@ -0,0 +1,3 @@ +#pragma once + +#define __Malloc __attribute__((malloc)) diff --git a/include/errno.h b/include/errno.h new file mode 100644 index 0000000..10345e6 --- /dev/null +++ b/include/errno.h @@ -0,0 +1,4 @@ +#pragma once +#include + +extern int errno; diff --git a/include/fcntl.h b/include/fcntl.h new file mode 100644 index 0000000..a5de346 --- /dev/null +++ b/include/fcntl.h @@ -0,0 +1,4 @@ +#pragma once +#include + +int open(const char *pathname, int flags, mode_t mode); diff --git a/include/signal.h b/include/signal.h new file mode 100644 index 0000000..8f6daf0 --- /dev/null +++ b/include/signal.h @@ -0,0 +1,16 @@ +#pragma once +#include + +#define SIG_DFL _sig_dfl +#define SIG_ERR ((sighandler_t) -1) +#define SIG_HOLD _sig_hold +#define SIG_IGN _sig_ign + +typedef void (*sighandler_t) (int); + +extern void _sig_dfl(int signum); +extern void _sig_hold(int signum); +extern void _sig_ign(int signum); + +sighandler_t signal(int signum, sighandler_t handler); +int sigaltstack(const stack_t *ss, stack_t *old_ss); diff --git a/include/stdint.h b/include/stdint.h new file mode 100644 index 0000000..0bd5e59 --- /dev/null +++ b/include/stdint.h @@ -0,0 +1,22 @@ +#pragma once + +// Exact-width integer types +typedef signed char int8_t; +typedef unsigned char uint8_t; + +typedef signed short int16_t; +typedef unsigned short uint16_t; + +typedef signed int int32_t; +typedef unsigned int uint32_t; + +typedef signed long int64_t; +typedef unsigned long uint64_t; + +// Integer types capable of holding object pointers +typedef int64_t intptr_t; +typedef uint64_t uintptr_t; + +// Greatest-width integer types +typedef int64_t intmax_t; +typedef uint64_t uintmax_t; diff --git a/include/stdio.h b/include/stdio.h new file mode 100644 index 0000000..ffa129b --- /dev/null +++ b/include/stdio.h @@ -0,0 +1,32 @@ +#pragma once +#include + +#define EOF -1 +#define BUFSIZ 8192 +#define _IOLBF 1 +#define _IONBF 2 +#define TMP_MAX 10000 +#define FOPEN_MAX 8 // TODO +#define FILENAME_MAX 1024 + +typedef struct __FILE FILE; + +extern FILE *const stdin; +extern FILE *const stdout; +extern FILE *const stderr; + +FILE *fopen(const char *pathname, const char *mode); +int fclose(FILE *fp); + +void flockfile(FILE *fp); +void funlockfile(FILE *fp); + +//// _unlocked functions +size_t fwrite_unlocked(const void *data, size_t size, size_t nmemb, FILE *fp); +size_t fread_unlocked(void *data, size_t size, size_t nmemb, FILE *fp); +int fgetc_unlocked(FILE *fp); +int fputc_unlocked(int ch, FILE *fp); + +//// Regular functions +size_t fwrite(const void *data, size_t size, size_t nmemb, FILE *fp); +size_t fread(void *data, size_t size, size_t nmemb, FILE *fp); diff --git a/include/stdlib.h b/include/stdlib.h new file mode 100644 index 0000000..6d32906 --- /dev/null +++ b/include/stdlib.h @@ -0,0 +1,10 @@ +#pragma once +#include +#include + +__Malloc void *malloc(size_t size); +void free(void *ptr); + +// XXX: POSIX doesn't define _Noreturn attribute on those? +void _Exit(int status); +void exit(int status); diff --git a/include/string.h b/include/string.h new file mode 100644 index 0000000..603cf5a --- /dev/null +++ b/include/string.h @@ -0,0 +1,36 @@ +#pragma once +#include + +void *memccpy(void *restrict dst, const void *restrict src, int c, size_t len); +void *memchr(const void *ptr, int v, size_t len); +int memcmp(const void *p0, const void *p1, size_t len); +void *memcpy(void *dest, const void *src, size_t n); +void *memmove(void *dst, const void *src, size_t len); +void *memset(void *dest, int c, size_t n); + +char *stpcpy(char *restrict dst, const char *restrict src); +char *stpncpy(char *restrict dst, const char *restrict src, size_t len); +char *strcat(char *dst, const char *src); +char *strchr(const char *str, int chr); +int strcmp(const char *a, const char *b); +int strcoll(const char *a, const char *b); +// TODO: strcoll_l +char *strcpy(char *restrict dst, const char *restrict src); +size_t strcspn(const char *a, const char *b); +char *strdup(const char *str); +char *strerror(int errnum); +// TODO: strerror_l +int strerror_r(int errnum, char *dst, size_t lim); +size_t strlen(const char *str); +char *strncat(char *restrict dst, const char *restrict src, size_t len); +int strncmp(const char *a, const char *b, size_t len); +char *strncpy(char *restrict dst, const char *restrict src, size_t len); +char *strndup(const char *str, size_t len); +size_t strnlen(const char *str, size_t len); +char *strpbrk(const char *str, const char *set); +char *strrchr(const char *str, int chr); +char *strsignal(int signum); +size_t strspn(const char *a, const char *b); +char *strstr(const char *a, const char *b); +char *strtok(char *restrict str, const char *restrict delim); +char *strtok_r(char *restrict str, const char *restrict delim, char **restrict saveptr); diff --git a/include/sys/mman.h b/include/sys/mman.h new file mode 100644 index 0000000..4a53617 --- /dev/null +++ b/include/sys/mman.h @@ -0,0 +1,6 @@ +#pragma once +#include +#include + +void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset); +int munmap(void *addr, size_t length); diff --git a/include/sys/types.h b/include/sys/types.h new file mode 100644 index 0000000..c25d82f --- /dev/null +++ b/include/sys/types.h @@ -0,0 +1,3 @@ +#pragma once +#include // size_t +#include diff --git a/include/unistd.h b/include/unistd.h new file mode 100644 index 0000000..182002c --- /dev/null +++ b/include/unistd.h @@ -0,0 +1,338 @@ +#pragma once +#include // size_t, ssize_t + +extern char **environ; + + +//// Defines +// POSIX conformance +#undef _POSIX_ADVISORY_INFO +#undef _POSIX_ASYNCHRONOUS_IO +#undef _POSIX_BARRIERS +#define _POSIX_CHOWN_RESTRICTED 200809L +#undef _POSIX_CLOCK_SELECTION +#undef _POSIX_CPU_TIME +#undef _POSIX_FSYNC // TODO: maybe I'll add this on a per-file basis +#undef _POSIX_IPV6 // I don't even support IPv4 yet lol +#define _POSIX_JOB_CONTROL 200809L +#undef _POSIX_MAPPED_FILES // TODO: I'll implement this eventually +#undef _POSIX_MEMLOCK +#undef _POSIX_MEMLOCK_RANGE +#undef _POSIX_MEMORY_PROTECTION +#undef _POSIX_MESSAGE_PASSING +#undef _POSIX_MONOTONIC_CLOCK // TODO +#define _POSIX_NO_TRUNC 200809L +#undef _POSIX_PRIORITIZED_IO +#undef _POSIX_PRIORITY_SCHEDULING // TODO: maybe just define that and ignore the priorities +#undef _POSIX_RAW_SOCKETS // TODO: the kernel kinda supports them, but pending rewrite +#undef _POSIX_READER_WRITER_LOCKS +#undef _POSIX_REALTIME_SIGNALS +#undef _POSIX_REGEXP // TODO +#undef _POSIX_SAVED_IDS // TODO? +#undef _POSIX_SEMAPHORES +#undef _POSIX_SHARED_MEMORY_OBJECTS // TODO +#define _POSIX_SHELL 200809L +#undef _POSIX_SPAWN // TODO? +#undef _POSIX_SPIN_LOCKS // TODO? +#undef _POSIX_SPORADIC_SERVER +#undef _POSIX_SYNCHRONIZED_IO +#undef _POSIX_THREAD_ATTR_STACKADDR +#undef _POSIX_THREAD_ATTR_STACKSIZE +#undef _POSIX_THREAD_CPUTIME +#undef _POSIX_THREAD_PRIO_INHERIT +#undef _POSIX_THREAD_PRIO_PROTECT +#undef _POSIX_THREAD_PRIORITY_SCHEDULING +#undef _POSIX_THREAD_PROCESS_SHARED +#undef _POSIX_THREAD_ROBUST_PRIO_INHERIT +#undef _POSIX_THREAD_ROBUST_PRIO_PROTECT +#define _POSIX_THREAD_SAFE_FUNCTIONS 200809L +#undef _POSIX_THREAD_SPORADIC_SERVER +#undef _POSIX_THREADS // TODO +#undef _POSIX_TIMEOUTS // TODO? +#undef _POSIX_TIMERS // TODO +#undef _POSIX_TRACE // TODO? +#undef _POSIX_TRACE_EVENT_FILTER +#undef _POSIX_TRACE_INHERIT +#undef _POSIX_TRACE_LOG +#undef _POSIX_TYPED_MEMORY_OBJECTS +#define _POSIX_V6_LP64_OFF64 200809L +#define _POSIX_V7_LP64_OFF64 200809L +#undef _POSIX2_C_BIND // Dunno what that is +#undef _POSIX2_C_DEV // Ditto +#undef _POSIX2_CHAR_TERM +#undef _POSIX2_FORT_DEV // Lel +#undef _POSIX2_FORT_RUN // Lmao +#undef _POSIX2_LOCALEDEV +#undef _POSIX2_PBS +#undef _POSIX2_PBS_ACCOUNTING +#undef _POSIX2_PBS_CHECKPOINT +#undef _POSIX2_PBS_LOCATE +#undef _POSIX2_PBS_MESSAGE +#undef _POSIX2_PBS_TRACK +#undef _POSIX2_SW_DEV +#undef _POSIX2_UPE +#undef _XOPEN_CRYPT +#undef _XOPEN_ENH_I18N +#undef _XOPEN_REALTIME +#undef _XOPEN_SHM +#undef _XOPEN_STREAMS +#undef _XOPEN_UUCP + +// TODO: merge these with kernel's fcntl.h +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 + +#define R_OK 4 +#define W_OK 2 +#define X_OK 1 +#define F_OK 0 + +// No POSIX advisory locks + +#define _PC_2_SYMLINKS 1 +#define _PC_ALLOC_SIZE_MIN 2 +#define _PC_ASYNC_IO 3 +#define _PC_CHOWN_RESTRICTED 4 +#define _PC_FILESIZEBITS 5 +#define _PC_LINK_MAX 6 +#define _PC_MAX_CANON 7 +#define _PC_MAX_INPUT 8 +#define _PC_NAME_MAX 9 +#define _PC_NO_TRUNC 10 +#define _PC_PATH_MAX 11 +#define _PC_PIPE_BUF 12 +#define _PC_PRIO_IO 13 +#define _PC_REC_INCR_XFER_SIZE 14 +#define _PC_REC_MAX_XFER_SIZE 15 +#define _PC_REC_MIN_XFER_SIZE 16 +#define _PC_REC_XFER_ALIGN 17 +#define _PC_SYMLINK_MAX 18 +#define _PC_SYNC_IO 19 +#define _PC_TIMESTAMP_RESOLUTION 20 +#define _PC_VDISABLE 21 + +#define _SC_2_C_BIND 1 +#define _SC_2_C_DEV 2 +#define _SC_2_CHAR_TERM 3 +#define _SC_2_FORT_DEV 4 +#define _SC_2_FORT_RUN 5 +#define _SC_2_LOCALEDEF 6 +#define _SC_2_PBS 7 +#define _SC_2_PBS_ACCOUNTING 8 +#define _SC_2_PBS_CHECKPOINT 9 +#define _SC_2_PBS_LOCATE 10 +#define _SC_2_PBS_MESSAGE 11 +#define _SC_2_PBS_TRACK 12 +#define _SC_2_SW_DEV 13 +#define _SC_2_UPE 14 +#define _SC_2_VERSION 15 +#define _SC_ADVISORY_INFO 16 +#define _SC_AIO_LISTIO_MAX 17 +#define _SC_AIO_MAX 18 +#define _SC_AIO_PRIO_DELTA_MAX 19 +#define _SC_ARG_MAX 20 +#define _SC_ASYNCHRONOUS_IO 21 +#define _SC_ATEXIT_MAX 22 +#define _SC_BARRIERS 23 +#define _SC_BC_BASE_MAX 24 +#define _SC_BC_DIM_MAX 25 +#define _SC_BC_SCALE_MAX 26 +#define _SC_BC_STRING_MAX 27 +#define _SC_CHILD_MAX 28 +#define _SC_CLK_TCK 29 +#define _SC_CLOCK_SELECTION 30 +#define _SC_COLL_WEIGHTS_MAX 31 +#define _SC_CPUTIME 32 +#define _SC_DELAYTIMER_MAX 33 +#define _SC_EXPR_NEST_MAX 34 +#define _SC_FSYNC 35 +#define _SC_GETGR_R_SIZE_MAX 36 +#define _SC_GETPW_R_SIZE_MAX 37 +#define _SC_HOST_NAME_MAX 38 +#define _SC_IOV_MAX 39 +#define _SC_IPV6 40 +#define _SC_JOB_CONTROL 41 +#define _SC_LINE_MAX 42 +#define _SC_LOGIN_NAME_MAX 43 +#define _SC_MAPPED_FILES 44 +#define _SC_MEMLOCK 45 +#define _SC_MEMLOCK_RANGE 46 +#define _SC_MEMORY_PROTECTION 47 +#define _SC_MESSAGE_PASSING 48 +#define _SC_MONOTONIC_CLOCK 49 +#define _SC_MQ_OPEN_MAX 50 +#define _SC_MQ_PRIO_MAX 51 +#define _SC_NGROUPS_MAX 52 +#define _SC_OPEN_MAX 53 +#define _SC_PAGE_SIZE 54 +#define _SC_PAGESIZE 55 +#define _SC_PRIORITIZED_IO 56 +#define _SC_PRIORITY_SCHEDULING 57 +#define _SC_RAW_SOCKETS 58 +#define _SC_RE_DUP_MAX 59 +#define _SC_READER_WRITER_LOCKS 60 +#define _SC_REALTIME_SIGNALS 61 +#define _SC_REGEXP 62 +#define _SC_RTSIG_MAX 63 +#define _SC_SAVED_IDS 64 +#define _SC_SEM_NSEMS_MAX 65 +#define _SC_SEM_VALUE_MAX 66 +#define _SC_SEMAPHORES 67 +#define _SC_SHARED_MEMORY_OBJECTS 68 +#define _SC_SHELL 69 +#define _SC_SIGQUEUE_MAX 70 +#define _SC_SPAWN 71 +#define _SC_SPIN_LOCKS 72 +#define _SC_SPORADIC_SERVER 73 +#define _SC_SS_REPL_MAX 74 +#define _SC_STREAM_MAX 75 +#define _SC_SYMLOOP_MAX 76 +#define _SC_SYNCHRONIZED_IO 77 +#define _SC_THREAD_ATTR_STACKADDR 78 +#define _SC_THREAD_ATTR_STACKSIZE 79 +#define _SC_THREAD_CPUTIME 80 +#define _SC_THREAD_DESTRUCTOR_ITERATIONS 81 +#define _SC_THREAD_KEYS_MAX 82 +#define _SC_THREAD_PRIO_INHERIT 83 +#define _SC_THREAD_PRIO_PROTECT 84 +#define _SC_THREAD_PRIORITY_SCHEDULING 85 +#define _SC_THREAD_PROCESS_SHARED 86 +#define _SC_THREAD_ROBUST_PRIO_INHERIT 87 +#define _SC_THREAD_ROBUST_PRIO_PROTECT 88 +#define _SC_THREAD_SAFE_FUNCTIONS 89 +#define _SC_THREAD_SPORADIC_SERVER 90 +#define _SC_THREAD_STACK_MIN 91 +#define _SC_THREAD_THREADS_MAX 92 +#define _SC_THREADS 93 +#define _SC_TIMEOUTS 94 +#define _SC_TIMER_MAX 95 +#define _SC_TIMERS 96 +#define _SC_TRACE 97 +#define _SC_TRACE_EVENT_FILTER 98 +#define _SC_TRACE_EVENT_NAME_MAX 99 +#define _SC_TRACE_INHERIT 100 +#define _SC_TRACE_LOG 101 +#define _SC_TRACE_NAME_MAX 102 +#define _SC_TRACE_SYS_MAX 103 +#define _SC_TRACE_USER_EVENT_MAX 104 +#define _SC_TTY_NAME_MAX 105 +#define _SC_TYPED_MEMORY_OBJECTS 106 +#define _SC_TZNAME_MAX 107 +#define _SC_V7_ILP32_OFF32 108 +#define _SC_V7_ILP32_OFFBIG 109 +#define _SC_V7_LP64_OFF64 110 +#define _SC_V7_LPBIG_OFFBIG 111 +#define _SC_V6_ILP32_OFF32 112 +#define _SC_V6_ILP32_OFFBIG 113 +#define _SC_V6_LP64_OFF64 114 +#define _SC_V6_LPBIG_OFFBIG 115 +#define _SC_VERSION 116 +#define _SC_XOPEN_CRYPT 117 +#define _SC_XOPEN_ENH_I18N 118 +#define _SC_XOPEN_REALTIME 119 +#define _SC_XOPEN_REALTIME_THREADS 120 +#define _SC_XOPEN_SHM 121 +#define _SC_XOPEN_STREAMS 122 +#define _SC_XOPEN_UNIX 123 +#define _SC_XOPEN_UUCP 124 +#define _SC_XOPEN_VERSION 125 + +#define _POSIX_VDISABLE 0 + +#define STDERR_FILENO 2 +#define STDOUT_FILENO 1 +#define STDIN_FILENO 0 + +// File control +int access(const char *pathname, int acc); //+ +int chdir(const char *pathname); //+ +int chown(const char *pathname, uid_t uid, gid_t gid); //+ +int close(int fd); //+ +int dup(int fd); //+ +int dup2(int oldfd, int newfd); //+ +int execl(const char *pathname, const char *arg, ...); //+ +int execle(const char *pathname, const char *arg, ...); //+ +int execlp(const char *file, const char *arg, ...); //- +int execv(const char *pathname, char *const argv[]); //+ +int execve(const char *pathname, char *const argv[], char *const envp[]); //+ +int execvp(const char *file, char *const argv[]); //- +int faccessat(int dfd, const char *pathname, int mode, int flags); //- +int fchdir(int dfd); //- +int fchown(int dfd, uid_t uid, gid_t gid); //- +int fchownat(int dfd, const char *pathname, uid_t uid, gid_t gid, int flags); //- +int fdatasync(int fd); //? +int fexecve(int fd, char *const argv[], char *const argp[]); //- +long fpathconf(int fd, int name); //- +int fsync(int fd); //? +int ftruncate(int fd, off_t size); //- +char *getcwd(char *buf, size_t lim); //+ +int isatty(int fd); //+ +int lchown(const char *pathname, uid_t uid, gid_t gid); //- +int link(const char *oldpath, const char *newpath); //- +int linkat(int old_dfd, const char *oldpath, int new_dfd, const char *newpath, int flags); //- +int lockf(int fd, int cmd, off_t len); //- +off_t lseek(int fd, off_t off, int whence); //+ +long pathconf(const char *pathname, int name); //+ +int pipe(int fds[2]); //+ +ssize_t pread(int fd, void *buf, size_t count, off_t offset); //- +ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset); //- +ssize_t read(int fd, void *buf, size_t count); //+ +ssize_t readlink(const char *restrict pathname, char *restrict buf, size_t lim); //- +ssize_t readlinkat(int dfd, const char *restrict pathname, char *restrict buf, size_t lim); //- +int rmdir(const char *dirname); //+ +int symlink(const char *target, const char *linkpath); //- +int symlinkat(const char *target, int linkdfd, const char *linkpath); //- +void sync(void); //+ +int truncate(const char *pathname, off_t size); //- +int unlink(const char *pathname); //+ +int unlinkat(int dfd, const char *pathname, int flags); //- +ssize_t write(int fd, const void *buf, size_t count); //+ + +// Access control +gid_t getegid(void); //+ +uid_t geteuid(void); //+ +gid_t getgid(void); //+ +int getgroups(int size, gid_t list[]); //? +uid_t getuid(void); //+ +int setegid(gid_t egid); //- +int seteuid(uid_t euid); //- +int setgid(gid_t gid); //+ +int setregid(gid_t rgid, gid_t egid); //- +int setreuid(uid_t ruid, uid_t euid); //- +int setuid(uid_t uid); //+ + +// System control +size_t confstr(int name, char *buf, size_t lim); //+ +long gethostid(void); //+ +int gethostname(char *buf, size_t lim); //+ +char *getlogin(void); //W +int getlogin_r(char *buf, size_t lim); //- +long sysconf(int name); //- + +// getopt +int getopt(int argc, char *const argv[], const char *optstr); // + +// Process control +_Noreturn void _exit(int status); //+ +pid_t fork(void); //+ +pid_t getpgid(pid_t pid); //+ +pid_t getpgrp(void); //+ +pid_t getpid(void); //+ +pid_t getppid(void); //- +pid_t getsid(void); //- +int nice(int inc); //+ +int pause(void); //+ +int setpgid(pid_t pid, pid_t pgid); //+ +pid_t setpgrp(void); //+ +pid_t setsid(void); //- +unsigned int sleep(unsigned int sec); //+ +pid_t tcgetprgp(int fd); //+ +int tcsetpgrp(int fd, pid_t pgrp); //+ +char *ttyname(int fd); //W +int ttyname_r(int fd, char *buf, size_t size); //? + +// Helpers and crypt +char *crypt(const char *key, const char *salt); // +void encrypt(char block[64], int edflag); // +void swab(const void *from, void *to, ssize_t n); // diff --git a/src/env/environ.c b/src/env/environ.c new file mode 100644 index 0000000..6f49e0c --- /dev/null +++ b/src/env/environ.c @@ -0,0 +1,2 @@ +static char *dummy[] = { (char *) 0 }; +char **environ = (char **) &dummy; diff --git a/src/errno/errno.c b/src/errno/errno.c new file mode 100644 index 0000000..14a8122 --- /dev/null +++ b/src/errno/errno.c @@ -0,0 +1,3 @@ +#include + +int errno = 0; diff --git a/src/exit/abort_init.c b/src/exit/abort_init.c new file mode 100644 index 0000000..e54c290 --- /dev/null +++ b/src/exit/abort_init.c @@ -0,0 +1,12 @@ +#include +#include +#include <_libc/abort.h> + +_Noreturn void __libc_abort_init(const char *reason) { + static const char prefix[] = "libc abort: "; + char ln = '\n'; + write(STDERR_FILENO, prefix, sizeof(prefix) - 1); + write(STDERR_FILENO, reason, strlen(reason)); + write(STDERR_FILENO, &ln, 1); + _exit(-1); +} diff --git a/src/exit/assert_fail.c b/src/exit/assert_fail.c new file mode 100644 index 0000000..848b014 --- /dev/null +++ b/src/exit/assert_fail.c @@ -0,0 +1,16 @@ +// TODO: move to a proper place once I do abort() +#include +#include +#include + +_Noreturn void _assert_fail(const char *func, const char *msg) { + static const char msg0[] = "In function `"; + static const char msg1[] = "':\n"; + write(STDERR_FILENO, msg0, sizeof(msg0) - 1); + write(STDERR_FILENO, func, strlen(func)); + write(STDERR_FILENO, msg1, sizeof(msg1) - 1); + write(STDERR_FILENO, msg, strlen(msg)); + write(STDERR_FILENO, msg1 + 2, 1); + + _exit(-1); +} diff --git a/src/exit/exit.c b/src/exit/exit.c new file mode 100644 index 0000000..d90b9e5 --- /dev/null +++ b/src/exit/exit.c @@ -0,0 +1,6 @@ +#include + +void exit(int status) { + // TODO: call atexit()s here + _Exit(status); +} diff --git a/src/malloc/free.c b/src/malloc/free.c new file mode 100644 index 0000000..f1940ff --- /dev/null +++ b/src/malloc/free.c @@ -0,0 +1,58 @@ +#include <_libc/malloc.h> +#include +#include + +void free(void *ptr) { + if (!ptr) { + return; + } + struct block *block = ptr - sizeof(struct block); + + if ((block->flags & BLOCK_MAGIC_MASK) != BLOCK_MAGIC) { + while (1); + } + if (!(block->flags & BLOCK_ALLOC)) { + while (1); + } + + if (block->flags & BLOCK_MMAP) { + void *base = (void *) ((uintptr_t) block & ~0xFFF); + size_t len = block->size + 0x1000; + munmap(base, len); + return; + } + + block->flags &= ~BLOCK_ALLOC; + struct block *prev, *next; + prev = block->prev; + next = block->next; + + if (prev && !(prev->flags & BLOCK_ALLOC)) { + block->flags = 0; + prev->next = next; + if (next) { + next->prev = prev; + } + prev->size += block->size + sizeof(struct block); + + block = prev; + } + + if (next && !(next->flags & BLOCK_ALLOC)) { + next->flags = 0; + + if (next->next) { + next->next->prev = block; + } + block->next = next->next; + block->size += next->size + sizeof(struct block); + } + + if (!block->prev && !block->next) { + struct zone *zone = (void *) block - sizeof(struct zone); + assert(!((uintptr_t) zone & 0xFFF)); + list_del(&zone->list); + zone_destroy(zone); + } +} + diff --git a/src/malloc/malloc.c b/src/malloc/malloc.c new file mode 100644 index 0000000..be22b0d --- /dev/null +++ b/src/malloc/malloc.c @@ -0,0 +1,91 @@ +#include <_libc/malloc.h> +#include <_libc/list.h> +#include +#include +#include + +// Small zone allocation function +// XXX: This is absolute bullshit: meet my first fit allocator +static void *zone_alloc(struct zone *zone, size_t count) { + struct block *begin = (struct block *) &zone[1]; + + count = (count + 15) & ~15; + + for (struct block *block = begin; block; block = block->next) { + if (block->flags & BLOCK_ALLOC) { + continue; + } + + if (count == block->size) { + block->flags |= BLOCK_ALLOC; + void *ptr = &block[1]; + memset(ptr, 0, count); + return ptr; + } else if (block->size >= count + sizeof(struct block)) { + // Insert new block after this one + struct block *cur_next = block->next; + struct block *new_block = (struct block *) (((uintptr_t) block) + sizeof(struct block) + count); + if (cur_next) { + cur_next->prev = new_block; + } + new_block->next = cur_next; + new_block->prev = block; + new_block->size = block->size - sizeof(struct block) - count; + new_block->flags = BLOCK_MAGIC; + block->next = new_block; + block->size = count; + block->flags |= 1; + void *ptr = &block[1]; + memset(ptr, 0, count); + return ptr; + } + } + + return NULL; +} + +/// + +static void *alloc_from(struct list_head *head, size_t zone_size, size_t size) { + struct zone *zone; + void *ptr; + +try_again: + list_for_each_entry(zone, head, list) { + if ((ptr = zone_alloc(zone, size))) { + return ptr; + } + } + + zone = zone_create(zone_size); + if (!zone) { + return NULL; + } + list_add(&zone->list, head); + + goto try_again; +} + +void *malloc(size_t size) { + if (size <= SMALL_ZONE_ELEM) { + return alloc_from(&small_zone_list, SMALL_ZONE_SIZE, size); + } else if (size <= MID_ZONE_ELEM) { + return alloc_from(&mid_zone_list, MID_ZONE_SIZE, size); + } else if (size <= LARGE_ZONE_ELEM) { + return alloc_from(&large_zone_list, LARGE_ZONE_SIZE, size); + } else { + size_t pages_needed = (size + 0xFFF) & ~0xFFF; + void *pages = mmap(NULL, pages_needed + 0x1000, 0, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + + if (pages == MAP_FAILED) { + return NULL; + } + + struct block *block = pages + 0x1000 - sizeof(struct block); + block->flags = BLOCK_MAGIC | BLOCK_ALLOC | BLOCK_MMAP; + block->size = pages_needed; + + return pages + 0x1000; + } +} + diff --git a/src/malloc/realloc.c b/src/malloc/realloc.c new file mode 100644 index 0000000..e92fe21 --- /dev/null +++ b/src/malloc/realloc.c @@ -0,0 +1,26 @@ +#include <_libc/malloc.h> +#include +#include +#include + +void *realloc(void *old, size_t size) { + // TODO: maybe optimize this + void *ptr = malloc(size); + if (!ptr) { + return NULL; + } + + if (old) { + struct block *old_block = old - sizeof(struct block); + size_t less_size = size; + if (less_size > old_block->size) { + less_size = old_block->size; + } + assert((old_block->flags & BLOCK_MAGIC_MASK) == BLOCK_MAGIC); + memcpy(ptr, old, less_size); + free(old); + } + + return ptr; +} + diff --git a/src/malloc/zone.c b/src/malloc/zone.c new file mode 100644 index 0000000..57a704c --- /dev/null +++ b/src/malloc/zone.c @@ -0,0 +1,33 @@ +#include <_libc/malloc.h> +#include +#include + +LIST_HEAD(small_zone_list); +LIST_HEAD(mid_zone_list); +LIST_HEAD(large_zone_list); + +struct zone *zone_create(size_t size) { + void *pages = mmap(NULL, size, 0, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (pages == MAP_FAILED) { + return NULL; + } + + struct zone *zone = pages; + struct block *head = pages + sizeof(struct zone); + + zone->size = size - sizeof(struct zone); + list_head_init(&zone->list); + + head->size = size - sizeof(struct zone) - sizeof(struct block); + head->flags = BLOCK_MAGIC; + head->prev = NULL; + head->next = NULL; + + return zone; +} + +void zone_destroy(struct zone *zone) { + assert(!((uintptr_t) zone & 0xFFF)); + munmap(zone, zone->size + sizeof(struct zone)); +} + diff --git a/src/signal/handle.c b/src/signal/handle.c new file mode 100644 index 0000000..024d2a5 --- /dev/null +++ b/src/signal/handle.c @@ -0,0 +1,6 @@ +#include +#include <_libc/signal.h> + +void _sig_dfl(int signum) { + exit(signum << 8); +} diff --git a/src/signal/impl.c b/src/signal/impl.c new file mode 100644 index 0000000..63eeffe --- /dev/null +++ b/src/signal/impl.c @@ -0,0 +1,50 @@ +/* + * Yggdrasil's signal implementation details + */ +#include +#include +#include +#include <_libc/abort.h> +#include <_libc/signal.h> +#include <_libc/syscalls.h> + +static sighandler_t signal_handlers[NSIG]; + +// _Noreturn because this function *must* end up +// calling sigreturn syscall +static _Noreturn void __libc_signal_handle(int signum) { + if (signum <= 0 || signum >= NSIG) { + // TODO: abort() + exit(-1); + } + + if (signal_handlers[signum]) { + signal_handlers[signum](signum); + } else { + _sig_dfl(signum); + } + + __syscall0(SYSCALL_NR_SIGRETURN); + // To enforce _Noreturn + while (1); +} + +void __libc_signal_init(void) { + stack_t ss; + void *sig_stack; + + sig_stack = malloc(__LIBC_SIGNAL_STACK_SIZE); + if (sig_stack == NULL) { + __libc_abort_init("Failed to allocate signal stack"); + } + + // Tell kernel about signal stack + ss.ss_sp = sig_stack; + ss.ss_size = __LIBC_SIGNAL_STACK_SIZE; + if (sigaltstack(&ss, NULL) != 0) { + __libc_abort_init("Failed to set signal stack"); + } + + // Tell kernel about signal entry + __syscall1(SYSCALL_NRX_SIGENTRY, (long) __libc_signal_handle); +} diff --git a/src/signal/sigaltstack.c b/src/signal/sigaltstack.c new file mode 100644 index 0000000..72ef05b --- /dev/null +++ b/src/signal/sigaltstack.c @@ -0,0 +1,8 @@ +#include +#include +#include +#include <_libc/syscalls.h> + +int sigaltstack(const stack_t *ss, stack_t *old_ss) { + return SET_ERRNO(int, __syscall2(SYSCALL_NR_SIGALTSTACK, (long) ss, (long) old_ss)); +} diff --git a/src/signal/signal.c b/src/signal/signal.c new file mode 100644 index 0000000..e69de29 diff --git a/src/stdio/fgetc_unlocked.c b/src/stdio/fgetc_unlocked.c new file mode 100644 index 0000000..9b00b53 --- /dev/null +++ b/src/stdio/fgetc_unlocked.c @@ -0,0 +1,44 @@ +#include <_libc/stdio.h> +#include +#include + +int fgetc_unlocked(FILE *fp) { + if (fp->buf_mode == _IONBF) { + unsigned char c; + if (fread_unlocked(&c, sizeof(c), 1, fp) == 1) { + return c; + } + return EOF; + } + + if (fp->flags & FILE_FLAG_EOF) { + return 0; + } + if (!(fp->flags & FILE_MODE_READ)) { + errno = EBADF; + fp->flags |= FILE_FLAG_ERROR; + return 0; + } + + __libc_file_flush_write(fp); + + if (fp->rdbufpos >= fp->rdbuf) { + // Reached end of readbuf + // TODO: arbitrary buffer size setting? + ssize_t bread = fp->read(fp->ctx, fp->buf, BUFSIZ); + + if (bread < 0) { + fp->flags |= FILE_FLAG_ERROR; + return EOF; + } + if (bread == 0) { + fp->flags |= FILE_FLAG_EOF; + return EOF; + } + + fp->rdbufpos = 0; + fp->rdbuf = bread; + } + + return ((char *) fp->buf)[fp->rdbufpos++]; +} diff --git a/src/stdio/file.c b/src/stdio/file.c new file mode 100644 index 0000000..17fe80c --- /dev/null +++ b/src/stdio/file.c @@ -0,0 +1,89 @@ +#include <_libc/stdio.h> +#include +#include +#include +#include +#include + +static void file_default_free(void *ctx, FILE *fp) { + (void) ctx; + free(fp); +} + +FILE *__libc_file_create(void) { + FILE *res = malloc(sizeof(FILE) + BUFSIZ); + if (!res) { + errno = ENOMEM; + return NULL; + } + memset(res, 0, sizeof(FILE)); + + res->free = file_default_free; + res->buf = ((void *) res) + sizeof(FILE); + + return res; +} + +int __libc_file_mode(const char *mode) { + int flags = 0; + switch (*mode++) { + case 'r': + flags |= FILE_MODE_READ; + break; + case 'w': + flags |= FILE_MODE_WRITE | FILE_MODE_CREAT | FILE_MODE_TRUNC; + break; + case 'a': + flags |= FILE_MODE_WRITE | FILE_MODE_CREAT | FILE_MODE_APPEND; + break; + default: + return -1; + } + return flags; +} + +int __libc_file_flush_read(FILE *fp) { + if ((fp->flags & FILE_MODE_READ) && fp->seek) { + // TODO: off_t + long count = fp->rdbuf - fp->rdbufpos; + if (count < 0) { + count = fp->seek(fp->ctx, count, SEEK_CUR); + // Reset file read buffer + fp->rdbuf = 0; + fp->rdbufpos = 0; + if (count < 0) { + fp->flags |= FILE_FLAG_ERROR; + return -1; + } + } + } + + return 0; +} + +int __libc_file_flush_write(FILE *fp) { + if (fp->flags & FILE_MODE_WRITE) { + size_t rem = fp->wrbuf; + size_t off = 0; + + fp->wrbuf = 0; + + while (rem) { + ssize_t bwrite = fp->write(fp->ctx, fp->buf + off, rem); + + if (bwrite < 0) { + fp->flags |= FILE_FLAG_ERROR; + return -1; + } + if (bwrite == 0) { + fp->flags |= FILE_FLAG_EOF; + return -1; + } + + rem -= bwrite; + off += bwrite; + } + } + + return 0; +} diff --git a/src/stdio/file_file.c b/src/stdio/file_file.c new file mode 100644 index 0000000..06bcb51 --- /dev/null +++ b/src/stdio/file_file.c @@ -0,0 +1,130 @@ +#include <_libc/stdio.h> +#include +#include +#include +#include + +static ssize_t file_read(void *ctx, void *buf, size_t lim); +static ssize_t file_write(void *ctx, const void *buf, size_t lim); +static int file_close(void *ctx); + +char _stdin_buf[BUFSIZ]; +char _stdout_buf[BUFSIZ]; +char _stderr_buf[BUFSIZ]; + +FILE _stdin = { + .buf = _stdin_buf, + .buf_mode = _IOLBF, + .ctx = &_stdin, + .fd = STDIN_FILENO, + .free = NULL, + .read = file_read, + .write = file_write, + .close = file_close, + .flags = FILE_MODE_READ +}; +FILE _stdout = { + .buf = _stdout_buf, + .buf_mode = _IOLBF, + .ctx = &_stdout, + .fd = STDOUT_FILENO, + .free = NULL, + .read = file_read, + .write = file_write, + .close = file_close, + .flags = FILE_MODE_WRITE +}; +FILE _stderr = { + .buf = _stderr_buf, + .buf_mode = _IONBF, + .ctx = &_stdout, + .fd = STDERR_FILENO, + .free = NULL, + .read = file_read, + .write = file_write, + .close = file_close, + .flags = FILE_MODE_WRITE +}; + +FILE *const stdin = &_stdin; +FILE *const stdout = &_stdout; +FILE *const stderr = &_stderr; + +static ssize_t file_read(void *ctx, void *buf, size_t lim) { + return read(((FILE *) ctx)->fd, buf, lim); +} + +static ssize_t file_write(void *ctx, const void *buf, size_t lim) { + return write(((FILE *) ctx)->fd, buf, lim); +} + +static int file_close(void *ctx) { + return close(((FILE *) ctx)->fd); +} + +static long file_seek(void *ctx, long off, int whence) { + return lseek(((FILE *) ctx)->fd, off, whence); +} + +int __libc_file_open_fd(FILE *fp, int fd, int flags) { + // TODO: disallow certain combinations of params + if (flags & FILE_MODE_READ) { + fp->flags |= FILE_MODE_READ; + } + if (flags & FILE_MODE_WRITE) { + fp->flags |= FILE_MODE_WRITE; + } + + fp->fd = fd; + fp->ctx = fp; + + fp->read = file_read; + fp->write = file_write; + fp->close = file_close; + fp->seek = file_seek; + + return 0; +} + +int __libc_file_open_path(FILE *fp, const char *pathname, const char *mode) { + int flags, c_flags = 0; + if ((flags = __libc_file_mode(mode)) == -1) { + errno = EINVAL; + return -1; + } + + if (!(flags & (FILE_MODE_WRITE | FILE_MODE_READ))) { + errno = EINVAL; + return -1; + } + + if (flags & FILE_MODE_WRITE) { + if (flags & FILE_MODE_READ) { + c_flags |= O_RDWR; + } else { + c_flags |= O_WRONLY; + } + } else { + c_flags |= O_RDONLY; + } + if (flags & FILE_MODE_CREAT) { + c_flags |= O_CREAT; + } + if (flags & FILE_MODE_TRUNC) { + c_flags |= O_TRUNC; + } + + int fd = open(pathname, c_flags, 0666); + if (fd < 0) { + return -1; + } + + if (__libc_file_open_fd(fp, fd, flags) != 0) { + int e = errno; + close(fd); + errno = e; + return -1; + } + + return 0; +} diff --git a/src/stdio/flockfile.c b/src/stdio/flockfile.c new file mode 100644 index 0000000..ecd7cc5 --- /dev/null +++ b/src/stdio/flockfile.c @@ -0,0 +1,6 @@ +#include + +void flockfile(FILE *fp) { + // TODO: pthread mutices + (void) fp; +} diff --git a/src/stdio/fopen.c b/src/stdio/fopen.c new file mode 100644 index 0000000..5d40d2c --- /dev/null +++ b/src/stdio/fopen.c @@ -0,0 +1,20 @@ +#include <_libc/stdio.h> +#include +#include +#include + +FILE *fopen(const char *pathname, const char *mode) { + FILE *fp = __libc_file_create(); + if (!fp) { + return NULL; + } + + if (__libc_file_open_path(fp, pathname, mode) != 0) { + int e = errno; + fclose(fp); + errno = e; + return NULL; + } + + return fp; +} diff --git a/src/stdio/fputc_unlocked.c b/src/stdio/fputc_unlocked.c new file mode 100644 index 0000000..9623d4b --- /dev/null +++ b/src/stdio/fputc_unlocked.c @@ -0,0 +1,30 @@ +#include <_libc/stdio.h> +#include +#include + +int fputc_unlocked(int ch, FILE *fp) { + if (fp->buf_mode == _IONBF) { + unsigned char c = ch; + if (fwrite_unlocked(&c, sizeof(c), 1, fp) == 1) { + return c; + } + return EOF; + } + if (!(fp->flags & FILE_MODE_WRITE)) { + errno = EBADF; + fp->flags |= FILE_FLAG_ERROR; + return 0; + } + + __libc_file_flush_read(fp); + + ((char *) fp->buf)[fp->wrbuf++] = ch; + + if ((fp->buf_mode == _IOLBF && ch == '\n') || fp->wrbuf >= BUFSIZ) { + if (__libc_file_flush_write(fp) != 0) { + return EOF; + } + } + + return ch; +} diff --git a/src/stdio/fread.c b/src/stdio/fread.c new file mode 100644 index 0000000..844f505 --- /dev/null +++ b/src/stdio/fread.c @@ -0,0 +1,8 @@ +#include + +size_t fread(void *buf, size_t size, size_t nmemb, FILE *fp) { + flockfile(fp); + size_t r = fread_unlocked(buf, size, nmemb, fp); + funlockfile(fp); + return r; +} diff --git a/src/stdio/fread_unlocked.c b/src/stdio/fread_unlocked.c new file mode 100644 index 0000000..90f5165 --- /dev/null +++ b/src/stdio/fread_unlocked.c @@ -0,0 +1,31 @@ +#include <_libc/stdio.h> +#include +#include + +size_t fread_unlocked(void *buf, size_t size, size_t nmemb, FILE *fp) { + // TODO: buffering + if (!(fp->flags & FILE_MODE_READ)) { + errno = EBADF; + fp->flags |= FILE_FLAG_ERROR; + return 0; + } + + size_t rem = size * nmemb; + size_t off = 0; + fp->flags &= ~FILE_FLAG_EOF; + while (rem) { + ssize_t bread = fp->read(fp->ctx, buf + off, rem); + if (bread < 0) { + fp->flags |= FILE_FLAG_ERROR; + return off / size; + } + if (bread == 0) { + fp->flags |= FILE_FLAG_EOF; + return off / size; + } + off += bread; + rem -= bread; + } + + return off / size; +} diff --git a/src/stdio/funlockfile.c b/src/stdio/funlockfile.c new file mode 100644 index 0000000..831fdd6 --- /dev/null +++ b/src/stdio/funlockfile.c @@ -0,0 +1,6 @@ +#include + +void funlockfile(FILE *fp) { + // TODO: pthread mutices + (void) fp; +} diff --git a/src/stdio/fwrite.c b/src/stdio/fwrite.c new file mode 100644 index 0000000..4197c2b --- /dev/null +++ b/src/stdio/fwrite.c @@ -0,0 +1,8 @@ +#include + +size_t fwrite(const void *data, size_t size, size_t nmemb, FILE *fp) { + flockfile(fp); + size_t r = fwrite_unlocked(data, size, nmemb, fp); + funlockfile(fp); + return r; +} diff --git a/src/stdio/fwrite_unlocked.c b/src/stdio/fwrite_unlocked.c new file mode 100644 index 0000000..be79d91 --- /dev/null +++ b/src/stdio/fwrite_unlocked.c @@ -0,0 +1,53 @@ +#include <_libc/stdio.h> +#include +#include +#include + +size_t fwrite_unlocked(const void *ptr, size_t size, size_t nmemb, FILE *fp) { + assert(fp); + if (fp->flags & FILE_FLAG_EOF) { + return 0; + } + + if (!(fp->flags & FILE_MODE_WRITE)) { + errno = EBADF; + fp->flags |= FILE_FLAG_ERROR; + return 0; + } + + if (fp->buf_mode == _IONBF) { + size_t rem = size * nmemb; + size_t off = 0; + + fp->flags &= ~FILE_FLAG_EOF; + while (rem) { + ssize_t res = fp->write(fp->ctx, ptr + off, rem); + if (res < 0) { + // Signalled error + fp->flags |= FILE_FLAG_ERROR; + return off / size; + } + if (res == 0) { + // Signalled EOF + fp->flags |= FILE_FLAG_EOF; + return off /size; + } + off += res; + rem -= res; + } + + return off / size; + } + + for (size_t i = 0; i < size * nmemb; i += size) { + for (size_t b = 0; b < size; ++b) { + int r = fputc_unlocked(((char *) ptr)[i + b], fp); + + if (r < 0) { + return i / size; + } + } + } + + return nmemb; +} diff --git a/src/string/memccpy.c b/src/string/memccpy.c new file mode 100644 index 0000000..e5f2557 --- /dev/null +++ b/src/string/memccpy.c @@ -0,0 +1,11 @@ +#include + +void *memccpy(void *dst, const void *src, int c, size_t len) { + for (size_t i = 0; i < len; ++i) { + ((unsigned char *) dst)[i] = ((unsigned char *) src)[i]; + if (((unsigned char *) dst)[i] == c) { + return dst + i; + } + } + return NULL; +} diff --git a/src/string/memchr.c b/src/string/memchr.c new file mode 100644 index 0000000..254ce68 --- /dev/null +++ b/src/string/memchr.c @@ -0,0 +1,10 @@ +#include + +void *memchr(const void *ptr, int v, size_t len) { + for (size_t i = 0; i < len; ++i) { + if (((unsigned char *) ptr)[i] == v) { + return (void *) ptr + i; + } + } + return NULL; +} diff --git a/src/string/memcmp.c b/src/string/memcmp.c new file mode 100644 index 0000000..9f819d0 --- /dev/null +++ b/src/string/memcmp.c @@ -0,0 +1,12 @@ +#include + +int memcmp(const void *p0, const void *p1, size_t n) { + int diff; + for (size_t i = 0; i < n; ++i) { + diff = ((unsigned char *) p0)[i] - ((unsigned char *) p1)[i]; + if (diff) { + return diff; + } + } + return 0; +} diff --git a/src/string/memcpy.c b/src/string/memcpy.c new file mode 100644 index 0000000..47e28b3 --- /dev/null +++ b/src/string/memcpy.c @@ -0,0 +1,8 @@ +#include + +void *memcpy(void *dst, const void *src, size_t sz) { + for (size_t i = 0; i < sz; ++i) { + ((unsigned char *) dst)[i] = ((unsigned char *) src)[i]; + } + return dst; +} diff --git a/src/string/memmove.c b/src/string/memmove.c new file mode 100644 index 0000000..c761ac4 --- /dev/null +++ b/src/string/memmove.c @@ -0,0 +1,24 @@ +#include + +void *memmove(void *dest, const void *src, size_t n) { + if (dest == src) { + return dest; + } + + if ((src + n) <= dest || (dest + n) <= src) { + return memcpy(dest, src, n); + } + + if (dest < src) { + ptrdiff_t a = src - dest; + memcpy( dest, src, a); + memcpy((void *) src, src + a, n - a); + } else { + ptrdiff_t a = dest - src; + memcpy( dest + a, dest, n - a); + memcpy( dest, src, a); + } + + return dest; +} + diff --git a/src/string/memset.c b/src/string/memset.c new file mode 100644 index 0000000..149c9b6 --- /dev/null +++ b/src/string/memset.c @@ -0,0 +1,8 @@ +#include + +void *memset(void *ptr, int v, size_t len) { + for (size_t i = 0; i < len; ++i) { + ((unsigned char *) ptr)[i] = v; + } + return ptr; +} diff --git a/src/string/stpcpy.c b/src/string/stpcpy.c new file mode 100644 index 0000000..7f5962e --- /dev/null +++ b/src/string/stpcpy.c @@ -0,0 +1,27 @@ +#include + +char *stpcpy(char *dest, const char *src) { + do { + *dest = *src; + if (!*src++) { + return dest; + } + ++dest; + } while (1); +} + +char *stpncpy(char *dest, const char *src, size_t n) { + if (!n) { + return dest; + } + do { + *dest = *src; + if (!*src++) { + return dest; + } + ++dest; + if (!--n) { + return dest; + } + } while (1); +} diff --git a/src/string/strcat.c b/src/string/strcat.c new file mode 100644 index 0000000..b610f01 --- /dev/null +++ b/src/string/strcat.c @@ -0,0 +1,25 @@ +#include + +char *strcat(char *dst, const char *src) { + size_t len = strlen(dst); + for (size_t i = 0;; ++i) { + dst[len + i] = src[i]; + if (!src[i]) { + break; + } + } + return dst; +} + +char *strncat(char *dst, const char *src, size_t n) { + size_t d = strlen(dst); + size_t i; + + for (i = 0; i < n && src[i]; ++i) { + dst[d + i] = src[i]; + } + dst[d + i] = 0; + + return dst; +} + diff --git a/src/string/strchr.c b/src/string/strchr.c new file mode 100644 index 0000000..ff11cc5 --- /dev/null +++ b/src/string/strchr.c @@ -0,0 +1,23 @@ +#include + +char *strchr(const char *str, int chr) { + for (; *str; ++str) { + if (*str == chr) { + return (char *) str; + } + } + return NULL; +} + +char *strrchr(const char *str, int chr) { + size_t len = strlen(str); + if (!len) { + return NULL; + } + while (--len) { + if (str[len] == chr) { + return (char *) &str[len]; + } + } + return NULL; +} diff --git a/src/string/strcmp.c b/src/string/strcmp.c new file mode 100644 index 0000000..a646d77 --- /dev/null +++ b/src/string/strcmp.c @@ -0,0 +1,27 @@ +#include + +int strcmp(const char *a, const char *b) { + for (;; ++a, ++b) { + int delta = *a - *b; + if (delta) { + return delta; + } + if (!*a) { // Implies !*b + break; + } + } + return 0; +} + +int strncmp(const char *a, const char *b, size_t lim) { + for (; lim; ++a, ++b, --lim) { + int delta = *a - *b; + if (delta) { + return delta; + } + if (!*a) { // Implies !*b + break; + } + } + return 0; +} diff --git a/src/string/strcoll.c b/src/string/strcoll.c new file mode 100644 index 0000000..98f46b7 --- /dev/null +++ b/src/string/strcoll.c @@ -0,0 +1,6 @@ +#include + +// XXX: Not actually implemented - current locale is C +int strcoll(const char *a, const char *b) { + return strcmp(a, b); +} diff --git a/src/string/strcpy.c b/src/string/strcpy.c new file mode 100644 index 0000000..1f118b4 --- /dev/null +++ b/src/string/strcpy.c @@ -0,0 +1,23 @@ +#include + +char *strcpy(char *dst, const char *src) { + size_t i; + for (i = 0;; ++i) { + dst[i] = src[i]; + if (!src[i]) { + break; + } + } + return dst; +} + +char *strncpy(char *dst, const char *src, size_t n) { + size_t i; + for (i = 0; i < n; ++i) { + dst[i] = src[i]; + if (!src[i]) { + break; + } + } + return dst; +} diff --git a/src/string/strdup.c b/src/string/strdup.c new file mode 100644 index 0000000..070798b --- /dev/null +++ b/src/string/strdup.c @@ -0,0 +1,21 @@ +#include +#include + +char *strdup(const char *str) { + char *ptr = malloc(strlen(str) + 1); + if (ptr) { + strcpy(ptr, str); + } + return ptr; +} + +char *strndup(const char *str, size_t len) { + char *ptr; + size_t l = strnlen(str, len); + ptr = malloc(l + 1); + if (ptr) { + strncpy(ptr, str, l); + ptr[l] = 0; + } + return ptr; +} diff --git a/src/string/strerror.c b/src/string/strerror.c new file mode 100644 index 0000000..25a85d5 --- /dev/null +++ b/src/string/strerror.c @@ -0,0 +1,24 @@ +#include + +// "Lower" group of errors +static const char *error0[64] = {}; + +char *strerror(int errnum) { + if (!errnum) { + return "success"; + } + if (errnum < 0 || errnum >= 64 || !error0[errnum]) { + return "unknown error"; + } + return (char *) error0[errnum]; +} + +int strerror_r(int errnum, char *buf, size_t len) { + const char *err = strerror(errnum); + if (!len) { + return -1; + } + strncpy(buf, err, len - 1); + buf[len - 1] = 0; + return 0; +} diff --git a/src/string/strlen.c b/src/string/strlen.c new file mode 100644 index 0000000..a65fa02 --- /dev/null +++ b/src/string/strlen.c @@ -0,0 +1,13 @@ +#include + +size_t strlen(const char *s) { + size_t r; + for (r = 0; s[r]; ++r); + return r; +} + +size_t strnlen(const char *s, size_t len) { + size_t r; + for (r = 0; r < len && s[r]; ++r); + return r; +} diff --git a/src/string/strpbrk.c b/src/string/strpbrk.c new file mode 100644 index 0000000..baaccac --- /dev/null +++ b/src/string/strpbrk.c @@ -0,0 +1,10 @@ +#include + +char *strpbrk(const char *str, const char *accept) { + for (; *str; ++str) { + if (strchr(accept, *str)) { + return (char *) str; + } + } + return NULL; +} diff --git a/src/string/strsignal.c b/src/string/strsignal.c new file mode 100644 index 0000000..30c06f2 --- /dev/null +++ b/src/string/strsignal.c @@ -0,0 +1,12 @@ +#include +#include + +static const char *signal0[NSIG] = { +}; + +char *strsignal(int signum) { + if (signum <= 0 || signum >= NSIG) { + return "unknown signal"; + } + return (char *) signal0[signum]; +} diff --git a/src/string/strspn.c b/src/string/strspn.c new file mode 100644 index 0000000..10c3f77 --- /dev/null +++ b/src/string/strspn.c @@ -0,0 +1,27 @@ +#include + +size_t strspn(const char *s, const char *accept) { + size_t l = 0; + + while (*s) { + if (!strchr(accept, *s)) { + return l; + } + ++l; + ++s; + } + return l; +} + +size_t strcspn(const char *s, const char *reject) { + size_t l = 0; + + while (*s) { + if (strchr(reject, *s)) { + return l; + } + ++l; + ++s; + } + return l; +} diff --git a/src/string/strstr.c b/src/string/strstr.c new file mode 100644 index 0000000..55586dd --- /dev/null +++ b/src/string/strstr.c @@ -0,0 +1,17 @@ +#include + +char *_strstr(const char *haystack, const char *needle) { + // TODO: maybe use KMP algorithm for small needle sizes + size_t n = strlen(needle); + if (!*needle && !*haystack) { + return (char *) haystack; + } + + for (size_t i = 0; haystack[i]; ++i) { + if (!strncmp(haystack + i, needle, n)) { + return (char *) haystack + i; + } + } + return NULL; +} + diff --git a/src/string/strtok.c b/src/string/strtok.c new file mode 100644 index 0000000..8a7824a --- /dev/null +++ b/src/string/strtok.c @@ -0,0 +1,38 @@ +#include + +char *strtok_r(char *str, const char *delim, char **saveptr) { + char *token; + + if (!str) { + str = *saveptr; + } + + // Skip leading delimiter + str += strspn(str, delim); + if (!*str) { + *saveptr = str; + // No next token - NULL + return NULL; + } + + token = str; + str = strpbrk(str, delim); + if (str) { + // Have a delimiter + *str = 0; + *saveptr = str + 1; + } else { + // Point to end + *saveptr = token + strlen(token); + } + return token; +} + +// TODO: throw an error "programmer" for using this +char *strtok(char *str, const char *delim) { + static char *saveptr; + if (str) { + saveptr = NULL; + } + return strtok_r(str, delim, &saveptr); +} diff --git a/src/sys/syscall_io.c b/src/sys/syscall_io.c new file mode 100644 index 0000000..3cfeb70 --- /dev/null +++ b/src/sys/syscall_io.c @@ -0,0 +1,8 @@ +#include <_libc/syscalls.h> +#include +#include +#include + +int open(const char *pathname, int flags, mode_t mode) { + return SET_ERRNO(int, __syscall3(SYSCALL_NR_OPEN, (long) pathname, flags, mode)); +} diff --git a/src/sys/syscall_mem.c b/src/sys/syscall_mem.c new file mode 100644 index 0000000..440b2ab --- /dev/null +++ b/src/sys/syscall_mem.c @@ -0,0 +1,24 @@ +#include <_libc/syscalls.h> +#include +#include +#include + +void *mmap(void *hint, size_t length, int prot, int flags, int fd, off_t offset) { + intptr_t res = (intptr_t) __syscall6(SYSCALL_NR_MMAP, + (long) hint, + length, + (long) prot, + (long) flags, + (long) fd, + offset); + if (res < 0) { + errno = (int) -res; + return (void *) -1; + } else { + return (void *) res; + } +} + +int munmap(void *ptr, size_t len) { + return SET_ERRNO(int, __syscall2(SYSCALL_NR_MUNMAP, (long) ptr, len)); +} diff --git a/src/unistd/_exit.c b/src/unistd/_exit.c new file mode 100644 index 0000000..aa41aad --- /dev/null +++ b/src/unistd/_exit.c @@ -0,0 +1,11 @@ +#include <_libc/syscalls.h> +#include +#include +#include + +_Noreturn void _exit(int status) { + __syscall1(SYSCALL_NR_EXIT, status); + while (1); +} + +_Noreturn void _Exit(int status) __attribute__((alias("_exit"))); diff --git a/src/unistd/access.c b/src/unistd/access.c new file mode 100644 index 0000000..eb25891 --- /dev/null +++ b/src/unistd/access.c @@ -0,0 +1,8 @@ +#include +#include <_libc/syscalls.h> +#include +#include + +int access(const char *pathname, int mode) { + return SET_ERRNO(int, __syscall2(SYSCALL_NR_ACCESS, (long) pathname, mode)); +} diff --git a/src/unistd/chdir.c b/src/unistd/chdir.c new file mode 100644 index 0000000..fe19e3e --- /dev/null +++ b/src/unistd/chdir.c @@ -0,0 +1,8 @@ +#include <_libc/syscalls.h> +#include +#include +#include + +int chdir(const char *pathname) { + return SET_ERRNO(int, __syscall1(SYSCALL_NR_CHDIR, (long) pathname)); +} diff --git a/src/unistd/chown.c b/src/unistd/chown.c new file mode 100644 index 0000000..c3b1bcb --- /dev/null +++ b/src/unistd/chown.c @@ -0,0 +1,8 @@ +#include <_libc/syscalls.h> +#include +#include +#include + +int chown(const char *pathname, uid_t uid, gid_t gid) { + return SET_ERRNO(int, __syscall3(SYSCALL_NR_CHOWN, (long) pathname, uid, gid)); +} diff --git a/src/unistd/close.c b/src/unistd/close.c new file mode 100644 index 0000000..652572c --- /dev/null +++ b/src/unistd/close.c @@ -0,0 +1,10 @@ +#include <_libc/syscalls.h> +#include +#include +#include + +int close(int fd) { + __syscall1(SYSCALL_NR_CLOSE, fd); + errno = 0; + return 0; +} diff --git a/src/unistd/confstr.c b/src/unistd/confstr.c new file mode 100644 index 0000000..fd77509 --- /dev/null +++ b/src/unistd/confstr.c @@ -0,0 +1,11 @@ +#include +#include + +size_t confstr(int name, char *buf, size_t len) { + (void) name; + (void) buf; + (void) len; + // TODO: _CS_PATH + errno = EINVAL; + return 0; +} diff --git a/src/unistd/dup.c b/src/unistd/dup.c new file mode 100644 index 0000000..425a82e --- /dev/null +++ b/src/unistd/dup.c @@ -0,0 +1,8 @@ +#include <_libc/syscalls.h> +#include +#include +#include + +int dup(int oldfd) { + return SET_ERRNO(int, __syscall1(SYSCALL_NR_DUP, oldfd)); +} diff --git a/src/unistd/dup2.c b/src/unistd/dup2.c new file mode 100644 index 0000000..9db290c --- /dev/null +++ b/src/unistd/dup2.c @@ -0,0 +1,9 @@ +#include <_libc/syscalls.h> +#include +#include +#include + +int dup2(int oldfd, int newfd) { + return SET_ERRNO(int, __syscall2(SYSCALL_NR_DUP2, oldfd, newfd)); +} + diff --git a/src/unistd/execl.c b/src/unistd/execl.c new file mode 100644 index 0000000..3ed34f8 --- /dev/null +++ b/src/unistd/execl.c @@ -0,0 +1,44 @@ +#include +#include +#include +#include + +int execl(const char *pathname, const char *arg, ...) { + va_list args; + size_t argc; + int res; + + if (!arg) { + // execv pathname without arguments + return execv(pathname, (char *const *) &arg); + } + + // 1. collect arg count + va_start(args, arg); + while (va_arg(args, const char *)) { + ++argc; + } + va_end(args); + + // 2. allocate space for args + char **argv = malloc(sizeof(char *) * (argc + 1)); + if (!argv) { + errno = ENOMEM; + return -1; + } + + // 3. copy args + va_start(args, arg); + for (size_t i = 0; i < argc; ++i) { + argv[i] = va_arg(args, char *); + } + va_end(args); + argv[argc] = NULL; + + res = execv(pathname, argv); + + // Won't return normally, so free() + free(argv); + + return res; +} diff --git a/src/unistd/execle.c b/src/unistd/execle.c new file mode 100644 index 0000000..f2c3bee --- /dev/null +++ b/src/unistd/execle.c @@ -0,0 +1,49 @@ +#include +#include +#include +#include + +int execle(const char *pathname, const char *arg, ...) { + va_list args; + char *const *envp; + size_t argc; + int res; + + if (!arg) { + va_start(args, arg); + char *const *envp = va_arg(args, char *const *); + va_end(args); + + return execve(pathname, (char *const *) &arg, envp); + } + + // 1. collect arg count + va_start(args, arg); + while (va_arg(args, const char *)) { + ++argc; + } + va_end(args); + + // 2. allocate space for args + char **argv = malloc(sizeof(char *) * (argc + 1)); + if (!argv) { + errno = ENOMEM; + return -1; + } + + // 3. copy args + va_start(args, arg); + for (size_t i = 0; i < argc; ++i) { + argv[i] = va_arg(args, char *); + } + envp = va_arg(args, char *const *); + va_end(args); + argv[argc] = NULL; + + res = execve(pathname, argv, envp); + + // Won't return normally, so free() + free(argv); + + return res; +} diff --git a/src/unistd/execlp.c b/src/unistd/execlp.c new file mode 100644 index 0000000..e9075c7 --- /dev/null +++ b/src/unistd/execlp.c @@ -0,0 +1,10 @@ +#include +#include + +int execlp(const char *file, const char *arg, ...) { + (void) file; + (void) arg; + // TODO: PATH search impl. + assert(0 && "function not implemented"); +} + diff --git a/src/unistd/execv.c b/src/unistd/execv.c new file mode 100644 index 0000000..c9ec524 --- /dev/null +++ b/src/unistd/execv.c @@ -0,0 +1,5 @@ +#include + +int execv(const char *pathname, char *const argv[]) { + return execve(pathname, argv, environ); +} diff --git a/src/unistd/execve.c b/src/unistd/execve.c new file mode 100644 index 0000000..139e148 --- /dev/null +++ b/src/unistd/execve.c @@ -0,0 +1,8 @@ +#include <_libc/syscalls.h> +#include +#include +#include + +int execve(const char *pathname, char *const argv[], char *const envp[]) { + return SET_ERRNO(int, __syscall3(SYSCALL_NR_EXECVE, (long) pathname, (long) argv, (long) envp)); +} diff --git a/src/unistd/execvp.c b/src/unistd/execvp.c new file mode 100644 index 0000000..65c28d9 --- /dev/null +++ b/src/unistd/execvp.c @@ -0,0 +1,10 @@ +#include +#include + +int execvp(const char *file, char *const argv[]) { + (void) file; + (void) argv; + // TODO: PATH search impl. + assert(0 && "function not implemented"); +} + diff --git a/src/unistd/faccessat.c b/src/unistd/faccessat.c new file mode 100644 index 0000000..bb4ff1a --- /dev/null +++ b/src/unistd/faccessat.c @@ -0,0 +1,14 @@ +#include <_libc/syscalls.h> +#include +#include +#include +#include + +int faccessat(int dfd, const char *pathname, int mode, int flags) { + (void) dfd; + (void) pathname; + (void) mode; + (void) flags; + assert(0 && "system call not yet implemented"); +} + diff --git a/src/unistd/fchdir.c b/src/unistd/fchdir.c new file mode 100644 index 0000000..e9bc2ba --- /dev/null +++ b/src/unistd/fchdir.c @@ -0,0 +1,11 @@ +#include <_libc/syscalls.h> +#include +#include +#include +#include + +int fchdir(int dfd) { + (void) dfd; + assert(0 && "system call not yet implemented"); +} + diff --git a/src/unistd/fchown.c b/src/unistd/fchown.c new file mode 100644 index 0000000..4ae7867 --- /dev/null +++ b/src/unistd/fchown.c @@ -0,0 +1,12 @@ +#include <_libc/syscalls.h> +#include +#include +#include +#include + +int fchown(int fd, uid_t uid, gid_t gid) { + (void) fd; + (void) uid; + (void) gid; + assert(0 && "system call not yet implemented"); +} diff --git a/src/unistd/fchownat.c b/src/unistd/fchownat.c new file mode 100644 index 0000000..344c813 --- /dev/null +++ b/src/unistd/fchownat.c @@ -0,0 +1,14 @@ +#include <_libc/syscalls.h> +#include +#include +#include +#include + +int fchownat(int dfd, const char *pathname, uid_t uid, gid_t gid, int flags) { + (void) dfd; + (void) pathname; + (void) uid; + (void) gid; + (void) flags; + assert(0 && "system call not yet implemented"); +} diff --git a/src/unistd/fdatasync.c b/src/unistd/fdatasync.c new file mode 100644 index 0000000..6ced854 --- /dev/null +++ b/src/unistd/fdatasync.c @@ -0,0 +1,11 @@ +#include <_libc/syscalls.h> +#include +#include +#include + +int fdatasync(int fd) { + (void) fd; + // FS is synchronous lol + return 0; +} + diff --git a/src/unistd/fexecve.c b/src/unistd/fexecve.c new file mode 100644 index 0000000..134ee43 --- /dev/null +++ b/src/unistd/fexecve.c @@ -0,0 +1,13 @@ +#include <_libc/syscalls.h> +#include +#include +#include +#include + +int fexecve(int fd, char *const argv[], char *const envp[]) { + (void) fd; + (void) argv; + (void) envp; + assert(0 && "system call not yet implemented"); +} + diff --git a/src/unistd/fork.c b/src/unistd/fork.c new file mode 100644 index 0000000..1364b08 --- /dev/null +++ b/src/unistd/fork.c @@ -0,0 +1,9 @@ +#include <_libc/syscalls.h> +#include +#include +#include + +pid_t fork(void) { + return SET_ERRNO(pid_t, __syscall0(SYSCALL_NR_FORK)); +} + diff --git a/src/unistd/fpathconf.c b/src/unistd/fpathconf.c new file mode 100644 index 0000000..43a1c09 --- /dev/null +++ b/src/unistd/fpathconf.c @@ -0,0 +1,12 @@ +#include <_libc/syscalls.h> +#include +#include +#include +#include + +long fpathconf(int fd, int name) { + (void) fd; + (void) name; + assert(0 && "system call not yet implemented"); +} + diff --git a/src/unistd/fsync.c b/src/unistd/fsync.c new file mode 100644 index 0000000..818589b --- /dev/null +++ b/src/unistd/fsync.c @@ -0,0 +1,11 @@ +#include <_libc/syscalls.h> +#include +#include +#include + +int fsync(int fd) { + (void) fd; + // FS is synchronous lol + return 0; +} + diff --git a/src/unistd/ftruncate.c b/src/unistd/ftruncate.c new file mode 100644 index 0000000..1f18bcf --- /dev/null +++ b/src/unistd/ftruncate.c @@ -0,0 +1,12 @@ +#include +#include +#include +#include + +int ftruncate(int fd, off_t size) { + (void) fd; + (void) size; + assert(0 && "system call not yet implemented"); +} + + diff --git a/src/unistd/getcwd.c b/src/unistd/getcwd.c new file mode 100644 index 0000000..40d332b --- /dev/null +++ b/src/unistd/getcwd.c @@ -0,0 +1,13 @@ +#include <_libc/syscalls.h> +#include +#include +#include +#include + +char *getcwd(char *buf, size_t size) { + if (SET_ERRNO(int, __syscall2(SYSCALL_NR_GETCWD, (long) buf, size)) == 0) { + return buf; + } else { + return NULL; + } +} diff --git a/src/unistd/getegid.c b/src/unistd/getegid.c new file mode 100644 index 0000000..135ae24 --- /dev/null +++ b/src/unistd/getegid.c @@ -0,0 +1,6 @@ +#include + +gid_t getegid(void) { + // TODO: differentiate between gid and egid + return getgid(); +} diff --git a/src/unistd/geteuid.c b/src/unistd/geteuid.c new file mode 100644 index 0000000..3842374 --- /dev/null +++ b/src/unistd/geteuid.c @@ -0,0 +1,6 @@ +#include + +uid_t geteuid(void) { + // TODO: differentiate between uid and euid + return getuid(); +} diff --git a/src/unistd/getgid.c b/src/unistd/getgid.c new file mode 100644 index 0000000..3dbe925 --- /dev/null +++ b/src/unistd/getgid.c @@ -0,0 +1,8 @@ +#include <_libc/syscalls.h> +#include +#include +#include + +gid_t getgid(void) { + return __syscall0(SYSCALL_NR_GETGID); +} diff --git a/src/unistd/getgroups.c b/src/unistd/getgroups.c new file mode 100644 index 0000000..3e0098d --- /dev/null +++ b/src/unistd/getgroups.c @@ -0,0 +1,8 @@ +#include + +int getgroups(int size, gid_t list[]) { + (void) size; + (void) list; + // TODO: supplementary groups + return 0; +} diff --git a/src/unistd/gethostid.c b/src/unistd/gethostid.c new file mode 100644 index 0000000..2c01c19 --- /dev/null +++ b/src/unistd/gethostid.c @@ -0,0 +1,5 @@ +#include + +long gethostid(void) { + return 0; +} diff --git a/src/unistd/gethostname.c b/src/unistd/gethostname.c new file mode 100644 index 0000000..574b04a --- /dev/null +++ b/src/unistd/gethostname.c @@ -0,0 +1,20 @@ +#include +#include +#include + +// TODO: sys/utsname.h +#include +extern int uname(struct utsname *buf); + +int gethostname(char *name, size_t len) { + // Use uname to retrieve hostname + struct utsname v; + if (!len || uname(&v) != 0) { + return -1; + } + + strncpy(name, v.nodename, len - 1); + name[len] = 0; + + return 0; +} diff --git a/src/unistd/getlogin_r.c b/src/unistd/getlogin_r.c new file mode 100644 index 0000000..b05ab1a --- /dev/null +++ b/src/unistd/getlogin_r.c @@ -0,0 +1,10 @@ +#include +#include + +int getlogin_r(char *buf, size_t bufsize) { + (void) buf; + (void) bufsize; + // TODO: read pwd for username + errno = ENOENT; + return -1; +} diff --git a/src/unistd/getpgid.c b/src/unistd/getpgid.c new file mode 100644 index 0000000..8ebb589 --- /dev/null +++ b/src/unistd/getpgid.c @@ -0,0 +1,8 @@ +#include <_libc/syscalls.h> +#include +#include +#include + +pid_t getpgid(pid_t pid) { + return SET_ERRNO(pid_t, __syscall1(SYSCALL_NR_GETPGID, pid)); +} diff --git a/src/unistd/getpgrp.c b/src/unistd/getpgrp.c new file mode 100644 index 0000000..923650e --- /dev/null +++ b/src/unistd/getpgrp.c @@ -0,0 +1,5 @@ +#include + +pid_t getpgrp(void) { + return getpgid(0); +} diff --git a/src/unistd/getpid.c b/src/unistd/getpid.c new file mode 100644 index 0000000..ac568b4 --- /dev/null +++ b/src/unistd/getpid.c @@ -0,0 +1,8 @@ +#include <_libc/syscalls.h> +#include +#include +#include + +pid_t getpid(void) { + return (pid_t) __syscall0(SYSCALL_NR_GETPID); +} diff --git a/src/unistd/getppid.c b/src/unistd/getppid.c new file mode 100644 index 0000000..28cc95c --- /dev/null +++ b/src/unistd/getppid.c @@ -0,0 +1,7 @@ +#include +#include +#include + +pid_t getppid(void) { + assert(0 && "System call not yet implemented"); +} diff --git a/src/unistd/getsid.c b/src/unistd/getsid.c new file mode 100644 index 0000000..478996e --- /dev/null +++ b/src/unistd/getsid.c @@ -0,0 +1,6 @@ +#include +#include + +pid_t getsid(void) { + assert(0 && "System call not yet implemented"); +} diff --git a/src/unistd/getuid.c b/src/unistd/getuid.c new file mode 100644 index 0000000..2abe5f8 --- /dev/null +++ b/src/unistd/getuid.c @@ -0,0 +1,8 @@ +#include <_libc/syscalls.h> +#include +#include +#include + +uid_t getuid(void) { + return __syscall0(SYSCALL_NR_GETUID); +} diff --git a/src/unistd/isatty.c b/src/unistd/isatty.c new file mode 100644 index 0000000..8eda3af --- /dev/null +++ b/src/unistd/isatty.c @@ -0,0 +1,17 @@ +#include <_libc/syscalls.h> +#include +#include +#include +#include + +// TODO: termios.h +extern int tcgetattr(int fd, struct termios *t); + +int isatty(int fd) { + struct termios dummy; + if (tcgetattr(fd, &dummy) == 0) { + return 1; + } else { + return 0; + } +} diff --git a/src/unistd/lchown.c b/src/unistd/lchown.c new file mode 100644 index 0000000..f421d9e --- /dev/null +++ b/src/unistd/lchown.c @@ -0,0 +1,11 @@ +#include +#include +#include +#include + +int lchown(const char *pathname, uid_t uid, gid_t gid) { + (void) pathname; + (void) uid; + (void) gid; + assert(0 && "system call not yet implemented"); +} diff --git a/src/unistd/link.c b/src/unistd/link.c new file mode 100644 index 0000000..80144e6 --- /dev/null +++ b/src/unistd/link.c @@ -0,0 +1,11 @@ +#include +#include +#include +#include + +int link(const char *old, const char *new) { + (void) old; + (void) new; + assert(0 && "system call not yet implemented"); +} + diff --git a/src/unistd/linkat.c b/src/unistd/linkat.c new file mode 100644 index 0000000..1d93970 --- /dev/null +++ b/src/unistd/linkat.c @@ -0,0 +1,14 @@ +#include +#include +#include +#include + +int linkat(int olddfd, const char *old, int newdfd, const char *new, int flags) { + (void) olddfd; + (void) old; + (void) newdfd; + (void) new; + (void) flags; + assert(0 && "system call not yet implemented"); +} + diff --git a/src/unistd/lockf.c b/src/unistd/lockf.c new file mode 100644 index 0000000..61f3422 --- /dev/null +++ b/src/unistd/lockf.c @@ -0,0 +1,11 @@ +#include +#include +#include +#include + +int lockf(int fd, int cmd, off_t len) { + (void) fd; + (void) cmd; + (void) len; + assert(0 && "system call not yet implemented"); +} diff --git a/src/unistd/lseek.c b/src/unistd/lseek.c new file mode 100644 index 0000000..a010467 --- /dev/null +++ b/src/unistd/lseek.c @@ -0,0 +1,9 @@ +#include <_libc/syscalls.h> +#include +#include +#include + +off_t lseek(int fd, off_t offset, int whence) { + return SET_ERRNO(off_t, __syscall3(SYSCALL_NR_LSEEK, fd, offset, whence)); +} + diff --git a/src/unistd/nice.c b/src/unistd/nice.c new file mode 100644 index 0000000..9f54453 --- /dev/null +++ b/src/unistd/nice.c @@ -0,0 +1,7 @@ +#include + +int nice(int incr) { + (void) incr; + // TODO: return something else? + return 0; +} diff --git a/src/unistd/pathconf.c b/src/unistd/pathconf.c new file mode 100644 index 0000000..6e00ed2 --- /dev/null +++ b/src/unistd/pathconf.c @@ -0,0 +1,10 @@ +#include +#include +#include +#include + +long pathconf(const char *pathname, int name) { + (void) pathname; + (void) name; + assert(0 && "system call not yet implemented"); +} diff --git a/src/unistd/pause.c b/src/unistd/pause.c new file mode 100644 index 0000000..b04e37a --- /dev/null +++ b/src/unistd/pause.c @@ -0,0 +1,20 @@ +#include + +// TODO: time.h +struct timespec { + uint64_t ts_sec; + uint64_t ts_nsec; +}; +extern int nanosleep(const struct timespec *ts, struct timespec *rem); + +int pause(void) { + struct timespec ts; + while (1) { + ts.ts_sec = 1000000; + ts.ts_nsec = 0; + + if (nanosleep(&ts, NULL) != 0) { + return 0; + } + } +} diff --git a/src/unistd/pipe.c b/src/unistd/pipe.c new file mode 100644 index 0000000..888f5c7 --- /dev/null +++ b/src/unistd/pipe.c @@ -0,0 +1,8 @@ +#include <_libc/syscalls.h> +#include +#include +#include + +int pipe(int fds[2]) { + return SET_ERRNO(int, __syscall1(SYSCALL_NR_PIPE, (long) fds)); +} diff --git a/src/unistd/pread.c b/src/unistd/pread.c new file mode 100644 index 0000000..6a5586d --- /dev/null +++ b/src/unistd/pread.c @@ -0,0 +1,12 @@ +#include +#include +#include +#include + +ssize_t pread(int fd, void *buf, size_t count, off_t offset) { + (void) fd; + (void) buf; + (void) offset; + (void) count; + assert(0 && "system call not yet implemented"); +} diff --git a/src/unistd/pwrite.c b/src/unistd/pwrite.c new file mode 100644 index 0000000..e9d39e4 --- /dev/null +++ b/src/unistd/pwrite.c @@ -0,0 +1,13 @@ +#include +#include +#include +#include + +ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset) { + (void) fd; + (void) buf; + (void) offset; + (void) count; + assert(0 && "system call not yet implemented"); +} + diff --git a/src/unistd/read.c b/src/unistd/read.c new file mode 100644 index 0000000..883dad7 --- /dev/null +++ b/src/unistd/read.c @@ -0,0 +1,8 @@ +#include <_libc/syscalls.h> +#include +#include +#include + +ssize_t read(int fd, void *data, size_t lim) { + return SET_ERRNO(ssize_t, __syscall3(SYSCALL_NR_READ, fd, (long) data, lim)); +} diff --git a/src/unistd/readlink.c b/src/unistd/readlink.c new file mode 100644 index 0000000..94ea0b1 --- /dev/null +++ b/src/unistd/readlink.c @@ -0,0 +1,11 @@ +#include +#include +#include +#include + +ssize_t readlink(const char *restrict pathname, char *restrict buf, size_t count) { + (void) pathname; + (void) buf; + (void) count; + assert(0 && "system call not yet implemented"); +} diff --git a/src/unistd/readlinkat.c b/src/unistd/readlinkat.c new file mode 100644 index 0000000..b0ca252 --- /dev/null +++ b/src/unistd/readlinkat.c @@ -0,0 +1,12 @@ +#include +#include +#include +#include + +ssize_t readlinkat(int dfd, const char *restrict pathname, char *restrict buf, size_t count) { + (void) dfd; + (void) pathname; + (void) buf; + (void) count; + assert(0 && "system call not yet implemented"); +} diff --git a/src/unistd/rmdir.c b/src/unistd/rmdir.c new file mode 100644 index 0000000..4bb0b79 --- /dev/null +++ b/src/unistd/rmdir.c @@ -0,0 +1,9 @@ +#include <_libc/syscalls.h> +#include +#include +#include + +int rmdir(const char *dirname) { + return SET_ERRNO(int, __syscall1(SYSCALL_NR_RMDIR, (long) dirname)); +} + diff --git a/src/unistd/setegid.c b/src/unistd/setegid.c new file mode 100644 index 0000000..d1a3e95 --- /dev/null +++ b/src/unistd/setegid.c @@ -0,0 +1,9 @@ +#include +#include +#include +#include + +int setegid(gid_t gid) { + (void) gid; + assert(0 && "system call not yet implemented"); +} diff --git a/src/unistd/seteuid.c b/src/unistd/seteuid.c new file mode 100644 index 0000000..487f0c9 --- /dev/null +++ b/src/unistd/seteuid.c @@ -0,0 +1,9 @@ +#include +#include +#include +#include + +int seteuid(uid_t uid) { + (void) uid; + assert(0 && "system call not yet implemented"); +} diff --git a/src/unistd/setgid.c b/src/unistd/setgid.c new file mode 100644 index 0000000..377c13c --- /dev/null +++ b/src/unistd/setgid.c @@ -0,0 +1,8 @@ +#include <_libc/syscalls.h> +#include +#include +#include + +int setgid(gid_t gid) { + return SET_ERRNO(int, __syscall1(SYSCALL_NR_SETGID, gid)); +} diff --git a/src/unistd/setpgid.c b/src/unistd/setpgid.c new file mode 100644 index 0000000..6243055 --- /dev/null +++ b/src/unistd/setpgid.c @@ -0,0 +1,8 @@ +#include <_libc/syscalls.h> +#include +#include +#include + +int setpgid(pid_t pid, pid_t pgid) { + return SET_ERRNO(int, __syscall2(SYSCALL_NR_SETPGID, pid, pgid)); +} diff --git a/src/unistd/setpgrp.c b/src/unistd/setpgrp.c new file mode 100644 index 0000000..33ea306 --- /dev/null +++ b/src/unistd/setpgrp.c @@ -0,0 +1,9 @@ +#include <_libc/syscalls.h> +#include +#include + +pid_t setpgrp(void) { + pid_t pid = getpid(); + setpgid(0, 0); + return pid; +} diff --git a/src/unistd/setregid.c b/src/unistd/setregid.c new file mode 100644 index 0000000..30f16bc --- /dev/null +++ b/src/unistd/setregid.c @@ -0,0 +1,10 @@ +#include +#include +#include +#include + +int setregid(gid_t rgid, gid_t egid) { + (void) rgid; + (void) egid; + assert(0 && "system call not yet implemented"); +} diff --git a/src/unistd/setreuid.c b/src/unistd/setreuid.c new file mode 100644 index 0000000..9b3fd50 --- /dev/null +++ b/src/unistd/setreuid.c @@ -0,0 +1,10 @@ +#include +#include +#include +#include + +int setreuid(uid_t ruid, uid_t euid) { + (void) ruid; + (void) euid; + assert(0 && "system call not yet implemented"); +} diff --git a/src/unistd/setsid.c b/src/unistd/setsid.c new file mode 100644 index 0000000..48c1f09 --- /dev/null +++ b/src/unistd/setsid.c @@ -0,0 +1,6 @@ +#include +#include + +pid_t setsid(void) { + assert(0 && "System call not yet implemented"); +} diff --git a/src/unistd/setuid.c b/src/unistd/setuid.c new file mode 100644 index 0000000..64076de --- /dev/null +++ b/src/unistd/setuid.c @@ -0,0 +1,8 @@ +#include <_libc/syscalls.h> +#include +#include +#include + +int setuid(uid_t uid) { + return SET_ERRNO(int, __syscall1(SYSCALL_NR_SETUID, uid)); +} diff --git a/src/unistd/sleep.c b/src/unistd/sleep.c new file mode 100644 index 0000000..4a50d1d --- /dev/null +++ b/src/unistd/sleep.c @@ -0,0 +1,22 @@ +#include + +// TODO: time.h +struct timespec { + uint64_t ts_sec; + uint64_t ts_nsec; +}; +extern int nanosleep(const struct timespec *ts, struct timespec *rem); + +unsigned int sleep(unsigned int sec) { + struct timespec ts; + struct timespec rem; + + ts.ts_sec = sec; + ts.ts_nsec = 0; + + if (nanosleep(&ts, &rem) != 0) { + return rem.ts_sec; + } else { + return 0; + } +} diff --git a/src/unistd/symlink.c b/src/unistd/symlink.c new file mode 100644 index 0000000..a62129e --- /dev/null +++ b/src/unistd/symlink.c @@ -0,0 +1,10 @@ +#include +#include +#include +#include + +int symlink(const char *target, const char *pathname) { + (void) target; + (void) pathname; + assert(0 && "system call not yet implemented"); +} diff --git a/src/unistd/symlinkat.c b/src/unistd/symlinkat.c new file mode 100644 index 0000000..2683613 --- /dev/null +++ b/src/unistd/symlinkat.c @@ -0,0 +1,11 @@ +#include +#include +#include +#include + +int symlinkat(const char *target, int linkdfd, const char *pathname) { + (void) target; + (void) linkdfd; + (void) pathname; + assert(0 && "system call not yet implemented"); +} diff --git a/src/unistd/sync.c b/src/unistd/sync.c new file mode 100644 index 0000000..d71c6f4 --- /dev/null +++ b/src/unistd/sync.c @@ -0,0 +1,8 @@ +#include <_libc/syscalls.h> +#include +#include +#include + +void sync(void) { + __syscall0(SYSCALL_NR_SYNC); +} diff --git a/src/unistd/sysconf.c b/src/unistd/sysconf.c new file mode 100644 index 0000000..1d7bcc6 --- /dev/null +++ b/src/unistd/sysconf.c @@ -0,0 +1,7 @@ +#include +#include + +long sysconf(int name) { + (void) name; + assert(0 && "Not implemented"); +} diff --git a/src/unistd/tcgetpgrp.c b/src/unistd/tcgetpgrp.c new file mode 100644 index 0000000..7cc25c5 --- /dev/null +++ b/src/unistd/tcgetpgrp.c @@ -0,0 +1,13 @@ +#include +#include + +// TODO: sys/ioctl.h +int ioctl(int fd, unsigned int cmd, void *arg); + +pid_t tcgetprgp(int fd) { + pid_t res; + if (ioctl(fd, TIOCGPGRP, &res) != 0) { + return -1; + } + return res; +} diff --git a/src/unistd/tcsetpgrp.c b/src/unistd/tcsetpgrp.c new file mode 100644 index 0000000..9209f1d --- /dev/null +++ b/src/unistd/tcsetpgrp.c @@ -0,0 +1,9 @@ +#include +#include + +// TODO: sys/ioctl.h +int ioctl(int fd, unsigned int cmd, void *arg); + +int tcsetpgrp(int fd, pid_t pgrp) { + return ioctl(fd, TIOCSPGRP, &pgrp); +} diff --git a/src/unistd/truncate.c b/src/unistd/truncate.c new file mode 100644 index 0000000..1b1ea6d --- /dev/null +++ b/src/unistd/truncate.c @@ -0,0 +1,10 @@ +#include +#include +#include +#include + +int truncate(const char *pathname, off_t size) { + (void) pathname; + (void) size; + assert(0 && "system call not yet implemented"); +} diff --git a/src/unistd/ttyname_r.c b/src/unistd/ttyname_r.c new file mode 100644 index 0000000..0eb93df --- /dev/null +++ b/src/unistd/ttyname_r.c @@ -0,0 +1,15 @@ +#include +#include +#include + +static const char *_ttyname = "-tty-"; + +int ttyname_r(int fd, char *buf, size_t lim) { + (void) fd; + if (lim < sizeof(_ttyname)) { + errno = ERANGE; + return -1; + } + strncpy(buf, _ttyname, lim); + return 0; +} diff --git a/src/unistd/unlink.c b/src/unistd/unlink.c new file mode 100644 index 0000000..e2a0bca --- /dev/null +++ b/src/unistd/unlink.c @@ -0,0 +1,8 @@ +#include <_libc/syscalls.h> +#include +#include +#include + +int unlink(const char *pathname) { + return SET_ERRNO(int, __syscall1(SYSCALL_NR_UNLINK, (long) pathname)); +} diff --git a/src/unistd/unlinkat.c b/src/unistd/unlinkat.c new file mode 100644 index 0000000..e2792d5 --- /dev/null +++ b/src/unistd/unlinkat.c @@ -0,0 +1,11 @@ +#include +#include +#include +#include + +int unlinkat(int dfd, const char *pathname, int flags) { + (void) dfd; + (void) pathname; + (void) flags; + assert(0 && "system call not yet implemented"); +} diff --git a/src/unistd/write.c b/src/unistd/write.c new file mode 100644 index 0000000..510f115 --- /dev/null +++ b/src/unistd/write.c @@ -0,0 +1,9 @@ +#include <_libc/syscalls.h> +#include +#include +#include + +ssize_t write(int fd, const void *data, size_t lim) { + return SET_ERRNO(ssize_t, __syscall3(SYSCALL_NR_WRITE, fd, (long) data, lim)); +} +