diff --git a/kernel/include/kernel/Process.h b/kernel/include/kernel/Process.h index 934a7217c..aab2fd599 100644 --- a/kernel/include/kernel/Process.h +++ b/kernel/include/kernel/Process.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -45,11 +46,17 @@ namespace Kernel void exit(int status, int signal); + static void for_each_process(const BAN::Function& callback); + void add_thread(Thread*); void on_thread_exit(Thread&); + pid_t sid() const { return m_sid; } + pid_t pgrp() const { return m_pgrp; } pid_t pid() const { return m_pid; } + bool is_session_leader() const { return pid() == sid(); } + BAN::ErrorOr sys_exit(int status); BAN::ErrorOr sys_gettermios(::termios*); @@ -111,7 +118,7 @@ namespace Kernel BAN::ErrorOr sys_clock_gettime(clockid_t, timespec*) const; - TTY& tty() { ASSERT(m_tty); return *m_tty; } + TTY& tty() { ASSERT(m_controlling_terminal); return *m_controlling_terminal; } static Process& current() { return Thread::current().process(); } @@ -121,8 +128,8 @@ namespace Kernel const userspace_info_t& userspace_info() const { return m_userspace_info; } private: - Process(const Credentials&, pid_t); - static Process* create_process(const Credentials&); + Process(const Credentials&, pid_t pid, pid_t parent, pid_t sid, pid_t pgrp); + static Process* create_process(const Credentials&, pid_t parent, pid_t sid = 0, pid_t pgrp = 0); static void register_process(Process*); // Load an elf file to virtual address space of the current page table @@ -150,9 +157,13 @@ namespace Kernel BAN::Vector> m_mapped_ranges; + pid_t m_sid; + pid_t m_pgrp; + const pid_t m_pid; + const pid_t m_parent; + mutable RecursiveSpinLock m_lock; - const pid_t m_pid = 0; BAN::String m_working_directory; BAN::Vector m_threads; @@ -167,7 +178,7 @@ namespace Kernel ExitStatus m_exit_status; BAN::UniqPtr m_page_table; - BAN::RefPtr m_tty; + BAN::RefPtr m_controlling_terminal; friend class Thread; }; diff --git a/kernel/include/kernel/Terminal/TTY.h b/kernel/include/kernel/Terminal/TTY.h index 43d81c6ba..fb5e68082 100644 --- a/kernel/include/kernel/Terminal/TTY.h +++ b/kernel/include/kernel/Terminal/TTY.h @@ -23,8 +23,8 @@ namespace Kernel uint32_t height() const { return m_height; } uint32_t width() const { return m_width; } - void set_foreground_process(pid_t pgid) { m_foreground_process = pgid; } - pid_t foreground_process() const { return m_foreground_process; } + void set_foreground_pgrp(pid_t pgrp) { m_foreground_pgrp = pgrp; } + pid_t foreground_pgrp() const { return m_foreground_pgrp; } // for kprint static void putchar_current(uint8_t ch); @@ -97,7 +97,7 @@ namespace Kernel TerminalDriver::Color m_foreground { TerminalColor::BRIGHT_WHITE }; TerminalDriver::Color m_background { TerminalColor::BLACK }; - pid_t m_foreground_process { 0 }; + pid_t m_foreground_pgrp { 0 }; termios m_termios; diff --git a/kernel/kernel/OpenFileDescriptorSet.cpp b/kernel/kernel/OpenFileDescriptorSet.cpp index 9d4829e9a..607c6a525 100644 --- a/kernel/kernel/OpenFileDescriptorSet.cpp +++ b/kernel/kernel/OpenFileDescriptorSet.cpp @@ -56,7 +56,7 @@ namespace Kernel BAN::ErrorOr OpenFileDescriptorSet::open(BAN::StringView absolute_path, int flags) { - if (flags & ~(O_RDONLY | O_WRONLY | O_NOFOLLOW | O_SEARCH | O_APPEND | O_TRUNC | O_CLOEXEC)) + if (flags & ~(O_RDONLY | O_WRONLY | O_NOFOLLOW | O_SEARCH | O_APPEND | O_TRUNC | O_CLOEXEC | O_TTY_INIT)) return BAN::Error::from_errno(ENOTSUP); int access_mask = O_EXEC | O_RDONLY | O_WRONLY | O_SEARCH; diff --git a/kernel/kernel/Process.cpp b/kernel/kernel/Process.cpp index b2ab8696f..43ee8c163 100644 --- a/kernel/kernel/Process.cpp +++ b/kernel/kernel/Process.cpp @@ -21,13 +21,43 @@ namespace Kernel { static BAN::Vector s_processes; - static SpinLock s_process_lock; + static RecursiveSpinLock s_process_lock; - Process* Process::create_process(const Credentials& credentials) + void Process::for_each_process(const BAN::Function& callback) { - static pid_t s_next_pid = 1; - auto* process = new Process(credentials, s_next_pid++); + LockGuard _(s_process_lock); + + for (auto* process : s_processes) + { + auto ret = callback(*process); + if (ret == BAN::Iteration::Break) + return; + ASSERT(ret == BAN::Iteration::Continue); + } + } + + Process* Process::create_process(const Credentials& credentials, pid_t parent, pid_t sid, pid_t pgrp) + { + static pid_t s_next_id = 1; + + pid_t pid; + { + CriticalScope _; + pid = s_next_id; + if (sid == 0 && pgrp == 0) + { + sid = s_next_id; + pgrp = s_next_id; + } + s_next_id++; + } + + ASSERT(sid > 0); + ASSERT(pgrp > 0); + + auto* process = new Process(credentials, pid, parent, sid, pgrp); ASSERT(process); + return process; } @@ -42,7 +72,7 @@ namespace Kernel Process* Process::create_kernel(entry_t entry, void* data) { - auto* process = create_process({ 0, 0, 0, 0 }); + auto* process = create_process({ 0, 0, 0, 0 }, 0); MUST(process->m_working_directory.push_back('/')); auto* thread = MUST(Thread::create_kernel(entry, data, process)); process->add_thread(thread); @@ -54,7 +84,7 @@ namespace Kernel { auto elf = TRY(load_elf_for_exec(credentials, path, "/"sv, {})); - auto* process = create_process(credentials); + auto* process = create_process(credentials, 0); MUST(process->m_working_directory.push_back('/')); process->m_page_table = BAN::UniqPtr::adopt(MUST(PageTable::create_userspace()));; @@ -95,11 +125,13 @@ namespace Kernel return process; } - Process::Process(const Credentials& credentials, pid_t pid) + Process::Process(const Credentials& credentials, pid_t pid, pid_t parent, pid_t sid, pid_t pgrp) : m_credentials(credentials) , m_open_file_descriptors(m_credentials) + , m_sid(sid) + , m_pgrp(pgrp) , m_pid(pid) - , m_tty(TTY::current()) + , m_parent(parent) { for (size_t i = 0; i < sizeof(m_signal_handlers) / sizeof(*m_signal_handlers); i++) m_signal_handlers[i] = (vaddr_t)SIG_DFL; @@ -148,9 +180,6 @@ namespace Kernel // NOTE: We must clear allocators while the page table is still alive m_fixed_width_allocators.clear(); m_general_allocator.clear(); - - if (m_tty && m_tty->foreground_process() == pid()) - m_tty->set_foreground_process(0); } void Process::on_thread_exit(Thread& thread) @@ -198,10 +227,11 @@ namespace Kernel BAN::ErrorOr Process::sys_gettermios(::termios* termios) { LockGuard _(m_lock); - if (!m_tty) + + if (!m_controlling_terminal) return BAN::Error::from_errno(ENOTTY); - Kernel::termios ktermios = m_tty->get_termios(); + Kernel::termios ktermios = m_controlling_terminal->get_termios(); termios->c_lflag = 0; if (ktermios.canonical) termios->c_lflag |= ICANON; @@ -214,14 +244,15 @@ namespace Kernel BAN::ErrorOr Process::sys_settermios(const ::termios* termios) { LockGuard _(m_lock); - if (!m_tty) + + if (!m_controlling_terminal) return BAN::Error::from_errno(ENOTTY); Kernel::termios ktermios; ktermios.echo = termios->c_lflag & ECHO; ktermios.canonical = termios->c_lflag & ICANON; - m_tty->set_termios(ktermios); + m_controlling_terminal->set_termios(ktermios); return 0; } @@ -325,8 +356,8 @@ namespace Kernel if (m_general_allocator) general_allocator = TRY(m_general_allocator->clone(*page_table)); - Process* forked = create_process(m_credentials); - forked->m_tty = m_tty; + Process* forked = create_process(m_credentials, m_pid, m_sid, m_pgrp); + forked->m_controlling_terminal = m_controlling_terminal; forked->m_working_directory = BAN::move(working_directory); forked->m_page_table = BAN::move(page_table); forked->m_open_file_descriptors = BAN::move(open_file_descriptors); @@ -455,12 +486,17 @@ namespace Kernel if (options) return BAN::Error::from_errno(EINVAL); - { - LockGuard _(s_process_lock); - for (auto* process : s_processes) - if (process->pid() == pid) - target = process; - } + for_each_process( + [&](Process& process) + { + if (process.pid() == pid) + { + target = &process; + return BAN::Iteration::Break; + } + return BAN::Iteration::Continue; + } + ); if (target == nullptr) return BAN::Error::from_errno(ECHILD); @@ -555,7 +591,14 @@ namespace Kernel flags &= ~O_CREAT; } - return TRY(m_open_file_descriptors.open(absolute_path, flags)); + int fd = TRY(m_open_file_descriptors.open(absolute_path, flags)); + auto inode = MUST(m_open_file_descriptors.inode_of(fd)); + + // Open controlling terminal + if ((flags & O_TTY_INIT) && !(flags & O_NOCTTY) && inode->is_tty() && is_session_leader() && !m_controlling_terminal) + m_controlling_terminal = (TTY*)inode.ptr(); + + return fd; } BAN::ErrorOr Process::sys_openat(int fd, BAN::StringView path, int flags, mode_t mode) @@ -791,14 +834,18 @@ namespace Kernel BAN::ErrorOr Process::sys_termid(char* buffer) const { LockGuard _(m_lock); - if (!m_tty) + + auto& tty = m_controlling_terminal; + + if (!tty) buffer[0] = '\0'; else { - ASSERT(minor(m_tty->rdev()) < 10); + ASSERT(minor(tty->rdev()) < 10); strcpy(buffer, "/dev/tty0"); - buffer[8] += minor(m_tty->rdev()); + buffer[8] += minor(tty->rdev()); } + return 0; } @@ -834,7 +881,7 @@ namespace Kernel BAN::ErrorOr Process::sys_kill(pid_t pid, int signal) { - if (pid <= 0) + if (pid == 0 || pid == -1) return BAN::Error::from_errno(ENOTSUP); if (signal != 0 && (signal < _SIGMIN || signal > _SIGMAX)) return BAN::Error::from_errno(EINVAL); @@ -842,19 +889,26 @@ namespace Kernel if (pid == Process::current().pid()) return Process::current().sys_raise(signal); - LockGuard process_guard(s_process_lock); - for (auto* process : s_processes) - { - if (process->pid() == pid) + bool found = false; + for_each_process( + [&](Process& process) { - if (signal == 0) - return 0; - CriticalScope _; - process->m_signal_pending_mask |= 1ull << signal; - return 0; + if (pid == process.pid() || -pid == process.pid()) + { + found = true; + if (signal) + { + CriticalScope _; + process.m_signal_pending_mask |= 1 << signal; + } + return (pid > 0) ? BAN::Iteration::Break : BAN::Iteration::Continue; + } + return BAN::Iteration::Continue; } - } + ); + if (found) + return 0; return BAN::Error::from_errno(ESRCH); } @@ -869,31 +923,37 @@ namespace Kernel return 0; } - BAN::ErrorOr Process::sys_tcsetpgrp(int fd, pid_t pgid) + BAN::ErrorOr Process::sys_tcsetpgrp(int fd, pid_t pgrp) { LockGuard _(m_lock); - // FIXME: validate the inode + if (!m_controlling_terminal) + return BAN::Error::from_errno(ENOTTY); + + bool valid_pgrp = false; + for_each_process( + [&](Process& process) + { + if (process.sid() == sid() && process.pgrp() == pgrp) + { + valid_pgrp = true; + return BAN::Iteration::Break; + } + return BAN::Iteration::Continue; + } + ); + if (!valid_pgrp) + return BAN::Error::from_errno(EPERM); + auto inode = TRY(m_open_file_descriptors.inode_of(fd)); if (!inode->is_tty()) return BAN::Error::from_errno(ENOTTY); + + if ((TTY*)inode.ptr() != m_controlling_terminal.ptr()) + return BAN::Error::from_errno(ENOTTY); - // FIXME: use process groups instead of process ids - // FIXME: return values - - LockGuard process_guard(s_process_lock); - for (auto* process : s_processes) - { - if (process->pid() == pgid) - { - if (!process->is_userspace()) - return BAN::Error::from_errno(EINVAL); - ((TTY*)inode.ptr())->set_foreground_process(pgid); - return 0; - } - } - - return BAN::Error::from_errno(EPERM); + ((TTY*)inode.ptr())->set_foreground_pgrp(pgrp); + return 0; } BAN::ErrorOr Process::sys_setuid(uid_t uid) diff --git a/kernel/kernel/Terminal/TTY.cpp b/kernel/kernel/Terminal/TTY.cpp index d52e39dcf..9cf26cad1 100644 --- a/kernel/kernel/Terminal/TTY.cpp +++ b/kernel/kernel/Terminal/TTY.cpp @@ -29,7 +29,7 @@ namespace Kernel static dev_t next_tty_rdev() { static dev_t major = DevFileSystem::get().get_next_rdev(); - static dev_t minor = 1; + static dev_t minor = 0; return makedev(major, minor++); } @@ -75,17 +75,17 @@ namespace Kernel ASSERT(MUST(Process::current().sys_read(fd, &event, sizeof(event))) == sizeof(event)); TTY& current_tty = *TTY::current(); - if (current_tty.m_foreground_process && + if (current_tty.m_foreground_pgrp && event.pressed() && event.ctrl() && !event.shift() && event.key == Input::Key::C ) { - if (auto ret = Process::sys_kill(current_tty.m_foreground_process, SIGINT); ret.is_error()) + if (auto ret = Process::sys_kill(-current_tty.m_foreground_pgrp, SIGINT); ret.is_error()) dwarnln("TTY: {}", ret.error()); } - else + else current_tty.on_key(event); } }, nullptr