waybar/include/util/command.hpp

121 lines
2.6 KiB
C++
Raw Normal View History

#pragma once
#include <giomm.h>
2020-05-22 20:57:41 +02:00
#include <spdlog/spdlog.h>
2020-05-24 21:33:38 +02:00
#include <sys/wait.h>
2018-12-26 11:13:36 +01:00
#include <unistd.h>
2020-05-24 21:33:38 +02:00
#include <array>
namespace waybar::util::command {
struct res {
2019-04-18 17:52:00 +02:00
int exit_code;
std::string out;
};
inline std::string read(FILE* fp) {
std::array<char, 128> buffer = {0};
2019-04-18 17:52:00 +02:00
std::string output;
while (feof(fp) == 0) {
if (fgets(buffer.data(), 128, fp) != nullptr) {
output += buffer.data();
}
}
// Remove last newline
2019-04-18 17:52:00 +02:00
if (!output.empty() && output[output.length() - 1] == '\n') {
output.erase(output.length() - 1);
}
return output;
}
inline int close(FILE* fp, pid_t pid) {
2020-05-22 20:57:41 +02:00
int stat = -1;
fclose(fp);
2020-05-22 20:57:41 +02:00
do {
2020-05-24 18:27:10 +02:00
waitpid(pid, &stat, WCONTINUED | WUNTRACED);
2020-05-22 20:57:41 +02:00
if (WIFEXITED(stat)) {
spdlog::debug("%s exited with code %d", WEXITSTATUS(stat));
} else if (WIFSIGNALED(stat)) {
spdlog::debug("%s killed by %d", WTERMSIG(stat));
} else if (WIFSTOPPED(stat)) {
spdlog::debug("%s stopped by %d", WSTOPSIG(stat));
} else if (WIFCONTINUED(stat)) {
spdlog::debug("%s continued");
} else {
break;
}
2020-05-22 20:57:41 +02:00
} while (!WIFEXITED(stat) && !WIFSIGNALED(stat));
return stat;
}
2020-05-24 21:33:38 +02:00
inline FILE* open(const std::string& cmd, int& pid) {
if (cmd == "") return nullptr;
int fd[2];
pipe(fd);
pid_t child_pid = fork();
if (child_pid < 0) {
printf("Unable to exec cmd %s, error %s", cmd.c_str(), strerror(errno));
return nullptr;
}
if (!child_pid) {
::close(fd[0]);
dup2(fd[1], 1);
setpgid(child_pid, child_pid);
2020-05-22 20:57:41 +02:00
execlp("/bin/sh", "sh", "-c", cmd.c_str(), (char*)0);
exit(0);
} else {
::close(fd[1]);
}
pid = child_pid;
return fdopen(fd[0], "r");
}
2020-05-24 21:33:38 +02:00
inline struct res exec(const std::string& cmd) {
int pid;
auto fp = command::open(cmd, pid);
if (!fp) return {-1, ""};
auto output = command::read(fp);
auto stat = command::close(fp, pid);
2020-05-22 20:57:41 +02:00
return {WEXITSTATUS(stat), output};
}
2020-05-24 21:33:38 +02:00
inline struct res execNoRead(const std::string& cmd) {
2020-05-24 18:27:10 +02:00
int pid;
auto fp = command::open(cmd, pid);
if (!fp) return {-1, ""};
auto stat = command::close(fp, pid);
return {WEXITSTATUS(stat), ""};
}
2020-05-24 21:33:38 +02:00
inline int32_t forkExec(const std::string& cmd) {
if (cmd == "") return -1;
int32_t pid = fork();
if (pid < 0) {
printf("Unable to exec cmd %s, error %s", cmd.c_str(), strerror(errno));
return pid;
}
// Child executes the command
if (!pid) {
setpgid(pid, pid);
2020-03-27 17:35:21 +01:00
signal(SIGCHLD, SIG_DFL);
execl("/bin/sh", "sh", "-c", cmd.c_str(), (char*)0);
exit(0);
} else {
2020-05-24 21:33:38 +02:00
signal(SIGCHLD, SIG_IGN);
}
return pid;
}
} // namespace waybar::util::command