diff --git a/Kernel/Syscall.cpp b/Kernel/Syscall.cpp index df6fe77662..6dc00beb29 100644 --- a/Kernel/Syscall.cpp +++ b/Kernel/Syscall.cpp @@ -65,7 +65,7 @@ DWORD handle(DWORD function, DWORD arg1, DWORD arg2, DWORD arg3) case Syscall::PosixGettimeofday: return current->sys$gettimeofday((timeval*)arg1); case Syscall::Spawn: - return current->sys$spawn((const char*)arg1); + return current->sys$spawn((const char*)arg1, (const char**)arg2); case Syscall::GetDirEntries: return current->sys$get_dir_entries((int)arg1, (void*)arg2, (size_t)arg3); case Syscall::PosixLstat: @@ -108,6 +108,8 @@ DWORD handle(DWORD function, DWORD arg1, DWORD arg2, DWORD arg3) current->sys$exit((int)arg1); ASSERT_NOT_REACHED(); return 0; + case Syscall::GetArguments: + return current->sys$get_arguments((int*)arg1, (char***)arg2); default: kprintf("int0x80: Unknown function %x requested {%x, %x, %x}\n", function, arg1, arg2, arg3); break; diff --git a/Kernel/Syscall.h b/Kernel/Syscall.h index 1c704b2fff..5f225fc12d 100644 --- a/Kernel/Syscall.h +++ b/Kernel/Syscall.h @@ -31,6 +31,7 @@ enum Function { PosixGetcwd = 0x1999, PosixGettimeofday = 0x2000, PosixGethostname = 0x2001, + GetArguments = 0x2002, }; void initialize(); diff --git a/Kernel/Task.cpp b/Kernel/Task.cpp index b505de76fc..e7abce35d2 100644 --- a/Kernel/Task.cpp +++ b/Kernel/Task.cpp @@ -185,18 +185,19 @@ int Task::sys$gethostname(char* buffer, size_t size) if (size < (hn.length() + 1)) return -ENAMETOOLONG; memcpy(buffer, hn.characters(), size); + return 0; } -int Task::sys$spawn(const char* path) +int Task::sys$spawn(const char* path, const char** args) { int error = 0; - auto* child = Task::createUserTask(path, m_uid, m_gid, m_pid, error); + auto* child = Task::createUserTask(path, m_uid, m_gid, m_pid, error, args); if (child) return child->pid(); return error; } -Task* Task::createUserTask(const String& path, uid_t uid, gid_t gid, pid_t parentPID, int& error) +Task* Task::createUserTask(const String& path, uid_t uid, gid_t gid, pid_t parentPID, int& error, const char** args) { auto parts = path.split('/'); if (parts.isEmpty()) { @@ -216,9 +217,20 @@ Task* Task::createUserTask(const String& path, uid_t uid, gid_t gid, pid_t paren return nullptr; } + Vector taskArguments; + if (args) { + for (size_t i = 0; args[i]; ++i) { + taskArguments.append(args[i]); + } + } else { + taskArguments.append(parts.last()); + } + InterruptDisabler disabler; // FIXME: Get rid of this, jesus christ. This "critical" section is HUGE. Task* t = new Task(parts.takeLast(), uid, gid, parentPID, Ring3); + t->m_arguments = move(taskArguments); + ExecSpace space; space.hookableAlloc = [&] (const String& name, size_t size) { if (!size) @@ -257,6 +269,25 @@ Task* Task::createUserTask(const String& path, uid_t uid, gid_t gid, pid_t paren return t; } +int Task::sys$get_arguments(int* argc, char*** argv) +{ + auto* region = allocateRegion(4096, "argv"); + if (!region) + return -ENOMEM; + MemoryManager::the().mapRegion(*this, *region); + char* argpage = (char*)region->linearAddress.get(); + *argc = m_arguments.size(); + *argv = (char**)argpage; + char* bufptr = argpage + (sizeof(char*) * m_arguments.size()); + for (size_t i = 0; i < m_arguments.size(); ++i) { + (*argv)[i] = bufptr; + memcpy(bufptr, m_arguments[i].characters(), m_arguments[i].length()); + bufptr += m_arguments[i].length(); + *(bufptr++) = '\0'; + } + return 0; +} + Task* Task::createKernelTask(void (*e)(), String&& name) { Task* task = new Task(move(name), (uid_t)0, (gid_t)0, (pid_t)0, Ring0); diff --git a/Kernel/Task.h b/Kernel/Task.h index 6cf40481b3..e2d9c35834 100644 --- a/Kernel/Task.h +++ b/Kernel/Task.h @@ -16,7 +16,7 @@ class Task : public InlineLinkedListNode { friend class InlineLinkedListNode; public: static Task* createKernelTask(void (*entry)(), String&& name); - static Task* createUserTask(const String& path, uid_t, gid_t, pid_t parentPID, int& error); + static Task* createUserTask(const String& path, uid_t, gid_t, pid_t parentPID, int& error, const char** args = nullptr); ~Task(); static Vector allTasks(); @@ -92,7 +92,7 @@ public: int sys$kill(pid_t pid, int sig); int sys$geterror() { return m_error; } void sys$exit(int status); - int sys$spawn(const char* path); + int sys$spawn(const char* path, const char** args); pid_t sys$waitpid(pid_t); void* sys$mmap(void*, size_t size); int sys$munmap(void*, size_t size); @@ -101,6 +101,7 @@ public: int sys$sleep(unsigned seconds); int sys$gettimeofday(timeval*); int sys$gethostname(char* name, size_t length); + int sys$get_arguments(int* argc, char*** argv); static void initialize(); @@ -170,6 +171,8 @@ private: LinearAddress m_nextRegion; pid_t m_parentPID { 0 }; + + Vector m_arguments; }; extern void task_init(); diff --git a/Kernel/_fs_contents b/Kernel/_fs_contents index 7ee095bf0e..a5772d962d 100644 Binary files a/Kernel/_fs_contents and b/Kernel/_fs_contents differ diff --git a/Kernel/sync-sh b/Kernel/sync-sh index 24ba204577..922f07931c 100755 --- a/Kernel/sync-sh +++ b/Kernel/sync-sh @@ -10,5 +10,6 @@ cp ../Userland/date mnt/bin/date cp ../Userland/true mnt/bin/true cp ../Userland/false mnt/bin/false cp ../Userland/hostname mnt/bin/hostname +cp ../Userland/cat mnt/bin/cat umount mnt sync diff --git a/LibC/entry.cpp b/LibC/entry.cpp index 2308bc453c..5d5eb27078 100644 --- a/LibC/entry.cpp +++ b/LibC/entry.cpp @@ -8,9 +8,12 @@ extern "C" int _start() { errno = 0; - // FIXME: Pass appropriate argc/argv. - int status = main(0, nullptr); - + int argc; + char** argv; + int rc = Syscall::invoke(Syscall::GetArguments, (dword)&argc, (dword)&argv); + int status = 254; + if (rc == 0) + status = main(argc, argv); Syscall::invoke(Syscall::PosixExit, status); // Birger's birthday <3 diff --git a/LibC/process.cpp b/LibC/process.cpp index 223b6871d7..eb3040b80e 100644 --- a/LibC/process.cpp +++ b/LibC/process.cpp @@ -4,9 +4,9 @@ extern "C" { -int spawn(const char* path) +int spawn(const char* path, const char** args) { - int rc = Syscall::invoke(Syscall::Spawn, (dword)path); + int rc = Syscall::invoke(Syscall::Spawn, (dword)path, (dword)args); __RETURN_WITH_ERRNO(rc, rc, -1); } diff --git a/LibC/process.h b/LibC/process.h index 2a35644085..235415469a 100644 --- a/LibC/process.h +++ b/LibC/process.h @@ -2,7 +2,7 @@ extern "C" { -int spawn(const char* path); +int spawn(const char* path, const char** args); } diff --git a/Userland/.gitignore b/Userland/.gitignore index ffdbff1187..2c52d710f8 100644 --- a/Userland/.gitignore +++ b/Userland/.gitignore @@ -1,3 +1,4 @@ +*.o id sh ps @@ -8,4 +9,4 @@ date false true hostname -*.o +cat diff --git a/Userland/Makefile b/Userland/Makefile index c5a8b4e209..d433c7422d 100644 --- a/Userland/Makefile +++ b/Userland/Makefile @@ -8,7 +8,8 @@ OBJS = \ date.o \ true.o \ false.o \ - hostname.o + hostname.o \ + cat.o APPS = \ id \ @@ -20,7 +21,8 @@ APPS = \ date \ true \ false \ - hostname + hostname \ + cat ARCH_FLAGS = STANDARD_FLAGS = -std=c++17 -nostdinc++ -nostdlib @@ -70,6 +72,9 @@ false: false.o hostname: hostname.o $(LD) -o $@ $(LDFLAGS) $< ../LibC/LibC.a +cat: cat.o + $(LD) -o $@ $(LDFLAGS) $< ../LibC/LibC.a + .cpp.o: @echo "CXX $<"; $(CXX) $(CXXFLAGS) -o $@ -c $< diff --git a/Userland/cat.cpp b/Userland/cat.cpp new file mode 100644 index 0000000000..ce99c6499b --- /dev/null +++ b/Userland/cat.cpp @@ -0,0 +1,30 @@ +#include +#include +#include +#include + +int main(int argc, char** argv) +{ + if (argc != 2) { + printf("usage: cat \n"); + return 1; + } + int fd = open(argv[1]); + if (fd == -1) { + printf("failed to open %s: %s\n", argv[1], strerror(errno)); + return 1; + } + for (;;) { + char buf[128]; + ssize_t nread = read(fd, buf, sizeof(buf)); + if (nread == 0) + break; + if (nread < 0) { + printf("read() error: %s\n", strerror(errno)); + return 2; + } + for (ssize_t i = 0; i < nread; ++i) + putchar(buf[i]); + } + return 0; +} diff --git a/Userland/sh.cpp b/Userland/sh.cpp index 35905dc861..b4adda1731 100644 --- a/Userland/sh.cpp +++ b/Userland/sh.cpp @@ -16,10 +16,21 @@ static int runcmd(char* cmd) { if (cmd[0] == 0) return 0; - //printf("command: '%s'\n", cmd); char buf[128]; sprintf(buf, "/bin/%s", cmd); - int ret = spawn(buf); + + const char* argv[32]; + size_t argi = 1; + argv[0] = &buf[0]; + size_t buflen = strlen(buf); + for (size_t i = 0; i < buflen; ++i) { + if (buf[i] == ' ') { + buf[i] = '\0'; + argv[argi++] = &buf[i + 1]; + } + } + argv[argi + 1] = nullptr; + int ret = spawn(argv[0], argv); if (ret == -1) { printf("spawn failed: %s (%s)\n", cmd, strerror(errno)); return 1;