summaryrefslogtreecommitdiff
path: root/src/libc/include
diff options
context:
space:
mode:
Diffstat (limited to 'src/libc/include')
-rw-r--r--src/libc/include/__errno.h26
-rw-r--r--src/libc/include/__errno.h.awk20
-rw-r--r--src/libc/include/_proc.h14
-rw-r--r--src/libc/include/alloca.h3
-rw-r--r--src/libc/include/bits/file.h2
-rw-r--r--src/libc/include/bits/panic.h5
-rw-r--r--src/libc/include/camellia.h5
-rw-r--r--src/libc/include/camellia/compat.h6
-rw-r--r--src/libc/include/camellia/fs/dir.h17
-rw-r--r--src/libc/include/camellia/fs/misc.h22
-rw-r--r--src/libc/include/ctype.h16
-rw-r--r--src/libc/include/dirent.h16
-rw-r--r--src/libc/include/draw.h24
-rw-r--r--src/libc/include/elfload.h14
-rw-r--r--src/libc/include/err.h10
-rw-r--r--src/libc/include/errno.h3
-rw-r--r--src/libc/include/esemaphore.h12
-rw-r--r--src/libc/include/fcntl.h25
-rw-r--r--src/libc/include/ftw.h6
l---------src/libc/include/getopt.h1
-rw-r--r--src/libc/include/grp.h11
-rw-r--r--src/libc/include/inttypes.h1
-rw-r--r--src/libc/include/limits.h6
-rw-r--r--src/libc/include/locale.h73
l---------src/libc/include/malloc.h1
-rw-r--r--src/libc/include/math.h27
-rw-r--r--src/libc/include/pwd.h14
-rw-r--r--src/libc/include/setjmp.h18
-rw-r--r--src/libc/include/signal.h54
-rw-r--r--src/libc/include/stdio.h84
-rw-r--r--src/libc/include/stdlib.h34
-rw-r--r--src/libc/include/string.h25
-rw-r--r--src/libc/include/strings.h5
-rw-r--r--src/libc/include/sys/ioctl.h13
-rw-r--r--src/libc/include/sys/mman.h18
-rw-r--r--src/libc/include/sys/param.h2
-rw-r--r--src/libc/include/sys/resource.h2
-rw-r--r--src/libc/include/sys/stat.h70
-rw-r--r--src/libc/include/sys/sysmacros.h3
-rw-r--r--src/libc/include/sys/time.h0
-rw-r--r--src/libc/include/sys/times.h13
-rw-r--r--src/libc/include/sys/types.h18
-rw-r--r--src/libc/include/sys/wait.h13
-rw-r--r--src/libc/include/termios.h0
-rw-r--r--src/libc/include/thread.h9
-rw-r--r--src/libc/include/time.h34
-rw-r--r--src/libc/include/unistd.h64
47 files changed, 859 insertions, 0 deletions
diff --git a/src/libc/include/__errno.h b/src/libc/include/__errno.h
new file mode 100644
index 0000000..7551ce0
--- /dev/null
+++ b/src/libc/include/__errno.h
@@ -0,0 +1,26 @@
+/* generated by awk */
+#ifdef E
+E( 1, "EGENERIC unknown error")
+E( 2, "EFAULT")
+E( 3, "EBADF bad file descriptor")
+E( 4, "EINVAL")
+E( 5, "ENOSYS unsupported")
+E( 6, "ERANGE")
+E( 7, "ENOMEM")
+E( 8, "ENOENT")
+E( 9, "ENOTEMPTY")
+E( 10, "EACCES")
+E( 11, "EMFILE all file descriptors taken")
+E( 12, "ECONNRESET")
+E( 13, "EPIPE")
+E( 14, "ECHILD")
+E(200, "EISDIR")
+E(201, "ENAMETOOLONG")
+E(202, "ENOTDIR")
+E(203, "ELOOP")
+E(204, "ENOEXEC")
+E(205, "EINTR")
+E(206, "EWOULDBLOCK")
+E(207, "EEXIST")
+E(208, "EAGAIN")
+#endif
diff --git a/src/libc/include/__errno.h.awk b/src/libc/include/__errno.h.awk
new file mode 100644
index 0000000..6232835
--- /dev/null
+++ b/src/libc/include/__errno.h.awk
@@ -0,0 +1,20 @@
+BEGIN {
+ print "/* generated by awk */";
+ print "#ifdef E";
+}
+
+END {
+ print "#endif";
+}
+
+/#define/ {
+ comment = $2;
+ num = $3;
+ # extract the comment, if present
+ if (index($0, "/*")) {
+ sub(/[^/]*\/\*/, "");
+ sub(/ *\*\//, "");
+ comment = comment $0;
+ }
+ printf "E(%3s, \"%s\")\n", num, comment;
+}
diff --git a/src/libc/include/_proc.h b/src/libc/include/_proc.h
new file mode 100644
index 0000000..5f9c321
--- /dev/null
+++ b/src/libc/include/_proc.h
@@ -0,0 +1,14 @@
+#pragma once
+
+struct _psdata {
+ /* Description of the process, see setprogname.
+ * Assumed to be null terminated. */
+ char desc[1024];
+
+ /* Base offset where the executable was loaded. */
+ void *base;
+};
+
+/* First allocated in bootstrap.
+ * Freed on every exec(), just to be immediately reallocated by _start2(). */
+static struct _psdata *const _psdata_loc = (void*)0x10000;
diff --git a/src/libc/include/alloca.h b/src/libc/include/alloca.h
new file mode 100644
index 0000000..9c7641c
--- /dev/null
+++ b/src/libc/include/alloca.h
@@ -0,0 +1,3 @@
+#pragma once
+#include <stddef.h>
+void *alloca(size_t size);
diff --git a/src/libc/include/bits/file.h b/src/libc/include/bits/file.h
new file mode 100644
index 0000000..63a31c4
--- /dev/null
+++ b/src/libc/include/bits/file.h
@@ -0,0 +1,2 @@
+#pragma once
+typedef struct _LIBC_FILE FILE;
diff --git a/src/libc/include/bits/panic.h b/src/libc/include/bits/panic.h
new file mode 100644
index 0000000..91aec5f
--- /dev/null
+++ b/src/libc/include/bits/panic.h
@@ -0,0 +1,5 @@
+#pragma once
+#include <stdio.h>
+#include <stdlib.h>
+
+#define __libc_panic(...) do { fprintf(stderr, "__libc_panic @ %s:", __func__); fprintf(stderr, __VA_ARGS__); fprintf(stderr, "\n"); abort(); } while (0)
diff --git a/src/libc/include/camellia.h b/src/libc/include/camellia.h
new file mode 100644
index 0000000..2e4998b
--- /dev/null
+++ b/src/libc/include/camellia.h
@@ -0,0 +1,5 @@
+#pragma once
+#include <camellia/flags.h>
+#include <camellia/types.h>
+
+hid_t camellia_open(const char *path, int flags);
diff --git a/src/libc/include/camellia/compat.h b/src/libc/include/camellia/compat.h
new file mode 100644
index 0000000..a7c6f1f
--- /dev/null
+++ b/src/libc/include/camellia/compat.h
@@ -0,0 +1,6 @@
+#pragma once
+#include <camellia/types.h>
+
+/* c0 - fs_wait returning a handle */
+long c0_fs_wait(char *buf, long len, struct ufs_request *res);
+long c0_fs_respond(void *buf, long ret, int flags);
diff --git a/src/libc/include/camellia/fs/dir.h b/src/libc/include/camellia/fs/dir.h
new file mode 100644
index 0000000..d34a652
--- /dev/null
+++ b/src/libc/include/camellia/fs/dir.h
@@ -0,0 +1,17 @@
+#pragma once
+#include <camellia/types.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+struct dirbuild {
+ long offset;
+ char *buf;
+ long bpos, blen;
+ long error;
+};
+
+void dir_start(struct dirbuild *db, long offset, char *buf, size_t buflen);
+bool dir_append(struct dirbuild *db, const char *name);
+bool dir_appendl(struct dirbuild *db, const char *name, size_t len);
+bool dir_append_from(struct dirbuild *db, hid_t h);
+long dir_finish(struct dirbuild *db);
diff --git a/src/libc/include/camellia/fs/misc.h b/src/libc/include/camellia/fs/misc.h
new file mode 100644
index 0000000..301c604
--- /dev/null
+++ b/src/libc/include/camellia/fs/misc.h
@@ -0,0 +1,22 @@
+#pragma once
+#include <stdbool.h>
+#include <stdlib.h>
+
+void forward_open(hid_t reqh, const char *path, long len, int flags);
+
+void fs_passthru(const char *prefix);
+void fs_whitelist(const char **list);
+void fs_union(const char **list);
+
+void fs_dirinject(const char *path);
+void fs_dirinject2(const char *injects[]);
+
+int mount_at(const char *path);
+
+// TODO separate fs drivers and wrappers around syscalls
+
+/** like _sys_fs_wait, but ensures *buf is a null terminated string on VFSOP_OPEN */
+hid_t ufs_wait(char *buf, size_t len, struct ufs_request *req);
+
+/** Mounts something and injects its path into the fs */
+#define MOUNT_AT(path) for (; mount_at(path) == 0; exit(1))
diff --git a/src/libc/include/ctype.h b/src/libc/include/ctype.h
new file mode 100644
index 0000000..1ebb111
--- /dev/null
+++ b/src/libc/include/ctype.h
@@ -0,0 +1,16 @@
+#pragma once
+
+int isalnum(int c);
+int isalpha(int c);
+int iscntrl(int c);
+int isdigit(int c);
+int isgraph(int c);
+int islower(int c);
+int isprint(int c);
+int ispunct(int c);
+int isspace(int c);
+int isupper(int c);
+int isxdigit(int c);
+
+int tolower(int c);
+int toupper(int c);
diff --git a/src/libc/include/dirent.h b/src/libc/include/dirent.h
new file mode 100644
index 0000000..7c419d7
--- /dev/null
+++ b/src/libc/include/dirent.h
@@ -0,0 +1,16 @@
+#pragma once
+#include <stdio.h>
+
+struct dirent {
+ ino_t d_ino;
+ char d_name[256]; /* NAME_MAX + 1 */
+};
+
+typedef struct {
+ FILE *fp;
+ struct dirent dent;
+} DIR;
+
+DIR *opendir(const char *name);
+int closedir(DIR *dir);
+struct dirent *readdir(DIR *dir);
diff --git a/src/libc/include/draw.h b/src/libc/include/draw.h
new file mode 100644
index 0000000..5e614be
--- /dev/null
+++ b/src/libc/include/draw.h
@@ -0,0 +1,24 @@
+#pragma once
+#include <camellia/types.h>
+#include <stddef.h>
+#include <stdint.h>
+
+struct framebuf {
+ size_t len, width, height, pitch;
+ uint8_t bpp;
+ char *b;
+
+ hid_t fd;
+};
+
+struct rect { uint32_t x1, y1, x2, y2; };
+void dirty_reset(struct rect *d);
+void dirty_mark(struct rect *d, uint32_t x, uint32_t y);
+void dirty_flush(struct rect *d, struct framebuf *fb);
+
+int fb_setup(struct framebuf *fb, const char *base);
+int fb_anon(struct framebuf *fb, size_t w, size_t h);
+uint32_t *fb_pixel(struct framebuf *fb, uint32_t x, uint32_t y);
+void fb_cpy(
+ struct framebuf *dest, const struct framebuf *src,
+ size_t xd, size_t yd, size_t xs, size_t ys, size_t w, size_t h);
diff --git a/src/libc/include/elfload.h b/src/libc/include/elfload.h
new file mode 100644
index 0000000..825f765
--- /dev/null
+++ b/src/libc/include/elfload.h
@@ -0,0 +1,14 @@
+#pragma once
+#include <bits/file.h>
+
+struct execdata {
+ int argc;
+ char **argv, **envp;
+ char *cwd;
+};
+
+void elf_execf(FILE *f, char **argv, char **envp);
+void elf_exec(void *base, char **argv, char **envp);
+void *elf_partialexec(void *elf); /* returns pointer to entry point */
+
+void elf_selfreloc(void); // elfreloc.c
diff --git a/src/libc/include/err.h b/src/libc/include/err.h
new file mode 100644
index 0000000..6b63c6c
--- /dev/null
+++ b/src/libc/include/err.h
@@ -0,0 +1,10 @@
+#pragma once
+#include <stdarg.h>
+
+_Noreturn void err(int ret, const char *fmt, ...);
+_Noreturn void errx(int ret, const char *fmt, ...);
+void warn(const char *fmt, ...);
+void warnx(const char *fmt, ...);
+
+void vwarn(const char *fmt, va_list args);
+void vwarnx(const char *fmt, va_list args);
diff --git a/src/libc/include/errno.h b/src/libc/include/errno.h
new file mode 100644
index 0000000..6686a01
--- /dev/null
+++ b/src/libc/include/errno.h
@@ -0,0 +1,3 @@
+#pragma once
+#include <camellia/errno.h>
+extern int errno;
diff --git a/src/libc/include/esemaphore.h b/src/libc/include/esemaphore.h
new file mode 100644
index 0000000..9cc85e0
--- /dev/null
+++ b/src/libc/include/esemaphore.h
@@ -0,0 +1,12 @@
+#pragma once
+#include <camellia/types.h>
+
+struct evil_sem {
+ hid_t wait, signal;
+};
+
+void esem_signal(struct evil_sem *sem);
+void esem_wait(struct evil_sem *sem);
+
+struct evil_sem *esem_new(int value);
+void esem_free(struct evil_sem *sem);
diff --git a/src/libc/include/fcntl.h b/src/libc/include/fcntl.h
new file mode 100644
index 0000000..6338d1f
--- /dev/null
+++ b/src/libc/include/fcntl.h
@@ -0,0 +1,25 @@
+#pragma once
+
+#define F_SETFL 1
+#define F_GETFL 2
+#define F_DUPFD 3
+#define F_SETFD 4
+
+#define FD_CLOEXEC 1
+
+#define O_APPEND 0
+#define O_CREAT 0
+#define O_EXCL 0
+#define O_NONBLOCK 0
+#define O_RDONLY 0
+#define O_RDWR 0
+#define O_TRUNC 0
+#define O_WRONLY 0
+
+#define R_OK 1
+#define W_OK 2
+#define X_OK 4
+
+/* it can either take an additonal mode_t argument or none */
+int open(const char *path, int flags, ...);
+int fcntl(int fd, int cmd, ...);
diff --git a/src/libc/include/ftw.h b/src/libc/include/ftw.h
new file mode 100644
index 0000000..6dc8132
--- /dev/null
+++ b/src/libc/include/ftw.h
@@ -0,0 +1,6 @@
+#pragma once
+#include <sys/stat.h>
+
+int ftw(const char *dirpath,
+ int (*fn)(const char *fpath, const struct stat *sb, int typeflag),
+ int nopenfd);
diff --git a/src/libc/include/getopt.h b/src/libc/include/getopt.h
new file mode 120000
index 0000000..4890ceb
--- /dev/null
+++ b/src/libc/include/getopt.h
@@ -0,0 +1 @@
+../vendor/getopt/getopt.h \ No newline at end of file
diff --git a/src/libc/include/grp.h b/src/libc/include/grp.h
new file mode 100644
index 0000000..e7b99c9
--- /dev/null
+++ b/src/libc/include/grp.h
@@ -0,0 +1,11 @@
+#pragma once
+#include <sys/types.h>
+
+struct group {
+ char *gr_name;
+ char *gr_passwd;
+ gid_t gr_gid;
+ char **gr_mem;
+};
+
+struct group *getgrgid(gid_t gid);
diff --git a/src/libc/include/inttypes.h b/src/libc/include/inttypes.h
new file mode 100644
index 0000000..9a6118b
--- /dev/null
+++ b/src/libc/include/inttypes.h
@@ -0,0 +1 @@
+#include <stdint.h>
diff --git a/src/libc/include/limits.h b/src/libc/include/limits.h
new file mode 100644
index 0000000..972553f
--- /dev/null
+++ b/src/libc/include/limits.h
@@ -0,0 +1,6 @@
+#pragma once
+#include <camellia/path.h> // just for PATH_MAX
+// #include_next <limits.h>
+
+#define _POSIX2_RE_DUP_MAX 255
+#define NAME_MAX 255
diff --git a/src/libc/include/locale.h b/src/libc/include/locale.h
new file mode 100644
index 0000000..1221375
--- /dev/null
+++ b/src/libc/include/locale.h
@@ -0,0 +1,73 @@
+#pragma once
+#include <limits.h>
+
+#define LC_ALL 0
+#define LC_COLLATE 1
+#define LC_CTYPE 2
+#define LC_MESSAGES 3
+#define LC_MONETARY 4
+#define LC_NUMERIC 5
+#define LC_TIME 6
+
+struct lconv {
+ char *decimal_point;
+ char *thousands_sep;
+ char *grouping;
+ char *mon_decimal_point;
+ char *mon_thousands_sep;
+ char *mon_grouping;
+ char *positive_sign;
+ char *negative_sign;
+ char *currency_symbol;
+ char frac_digits;
+ char p_cs_precedes;
+ char n_cs_precedes;
+ char p_sep_by_space;
+ char n_sep_by_space;
+ char p_sign_posn;
+ char n_sign_posn;
+ char *int_curr_symbol;
+ char int_frac_digits;
+ char int_p_cs_precedes;
+ char int_n_cs_precedes;
+ char int_p_sep_by_space;
+ char int_n_sep_by_space;
+ char int_p_sign_posn;
+ char int_n_sign_posn;
+};
+
+static inline struct lconv *localeconv(void) {
+ /* per Linux's lconv(3) */
+ static struct lconv locale = (struct lconv){
+ .decimal_point = ".",
+ .thousands_sep = "",
+ .grouping = "",
+ .mon_decimal_point = "",
+ .mon_thousands_sep = "",
+ .mon_grouping = "",
+ .positive_sign = "",
+ .negative_sign = "",
+ .currency_symbol = "",
+ .frac_digits = CHAR_MAX,
+ .p_cs_precedes = CHAR_MAX,
+ .n_cs_precedes = CHAR_MAX,
+ .p_sep_by_space = CHAR_MAX,
+ .n_sep_by_space = CHAR_MAX,
+ .p_sign_posn = CHAR_MAX,
+ .n_sign_posn = CHAR_MAX,
+ .int_curr_symbol = "",
+ .int_frac_digits = CHAR_MAX,
+ .int_p_cs_precedes = CHAR_MAX,
+ .int_n_cs_precedes = CHAR_MAX,
+ .int_p_sep_by_space = CHAR_MAX,
+ .int_n_sep_by_space = CHAR_MAX,
+ .int_p_sign_posn = CHAR_MAX,
+ .int_n_sign_posn = CHAR_MAX,
+ };
+ return &locale;
+}
+
+static inline char *setlocale(int category, const char *locale) {
+ (void)category; (void)locale;
+ return NULL;
+}
diff --git a/src/libc/include/malloc.h b/src/libc/include/malloc.h
new file mode 120000
index 0000000..80b9bf5
--- /dev/null
+++ b/src/libc/include/malloc.h
@@ -0,0 +1 @@
+../vendor/dlmalloc/malloc.h \ No newline at end of file
diff --git a/src/libc/include/math.h b/src/libc/include/math.h
new file mode 100644
index 0000000..1aec564
--- /dev/null
+++ b/src/libc/include/math.h
@@ -0,0 +1,27 @@
+#pragma once
+
+#define INFINITY __builtin_inff()
+#define HUGE_VAL ((double)INFINITY)
+
+double acos(double x);
+double asin(double x);
+double atan2(double x, double y);
+double cos(double x);
+double cosh(double x);
+double sin(double x);
+double sinh(double x);
+double tan(double x);
+double tanh(double x);
+
+double fabs(double x);
+double floor(double x);
+double ceil(double x);
+double log(double x);
+double log2(double x);
+double log10(double x);
+double exp(double x);
+double fmod(double x, double y);
+double frexp(double num, int *exp);
+double ldexp(double x, int exp);
+double pow(double x, double y);
+double sqrt(double x);
diff --git a/src/libc/include/pwd.h b/src/libc/include/pwd.h
new file mode 100644
index 0000000..6721ca2
--- /dev/null
+++ b/src/libc/include/pwd.h
@@ -0,0 +1,14 @@
+#pragma once
+#include <sys/types.h>
+
+struct passwd {
+ char *pw_name;
+ char *pw_passwd;
+ uid_t pw_uid;
+ gid_t pw_gid;
+ char *pw_gecos;
+ char *pw_dir;
+ char *pw_shell;
+};
+
+struct passwd *getpwuid(uid_t uid);
diff --git a/src/libc/include/setjmp.h b/src/libc/include/setjmp.h
new file mode 100644
index 0000000..6d05d79
--- /dev/null
+++ b/src/libc/include/setjmp.h
@@ -0,0 +1,18 @@
+#pragma once
+#include <bits/panic.h>
+
+typedef uint64_t jmp_buf[8]; /* rbx, rsp, rbp, r12, r13, r14, r15, rip */
+typedef char sigjmp_buf[1];
+
+int setjmp(jmp_buf env);
+_Noreturn void longjmp(jmp_buf env, int val);
+
+static inline int sigsetjmp(sigjmp_buf env, int savemask) {
+ (void)env; (void)savemask;
+ return 0;
+}
+
+static inline _Noreturn void siglongjmp(sigjmp_buf env, int val) {
+ (void)env; (void)val;
+ __libc_panic("unimplemented");
+}
diff --git a/src/libc/include/signal.h b/src/libc/include/signal.h
new file mode 100644
index 0000000..012481e
--- /dev/null
+++ b/src/libc/include/signal.h
@@ -0,0 +1,54 @@
+#pragma once
+#include <bits/panic.h>
+#include <sys/types.h>
+#include <errno.h> // only for ENOSYS
+
+#define SIGHUP 1
+#define SIGINT 2
+#define SIGQUIT 3
+#define SIGILL 4
+#define SIGTRAP 5
+#define SIGABRT 6
+#define SIGFPE 8
+#define SIGKILL 9
+#define SIGSEGV 11
+#define SIGPIPE 13
+#define SIGALRM 14
+#define SIGTERM 15
+
+#define SIGCONT 16
+#define SIGPIPE 17
+#define SIGTSTP 18
+#define SIGTTIN 19
+#define SIGTTOU 20
+#define SIGWINCH 21
+#define SIGCHLD 22
+
+#define NSIG 32
+
+#define SIG_DFL 0
+#define SIG_ERR 0
+#define SIG_IGN 0
+#define SIG_SETMASK 0
+
+typedef int sig_atomic_t;
+typedef struct {} sigset_t;
+typedef struct {} siginfo_t;
+extern const char *const sys_siglist[];
+
+struct sigaction {
+ void (*sa_handler)(int);
+ void (*sa_sigaction)(int, siginfo_t *, void *);
+ sigset_t sa_mask;
+ int sa_flags;
+ void (*sa_restorer)(void);
+};
+
+int sigaction(int sig, const struct sigaction *act, struct sigaction *oldact);
+int sigemptyset(sigset_t *set);
+int sigfillset(sigset_t *set);
+int sigprocmask(int how, const sigset_t *set, const sigset_t *oldset);
+int sigsuspend(const sigset_t *mask);
+int signal(int sig, void (*func)(int));
+int kill(pid_t pid, int sig);
+int raise(int sig);
diff --git a/src/libc/include/stdio.h b/src/libc/include/stdio.h
new file mode 100644
index 0000000..48d5058
--- /dev/null
+++ b/src/libc/include/stdio.h
@@ -0,0 +1,84 @@
+#pragma once
+#include <bits/file.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <sys/types.h>
+
+#define EOF (-1)
+#define STDIN_FILENO 0
+#define STDOUT_FILENO 1
+#define STDERR_FILENO 2
+
+#define SEEK_SET 1
+#define SEEK_CUR 2
+#define SEEK_END 3
+
+#define _IONBF 0
+#define _IOFBF 1
+#define _IOLBF 2
+
+#define BUFSIZ 4096
+
+/* stop fread() from trying to fill the entire buffer before returning
+ * i.e. it will call _sys_read() exactly once */
+#define FEXT_NOFILL 1
+
+int printf(const char *restrict fmt, ...);
+int fprintf(FILE *restrict f, const char *restrict fmt, ...);
+
+int sprintf(char *restrict s, const char *restrict fmt, ...);
+
+int vprintf(const char *restrict fmt, va_list ap);
+int vfprintf(FILE *restrict f, const char *restrict fmt, va_list ap);
+
+int _klogf(const char *fmt, ...); // for kernel debugging only
+
+
+extern FILE *const stdin, *const stdout, *const stderr;
+
+FILE *fopen(const char *path, const char *mode);
+FILE *freopen(const char *path, const char *mode, FILE *);
+FILE *fdopen(int fd, const char *mode);
+FILE *file_clone(const FILE *, const char *mode);
+FILE *popen(const char *cmd, const char *mode);
+int pclose(FILE *f);
+FILE *tmpfile(void);
+
+int fextflags(FILE *, int extflags);
+int setvbuf(FILE *restrict f, char *restrict buf, int type, size_t size);
+int fclose(FILE *);
+int fflush(FILE *f);
+
+size_t fread(void *restrict ptr, size_t size, size_t nitems, FILE *restrict);
+size_t fwrite(const void *restrict ptr, size_t size, size_t nitems, FILE *restrict);
+int fputs(const char *s, FILE *f);
+char *fgets(char *buf, int size, FILE *f);
+int fgetc(FILE *f);
+int getc(FILE *f);
+int fputc(int c, FILE *f);
+int putc(int c, FILE *f);
+int ungetc(int c, FILE *f);
+
+int fseek(FILE *f, long offset, int whence);
+int fseeko(FILE *f, off_t offset, int whence);
+long ftell(FILE *f);
+off_t ftello(FILE *f);
+
+int feof(FILE *);
+int ferror(FILE *);
+void clearerr(FILE *f);
+
+void perror(const char *s);
+int puts(const char *s);
+int getchar(void);
+int putchar(int c);
+
+off_t lseek(int fd, off_t off, int whence);
+
+int remove(const char *path);
+int rename(const char *old, const char *new);
+
+#define L_tmpnam (5 + 16 + 1)
+char *tmpnam(char *s);
+
+int sscanf(const char *restrict s, const char *restrict format, ...);
diff --git a/src/libc/include/stdlib.h b/src/libc/include/stdlib.h
new file mode 100644
index 0000000..ee9d179
--- /dev/null
+++ b/src/libc/include/stdlib.h
@@ -0,0 +1,34 @@
+#pragma once
+#include <stddef.h>
+#include <stdlib.h>
+
+#ifndef NO_MALLOC_H
+#include <malloc.h>
+#endif
+
+#define EXIT_SUCCESS 0
+#define EXIT_FAILURE 1
+
+_Noreturn void abort(void);
+_Noreturn void exit(int);
+
+const char *getprogname(void);
+void setprogname(const char *progname);
+void setproctitle(const char *fmt, ...);
+
+int mkstemp(char *template);
+char *getenv(const char *name);
+int system(const char *cmd);
+
+int abs(int i);
+
+int atoi(const char *s);
+double atof(const char *s);
+
+long strtol(const char *restrict s, char **restrict end, int base);
+long long strtoll(const char *restrict s, char **restrict end, int base);
+unsigned long strtoul(const char *restrict s, char **restrict end, int base);
+unsigned long long strtoull(const char *restrict s, char **restrict end, int base);
+double strtod(const char *restrict s, char **restrict end);
+
+void qsort(void *base, size_t nmemb, size_t size, int (*cmp)(const void *a, const void *b));
diff --git a/src/libc/include/string.h b/src/libc/include/string.h
new file mode 100644
index 0000000..78bed9b
--- /dev/null
+++ b/src/libc/include/string.h
@@ -0,0 +1,25 @@
+#pragma once
+#include <shared/mem.h>
+#include <strings.h> /* work around bad include in dash */
+
+char *strchr(const char *s, int c);
+char *strrchr(const char *s, int c);
+
+size_t strspn(const char *s, const char *accept);
+size_t strcspn(const char *s, const char *reject);
+char *strpbrk(const char *s1, const char *s2);
+
+char *strtok(char *restrict s, const char *restrict sep);
+char *strtok_r(char *restrict s, const char *restrict sep, char **restrict state);
+
+int strncmp(const char *s1, const char *s2, size_t n);
+int strcoll(const char *s1, const char *s2);
+
+char *strstr(const char *s1, const char *s2);
+
+char *strcpy(char *restrict s1, const char *restrict s2);
+char *strncpy(char *restrict s1, const char *restrict s2, size_t n);
+char *stpncpy(char *restrict dst, const char *restrict src, size_t n);
+char *strdup(const char *s);
+
+char *strerror(int errnum);
diff --git a/src/libc/include/strings.h b/src/libc/include/strings.h
new file mode 100644
index 0000000..d0abc47
--- /dev/null
+++ b/src/libc/include/strings.h
@@ -0,0 +1,5 @@
+#pragma once
+#include <stddef.h>
+
+int strcasecmp(const char *s1, const char *s2);
+int strncasecmp(const char *s1, const char *s2, size_t n);
diff --git a/src/libc/include/sys/ioctl.h b/src/libc/include/sys/ioctl.h
new file mode 100644
index 0000000..708bc3f
--- /dev/null
+++ b/src/libc/include/sys/ioctl.h
@@ -0,0 +1,13 @@
+#pragma once
+#include <errno.h> // only for ENOSYS
+
+#define TIOCGWINSZ 0
+struct winsize {
+ int ws_row, ws_col;
+};
+
+static inline int ioctl(int fd, int req, ...) {
+ (void)fd; (void)req;
+ errno = ENOSYS;
+ return -1;
+}
diff --git a/src/libc/include/sys/mman.h b/src/libc/include/sys/mman.h
new file mode 100644
index 0000000..074ebe2
--- /dev/null
+++ b/src/libc/include/sys/mman.h
@@ -0,0 +1,18 @@
+#pragma once
+#include <camellia/flags.h>
+#include <sys/types.h>
+
+#define MMAP_UNSUPPORTED 0xFFFF
+
+#define PROT_EXEC 1
+#define PROT_NONE MMAP_UNSUPPORTED
+#define PROT_READ 1
+#define PROT_WRITE 1
+
+#define MAP_FIXED MMAP_UNSUPPORTED
+#define MAP_PRIVATE 0
+#define MAP_SHARED MMAP_UNSUPPORTED
+#define MAP_ANONYMOUS 1
+
+void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t off);
+int munmap(void *addr, size_t len);
diff --git a/src/libc/include/sys/param.h b/src/libc/include/sys/param.h
new file mode 100644
index 0000000..e6c9d6f
--- /dev/null
+++ b/src/libc/include/sys/param.h
@@ -0,0 +1,2 @@
+#define MIN(a, b) ((a)<(b) ? (a):(b))
+#define MAX(a, b) ((a)<(b) ? (b):(a))
diff --git a/src/libc/include/sys/resource.h b/src/libc/include/sys/resource.h
new file mode 100644
index 0000000..4582ce0
--- /dev/null
+++ b/src/libc/include/sys/resource.h
@@ -0,0 +1,2 @@
+#pragma once
+struct rusage {};
diff --git a/src/libc/include/sys/stat.h b/src/libc/include/sys/stat.h
new file mode 100644
index 0000000..343db55
--- /dev/null
+++ b/src/libc/include/sys/stat.h
@@ -0,0 +1,70 @@
+#pragma once
+#include <bits/panic.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <time.h> // struct timespec
+#include <errno.h> // only for ENOSYS
+
+struct stat {
+ dev_t st_dev;
+ ino_t st_ino;
+ mode_t st_mode;
+ nlink_t st_nlink;
+ uid_t st_uid;
+ gid_t st_gid;
+ dev_t st_rdev;
+ off_t st_size;
+ blksize_t st_blksize;
+ blkcnt_t st_blocks;
+
+ struct timespec st_atim;
+ struct timespec st_mtim;
+ struct timespec st_ctim;
+
+#define st_atime st_atim.tv_sec
+#define st_mtime st_mtim.tv_sec
+#define st_ctime st_ctim.tv_sec
+};
+
+#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_ISUID 04000
+#define S_ISGID 02000
+#define S_ISVTX 01000
+
+/* inode(7) */
+#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)
+
+int fstat(int fd, struct stat *sb);
+int stat(const char *restrict path, struct stat *restrict sb);
+int lstat(const char *restrict path, struct stat *restrict sb);
+int mkdir(const char *path, mode_t mode);
+
+static inline mode_t umask(mode_t mask) {
+ (void)mask;
+ __libc_panic("unimplemented");
+}
+
+static inline int chmod(const char *path, mode_t mode) {
+ (void)path; (void)mode;
+ errno = ENOSYS;
+ return -1;
+}
+
+static inline int mknod(const char *path, mode_t mode, dev_t dev) {
+ (void)path; (void)mode; (void)dev;
+ errno = ENOSYS;
+ return -1;
+}
diff --git a/src/libc/include/sys/sysmacros.h b/src/libc/include/sys/sysmacros.h
new file mode 100644
index 0000000..30e0efd
--- /dev/null
+++ b/src/libc/include/sys/sysmacros.h
@@ -0,0 +1,3 @@
+#define makedev(maj, min) 0
+#define major(x) 0
+#define minor(x) 0
diff --git a/src/libc/include/sys/time.h b/src/libc/include/sys/time.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/libc/include/sys/time.h
diff --git a/src/libc/include/sys/times.h b/src/libc/include/sys/times.h
new file mode 100644
index 0000000..4a8d3ef
--- /dev/null
+++ b/src/libc/include/sys/times.h
@@ -0,0 +1,13 @@
+#pragma once
+#include <bits/panic.h>
+
+struct tms {
+ clock_t tms_utime;
+ clock_t tms_stime;
+ clock_t tms_cutime;
+ clock_t tms_cstime;
+};
+
+static inline clock_t times(struct tms *buf) {
+ __libc_panic("unimplemented");
+}
diff --git a/src/libc/include/sys/types.h b/src/libc/include/sys/types.h
new file mode 100644
index 0000000..faf656a
--- /dev/null
+++ b/src/libc/include/sys/types.h
@@ -0,0 +1,18 @@
+#pragma once
+#include <stddef.h>
+#include <stdint.h>
+
+typedef long long off_t;
+typedef int64_t time_t;
+typedef uint64_t clock_t;
+typedef int mode_t;
+
+typedef int dev_t;
+typedef int ino_t;
+typedef int mode_t;
+typedef int nlink_t;
+typedef int uid_t;
+typedef int gid_t;
+typedef int blksize_t;
+typedef int blkcnt_t;
+typedef int pid_t;
diff --git a/src/libc/include/sys/wait.h b/src/libc/include/sys/wait.h
new file mode 100644
index 0000000..cff407e
--- /dev/null
+++ b/src/libc/include/sys/wait.h
@@ -0,0 +1,13 @@
+#pragma once
+#include <sys/types.h>
+
+#define WIFSTOPPED(x) 0
+#define WEXITSTATUS(x) ((x)&0xFF)
+#define WIFEXITED(x) 1
+#define WSTOPSIG(x) 0
+#define WTERMSIG(x) 0
+
+#define WNOHANG 0
+#define WUNTRACED 0
+
+pid_t wait3(int *wstatus, int opts, struct rusage *rusage);
diff --git a/src/libc/include/termios.h b/src/libc/include/termios.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/libc/include/termios.h
diff --git a/src/libc/include/thread.h b/src/libc/include/thread.h
new file mode 100644
index 0000000..5a5ddc0
--- /dev/null
+++ b/src/libc/include/thread.h
@@ -0,0 +1,9 @@
+#pragma once
+#include <stdlib.h>
+
+void thread_creates(int flags, void (*fn)(void*), void *arg, void *stack);
+
+static inline void thread_create(int flags, void (*fn)(void*), void *arg) {
+ /* error checking is for WIMPS. */
+ thread_creates(flags, fn, arg, malloc(4096) + 4096);
+}
diff --git a/src/libc/include/time.h b/src/libc/include/time.h
new file mode 100644
index 0000000..5d03664
--- /dev/null
+++ b/src/libc/include/time.h
@@ -0,0 +1,34 @@
+#pragma once
+#include <sys/types.h>
+
+#define CLOCKS_PER_SEC 1000000
+
+struct tm {
+ int tm_sec; /* Seconds [0,60]. */
+ int tm_min; /* Minutes [0,59]. */
+ int tm_hour; /* Hour [0,23]. */
+ int tm_mday; /* Day of month [1,31]. */
+ int tm_mon; /* Month of year [0,11]. */
+ int tm_year; /* Years since 1900. */
+ int tm_wday; /* Day of week [0,6] (Sunday =0). */
+ int tm_yday; /* Day of year [0,365]. */
+ int tm_isdst; /* Daylight Savings flag. */
+};
+
+struct timespec {
+ time_t tv_sec;
+ long long tv_nsec;
+};
+
+time_t time(time_t *tloc);
+clock_t clock(void);
+
+struct tm *gmtime(const time_t *timer);
+struct tm *localtime(const time_t *timer);
+time_t mktime(struct tm *timeptr);
+
+double difftime(time_t time1, time_t time0);
+
+size_t strftime(
+ char *restrict s, size_t maxsize,
+ const char *restrict format, const struct tm *restrict timeptr);
diff --git a/src/libc/include/unistd.h b/src/libc/include/unistd.h
new file mode 100644
index 0000000..005e79c
--- /dev/null
+++ b/src/libc/include/unistd.h
@@ -0,0 +1,64 @@
+#pragma once
+#include <camellia/types.h> // TODO only needed because of hid_t
+#include <sys/types.h>
+#include <getopt.h>
+
+// TODO custom stdint.h, ssize_t doesn't belong here
+typedef long long ssize_t;
+
+extern char **environ;
+
+int fork(void);
+pid_t vfork(void);
+int close(hid_t h);
+_Noreturn void _exit(int);
+
+ssize_t readlink(const char *restrict path, char *restrict buf, size_t bufsize);
+int link(const char *path1, const char *path2);
+int unlink(const char *path);
+int symlink(const char *path1, const char *path2);
+int isatty(int fd);
+
+int execv(const char *path, char *const argv[]);
+int execve(const char *path, char *const argv[], char *const envp[]);
+
+int chdir(const char *path);
+char *getcwd(char *buf, size_t size);
+
+uid_t getuid(void);
+uid_t geteuid(void);
+gid_t getgid(void);
+gid_t getegid(void);
+
+int chown(const char *path, uid_t owner, gid_t group);
+
+int setpgid(pid_t pid, pid_t pgid);
+pid_t tcgetpgrp(int fd);
+int tcsetpgrp(int fd, pid_t pgrp);
+pid_t getpgrp(void);
+pid_t getpid(void);
+pid_t getppid(void);
+
+int getgroups(int size, gid_t list[]);
+
+ssize_t read(int fd, void *buf, size_t count);
+ssize_t write(int fd, const void *buf, size_t count);
+int pipe(int pipefd[2]);
+int dup2(int oldfd, int newfd);
+
+/* Converts a relative path to an absolute one, simplifying it if possible.
+ * If in == NULL - return the length of cwd. Doesn't include the trailing slash,
+ * except for the root dir. Includes the null byte.
+ * If size isn't enough to fit the path, returns the amount of bytes needed to fit
+ * it, including the null byte.
+ *
+ * Note that some errors are only detected if *out != NULL, so you must check the return
+ * value twice.
+ * @return 0 on failure, length of the path otherwise */
+size_t absolutepath(char *out, const char *in, size_t size);
+
+// TODO put in an internal libc header
+void __setinitialcwd(const char *c);
+
+void intr_set(void (*fn)(void));
+void intr_default(void);