mirror of
https://github.com/SerenityOS/serenity.git
synced 2025-01-25 19:02:07 -05:00
d43a7eae54
As usual, this removes many unused includes and moves used includes further down the chain.
102 lines
3 KiB
C++
102 lines
3 KiB
C++
/*
|
|
* Copyright (c) 2020, Itamar S. <itamar8910@gmail.com>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#include "Command.h"
|
|
#include <AK/Format.h>
|
|
#include <AK/ScopeGuard.h>
|
|
#include <LibCore/DeprecatedFile.h>
|
|
#include <fcntl.h>
|
|
#include <stdio.h>
|
|
#include <sys/wait.h>
|
|
#include <unistd.h>
|
|
|
|
namespace Core {
|
|
|
|
// Only supported in serenity mode because we use `posix_spawn_file_actions_addchdir`
|
|
#ifdef AK_OS_SERENITY
|
|
|
|
ErrorOr<CommandResult> command(DeprecatedString const& command_string, Optional<LexicalPath> chdir)
|
|
{
|
|
auto parts = command_string.split(' ');
|
|
if (parts.is_empty())
|
|
return Error::from_string_literal("empty command");
|
|
auto program = parts[0];
|
|
parts.remove(0);
|
|
return command(program, parts, chdir);
|
|
}
|
|
|
|
ErrorOr<CommandResult> command(DeprecatedString const& program, Vector<DeprecatedString> const& arguments, Optional<LexicalPath> chdir)
|
|
{
|
|
int stdout_pipe[2] = {};
|
|
int stderr_pipe[2] = {};
|
|
if (pipe2(stdout_pipe, O_CLOEXEC)) {
|
|
return Error::from_errno(errno);
|
|
}
|
|
if (pipe2(stderr_pipe, O_CLOEXEC)) {
|
|
perror("pipe2");
|
|
return Error::from_errno(errno);
|
|
}
|
|
|
|
auto close_pipes = ScopeGuard([stderr_pipe, stdout_pipe] {
|
|
// The write-ends of these pipes are closed manually
|
|
close(stdout_pipe[0]);
|
|
close(stderr_pipe[0]);
|
|
});
|
|
|
|
Vector<char const*> parts = { program.characters() };
|
|
for (auto const& part : arguments) {
|
|
parts.append(part.characters());
|
|
}
|
|
parts.append(nullptr);
|
|
|
|
char const** argv = parts.data();
|
|
|
|
posix_spawn_file_actions_t action;
|
|
posix_spawn_file_actions_init(&action);
|
|
if (chdir.has_value()) {
|
|
posix_spawn_file_actions_addchdir(&action, chdir.value().string().characters());
|
|
}
|
|
posix_spawn_file_actions_adddup2(&action, stdout_pipe[1], STDOUT_FILENO);
|
|
posix_spawn_file_actions_adddup2(&action, stderr_pipe[1], STDERR_FILENO);
|
|
|
|
pid_t pid;
|
|
if ((errno = posix_spawnp(&pid, program.characters(), &action, nullptr, const_cast<char**>(argv), environ))) {
|
|
perror("posix_spawn");
|
|
VERIFY_NOT_REACHED();
|
|
}
|
|
|
|
// close the write-ends so reading wouldn't block
|
|
close(stdout_pipe[1]);
|
|
close(stderr_pipe[1]);
|
|
|
|
auto read_all_from_pipe = [](int pipe[2]) {
|
|
auto result_file = Core::DeprecatedFile::construct();
|
|
if (!result_file->open(pipe[0], Core::OpenMode::ReadOnly, Core::DeprecatedFile::ShouldCloseFileDescriptor::Yes)) {
|
|
perror("open");
|
|
VERIFY_NOT_REACHED();
|
|
}
|
|
return DeprecatedString::copy(result_file->read_all());
|
|
};
|
|
auto output = read_all_from_pipe(stdout_pipe);
|
|
auto error = read_all_from_pipe(stderr_pipe);
|
|
|
|
int wstatus { 0 };
|
|
waitpid(pid, &wstatus, 0);
|
|
posix_spawn_file_actions_destroy(&action);
|
|
int exit_code = WEXITSTATUS(wstatus);
|
|
|
|
if (exit_code != 0) {
|
|
# ifdef DBG_FAILED_COMMANDS
|
|
dbgln("command failed. stderr: {}", );
|
|
# endif
|
|
}
|
|
|
|
return CommandResult { WEXITSTATUS(wstatus), output, error };
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|