Merge pull request #4892 from khaneliman/bugfix/stab-004-command-exec-failure
fix(command): return non-zero when child exec fails
This commit is contained in:
@@ -20,6 +20,8 @@ extern std::list<pid_t> reap;
|
||||
|
||||
namespace waybar::util::command {
|
||||
|
||||
constexpr int kExecFailureExitCode = 127;
|
||||
|
||||
struct res {
|
||||
int exit_code;
|
||||
std::string out;
|
||||
@@ -114,7 +116,9 @@ inline FILE* open(const std::string& cmd, int& pid, const std::string& output_na
|
||||
setenv("WAYBAR_OUTPUT_NAME", output_name.c_str(), 1);
|
||||
}
|
||||
execlp("/bin/sh", "sh", "-c", cmd.c_str(), (char*)0);
|
||||
exit(0);
|
||||
const int saved_errno = errno;
|
||||
spdlog::error("execlp(/bin/sh) failed in open: {}", strerror(saved_errno));
|
||||
_exit(kExecFailureExitCode);
|
||||
} else {
|
||||
::close(fd[1]);
|
||||
}
|
||||
@@ -162,7 +166,9 @@ inline int32_t forkExec(const std::string& cmd, const std::string& output_name)
|
||||
setenv("WAYBAR_OUTPUT_NAME", output_name.c_str(), 1);
|
||||
}
|
||||
execl("/bin/sh", "sh", "-c", cmd.c_str(), (char*)0);
|
||||
exit(0);
|
||||
const int saved_errno = errno;
|
||||
spdlog::error("execl(/bin/sh) failed in forkExec: {}", strerror(saved_errno));
|
||||
_exit(kExecFailureExitCode);
|
||||
} else {
|
||||
reap_mtx.lock();
|
||||
reap.push_back(pid);
|
||||
|
||||
56
test/utils/command.cpp
Normal file
56
test/utils/command.cpp
Normal file
@@ -0,0 +1,56 @@
|
||||
#if __has_include(<catch2/catch_test_macros.hpp>)
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#else
|
||||
#include <catch2/catch.hpp>
|
||||
#endif
|
||||
|
||||
#include <cerrno>
|
||||
#include <list>
|
||||
#include <mutex>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
std::mutex reap_mtx;
|
||||
std::list<pid_t> reap;
|
||||
|
||||
extern "C" int waybar_test_execl(const char* path, const char* arg, ...);
|
||||
extern "C" int waybar_test_execlp(const char* file, const char* arg, ...);
|
||||
|
||||
#define execl waybar_test_execl
|
||||
#define execlp waybar_test_execlp
|
||||
#include "util/command.hpp"
|
||||
#undef execl
|
||||
#undef execlp
|
||||
|
||||
extern "C" int waybar_test_execl(const char* path, const char* arg, ...) {
|
||||
(void)path;
|
||||
(void)arg;
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
extern "C" int waybar_test_execlp(const char* file, const char* arg, ...) {
|
||||
(void)file;
|
||||
(void)arg;
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
TEST_CASE("command::execNoRead returns 127 when shell exec fails", "[util][command]") {
|
||||
const auto result = waybar::util::command::execNoRead("echo should-not-run");
|
||||
REQUIRE(result.exit_code == waybar::util::command::kExecFailureExitCode);
|
||||
REQUIRE(result.out.empty());
|
||||
}
|
||||
|
||||
TEST_CASE("command::forkExec child exits 127 when shell exec fails", "[util][command]") {
|
||||
const auto pid = waybar::util::command::forkExec("echo should-not-run", "test-output");
|
||||
REQUIRE(pid > 0);
|
||||
|
||||
int status = -1;
|
||||
REQUIRE(waitpid(pid, &status, 0) == pid);
|
||||
REQUIRE(WIFEXITED(status));
|
||||
REQUIRE(WEXITSTATUS(status) == waybar::util::command::kExecFailureExitCode);
|
||||
|
||||
std::scoped_lock<std::mutex> lock(reap_mtx);
|
||||
reap.remove(pid);
|
||||
}
|
||||
@@ -14,6 +14,7 @@ test_src = files(
|
||||
'JsonParser.cpp',
|
||||
'SafeSignal.cpp',
|
||||
'sleeper_thread.cpp',
|
||||
'command.cpp',
|
||||
'css_reload_helper.cpp',
|
||||
'../../src/util/css_reload_helper.cpp',
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user