Serenity Operating System
at master 137 lines 4.0 kB view raw
1/* 2 * Copyright (c) 2021, Andreas Kling <kling@serenityos.org> 3 * Copyright (c) 2022, MacDue <macdue@dueutil.tech> 4 * Copyright (c) 2023, Sam Atkins <atkinssj@serenityos.org> 5 * 6 * SPDX-License-Identifier: BSD-2-Clause 7 */ 8 9#include <AK/DeprecatedString.h> 10#include <AK/String.h> 11#include <AK/Vector.h> 12#include <LibCore/Process.h> 13#include <LibCore/System.h> 14#include <errno.h> 15#include <spawn.h> 16#include <unistd.h> 17 18#ifdef AK_OS_SERENITY 19# include <serenity.h> 20# include <syscall.h> 21#endif 22 23extern char** environ; 24 25namespace Core { 26 27struct ArgvList { 28 DeprecatedString m_path; 29 DeprecatedString m_working_directory; 30 Vector<char const*, 10> m_argv; 31 32 ArgvList(DeprecatedString path, size_t size) 33 : m_path { path } 34 { 35 m_argv.ensure_capacity(size + 2); 36 m_argv.append(m_path.characters()); 37 } 38 39 void append(char const* arg) 40 { 41 m_argv.append(arg); 42 } 43 44 Span<char const*> get() 45 { 46 if (m_argv.is_empty() || m_argv.last() != nullptr) 47 m_argv.append(nullptr); 48 return m_argv; 49 } 50 51 void set_working_directory(DeprecatedString const& working_directory) 52 { 53 m_working_directory = working_directory; 54 } 55 56 ErrorOr<pid_t> spawn() 57 { 58#ifdef AK_OS_SERENITY 59 posix_spawn_file_actions_t spawn_actions; 60 posix_spawn_file_actions_init(&spawn_actions); 61 if (!m_working_directory.is_empty()) 62 posix_spawn_file_actions_addchdir(&spawn_actions, m_working_directory.characters()); 63 64 auto pid = TRY(System::posix_spawn(m_path.view(), &spawn_actions, nullptr, const_cast<char**>(get().data()), environ)); 65 TRY(System::disown(pid)); 66#else 67 auto pid = TRY(System::posix_spawn(m_path.view(), nullptr, nullptr, const_cast<char**>(get().data()), environ)); 68#endif 69 return pid; 70 } 71}; 72 73ErrorOr<pid_t> Process::spawn(StringView path, ReadonlySpan<DeprecatedString> arguments, DeprecatedString working_directory) 74{ 75 ArgvList argv { path, arguments.size() }; 76 for (auto const& arg : arguments) 77 argv.append(arg.characters()); 78 argv.set_working_directory(working_directory); 79 return argv.spawn(); 80} 81 82ErrorOr<pid_t> Process::spawn(StringView path, ReadonlySpan<StringView> arguments, DeprecatedString working_directory) 83{ 84 Vector<DeprecatedString> backing_strings; 85 backing_strings.ensure_capacity(arguments.size()); 86 ArgvList argv { path, arguments.size() }; 87 for (auto const& arg : arguments) { 88 backing_strings.append(arg); 89 argv.append(backing_strings.last().characters()); 90 } 91 argv.set_working_directory(working_directory); 92 return argv.spawn(); 93} 94 95ErrorOr<pid_t> Process::spawn(StringView path, ReadonlySpan<char const*> arguments, DeprecatedString working_directory) 96{ 97 ArgvList argv { path, arguments.size() }; 98 for (auto arg : arguments) 99 argv.append(arg); 100 argv.set_working_directory(working_directory); 101 return argv.spawn(); 102} 103 104ErrorOr<String> Process::get_name() 105{ 106#if defined(AK_OS_SERENITY) 107 char buffer[BUFSIZ]; 108 int rc = get_process_name(buffer, BUFSIZ); 109 if (rc != 0) 110 return Error::from_syscall("get_process_name"sv, -rc); 111 return String::from_utf8(StringView { buffer, strlen(buffer) }); 112#else 113 // FIXME: Implement Process::get_name() for other platforms. 114 return "???"_short_string; 115#endif 116} 117 118ErrorOr<void> Process::set_name([[maybe_unused]] StringView name, [[maybe_unused]] SetThreadName set_thread_name) 119{ 120#if defined(AK_OS_SERENITY) 121 int rc = set_process_name(name.characters_without_null_termination(), name.length()); 122 if (rc != 0) 123 return Error::from_syscall("set_process_name"sv, -rc); 124 if (set_thread_name == SetThreadName::No) 125 return {}; 126 127 rc = syscall(SC_set_thread_name, gettid(), name.characters_without_null_termination(), name.length()); 128 if (rc != 0) 129 return Error::from_syscall("set_thread_name"sv, -rc); 130 return {}; 131#else 132 // FIXME: Implement Process::set_name() for other platforms. 133 return {}; 134#endif 135} 136 137}