summaryrefslogtreecommitdiff
path: root/userland/libc/unistd/execvp.c
diff options
context:
space:
mode:
Diffstat (limited to 'userland/libc/unistd/execvp.c')
-rw-r--r--userland/libc/unistd/execvp.c46
1 files changed, 43 insertions, 3 deletions
diff --git a/userland/libc/unistd/execvp.c b/userland/libc/unistd/execvp.c
index e38b4b7..af3ed29 100644
--- a/userland/libc/unistd/execvp.c
+++ b/userland/libc/unistd/execvp.c
@@ -1,8 +1,48 @@
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include <syscall.h>
+#include <tb/sb.h>
+#include <tb/sv.h>
#include <unistd.h>
-// FIXME: Path resolution
+int execv(const char *pathname, char *const argv[]) {
+ struct SYS_EXEC_PARAMS args = {.path = pathname, .argv = (char **)argv};
+ RC_ERRNO(syscall(SYS_EXEC, &args, 0, 0, 0, 0));
+}
+
int execvp(const char *file, char *const argv[]) {
- struct SYS_EXEC_PARAMS args = {.path = file, .argv = (char **)argv};
- return syscall(SYS_EXEC, &args, 0, 0, 0, 0);
+ if ('/' == *file) {
+ return execv(file, argv);
+ }
+
+ char *p = getenv("PATH");
+ if (!p) {
+ errno = ENOENT;
+ return -1;
+ }
+
+ struct sv paths = C_TO_SV(p);
+
+ struct sb builder;
+ sb_init(&builder);
+ for (;;) {
+ struct sv path = sv_split_delim(paths, &paths, ':');
+ if (0 == sv_length(path)) {
+ break;
+ }
+ sb_reset(&builder);
+ sb_append_sv(&builder, path);
+ sb_append(&builder, "/");
+ sb_append(&builder, file);
+ sb_append_buffer(&builder, "\0", 1);
+
+ if (-1 == execv(builder.string, argv)) {
+ continue;
+ }
+ }
+ sb_free(&builder);
+ errno = ENOENT;
+ return -1;
}