summaryrefslogtreecommitdiff
path: root/src/user
diff options
context:
space:
mode:
authordzwdz2022-08-08 19:04:27 +0200
committerdzwdz2022-08-08 19:04:27 +0200
commitf2703089da21898e9c3127615e98c1717c7ceeb5 (patch)
treed4a80164a20b34cbf594e72d758708be23c0e6e1 /src/user
parenta4634ea9458fcc4856ad52bcf383efcb9134091f (diff)
user/libc: cwd
Diffstat (limited to 'src/user')
-rw-r--r--src/user/app/shell/builtins.c2
-rw-r--r--src/user/app/shell/shell.c7
-rw-r--r--src/user/lib/file.c41
-rw-r--r--src/user/lib/include/unistd.h9
-rw-r--r--src/user/lib/stdlib.c84
5 files changed, 127 insertions, 16 deletions
diff --git a/src/user/app/shell/builtins.c b/src/user/app/shell/builtins.c
index 0f06482..efc427d 100644
--- a/src/user/app/shell/builtins.c
+++ b/src/user/app/shell/builtins.c
@@ -107,7 +107,7 @@ static void cmd_ls(int argc, char **argv) {
const size_t buflen = 4096;
char *buf = malloc(buflen);
- DEFAULT_ARGV("/");
+ DEFAULT_ARGV(".");
for (int i = 1; i < argc; i++) {
char *path = (void*)argv[i];
int pathlen = strlen(path);
diff --git a/src/user/app/shell/shell.c b/src/user/app/shell/shell.c
index d96ef4c..0f97d7a 100644
--- a/src/user/app/shell/shell.c
+++ b/src/user/app/shell/shell.c
@@ -47,6 +47,11 @@ void run_args(int argc, char **argv, struct redir *redir) {
exit(1);
}
return;
+ } else if (!strcmp(argv[0], "cd")) {
+ if (chdir(argc > 1 ? argv[1] : "/") < 0)
+ eprintf("error");
+ // TODO strerror
+ return;
} else if (!strcmp(argv[0], "time")) {
uint64_t time = __rdtsc();
uint64_t div = 3000;
@@ -148,7 +153,7 @@ int main(int argc, char **argv) {
for (;;) {
if (f == stdin)
- printf("$ ");
+ printf("%s $ ", getcwd(buf, sizeof buf));
if (!fgets(buf, 256, f))
return 0;
run(buf);
diff --git a/src/user/lib/file.c b/src/user/lib/file.c
index 942b522..080217c 100644
--- a/src/user/lib/file.c
+++ b/src/user/lib/file.c
@@ -18,7 +18,11 @@ FILE *fopen(const char *path, const char *mode) {
FILE *f;
handle_t h;
int flags = 0;
- if (path && path[0] == '!') {
+ char *tmppath = NULL;
+ if (!path) {
+ errno = -1;
+ return NULL;
+ } else if (path[0] == '!') {
/* special handling for "!files" */
path++;
if (!strcmp(path, "stdin")) return file_clone(stdin, mode);
@@ -26,23 +30,32 @@ FILE *fopen(const char *path, const char *mode) {
if (!strcmp(path, "stderr")) return file_clone(stderr, mode);
errno = -1;
return NULL;
- } else {
- if (mode[0] == 'w' || mode[0] == 'a')
- flags |= OPEN_CREATE;
+ }
- h = _syscall_open(path, strlen(path), flags);
- if (h < 0) {
- errno = -h;
- return NULL;
- }
+ if (path && path[0] != '/') {
+ size_t len = absolutepath(NULL, path, 0);
+ tmppath = malloc(len);
+ if (!tmppath) return NULL;
+ absolutepath(tmppath, path, len);
+ path = tmppath;
+ }
- if (mode[0] == 'w')
- _syscall_write(h, NULL, 0, 0, WRITE_TRUNCATE);
+ if (mode[0] == 'w' || mode[0] == 'a')
+ flags |= OPEN_CREATE;
- f = fdopen(h, mode);
- if (!f) close(h);
- return f;
+ h = _syscall_open(path, strlen(path), flags);
+ if (tmppath) free(tmppath);
+ if (h < 0) {
+ errno = -h;
+ return NULL;
}
+
+ if (mode[0] == 'w')
+ _syscall_write(h, NULL, 0, 0, WRITE_TRUNCATE);
+
+ f = fdopen(h, mode);
+ if (!f) close(h);
+ return f;
}
FILE *freopen(const char *path, const char *mode, FILE *f) {
diff --git a/src/user/lib/include/unistd.h b/src/user/lib/include/unistd.h
index 4f367ca..aedca1b 100644
--- a/src/user/lib/include/unistd.h
+++ b/src/user/lib/include/unistd.h
@@ -6,3 +6,12 @@ int close(handle_t h);
_Noreturn void exit(int);
int execv(const char *path, char *const argv[]);
+
+int chdir(const char *path);
+char *getcwd(char *buf, size_t size);
+/* Converts a relative path to an absolute one, simplifying it if possible.
+ * If in == NULL - return the length of cwd (without a trailing slash)
+ * If size isn't enough to fit the path, returns the amount of bytes needed to fit
+ * it, including the null byte.
+ * @return 0 on failure, length of the path otherwise */
+size_t absolutepath(char *out, const char *in, size_t size);
diff --git a/src/user/lib/stdlib.c b/src/user/lib/stdlib.c
index 94e12d3..566eb3e 100644
--- a/src/user/lib/stdlib.c
+++ b/src/user/lib/stdlib.c
@@ -1,6 +1,8 @@
+#include <camellia/path.h>
#include <camellia/syscalls.h>
#include <errno.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <user/lib/elfload.h>
@@ -49,3 +51,85 @@ int execv(const char *path, char *const argv[]) {
_Noreturn void abort(void) {
_syscall_exit(1);
}
+
+
+static char *cwd = NULL, *cwd2 = NULL;
+static size_t cwdcapacity = 0;
+
+int chdir(const char *path) {
+ handle_t h;
+ char *tmp;
+ size_t len = absolutepath(NULL, path, 0) + 1; /* +1 for the trailing slash */
+ if (cwdcapacity < len) {
+ cwdcapacity = len;
+ if (cwd) {
+ cwd = realloc(cwd, len);
+ cwd2 = realloc(cwd2, len);
+ } else {
+ cwd = malloc(len);
+ cwd[0] = '/';
+ cwd[1] = '\0';
+ cwd2 = malloc(len);
+ cwd2[0] = '/';
+ cwd2[1] = '\0';
+ }
+ }
+ absolutepath(cwd2, path, cwdcapacity);
+ len = strlen(cwd2);
+ if (cwd2[len - 1] != '/') {
+ cwd2[len] = '/';
+ cwd2[len + 1] = '\0';
+ }
+
+ h = _syscall_open(cwd2, strlen(cwd2), 0);
+ if (h < 0) {
+ errno = ENOENT;
+ return -1;
+ }
+ _syscall_close(h);
+
+ tmp = cwd;
+ cwd = cwd2;
+ cwd2 = tmp;
+ return 0;
+}
+
+char *getcwd(char *buf, size_t size) {
+ const char *realcwd = cwd ? cwd : "/";
+ // TODO bounds checking
+ memcpy(buf, realcwd, strlen(realcwd) + 1);
+ return buf;
+}
+
+size_t absolutepath(char *out, const char *in, size_t size) {
+ const char *realcwd = cwd ? cwd : "/";
+ size_t len, pos = 0;
+ if (!in) return strlen(realcwd);
+
+ if (!(in[0] == '/')) {
+ len = strlen(realcwd);
+ if (pos + len <= size && out != realcwd)
+ memcpy(out + pos, realcwd, len);
+ pos += len;
+
+ if (realcwd[len - 1] != '/') {
+ if (pos + 1 <= size) out[pos] = '/';
+ pos++;
+ }
+ }
+
+ len = strlen(in);
+ if (pos + len <= size)
+ memcpy(out + pos, in, len);
+ pos += len;
+
+ if (pos <= size) {
+ pos = path_simplify(out, out, pos);
+ if (pos > 0) out[pos] = '\0';
+ }
+
+ if (pos + 1 <= size) out[pos] = '\0';
+ pos++;
+
+ return pos;
+}