Process.cpp 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  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. #include <AK/DeprecatedString.h>
  9. #include <AK/String.h>
  10. #include <AK/Vector.h>
  11. #include <LibCore/Process.h>
  12. #include <LibCore/System.h>
  13. #include <errno.h>
  14. #include <spawn.h>
  15. #include <unistd.h>
  16. #ifdef AK_OS_SERENITY
  17. # include <serenity.h>
  18. # include <syscall.h>
  19. #endif
  20. extern char** environ;
  21. namespace Core {
  22. struct ArgvList {
  23. DeprecatedString m_path;
  24. DeprecatedString m_working_directory;
  25. Vector<char const*, 10> m_argv;
  26. ArgvList(DeprecatedString path, size_t size)
  27. : m_path { path }
  28. {
  29. m_argv.ensure_capacity(size + 2);
  30. m_argv.append(m_path.characters());
  31. }
  32. void append(char const* arg)
  33. {
  34. m_argv.append(arg);
  35. }
  36. Span<char const*> get()
  37. {
  38. if (m_argv.is_empty() || m_argv.last() != nullptr)
  39. m_argv.append(nullptr);
  40. return m_argv;
  41. }
  42. void set_working_directory(DeprecatedString const& working_directory)
  43. {
  44. m_working_directory = working_directory;
  45. }
  46. ErrorOr<pid_t> spawn()
  47. {
  48. #ifdef AK_OS_SERENITY
  49. posix_spawn_file_actions_t spawn_actions;
  50. posix_spawn_file_actions_init(&spawn_actions);
  51. if (!m_working_directory.is_empty())
  52. posix_spawn_file_actions_addchdir(&spawn_actions, m_working_directory.characters());
  53. auto pid = TRY(System::posix_spawn(m_path.view(), &spawn_actions, nullptr, const_cast<char**>(get().data()), environ));
  54. TRY(System::disown(pid));
  55. #else
  56. auto pid = TRY(System::posix_spawn(m_path.view(), nullptr, nullptr, const_cast<char**>(get().data()), environ));
  57. #endif
  58. return pid;
  59. }
  60. };
  61. ErrorOr<pid_t> Process::spawn(StringView path, ReadonlySpan<DeprecatedString> arguments, DeprecatedString working_directory)
  62. {
  63. ArgvList argv { path, arguments.size() };
  64. for (auto const& arg : arguments)
  65. argv.append(arg.characters());
  66. argv.set_working_directory(working_directory);
  67. return argv.spawn();
  68. }
  69. ErrorOr<pid_t> Process::spawn(StringView path, ReadonlySpan<StringView> arguments, DeprecatedString working_directory)
  70. {
  71. Vector<DeprecatedString> backing_strings;
  72. backing_strings.ensure_capacity(arguments.size());
  73. ArgvList argv { path, arguments.size() };
  74. for (auto const& arg : arguments) {
  75. backing_strings.append(arg);
  76. argv.append(backing_strings.last().characters());
  77. }
  78. argv.set_working_directory(working_directory);
  79. return argv.spawn();
  80. }
  81. ErrorOr<pid_t> Process::spawn(StringView path, ReadonlySpan<char const*> arguments, DeprecatedString working_directory)
  82. {
  83. ArgvList argv { path, arguments.size() };
  84. for (auto arg : arguments)
  85. argv.append(arg);
  86. argv.set_working_directory(working_directory);
  87. return argv.spawn();
  88. }
  89. ErrorOr<String> Process::get_name()
  90. {
  91. #if defined(AK_OS_SERENITY)
  92. char buffer[BUFSIZ];
  93. int rc = get_process_name(buffer, BUFSIZ);
  94. if (rc != 0)
  95. return Error::from_syscall("get_process_name"sv, -rc);
  96. return String::from_utf8(StringView { buffer, strlen(buffer) });
  97. #else
  98. // FIXME: Implement Process::get_name() for other platforms.
  99. return "???"_short_string;
  100. #endif
  101. }
  102. ErrorOr<void> Process::set_name([[maybe_unused]] StringView name, [[maybe_unused]] SetThreadName set_thread_name)
  103. {
  104. #if defined(AK_OS_SERENITY)
  105. int rc = set_process_name(name.characters_without_null_termination(), name.length());
  106. if (rc != 0)
  107. return Error::from_syscall("set_process_name"sv, -rc);
  108. if (set_thread_name == SetThreadName::No)
  109. return {};
  110. rc = syscall(SC_set_thread_name, gettid(), name.characters_without_null_termination(), name.length());
  111. if (rc != 0)
  112. return Error::from_syscall("set_thread_name"sv, -rc);
  113. return {};
  114. #else
  115. // FIXME: Implement Process::set_name() for other platforms.
  116. return {};
  117. #endif
  118. }
  119. }