Compare commits
No commits in common. "e100cd15d17808c6fafbb093c4e6f73f771982f1" and "e1500b8e6d9f37cd278cc3105810ca02c163d422" have entirely different histories.
e100cd15d1
...
e1500b8e6d
|
|
@ -6,7 +6,6 @@
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <optional>
|
|
||||||
|
|
||||||
namespace sh
|
namespace sh
|
||||||
{
|
{
|
||||||
|
|
@ -40,15 +39,9 @@ namespace sh
|
||||||
|
|
||||||
std::optional<std::filesystem::path> isExec(const std::string& input);
|
std::optional<std::filesystem::path> isExec(const std::string& input);
|
||||||
|
|
||||||
void printType(const std::string& input, const std::optional<std::filesystem::path>& stdoutFilePath = std::nullopt);
|
void printType(const std::string& input);
|
||||||
|
|
||||||
std::filesystem::path getWorkingDir();
|
std::filesystem::path getWorkingDir();
|
||||||
|
|
||||||
void changeDir(const std::vector<std::string>& tokens, const std::optional<std::filesystem::path>& stdoutFilePath = std::nullopt);
|
void changeDir(const std::vector<std::string>& tokens);
|
||||||
|
}
|
||||||
void printCommandStdout(std::string_view input, const std::optional<std::filesystem::path>& outputFilePath = std::nullopt, bool append = false);
|
|
||||||
|
|
||||||
void printCommandStderr(std::string_view input, const std::optional<std::filesystem::path>& outputFilePath = std::nullopt, bool append = false);
|
|
||||||
|
|
||||||
void executeCommand(const std::filesystem::path& exePath, const std::vector<std::string>& tokens, const std::optional<std::filesystem::path>& stdoutFilePath = std::nullopt, const std::optional<std::filesystem::path>& stderrFilePath = std::nullopt, bool appendStdout = false, bool appendStderr = false);
|
|
||||||
}
|
|
||||||
147
src/main.cpp
147
src/main.cpp
|
|
@ -1,11 +1,16 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <map>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <fstream>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <optional>
|
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <process.h>
|
||||||
|
#else
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "shellUtils.h"
|
#include "shellUtils.h"
|
||||||
|
|
||||||
|
|
@ -20,10 +25,6 @@ int main()
|
||||||
while (!shouldExit)
|
while (!shouldExit)
|
||||||
{
|
{
|
||||||
tokens.clear();
|
tokens.clear();
|
||||||
std::optional<std::filesystem::path> stdoutFile;
|
|
||||||
std::optional<std::filesystem::path> stderrFile;
|
|
||||||
bool appendStdout{false};
|
|
||||||
bool appendStderr{false};
|
|
||||||
|
|
||||||
std::string input;
|
std::string input;
|
||||||
std::string line;
|
std::string line;
|
||||||
|
|
@ -33,12 +34,6 @@ int main()
|
||||||
|
|
||||||
while (!finshedInput and std::getline(std::cin, line))
|
while (!finshedInput and std::getline(std::cin, line))
|
||||||
{
|
{
|
||||||
if (line.empty())
|
|
||||||
{
|
|
||||||
finshedInput = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto end = line.size() - 1;
|
auto end = line.size() - 1;
|
||||||
if (line[end] == '\\')
|
if (line[end] == '\\')
|
||||||
{
|
{
|
||||||
|
|
@ -79,69 +74,7 @@ int main()
|
||||||
//we can now assume there is actual text from the input
|
//we can now assume there is actual text from the input
|
||||||
sh::tokenize(tokens, input);
|
sh::tokenize(tokens, input);
|
||||||
|
|
||||||
//check for redirection
|
|
||||||
for (size_t i = 0; i < tokens.size();)
|
|
||||||
{
|
|
||||||
if (tokens[i] == ">>" or tokens[i] == "1>>")
|
|
||||||
{
|
|
||||||
if (i + 1 >= tokens.size())
|
|
||||||
{
|
|
||||||
std::cerr << "Syntax error: expeceted filepath after '>>'\n";
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
appendStdout = true;
|
|
||||||
stdoutFile = tokens[i+1];
|
|
||||||
|
|
||||||
tokens.erase(tokens.begin() + i, tokens.begin() + i + 2);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tokens[i] == "2>>")
|
|
||||||
{
|
|
||||||
if (i + 1 >= tokens.size())
|
|
||||||
{
|
|
||||||
std::cerr << "Syntax error: expeceted filepath after '>>'\n";
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
appendStderr = true;
|
|
||||||
stderrFile = tokens[i+1];
|
|
||||||
|
|
||||||
tokens.erase(tokens.begin() + i, tokens.begin() + i + 2);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tokens[i] == ">" or tokens[i] == "1>")
|
|
||||||
{//stdout redirect
|
|
||||||
if (i + 1 >= tokens.size())
|
|
||||||
{//if no output specified, just remove and continue as normal
|
|
||||||
std::cerr << "Syntax error: expeceted filepath after '>'\n";
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
stdoutFile = tokens[i+1];
|
|
||||||
tokens.erase(tokens.begin() + i, tokens.begin() + i + 2);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tokens[i] == "2>")
|
|
||||||
{//stdout redirect
|
|
||||||
if (i + 1 >= tokens.size())
|
|
||||||
{//if no output specified, just remove and continue as normal
|
|
||||||
std::cerr << "Syntax error: expeceted filepath after '>'\n";
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
stderrFile = tokens[i+1];
|
|
||||||
tokens.erase(tokens.begin() + i, tokens.begin() + i + 2);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<std::filesystem::path> result;
|
std::optional<std::filesystem::path> result;
|
||||||
std::ostringstream output;
|
|
||||||
|
|
||||||
switch (sh::Command command = sh::getCommand(tokens[0]))
|
switch (sh::Command command = sh::getCommand(tokens[0]))
|
||||||
{
|
{
|
||||||
|
|
@ -149,43 +82,73 @@ int main()
|
||||||
shouldExit = true;
|
shouldExit = true;
|
||||||
break;
|
break;
|
||||||
case sh::Command::echo:
|
case sh::Command::echo:
|
||||||
if (stderrFile)
|
|
||||||
{
|
|
||||||
std::ofstream err{stderrFile.value()};
|
|
||||||
err.close();
|
|
||||||
}
|
|
||||||
for (int i = 1; i < tokens.size(); i++)
|
for (int i = 1; i < tokens.size(); i++)
|
||||||
{
|
{
|
||||||
output << tokens[i];
|
std::cout << tokens[i] << " ";
|
||||||
if (i < tokens.size() - 1) output << " ";
|
|
||||||
}
|
}
|
||||||
stdoutFile ?
|
std::cout << "\n";
|
||||||
sh::printCommandStdout(output.str(), stdoutFile.value(), appendStdout) :
|
|
||||||
sh::printCommandStdout(output.str());
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case sh::Command::unknown:
|
case sh::Command::unknown:
|
||||||
result = sh::isExec(tokens[0]);
|
result = sh::isExec(tokens[0]);
|
||||||
if (result)
|
if (result)
|
||||||
{
|
{
|
||||||
sh::executeCommand(result.value(), tokens, stdoutFile, stderrFile, appendStdout, appendStderr);
|
std::string filename = result.value().filename().string();
|
||||||
|
std::string fullPath = result.value().string();
|
||||||
|
#ifdef _WIN32
|
||||||
|
std::vector<const char*> args;
|
||||||
|
args.push_back(filename.c_str());// have exe path on seperate element for _spawnv
|
||||||
|
|
||||||
|
for (size_t i = 1; i < tokens.size(); i++)
|
||||||
|
{
|
||||||
|
args.push_back(const_cast<char*>(tokens[i].c_str()));
|
||||||
|
}
|
||||||
|
|
||||||
|
args.push_back(nullptr);
|
||||||
|
|
||||||
|
intptr_t status = _spawnv(_P_WAIT, fullPath.c_str(), args.data());
|
||||||
|
|
||||||
|
if (status == -1)
|
||||||
|
{
|
||||||
|
perror("\n\nError executing program\n\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
std::vector<char*> args;
|
||||||
|
args.push_back(const_cast<char*>(filename.c_str()));// have exe path on seperate element for execv
|
||||||
|
|
||||||
|
for (size_t i = 1; i < tokens.size(); i++)
|
||||||
|
{
|
||||||
|
args.push_back(const_cast<char*>(tokens[i].c_str()));
|
||||||
|
}
|
||||||
|
|
||||||
|
args.push_back(nullptr);
|
||||||
|
pid_t pid = fork();
|
||||||
|
if (pid == 0)
|
||||||
|
{// child process
|
||||||
|
execv(result.value().c_str(), args.data());
|
||||||
|
perror("\n\nError executing program\n\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int status;
|
||||||
|
waitpid(pid, &status, 0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
output << tokens[0] << ": command not found";
|
std::cout << tokens[0] << ": command not found\n";
|
||||||
stdoutFile ?
|
|
||||||
sh::printCommandStdout(output.str(), stdoutFile.value()) :
|
|
||||||
sh::printCommandStdout(output.str());
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case sh::Command::type:
|
case sh::Command::type:
|
||||||
sh::printType(tokens[1], stdoutFile);
|
sh::printType(tokens[1]);
|
||||||
break;
|
break;
|
||||||
case sh::Command::pwd:
|
case sh::Command::pwd:
|
||||||
std::cout << std::filesystem::current_path().string() << "\n";
|
std::cout << std::filesystem::current_path().string() << "\n";
|
||||||
break;
|
break;
|
||||||
case sh::Command::cd:
|
case sh::Command::cd:
|
||||||
sh::changeDir(tokens, stdoutFile);
|
sh::changeDir(tokens);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,23 +6,14 @@
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <fstream>
|
|
||||||
#include <sstream>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <fcntl.h> // For _O_RDWR, _O_CREAT, etc.
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#define HOME "USERPROFILE"
|
#define HOME "USERPROFILE"
|
||||||
#include <process.h>
|
|
||||||
#include <io.h>
|
|
||||||
#include <sys/stat.h> // For _S_IWRITE
|
|
||||||
#else
|
#else
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/wait.h>
|
|
||||||
|
|
||||||
#define HOME "HOME"
|
#define HOME "HOME"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
namespace sh
|
namespace sh
|
||||||
{
|
{
|
||||||
void tokenize(std::vector<std::string>& tokens, const std::string& input)
|
void tokenize(std::vector<std::string>& tokens, const std::string& input)
|
||||||
|
|
@ -76,6 +67,19 @@ namespace sh
|
||||||
{
|
{
|
||||||
tokens.emplace_back(currentToken);
|
tokens.emplace_back(currentToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// std::istringstream tokens {input};
|
||||||
|
// std::string currentToken;
|
||||||
|
// while (tokens >> currentToken)
|
||||||
|
// {
|
||||||
|
// // check for escaped white space
|
||||||
|
// if (currentToken.back() == '\\')
|
||||||
|
// {//add whitespace to token
|
||||||
|
// currentToken.append(1, ' ');
|
||||||
|
// }
|
||||||
|
// tokenContainer.emplace_back(currentToken);
|
||||||
|
// }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Command getCommand(std::string_view input)
|
Command getCommand(std::string_view input)
|
||||||
|
|
@ -136,36 +140,31 @@ namespace sh
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void printType(const std::string& input, const std::optional<std::filesystem::path>& stdoutFilePath)
|
void printType(const std::string& input)
|
||||||
{
|
{
|
||||||
std::ostringstream output;
|
|
||||||
if (commandMap.contains(input))
|
if (commandMap.contains(input))
|
||||||
{
|
{
|
||||||
output << input << " is a shell builtin";
|
std::cout << input;
|
||||||
}
|
std::cout << " is a shell builtin\n";
|
||||||
else if (const auto fullPath {isExec(input)})
|
return;
|
||||||
{
|
|
||||||
output << input;
|
|
||||||
output << " is " << fullPath.value().string();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
output << input;
|
|
||||||
output << ": not found";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
stdoutFilePath ?
|
if (const auto fullPath {isExec(input)})
|
||||||
printCommandStdout(output.str(), stdoutFilePath.value()) :
|
{
|
||||||
printCommandStdout(output.str());
|
std::cout << input;
|
||||||
}
|
std::cout << " is " << fullPath.value().string() << "\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
void changeDir(const std::vector<std::string>& tokens, const std::optional<std::filesystem::path>& stdoutFilePath)
|
std::cout << input;
|
||||||
|
std::cout << ": not found\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
void changeDir(const std::vector<std::string>& tokens)
|
||||||
{
|
{
|
||||||
if (tokens.size() > 2)
|
if (tokens.size() > 2)
|
||||||
{
|
{
|
||||||
stdoutFilePath.has_value() ?
|
std::cerr << "cd: too many arguments\n";
|
||||||
printCommandStderr("cd: too many arguments", stdoutFilePath.value()) :
|
|
||||||
printCommandStderr("cd: too many arguments");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -206,207 +205,9 @@ namespace sh
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::ostringstream output;
|
std::cerr << "cd: " << expandedPath.string() << ": No such file or directory\n";
|
||||||
output << "cd: " << expandedPath.string() << ": No such file or directory";
|
|
||||||
|
|
||||||
stdoutFilePath.has_value() ?
|
|
||||||
printCommandStderr(output.str(), stdoutFilePath.value()) :
|
|
||||||
printCommandStderr(output.str());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void printCommandStdout(const std::string_view input, const std::optional<std::filesystem::path>& stdoutFilePath, bool append)
|
|
||||||
{
|
|
||||||
if (stdoutFilePath)
|
|
||||||
{
|
|
||||||
auto mode = append ? std::ios::app : std::ios::trunc;
|
|
||||||
std::ofstream output {stdoutFilePath.value(), mode};
|
|
||||||
|
|
||||||
if (!output)
|
|
||||||
{
|
|
||||||
std::cerr << "ERROR: cannot open " << stdoutFilePath.value().string() << "\n";
|
|
||||||
}
|
|
||||||
output << input << "\n";
|
|
||||||
output.close();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << input << "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
void printCommandStderr(const std::string_view input, const std::optional<std::filesystem::path>& stderrFilePath, bool append)
|
|
||||||
{
|
|
||||||
if (stderrFilePath)
|
|
||||||
{
|
|
||||||
auto mode = append ? std::ios::app : std::ios::trunc;
|
|
||||||
std::ofstream output {stderrFilePath.value(), mode};
|
|
||||||
|
|
||||||
if (!output)
|
|
||||||
{
|
|
||||||
std::cerr << "ERROR: cannot open " << stderrFilePath.value().string() << "\n";
|
|
||||||
}
|
|
||||||
output << input;
|
|
||||||
output.close();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cerr << input << "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
void executeCommand(const std::filesystem::path& exePath,const std::vector<std::string>& tokens, const std::optional<std::filesystem::path>& stdoutFilePath, const std::optional<std::filesystem::path>& stderrFilePath, bool appendStdout, bool appendStderr)
|
|
||||||
{
|
|
||||||
std::string filename = exePath.filename().string();
|
|
||||||
std::string fullPath = exePath.string();
|
|
||||||
#ifdef _WIN32
|
|
||||||
std::vector<const char*> args;
|
|
||||||
args.push_back(filename.c_str());// have exe path on seperate element for _spawnv
|
|
||||||
|
|
||||||
for (size_t i = 1; i < tokens.size(); i++)
|
|
||||||
{
|
|
||||||
args.push_back(const_cast<char*>(tokens[i].c_str()));
|
|
||||||
}
|
|
||||||
|
|
||||||
args.push_back(nullptr);
|
|
||||||
|
|
||||||
int originalStdout = -1;
|
|
||||||
int originalStderr = -1;
|
|
||||||
int stdoutFd = -1;
|
|
||||||
int stderrFd = -1;
|
|
||||||
|
|
||||||
if (stdoutFilePath)
|
|
||||||
{
|
|
||||||
originalStdout = _dup(1); // save out connection to the shell
|
|
||||||
|
|
||||||
if (appendStdout)
|
|
||||||
{
|
|
||||||
stdoutFd = _open(stdoutFilePath.value().c_str(), _O_WRONLY | _O_CREAT, _S_IWRITE);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
stdoutFd = _open(stdoutFilePath.value().c_str(), _O_WRONLY | _O_CREAT | _O_TRUNC, _S_IWRITE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stdoutFd == -1)
|
|
||||||
{
|
|
||||||
perror("Could not open redirect file\n");
|
|
||||||
_close(originalStdout);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_dup2(stdoutFd, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stderrFilePath)
|
|
||||||
{
|
|
||||||
originalStderr = _dup(2);
|
|
||||||
if (appendStderr)
|
|
||||||
{
|
|
||||||
stderrFd = _open(stderrFilePath.value().c_str(), _O_WRONLY | _O_CREAT | _O_APPEND, _S_IWRITE);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
stderrFd = _open(stderrFilePath.value().c_str(), _O_WRONLY | _O_CREAT | _O_TRUNC, _S_IWRITE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stderrFd == -1)
|
|
||||||
{
|
|
||||||
perror("could not redirect stderr to file");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_dup2(stderrFd, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
intptr_t status = _spawnv(_P_WAIT, fullPath.c_str(), args.data());
|
|
||||||
|
|
||||||
if (stdoutFilePath)
|
|
||||||
{
|
|
||||||
_dup2(originalStdout, 1);
|
|
||||||
_close(originalStdout);
|
|
||||||
_close(stdoutFd);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stderrFilePath)
|
|
||||||
{
|
|
||||||
_dup2(originalStderr, 2);
|
|
||||||
_close(originalStderr);
|
|
||||||
_close(stderrFd);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status == -1)
|
|
||||||
{
|
|
||||||
perror("\n\nError executing program\n\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
std::vector<char*> args;
|
|
||||||
args.push_back(const_cast<char*>(filename.c_str()));// have exe path on seperate element for execv
|
|
||||||
|
|
||||||
for (size_t i = 1; i < tokens.size(); i++)
|
|
||||||
{
|
|
||||||
args.push_back(const_cast<char*>(tokens[i].c_str()));
|
|
||||||
}
|
|
||||||
|
|
||||||
args.push_back(nullptr);
|
|
||||||
pid_t pid = fork();
|
|
||||||
if (pid == 0)
|
|
||||||
{// child process
|
|
||||||
if (stdoutFilePath)
|
|
||||||
{
|
|
||||||
int fileFd;
|
|
||||||
if (appendStdout)
|
|
||||||
{
|
|
||||||
fileFd = open(stdoutFilePath.value().c_str(), O_WRONLY | O_CREAT | O_APPEND, 0644);// 0644: Permissions (rw-r--r--)
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fileFd = open(stdoutFilePath.value().c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0644);// 0644: Permissions (rw-r--r--)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fileFd == -1)
|
|
||||||
{
|
|
||||||
perror("Error opening redirect file\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
dup2(fileFd, STDOUT_FILENO);
|
|
||||||
|
|
||||||
close(fileFd);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stderrFilePath)
|
|
||||||
{
|
|
||||||
int fileFd;
|
|
||||||
if (appendStderr)
|
|
||||||
{
|
|
||||||
fileFd = open(stderrFilePath.value().c_str(), O_WRONLY | O_CREAT| O_APPEND, 0644);// 0644: Permissions (rw-r--r--)
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fileFd = open(stderrFilePath.value().c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0644);// 0644: Permissions (rw-r--r--)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fileFd == -1)
|
|
||||||
{
|
|
||||||
perror("Error opening redirect file\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
dup2(fileFd, STDERR_FILENO);
|
|
||||||
|
|
||||||
close(fileFd);
|
|
||||||
}
|
|
||||||
|
|
||||||
execv(exePath.c_str(), args.data());
|
|
||||||
perror("\n\nError executing program\n\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int status;
|
|
||||||
waitpid(pid, &status, 0);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue