mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-06-10 18:10:56 +09:00
LibCore: Add a wrapper for execvpe() and friends
This is a single function, which behaves like the various LibC exec() functions depending on the passed parameters. No direct equivalent is made for execl() - you have to wrap your arguments in a Span of some kind. On Serenity, this calls the syscall directly, whereas Lagom forwards to the appropriate LibC function.
This commit is contained in:
parent
b4c6fd51be
commit
32ab09a930
Notes:
sideshowbarker
2024-07-17 12:06:10 +09:00
Author: https://github.com/AtkinsSJ
Commit: 32ab09a930
Pull-request: https://github.com/SerenityOS/serenity/pull/13013
Reviewed-by: https://github.com/ADKaster
Reviewed-by: https://github.com/bgianfo
2 changed files with 130 additions and 1 deletions
|
@ -1,12 +1,14 @@
|
|||
/*
|
||||
* Copyright (c) 2021-2022, Andreas Kling <kling@serenityos.org>
|
||||
* Copyright (c) 2021-2022, Kenneth Myhra <kennethmyhra@gmail.com>
|
||||
* Copyright (c) 2021, Sam Atkins <atkinssj@serenityos.org>
|
||||
* Copyright (c) 2021-2022, Sam Atkins <atkinssj@serenityos.org>
|
||||
* Copyright (c) 2022, Matthias Zimmerman <matthias291999@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/FixedArray.h>
|
||||
#include <AK/ScopedValueRollback.h>
|
||||
#include <AK/StdLibExtras.h>
|
||||
#include <AK/String.h>
|
||||
#include <AK/Vector.h>
|
||||
|
@ -906,6 +908,128 @@ ErrorOr<void> adjtime(const struct timeval* delta, struct timeval* old_delta)
|
|||
#endif
|
||||
}
|
||||
|
||||
ErrorOr<void> exec(StringView filename, Span<StringView> arguments, SearchInPath search_in_path, Optional<Span<StringView>> environment)
|
||||
{
|
||||
#ifdef __serenity__
|
||||
Syscall::SC_execve_params params;
|
||||
|
||||
auto argument_strings = TRY(FixedArray<Syscall::StringArgument>::try_create(arguments.size()));
|
||||
for (size_t i = 0; i < arguments.size(); ++i) {
|
||||
argument_strings[i] = { arguments[i].characters_without_null_termination(), arguments[i].length() };
|
||||
}
|
||||
params.arguments.strings = argument_strings.data();
|
||||
params.arguments.length = argument_strings.size();
|
||||
|
||||
size_t env_count = 0;
|
||||
if (environment.has_value()) {
|
||||
env_count = environment->size();
|
||||
} else {
|
||||
for (size_t i = 0; environ[i]; ++i)
|
||||
++env_count;
|
||||
}
|
||||
|
||||
auto environment_strings = TRY(FixedArray<Syscall::StringArgument>::try_create(env_count));
|
||||
if (environment.has_value()) {
|
||||
for (size_t i = 0; i < env_count; ++i) {
|
||||
environment_strings[i] = { environment->at(i).characters_without_null_termination(), environment->at(i).length() };
|
||||
}
|
||||
} else {
|
||||
for (size_t i = 0; i < env_count; ++i) {
|
||||
environment_strings[i] = { environ[i], strlen(environ[i]) };
|
||||
}
|
||||
}
|
||||
params.environment.strings = environment_strings.data();
|
||||
params.environment.length = environment_strings.size();
|
||||
|
||||
auto run_exec = [](Syscall::SC_execve_params& params) -> ErrorOr<void> {
|
||||
int rc = syscall(Syscall::SC_execve, ¶ms);
|
||||
if (rc < 0)
|
||||
return Error::from_syscall("exec"sv, rc);
|
||||
return {};
|
||||
};
|
||||
|
||||
if (search_in_path == SearchInPath::Yes && !filename.contains('/')) {
|
||||
StringView path = getenv("PATH");
|
||||
if (path.is_empty())
|
||||
path = "/bin:/usr/bin";
|
||||
auto parts = path.split_view(':');
|
||||
for (auto& part : parts) {
|
||||
auto candidate = String::formatted("{}/{}", part, filename);
|
||||
params.path = { candidate.characters(), candidate.length() };
|
||||
auto result = run_exec(params);
|
||||
if (result.is_error()) {
|
||||
if (result.error().code() != ENOENT)
|
||||
return result.error();
|
||||
} else {
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
}
|
||||
return Error::from_syscall("exec"sv, -ENOENT);
|
||||
} else {
|
||||
params.path = { filename.characters_without_null_termination(), filename.length() };
|
||||
}
|
||||
|
||||
TRY(run_exec(params));
|
||||
VERIFY_NOT_REACHED();
|
||||
#else
|
||||
String filename_string { filename };
|
||||
|
||||
auto argument_strings = TRY(FixedArray<String>::try_create(arguments.size()));
|
||||
auto argv = TRY(FixedArray<char*>::try_create(arguments.size() + 1));
|
||||
for (size_t i = 0; i < arguments.size(); ++i) {
|
||||
argument_strings[i] = arguments[i].to_string();
|
||||
argv[i] = const_cast<char*>(argument_strings[i].characters());
|
||||
}
|
||||
argv[arguments.size()] = nullptr;
|
||||
|
||||
int rc = 0;
|
||||
if (environment.has_value()) {
|
||||
auto environment_strings = TRY(FixedArray<String>::try_create(environment->size()));
|
||||
auto envp = TRY(FixedArray<char*>::try_create(environment->size() + 1));
|
||||
for (size_t i = 0; i < environment->size(); ++i) {
|
||||
environment_strings[i] = environment->at(i).to_string();
|
||||
envp[i] = const_cast<char*>(environment_strings[i].characters());
|
||||
}
|
||||
envp[environment->size()] = nullptr;
|
||||
|
||||
if (search_in_path == SearchInPath::Yes && !filename.contains('/')) {
|
||||
# if defined(__APPLE__) || defined(__FreeBSD__)
|
||||
// These BSDs don't support execvpe(), so we'll have to manually search the PATH.
|
||||
// This is copy-pasted from LibC's execvpe() with minor changes.
|
||||
ScopedValueRollback errno_rollback(errno);
|
||||
String path = getenv("PATH");
|
||||
if (path.is_empty())
|
||||
path = "/bin:/usr/bin";
|
||||
auto parts = path.split(':');
|
||||
for (auto& part : parts) {
|
||||
auto candidate = String::formatted("{}/{}", part, filename);
|
||||
rc = ::execve(candidate.characters(), argv.data(), envp.data());
|
||||
if (rc < 0 && errno != ENOENT) {
|
||||
errno_rollback.set_override_rollback_value(errno);
|
||||
return Error::from_syscall("exec"sv, rc);
|
||||
}
|
||||
}
|
||||
errno_rollback.set_override_rollback_value(ENOENT);
|
||||
# else
|
||||
rc = ::execvpe(filename_string.characters(), argv.data(), envp.data());
|
||||
# endif
|
||||
} else {
|
||||
rc = ::execve(filename_string.characters(), argv.data(), envp.data());
|
||||
}
|
||||
|
||||
} else {
|
||||
if (search_in_path == SearchInPath::Yes)
|
||||
rc = ::execvp(filename_string.characters(), argv.data());
|
||||
else
|
||||
rc = ::execv(filename_string.characters(), argv.data());
|
||||
}
|
||||
|
||||
if (rc < 0)
|
||||
return Error::from_syscall("exec"sv, rc);
|
||||
VERIFY_NOT_REACHED();
|
||||
#endif
|
||||
}
|
||||
|
||||
ErrorOr<int> socket(int domain, int type, int protocol)
|
||||
{
|
||||
auto fd = ::socket(domain, type, protocol);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue