summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/kernel/pipe.c3
-rw-r--r--src/kernel/proc.c6
-rw-r--r--src/kernel/proc.h1
-rw-r--r--src/kernel/syscalls.c5
-rw-r--r--src/libc/ctype.c4
-rw-r--r--src/libc/elfload.c25
-rw-r--r--src/libc/include/ctype.h1
-rw-r--r--src/libc/include/inttypes.h3
-rw-r--r--src/libc/include/spawn.h21
-rw-r--r--src/libc/include/stdio.h4
-rw-r--r--src/libc/include/string.h1
-rw-r--r--src/libc/include/sys/wait.h2
-rw-r--r--src/libc/include/unistd.h1
-rw-r--r--src/libc/spawn.c82
-rw-r--r--src/libc/stdio/file.c2
-rw-r--r--src/libc/string/string.c6
-rw-r--r--src/libc/syswait.c11
-rw-r--r--src/libc/unistd.c30
-rw-r--r--src/libc/vendor/sortix/fscanf.c30
-rw-r--r--src/libc/vendor/sortix/vfscanf.c43
-rw-r--r--src/libk/printf.c32
21 files changed, 283 insertions, 30 deletions
diff --git a/src/kernel/pipe.c b/src/kernel/pipe.c
index 6325369..b7f5ad3 100644
--- a/src/kernel/pipe.c
+++ b/src/kernel/pipe.c
@@ -1,3 +1,4 @@
+#include <camellia/errno.h>
#include <kernel/panic.h>
#include <kernel/pipe.h>
#include <kernel/util.h>
@@ -8,7 +9,7 @@ void pipe_joinqueue(Handle *h, Proc *proc, void __user *pbuf, size_t pbuflen) {
assert(h && h->type == HANDLE_PIPE);
assert(h->readable ^ h->writeable);
if (!h->pipe.sister) {
- regs_savereturn(&proc->regs, -1);
+ regs_savereturn(&proc->regs, h->readable ? 0 : -EPIPE);
return;
}
diff --git a/src/kernel/proc.c b/src/kernel/proc.c
index 3ef35c0..cd9db9b 100644
--- a/src/kernel/proc.c
+++ b/src/kernel/proc.c
@@ -349,10 +349,14 @@ void proc_tryreap(Proc *dead) {
if (parent->state != PS_WAITS4CHILDDEATH) {
return; /* don't reap yet */
}
+ uint32_t pid = proc_ns_id(parent->pns, dead);
+ if (parent->awaited_death.pid && parent->awaited_death.pid != pid) {
+ return; /* we're not The One */
+ }
if (parent->awaited_death.legacy) {
regs_savereturn(&parent->regs, dead->death_msg);
} else {
- regs_savereturn(&parent->regs, proc_ns_id(parent->pns, dead));
+ regs_savereturn(&parent->regs, pid);
if (parent->awaited_death.out) {
struct sys_wait2 __user *out = parent->awaited_death.out;
struct sys_wait2 data;
diff --git a/src/kernel/proc.h b/src/kernel/proc.h
index a1820dc..afa4439 100644
--- a/src/kernel/proc.h
+++ b/src/kernel/proc.h
@@ -46,6 +46,7 @@ struct Proc {
int death_msg; // PS_DEAD
struct {
bool legacy; /* false = wait2, true = await */
+ uint32_t pid; /* valid if nonzero */
struct sys_wait2 __user *out;
} awaited_death;
struct {
diff --git a/src/kernel/syscalls.c b/src/kernel/syscalls.c
index ebdf64e..a8b47ae 100644
--- a/src/kernel/syscalls.c
+++ b/src/kernel/syscalls.c
@@ -26,6 +26,7 @@ long _sys_await(void) {
bool has_children = false;
proc_setstate(proc_cur, PS_WAITS4CHILDDEATH);
proc_cur->awaited_death.legacy = true;
+ proc_cur->awaited_death.pid = 0;
for (Proc *iter = proc_cur->child;
iter; iter = iter->sibling)
@@ -403,7 +404,7 @@ uint32_t _sys_getppid(void) {
}
int _sys_wait2(int pid, int flags, struct sys_wait2 __user *out) {
- if (pid != -1 || flags != 0) {
+ if (flags != 0) {
SYSCALL_RETURN(-ENOSYS);
}
@@ -411,13 +412,13 @@ int _sys_wait2(int pid, int flags, struct sys_wait2 __user *out) {
proc_setstate(proc_cur, PS_WAITS4CHILDDEATH);
proc_cur->awaited_death.legacy = false;
proc_cur->awaited_death.out = out;
+ proc_cur->awaited_death.pid = (0 < pid) ? pid : 0;
for (Proc *iter = proc_cur->child; iter; iter = iter->sibling) {
if (iter->noreap) continue;
has_children = true;
if (iter->state == PS_TOREAP) {
proc_tryreap(iter);
- return 0; // dummy
}
}
diff --git a/src/libc/ctype.c b/src/libc/ctype.c
index fa49a07..de10024 100644
--- a/src/libc/ctype.c
+++ b/src/libc/ctype.c
@@ -8,6 +8,10 @@ int isalpha(int c) {
return islower(c) || isupper(c);
}
+int isblank(int c) {
+ return c == ' ' || c == '\t';
+}
+
int iscntrl(int c) {
return c <= 0x1f || c == 0x7f;
}
diff --git a/src/libc/elfload.c b/src/libc/elfload.c
index 66144bb..0038f9b 100644
--- a/src/libc/elfload.c
+++ b/src/libc/elfload.c
@@ -42,19 +42,22 @@ static bool valid_ehdr(const struct Elf64_Ehdr *h) {
static bool load_phdr(const void *elf, void *exebase, size_t idx) {
const struct Elf64_Ehdr *ehdr = elf;
const struct Elf64_Phdr *phdr = elf + ehdr->e_phoff + idx * ehdr->e_phentsize;
-
- if (phdr->p_type == PT_DYNAMIC) return true;
-
- if (phdr->p_type != PT_LOAD) {
- printf("unknown type %x\n", phdr->p_type);
+
+ switch (phdr->p_type) {
+ case PT_DYNAMIC:
+ case 0x6474e551: /* GNU_STACK */
+ return true;
+ case PT_LOAD:
+ // TODO overlap check
+ // TODO don't ignore flags
+ _sys_memflag(exebase + phdr->p_vaddr, phdr->p_memsz, MEMFLAG_PRESENT);
+ // TODO check that filesz <= memsz
+ memcpy(exebase + phdr->p_vaddr, elf + phdr->p_offset, phdr->p_filesz);
+ return true;
+ default:
+ printf("unknown elf phdr %x\n", phdr->p_type);
return false;
}
- // TODO overlap check
- // TODO don't ignore flags
- _sys_memflag(exebase + phdr->p_vaddr, phdr->p_memsz, MEMFLAG_PRESENT);
- // TODO check that filesz <= memsz
- memcpy(exebase + phdr->p_vaddr, elf + phdr->p_offset, phdr->p_filesz);
- return true;
}
static size_t elf_spread(const void *elf) {
diff --git a/src/libc/include/ctype.h b/src/libc/include/ctype.h
index 1ebb111..f33b645 100644
--- a/src/libc/include/ctype.h
+++ b/src/libc/include/ctype.h
@@ -2,6 +2,7 @@
int isalnum(int c);
int isalpha(int c);
+int isblank(int c);
int iscntrl(int c);
int isdigit(int c);
int isgraph(int c);
diff --git a/src/libc/include/inttypes.h b/src/libc/include/inttypes.h
index d44129a..2890655 100644
--- a/src/libc/include/inttypes.h
+++ b/src/libc/include/inttypes.h
@@ -1,6 +1,7 @@
#include <stdint.h>
#define PRId64 "ld"
+#define PRIi64 "li"
#define PRIo64 "lo"
#define PRIu64 "lu"
#define PRIx64 "lx"
@@ -9,11 +10,13 @@
#define PRId32 "d"
#define PRIo32 "o"
#define PRIu32 "u"
+#define PRIuLEAST32 "u"
#define PRIx32 "x"
#define SCNu32 "u"
#define PRId16 "d"
#define PRIo16 "o"
#define PRIu16 "u"
+#define PRIuLEAST16 "u"
#define PRIx16 "x"
#define SCNu16 "u"
diff --git a/src/libc/include/spawn.h b/src/libc/include/spawn.h
new file mode 100644
index 0000000..936518a
--- /dev/null
+++ b/src/libc/include/spawn.h
@@ -0,0 +1,21 @@
+#pragma once
+#include <sys/types.h>
+
+typedef struct {
+ struct file_action *f;
+} posix_spawn_file_actions_t;
+
+typedef struct {} posix_spawnattr_t;
+
+int posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t *facts, int from, int to);
+int posix_spawn_file_actions_destroy(posix_spawn_file_actions_t *facts);
+int posix_spawn_file_actions_init(posix_spawn_file_actions_t *facts);
+
+int posix_spawnp(
+ pid_t *restrict pid,
+ const char *restrict file,
+ const posix_spawn_file_actions_t *restrict file_actions,
+ const posix_spawnattr_t *restrict attrp,
+ char *const argv[restrict],
+ char *const envp[restrict]
+);
diff --git a/src/libc/include/stdio.h b/src/libc/include/stdio.h
index c579df5..b582e8f 100644
--- a/src/libc/include/stdio.h
+++ b/src/libc/include/stdio.h
@@ -1,4 +1,5 @@
#pragma once
+
#include <bits/file.h>
#include <stdarg.h>
#include <stddef.h>
@@ -27,6 +28,7 @@ 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 snprintf(char *restrict str, size_t len, const char *restrict fmt, ...);
int vprintf(const char *restrict fmt, va_list ap);
int vsprintf(char *restrict s, const char *restrict fmt, va_list ap);
@@ -86,4 +88,6 @@ char *tmpnam(char *s);
int sscanf(const char *restrict s, const char *restrict format, ...);
int vsscanf(const char* str, const char* format, va_list ap);
+int fscanf(FILE* fp, const char* format, ...);
+int vfscanf(FILE* fp, const char* format, va_list ap);
int vcbscanf(void* fp, int (*fgetc)(void*), int (*ungetc)(int, void*), const char* restrict format, va_list ap);
diff --git a/src/libc/include/string.h b/src/libc/include/string.h
index 8b04b39..0bf4082 100644
--- a/src/libc/include/string.h
+++ b/src/libc/include/string.h
@@ -27,3 +27,4 @@ char *strdup(const char *s);
size_t strnlen(const char *s, size_t len);
char *strerror(int errnum);
+char *strsignal(int sig);
diff --git a/src/libc/include/sys/wait.h b/src/libc/include/sys/wait.h
index 5f0d2cc..cc8b9a8 100644
--- a/src/libc/include/sys/wait.h
+++ b/src/libc/include/sys/wait.h
@@ -4,6 +4,7 @@
#define WIFSTOPPED(x) 0
#define WEXITSTATUS(x) ((x)&0xFF)
#define WIFEXITED(x) 1
+#define WIFSIGNALED(x) 0
#define WSTOPSIG(x) 0
#define WTERMSIG(x) 0
@@ -12,3 +13,4 @@
pid_t wait(int *wstatus);
pid_t wait3(int *wstatus, int opts, struct rusage *rusage);
+pid_t waitpid(pid_t pid, int *wstatus, int opts);
diff --git a/src/libc/include/unistd.h b/src/libc/include/unistd.h
index ac5afc0..750d6e2 100644
--- a/src/libc/include/unistd.h
+++ b/src/libc/include/unistd.h
@@ -22,6 +22,7 @@ int isatty(int fd);
int execv(const char *path, char *const argv[]);
int execvp(const char *path, char *const argv[]);
+int execvpe(const char *path, char *const argv[], char *const envp[]);
int execve(const char *path, char *const argv[], char *const envp[]);
int chdir(const char *path);
diff --git a/src/libc/spawn.c b/src/libc/spawn.c
new file mode 100644
index 0000000..c10b428
--- /dev/null
+++ b/src/libc/spawn.c
@@ -0,0 +1,82 @@
+#include <camellia/syscalls.h>
+#include <errno.h>
+#include <spawn.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+enum act {
+ ACT_DUP2 = 1,
+};
+
+struct file_action {
+ struct file_action *next;
+ enum act type;
+ int a, b;
+};
+
+int
+posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t *facts, int from, int to)
+{
+ struct file_action *fact, **tail;
+ fact = calloc(1, sizeof(*fact));
+ if (!fact) return ENOMEM;
+
+ fact->type = ACT_DUP2;
+ fact->a = from;
+ fact->b = to;
+
+ tail = &facts->f;
+ while (*tail) {
+ tail = &(*tail)->next;
+ }
+ *tail = fact;
+ return 0;
+}
+
+int
+posix_spawn_file_actions_destroy(posix_spawn_file_actions_t *facts)
+{
+ while (facts->f) {
+ struct file_action *cur = facts->f;
+ facts->f = cur->next;
+ free(cur);
+ }
+ return 0;
+}
+
+int
+posix_spawn_file_actions_init(posix_spawn_file_actions_t *facts)
+{
+ facts->f = NULL;
+ return 0;
+}
+
+int
+posix_spawnp(
+ pid_t *restrict pidp,
+ const char *restrict file,
+ const posix_spawn_file_actions_t *restrict facts,
+ const posix_spawnattr_t *restrict attrp,
+ char *const argv[restrict],
+ char *const envp[restrict]
+) {
+ if (attrp) return ENOSYS;
+
+ pid_t pid = fork();
+ if (pid < 0) return errno;
+ if (pid == 0) {
+ struct file_action *fact = facts ? facts->f : NULL;
+ while (fact) {
+ switch (fact->type) {
+ case ACT_DUP2:
+ dup2(fact->a, fact->b);
+ break;
+ }
+ fact = fact->next;
+ }
+ execvpe(file, argv, envp);
+ _sys_exit(127);
+ }
+ if (pidp) *pidp = pid;
+ return 0;
+}
diff --git a/src/libc/stdio/file.c b/src/libc/stdio/file.c
index de88a9f..30a578e 100644
--- a/src/libc/stdio/file.c
+++ b/src/libc/stdio/file.c
@@ -248,7 +248,7 @@ size_t fwrite(const void *restrict ptr, size_t size, size_t nitems, FILE *restri
}
int fputs(const char *s, FILE *f) {
- return fprintf(f, "%s\n", s);
+ return fprintf(f, "%s", s);
}
char *fgets(char *buf, int size, FILE *f) {
diff --git a/src/libc/string/string.c b/src/libc/string/string.c
index 014be4a..748b0b5 100644
--- a/src/libc/string/string.c
+++ b/src/libc/string/string.c
@@ -124,6 +124,12 @@ size_t strnlen(const char *s, size_t len) {
return len;
}
+char *strsignal(int sig) {
+ static char buf[32];
+ snprintf(buf, sizeof(buf), "signal %d", sig);
+ return buf;
+}
+
/* strings.h */
int strcasecmp(const char *s1, const char *s2) {
return strncasecmp(s1, s2, ~0);
diff --git a/src/libc/syswait.c b/src/libc/syswait.c
index 43c20ae..d7da2e0 100644
--- a/src/libc/syswait.c
+++ b/src/libc/syswait.c
@@ -10,11 +10,18 @@ pid_t wait(int *wstatus) {
}
pid_t wait3(int *wstatus, int opts, struct rusage *rusage) {
+ if (rusage) {
+ __libc_panic("unimplemented");
+ }
+ return waitpid(-1, wstatus, opts);
+}
+
+pid_t waitpid(pid_t pid, int *wstatus, int opts) {
struct sys_wait2 res;
- if (opts || rusage) {
+ if (opts) {
__libc_panic("unimplemented");
}
- pid_t ret = _sys_wait2(-1, 0, &res);
+ pid_t ret = _sys_wait2(pid, 0, &res);
if (ret < 0) {
errno = -ret;
return -1;
diff --git a/src/libc/unistd.c b/src/libc/unistd.c
index 549da89..e87cdb9 100644
--- a/src/libc/unistd.c
+++ b/src/libc/unistd.c
@@ -77,6 +77,19 @@ int execvp(const char *path, char *const argv[]) {
return execve(path, argv, NULL);
}
+int execvpe(const char *path, char *const argv[], char *const envp[]) {
+ if (path[0] != '/') {
+ char *exp = malloc(strlen(path) + 6);
+ int ret;
+ strcpy(exp, "/bin/");
+ strcat(exp, path);
+ ret = execve(exp, argv, envp);
+ free(exp);
+ return ret;
+ }
+ return execve(path, argv, envp);
+}
+
int execve(const char *path, char *const argv[], char *const envp[]) {
FILE *file = fopen(path, "e");
char hdr[4] = {0};
@@ -225,8 +238,13 @@ ssize_t write(int fd, const void *buf, size_t count) {
}
int pipe(int pipefd[2]) {
- (void)pipefd;
- __libc_panic("unimplemented");
+ // TODO pipe buffering
+ int ret = _sys_pipe(pipefd, 0);
+ if (ret < 0) {
+ errno = -ret;
+ return -1;
+ }
+ return 0;
}
int dup(int oldfd) {
@@ -235,8 +253,12 @@ int dup(int oldfd) {
}
int dup2(int oldfd, int newfd) {
- (void)oldfd; (void)newfd;
- __libc_panic("unimplemented");
+ int ret = _sys_dup(oldfd, newfd, 0);
+ if (ret < 0) {
+ errno = -ret;
+ ret = -1;
+ }
+ return ret;
}
unsigned int sleep(unsigned int seconds) {
diff --git a/src/libc/vendor/sortix/fscanf.c b/src/libc/vendor/sortix/fscanf.c
new file mode 100644
index 0000000..93d300a
--- /dev/null
+++ b/src/libc/vendor/sortix/fscanf.c
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2012, 2013 Jonas 'Sortie' Termansen.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * stdio/fscanf.c
+ * Input format conversion.
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+
+int fscanf(FILE* fp, const char* format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ int ret = vfscanf(fp, format, ap);
+ va_end(ap);
+ return ret;
+}
diff --git a/src/libc/vendor/sortix/vfscanf.c b/src/libc/vendor/sortix/vfscanf.c
new file mode 100644
index 0000000..44efc38
--- /dev/null
+++ b/src/libc/vendor/sortix/vfscanf.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2012, 2013, 2014 Jonas 'Sortie' Termansen.
+ * Modified by dzwdz.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * stdio/vfscanf.c
+ * Input format conversion.
+ *
+ * stdio/vfscanf_unlocked.c
+ * Input format conversion.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+
+static int wrap_fgetc(void* fp)
+{
+ return fgetc((FILE*) fp);
+}
+
+static int wrap_ungetc(int c, void* fp)
+{
+ return ungetc(c, (FILE*) fp);
+}
+
+int vfscanf(FILE* fp, const char* format, va_list ap)
+{
+ // if ( !(fp->flags & _FILE_READABLE) )
+ // return errno = EBADF, fp->flags |= _FILE_STATUS_ERROR, EOF;
+
+ return vcbscanf(fp, wrap_fgetc, wrap_ungetc, format, ap);
+}
diff --git a/src/libk/printf.c b/src/libk/printf.c
index fffd801..cbf89df 100644
--- a/src/libk/printf.c
+++ b/src/libk/printf.c
@@ -96,6 +96,22 @@ static void output_uint16(struct out_state *os, struct mods *m, unsigned long lo
}
}
+static void output_octal(struct out_state *os, struct mods *m, unsigned long long n) {
+ char buf[sizeof(unsigned long long) * 3];
+ size_t pos = sizeof(buf);
+
+ if (!n) {
+ buf[--pos] = '0';
+ } else while (n) {
+ unsigned long long q = n / 8, r = n % 8;
+ buf[--pos] = r + '0';
+ n = q;
+ }
+ size_t len = sizeof(buf) - pos;
+ padnum(os, m, len, '\0');
+ output(os, buf + pos, len);
+}
+
int __printf_internal(const char *fmt, va_list argp,
void (*back)(void*, const char*, size_t), void *backarg)
@@ -170,6 +186,10 @@ int __printf_internal(const char *fmt, va_list argp,
lm = LM_size;
c = *fmt++;
break;
+ case 'j':
+ lm = LM_longlong;
+ c = *fmt++;
+ break;
default:
lm = LM_int;
break;
@@ -201,19 +221,15 @@ int __printf_internal(const char *fmt, va_list argp,
break;
case 'x':
- if (lm == LM_int) n = va_arg(argp, unsigned int);
- else if (lm == LM_long) n = va_arg(argp, unsigned long);
- else if (lm == LM_longlong) n = va_arg(argp, unsigned long long);
- else if (lm == LM_size) n = va_arg(argp, size_t);
- output_uint16(&os, &m, n);
- break;
-
case 'u':
+ case 'o':
if (lm == LM_int) n = va_arg(argp, unsigned int);
else if (lm == LM_long) n = va_arg(argp, unsigned long);
else if (lm == LM_longlong) n = va_arg(argp, unsigned long long);
else if (lm == LM_size) n = va_arg(argp, size_t);
- output_uint(&os, &m, n, '\0');
+ if (c == 'x') output_uint16(&os, &m, n);
+ if (c == 'u') output_uint(&os, &m, n, '\0');
+ if (c == 'o') output_octal(&os, &m, n);
break;
case 'd':