#pragma once #include #include #include namespace waybar::util::command { struct res { int exit_code; std::string out; }; inline std::string read(FILE* fp) { std::array buffer = {0}; std::string output; while (feof(fp) == 0) { if (fgets(buffer.data(), 128, fp) != nullptr) { output += buffer.data(); } } // Remove last newline if (!output.empty() && output[output.length() - 1] == '\n') { output.erase(output.length() - 1); } return output; } inline int close(FILE* fp, pid_t pid) { int stat; fclose(fp); while (waitpid(pid, &stat, 0) == -1) { if (errno != EINTR) { stat = 0; break; } } return stat; } 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); execl("/bin/sh", "sh", "-c", cmd.c_str(), (char*)0); exit(0); } else { ::close(fd[1]); } pid = child_pid; return fdopen(fd[0], "r"); } inline struct res exec(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); if (WIFEXITED(stat)) { return {WEXITSTATUS(stat), output}; } return {-1, output}; } inline int32_t forkExec(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); signal(SIGCHLD, SIG_DFL); execl("/bin/sh", "sh", "-c", cmd.c_str(), (char*)0); exit(0); } else { signal(SIGCHLD,SIG_IGN); } return pid; } } // namespace waybar::util::command