diff options
author | dzwdz | 2022-08-08 19:04:27 +0200 |
---|---|---|
committer | dzwdz | 2022-08-08 19:04:27 +0200 |
commit | f2703089da21898e9c3127615e98c1717c7ceeb5 (patch) | |
tree | d4a80164a20b34cbf594e72d758708be23c0e6e1 /src/user | |
parent | a4634ea9458fcc4856ad52bcf383efcb9134091f (diff) |
user/libc: cwd
Diffstat (limited to 'src/user')
-rw-r--r-- | src/user/app/shell/builtins.c | 2 | ||||
-rw-r--r-- | src/user/app/shell/shell.c | 7 | ||||
-rw-r--r-- | src/user/lib/file.c | 41 | ||||
-rw-r--r-- | src/user/lib/include/unistd.h | 9 | ||||
-rw-r--r-- | src/user/lib/stdlib.c | 84 |
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; +} |