-
-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
203 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
#pragma once | ||
|
||
#include <string> | ||
#include <vector> | ||
|
||
namespace Hyprutils { | ||
namespace OS { | ||
class CProcess { | ||
public: | ||
/* Creates a process object, doesn't run yet */ | ||
CProcess(const std::string& binary_, const std::vector<std::string>& args_); | ||
|
||
/* Run the process, synchronously, get the stdout and stderr. False on fail */ | ||
bool runSync(); | ||
|
||
/* Run the process, asynchronously. This will detach the process from this object (and process) and let it live a happy life. False on fail. */ | ||
bool runAsync(); | ||
|
||
// only populated when ran sync | ||
const std::string& stdOut(); | ||
const std::string& stdErr(); | ||
|
||
private: | ||
std::string binary, out, err; | ||
std::vector<std::string> args; | ||
}; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
#include <hyprutils/os/Process.hpp> | ||
using namespace Hyprutils::OS; | ||
|
||
#include <cstdio> | ||
#include <unistd.h> | ||
#include <cstring> | ||
#include <array> | ||
|
||
#include <sys/wait.h> | ||
|
||
Hyprutils::OS::CProcess::CProcess(const std::string& binary_, const std::vector<std::string>& args_) : binary(binary_), args(args_) { | ||
; | ||
} | ||
|
||
bool Hyprutils::OS::CProcess::runSync() { | ||
int outPipe[2], errPipe[2]; | ||
if (pipe(outPipe)) | ||
return false; | ||
if (pipe(errPipe)) { | ||
close(outPipe[0]); | ||
close(outPipe[1]); | ||
return false; | ||
} | ||
|
||
int pid = fork(); | ||
if (pid == -1) { | ||
close(outPipe[0]); | ||
close(outPipe[1]); | ||
close(outPipe[0]); | ||
close(outPipe[1]); | ||
return false; | ||
} | ||
|
||
if (!pid) { | ||
// child | ||
close(outPipe[0]); | ||
close(errPipe[0]); | ||
|
||
dup2(outPipe[1], 1 /* stdout */); | ||
dup2(errPipe[1], 2 /* stderr */); | ||
|
||
// build argv | ||
std::vector<const char*> argsC; | ||
argsC.emplace_back(strdup(binary.c_str())); | ||
for (auto& arg : args) { | ||
// TODO: does this leak? Can we just pipe c_str() as the strings won't be realloc'd? | ||
argsC.emplace_back(strdup(arg.c_str())); | ||
} | ||
|
||
argsC.emplace_back(nullptr); | ||
|
||
execvp(binary.c_str(), (char* const*)argsC.data()); | ||
exit(1); | ||
} else { | ||
// parent | ||
close(outPipe[1]); | ||
close(errPipe[1]); | ||
|
||
waitpid(pid, nullptr, 0); | ||
|
||
std::string readOutData; | ||
std::array<char, 1024> buf; | ||
buf.fill(0); | ||
|
||
// wait for read | ||
size_t ret = 0; | ||
while ((ret = read(outPipe[0], buf.data(), 1023)) > 0) { | ||
readOutData += std::string{(char*)buf.data(), ret}; | ||
} | ||
|
||
out = readOutData; | ||
readOutData = ""; | ||
|
||
while ((ret = read(errPipe[0], buf.data(), 1023)) > 0) { | ||
readOutData += std::string{(char*)buf.data(), ret}; | ||
} | ||
|
||
err = readOutData; | ||
|
||
close(outPipe[0]); | ||
close(errPipe[0]); | ||
|
||
return true; | ||
} | ||
|
||
return true; | ||
} | ||
|
||
bool Hyprutils::OS::CProcess::runAsync() { | ||
int socket[2]; | ||
if (pipe(socket) != 0) | ||
return false; | ||
|
||
pid_t child, grandchild; | ||
child = fork(); | ||
if (child < 0) { | ||
close(socket[0]); | ||
close(socket[1]); | ||
return false; | ||
} | ||
|
||
if (child == 0) { | ||
// run in child | ||
sigset_t set; | ||
sigemptyset(&set); | ||
sigprocmask(SIG_SETMASK, &set, NULL); | ||
|
||
grandchild = fork(); | ||
if (grandchild == 0) { | ||
// run in grandchild | ||
close(socket[0]); | ||
close(socket[1]); | ||
// build argv | ||
std::vector<const char*> argsC; | ||
argsC.emplace_back(strdup(binary.c_str())); | ||
for (auto& arg : args) { | ||
// TODO: does this leak? Can we just pipe c_str() as the strings won't be realloc'd? | ||
argsC.emplace_back(strdup(arg.c_str())); | ||
} | ||
|
||
argsC.emplace_back(nullptr); | ||
|
||
execvp(binary.c_str(), (char* const*)argsC.data()); | ||
// exit grandchild | ||
_exit(0); | ||
} | ||
close(socket[0]); | ||
write(socket[1], &grandchild, sizeof(grandchild)); | ||
close(socket[1]); | ||
// exit child | ||
_exit(0); | ||
} | ||
// run in parent | ||
close(socket[1]); | ||
read(socket[0], &grandchild, sizeof(grandchild)); | ||
close(socket[0]); | ||
// clear child and leave grandchild to init | ||
waitpid(child, NULL, 0); | ||
|
||
return true; | ||
} | ||
|
||
const std::string& Hyprutils::OS::CProcess::stdOut() { | ||
return out; | ||
} | ||
|
||
const std::string& Hyprutils::OS::CProcess::stdErr() { | ||
return err; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
#include <hyprutils/os/Process.hpp> | ||
#include "shared.hpp" | ||
|
||
using namespace Hyprutils::OS; | ||
|
||
int main(int argc, char** argv, char** envp) { | ||
int ret = 0; | ||
|
||
CProcess process("echo", {"Hello World!"}); | ||
|
||
EXPECT(process.runAsync(), true); | ||
EXPECT(process.runSync(), true); | ||
|
||
EXPECT(process.stdOut(), std::string{"Hello World!\n"}); | ||
EXPECT(process.stdErr(), std::string{""}); | ||
|
||
return ret; | ||
} |