shell: add exec functions
This commit is contained in:
parent
32c2c3dab8
commit
95c86ba024
2 changed files with 204 additions and 113 deletions
|
|
@ -6,6 +6,8 @@
|
||||||
#include <queue>
|
#include <queue>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
|
||||||
#include "wait.hpp"
|
#include "wait.hpp"
|
||||||
|
|
||||||
|
|
@ -15,13 +17,16 @@
|
||||||
|
|
||||||
namespace ztd
|
namespace ztd
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/// SHELL CALLS ///
|
||||||
|
|
||||||
//! @brief Execute a shell command and retrieve its output
|
//! @brief Execute a shell command and retrieve its output
|
||||||
/*!
|
/*!
|
||||||
@param command Shell command to execute
|
@param command Shell command to execute
|
||||||
@param to_console Output to console
|
Doesn't output to console
|
||||||
@return Output of command
|
@return Output of command
|
||||||
*/
|
*/
|
||||||
std::string sh(const std::string& command, bool to_console=false);
|
std::string sh(const std::string& command);
|
||||||
|
|
||||||
//! @brief Execute a shell command and retrieve its return value
|
//! @brief Execute a shell command and retrieve its return value
|
||||||
/*!
|
/*!
|
||||||
|
|
@ -34,31 +39,17 @@ namespace ztd
|
||||||
//! @brief Execute a shell command and retrieve its output and return value
|
//! @brief Execute a shell command and retrieve its output and return value
|
||||||
/*!
|
/*!
|
||||||
@param command Shell command to execute
|
@param command Shell command to execute
|
||||||
@param to_console Output to console
|
Doesn't output to console
|
||||||
@return @b first Output of command\n@b second Return value of command
|
@return @b first Output of command\n@b second Return value of command
|
||||||
*/
|
*/
|
||||||
std::pair<std::string, int> shp(const std::string& command, bool to_console=false);
|
std::pair<std::string, int> shp(const std::string& command);
|
||||||
|
|
||||||
//! @brief popen C function with added pid functionality
|
|
||||||
/*!
|
|
||||||
@param pid Pointer to an @a int in which the process's pid will be stored
|
|
||||||
@see <a href="http://man7.org/linux/man-pages/man3/popen.3.html">popen(), pclose()</a>
|
|
||||||
*/
|
|
||||||
FILE* popen2(const char* command, const char* type, int* pid);
|
|
||||||
//! @brief pclose C function with added pid functionality
|
|
||||||
/*!
|
|
||||||
@param pid Pid of the opened process
|
|
||||||
@see <a href="http://man7.org/linux/man-pages/man3/popen.3.html">popen(), pclose()</a>
|
|
||||||
*/
|
|
||||||
int pclose2(FILE* fp, pid_t pid);
|
|
||||||
|
|
||||||
|
|
||||||
//! @brief Shell call class
|
//! @brief Shell call class
|
||||||
class shc
|
class shc
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
//! @brief constructor
|
//! @brief constructor
|
||||||
shc(std::string const& cmd="", bool const cout=false);
|
shc(std::string const& cmd="");
|
||||||
virtual ~shc();
|
virtual ~shc();
|
||||||
|
|
||||||
//! @brief Start the command
|
//! @brief Start the command
|
||||||
|
|
@ -68,6 +59,7 @@ namespace ztd
|
||||||
|
|
||||||
//! @brief Wait until the command gives output
|
//! @brief Wait until the command gives output
|
||||||
void wait_output();
|
void wait_output();
|
||||||
|
inline bool has_output() { return this->output.size() > 0; }
|
||||||
//! @brief Retrieve a line from the command's output
|
//! @brief Retrieve a line from the command's output
|
||||||
std::string get_output();
|
std::string get_output();
|
||||||
|
|
||||||
|
|
@ -76,8 +68,6 @@ namespace ztd
|
||||||
|
|
||||||
//! @brief Command to execute
|
//! @brief Command to execute
|
||||||
std::string command;
|
std::string command;
|
||||||
//! @brief Output the command result to console
|
|
||||||
bool to_console;
|
|
||||||
|
|
||||||
//! @brief Run status of the command
|
//! @brief Run status of the command
|
||||||
bool running;
|
bool running;
|
||||||
|
|
@ -92,10 +82,66 @@ namespace ztd
|
||||||
ztd::wait_pool wp_output;
|
ztd::wait_pool wp_output;
|
||||||
ztd::wait_pool wp_finish;
|
ztd::wait_pool wp_finish;
|
||||||
|
|
||||||
|
std::thread thread;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void run_process(shc* p);
|
static void run_process(shc* p, ztd::wait_pool* wp);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//// POPEN WITH PID ////
|
||||||
|
|
||||||
|
//// EXEC EXTENSIONS ////
|
||||||
|
|
||||||
|
/// open/close extensions
|
||||||
|
|
||||||
|
//! @brief Similar to popen2() but calls an executable instead of a shell
|
||||||
|
/*!
|
||||||
|
@param type Mode of the execution (r/w)
|
||||||
|
@param pid Pointer to an @a int in which the process's pid will be stored
|
||||||
|
@param bin Binary to execute. Has PATH resolution
|
||||||
|
@param args
|
||||||
|
@return File descriptor for the stream in question
|
||||||
|
*/
|
||||||
|
FILE* eopen(const char* type, int* pid, const char* bin, std::vector<char*> args);
|
||||||
|
//! @brief Similar to pclose2() but for eopen()
|
||||||
|
/*!
|
||||||
|
@param fd
|
||||||
|
@param pid Pid of the opened process
|
||||||
|
@return Return value of the command
|
||||||
|
*/
|
||||||
|
int eclose(FILE* fd, pid_t pid);
|
||||||
|
|
||||||
|
//! @brief popen C function with added pid functionality
|
||||||
|
/*!
|
||||||
|
@param command Shell command to execute
|
||||||
|
@param type Mode of the execution (r/w)
|
||||||
|
@param pid Pointer to an @a int in which the process's pid will be stored
|
||||||
|
@return File descriptor for the stream in question
|
||||||
|
@see <a href="http://man7.org/linux/man-pages/man3/popen.3.html">popen(), pclose()</a>
|
||||||
|
*/
|
||||||
|
inline FILE* popen2(const char* command, const char* type, int* pid) { std::vector<char*> tvec = {"-c",(char*) command}; return eopen(type, pid, "/bin/sh", tvec) ; }
|
||||||
|
//! @brief pclose C function with added pid functionality
|
||||||
|
/*!
|
||||||
|
@param fd
|
||||||
|
@param pid Pid of the opened process
|
||||||
|
@return Return value of the command
|
||||||
|
@see <a href="http://man7.org/linux/man-pages/man3/popen.3.html">popen(), pclose()</a>
|
||||||
|
*/
|
||||||
|
inline int pclose2(FILE* fd, pid_t pid) { return eclose(fd, pid); }
|
||||||
|
|
||||||
|
|
||||||
|
/// exec extensions
|
||||||
|
|
||||||
|
//! @brief Execute a binary and retrieve its outputs
|
||||||
|
/*!
|
||||||
|
@param bin Binary file to execute. Has PATH resolution
|
||||||
|
@param args Arguments given to the binary
|
||||||
|
*/
|
||||||
|
std::pair<std::string, int> exec(std::string const& bin, std::vector<char*> const& args);
|
||||||
|
//! @brief @see exec(std::string const& bin, std::vector<char*> const& args)
|
||||||
|
std::pair<std::string, int> exec(std::string const& bin, std::vector<std::string> const& args);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //SHELL_HPP
|
#endif //SHELL_HPP
|
||||||
|
|
|
||||||
227
src/shell.cpp
227
src/shell.cpp
|
|
@ -1,6 +1,7 @@
|
||||||
#include "shell.hpp"
|
#include "shell.hpp"
|
||||||
|
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
@ -9,9 +10,11 @@
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
std::string ztd::sh(const std::string& command, bool to_console)
|
//// SHELL CALLS ////
|
||||||
|
|
||||||
|
std::string ztd::sh(const std::string& command)
|
||||||
{
|
{
|
||||||
return ztd::shp(command, to_console).first;
|
return ztd::shp(command).first;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ztd::shr(const std::string& command)
|
int ztd::shr(const std::string& command)
|
||||||
|
|
@ -19,7 +22,7 @@ int ztd::shr(const std::string& command)
|
||||||
return WEXITSTATUS(system(command.c_str()));
|
return WEXITSTATUS(system(command.c_str()));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<std::string, int> ztd::shp(const std::string& command, bool to_console)
|
std::pair<std::string, int> ztd::shp(const std::string& command)
|
||||||
{
|
{
|
||||||
std::string ret;
|
std::string ret;
|
||||||
FILE *stream = popen(command.c_str(), "r");
|
FILE *stream = popen(command.c_str(), "r");
|
||||||
|
|
@ -27,100 +30,42 @@ std::pair<std::string, int> ztd::shp(const std::string& command, bool to_console
|
||||||
size_t buff_size = 0;
|
size_t buff_size = 0;
|
||||||
while (getline(&buff, &buff_size, stream) > 0)
|
while (getline(&buff, &buff_size, stream) > 0)
|
||||||
{
|
{
|
||||||
if(to_console)
|
|
||||||
printf("%s", buff);
|
|
||||||
|
|
||||||
ret += buff;
|
ret += buff;
|
||||||
}
|
}
|
||||||
return std::make_pair(ret, WEXITSTATUS(pclose(stream)));
|
return std::make_pair(ret, WEXITSTATUS(pclose(stream)));
|
||||||
}
|
/* shc method
|
||||||
|
std::string ret;
|
||||||
FILE* ztd::popen2(const char* command, const char* type, int* pid)
|
ztd::shc r(command);
|
||||||
{
|
r.run();
|
||||||
const int READ=0, WRITE=1;
|
r.wait_finish();
|
||||||
pid_t child_pid;
|
while(r.has_output())
|
||||||
int fd[2];
|
ret += r.get_output();
|
||||||
pipe(fd);
|
return std::make_pair(ret, r.return_value);
|
||||||
|
*/
|
||||||
if((child_pid = fork()) == -1)
|
|
||||||
{
|
|
||||||
perror("fork");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* child process */
|
|
||||||
if (child_pid == 0)
|
|
||||||
{
|
|
||||||
if ( index(type, 'r') != NULL )
|
|
||||||
{
|
|
||||||
close(fd[READ]); //Close the READ end of the pipe since the child's fd is write-only
|
|
||||||
dup2(fd[WRITE], 1); //Redirect stdout to pipe
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
close(fd[WRITE]); //Close the WRITE end of the pipe since the child's fd is read-only
|
|
||||||
dup2(fd[READ], 0); //Redirect stdin to pipe
|
|
||||||
}
|
|
||||||
|
|
||||||
setpgid(child_pid, child_pid); //Needed so negative PIDs can kill children of /bin/sh
|
|
||||||
execl("/bin/sh", "/bin/sh", "-c", command, NULL);
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if ( index(type, 'r') != NULL )
|
|
||||||
{
|
|
||||||
close(fd[WRITE]); //Close the WRITE end of the pipe since parent's fd is read-only
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
close(fd[READ]); //Close the READ end of the pipe since parent's fd is write-only
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(pid != NULL)
|
|
||||||
*pid = child_pid;
|
|
||||||
|
|
||||||
if ( index(type, 'r') != NULL )
|
|
||||||
{
|
|
||||||
return fdopen(fd[READ], "r");
|
|
||||||
}
|
|
||||||
|
|
||||||
return fdopen(fd[WRITE], "w");
|
|
||||||
}
|
|
||||||
|
|
||||||
int ztd::pclose2(FILE* fp, pid_t pid)
|
|
||||||
{
|
|
||||||
int stat;
|
|
||||||
|
|
||||||
fclose(fp);
|
|
||||||
while (waitpid(pid, &stat, 0) == -1)
|
|
||||||
{
|
|
||||||
if (errno != EINTR)
|
|
||||||
{
|
|
||||||
stat = -1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return stat;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SHC
|
// SHC
|
||||||
|
|
||||||
ztd::shc::shc(std::string const& cmd, bool const cout)
|
ztd::shc::shc(std::string const& cmd)
|
||||||
{
|
{
|
||||||
this->command=cmd;
|
this->command=cmd;
|
||||||
this->to_console=cout;
|
this->running=false;
|
||||||
|
this->pid=0;
|
||||||
}
|
}
|
||||||
ztd::shc::~shc()
|
ztd::shc::~shc()
|
||||||
{
|
{
|
||||||
if(this->running)
|
if(this->running)
|
||||||
this->kill_int();
|
this->kill_int();
|
||||||
|
this->thread.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ztd::shc::run()
|
void ztd::shc::run()
|
||||||
{
|
{
|
||||||
std::thread(ztd::shc::run_process, this).detach();
|
ztd::wait_pool wait_for_start;
|
||||||
|
if(!this->running)
|
||||||
|
this->thread = std::thread(ztd::shc::run_process, this, &wait_for_start);
|
||||||
|
if(!this->running)
|
||||||
|
wait_for_start.wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
int ztd::shc::kill_int()
|
int ztd::shc::kill_int()
|
||||||
|
|
@ -133,7 +78,7 @@ int ztd::shc::kill_int()
|
||||||
|
|
||||||
void ztd::shc::wait_output()
|
void ztd::shc::wait_output()
|
||||||
{
|
{
|
||||||
while(this->output.size() <= 0)
|
while(this->running && !(this->has_output()) )
|
||||||
this->wp_output.wait();
|
this->wp_output.wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -155,31 +100,131 @@ void ztd::shc::wait_finish()
|
||||||
this->wp_finish.wait();
|
this->wp_finish.wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ztd::shc::run_process(shc* p)
|
void ztd::shc::run_process(shc* p, ztd::wait_pool* wp)
|
||||||
{
|
{
|
||||||
if(p->running)
|
if(p->running)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
p->running = true;
|
||||||
|
wp->notify_all();
|
||||||
|
|
||||||
char* buff = NULL;
|
char* buff = NULL;
|
||||||
size_t buff_size = 0;
|
size_t buff_size = 0;
|
||||||
int pid = 0;
|
int pid = 0;
|
||||||
|
std::vector<char*> args = { "-c", (char*) p->command.c_str() };
|
||||||
|
// FILE *stream = ztd::eopen("r", &pid, "/bin/sh", args);
|
||||||
FILE *stream = ztd::popen2(p->command.c_str(), "r", &pid);
|
FILE *stream = ztd::popen2(p->command.c_str(), "r", &pid);
|
||||||
p->pid = pid;
|
p->pid = pid;
|
||||||
p->running = true;
|
|
||||||
|
|
||||||
std::string ln;
|
std::string ln;
|
||||||
while ( getline(&buff, &buff_size, stream) > 0 ) //retrieve device lines
|
while ( getline(&buff, &buff_size, stream) > 0 ) //retrieve lines
|
||||||
{
|
{
|
||||||
if(p->to_console)
|
p->output.push(std::string(buff));
|
||||||
printf("%s", buff);
|
|
||||||
|
|
||||||
ln = std::string(buff, buff_size);
|
|
||||||
p->output.push(ln);
|
|
||||||
p->wp_output.notify_all();
|
p->wp_output.notify_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
p->running = false;
|
|
||||||
p->wp_finish.notify_all();
|
|
||||||
p->return_value = WEXITSTATUS(ztd::pclose2(stream, pid));
|
p->return_value = WEXITSTATUS(ztd::pclose2(stream, pid));
|
||||||
|
p->running = false;
|
||||||
|
p->wp_output.notify_all();
|
||||||
|
p->wp_finish.notify_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
//// EXEC EXTENTIONS ////
|
||||||
|
|
||||||
|
// open/close calls
|
||||||
|
|
||||||
|
FILE* ztd::eopen(const char* type, int* pid, const char* bin, std::vector<char*> args)
|
||||||
|
{
|
||||||
|
const int READ=0, WRITE=1;
|
||||||
|
pid_t child_pid;
|
||||||
|
int fd[2];
|
||||||
|
pipe(fd);
|
||||||
|
|
||||||
|
args.push_back(NULL); // NULL terminated array for execv()
|
||||||
|
args.insert(args.begin(), (char*) bin); // first arg is name of the exec
|
||||||
|
|
||||||
|
// forking
|
||||||
|
if((child_pid = fork()) == -1)
|
||||||
|
{
|
||||||
|
perror("fork");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (child_pid == 0) // child process
|
||||||
|
{
|
||||||
|
if ( index(type, 'r') != NULL )
|
||||||
|
{
|
||||||
|
close(fd[READ]); //Close the READ end of the pipe since the child's fd is write-only
|
||||||
|
dup2(fd[WRITE], 1); //Redirect stdout to pipe
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
close(fd[WRITE]); //Close the WRITE end of the pipe since the child's fd is read-only
|
||||||
|
dup2(fd[READ], 0); //Redirect stdin to pipe
|
||||||
|
}
|
||||||
|
setpgid(child_pid, child_pid); //Needed so negative PIDs can kill children of /bin/sh
|
||||||
|
execvp(bin, args.data());
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
else // main process
|
||||||
|
{
|
||||||
|
if ( index(type, 'r') != NULL )
|
||||||
|
{
|
||||||
|
close(fd[WRITE]); //Close the WRITE end of the pipe since parent's fd is read-only
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
close(fd[READ]); //Close the READ end of the pipe since parent's fd is write-only
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(pid != NULL)
|
||||||
|
*pid = child_pid;
|
||||||
|
|
||||||
|
if ( index(type, 'r') != NULL )
|
||||||
|
{
|
||||||
|
return fdopen(fd[READ], "r");
|
||||||
|
}
|
||||||
|
|
||||||
|
return fdopen(fd[WRITE], "w");
|
||||||
|
}
|
||||||
|
|
||||||
|
int ztd::eclose(FILE* fd, pid_t pid)
|
||||||
|
{
|
||||||
|
int stat;
|
||||||
|
|
||||||
|
fclose(fd);
|
||||||
|
while (waitpid(pid, &stat, 0) == -1)
|
||||||
|
{
|
||||||
|
if (errno != EINTR)
|
||||||
|
{
|
||||||
|
stat = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return stat;
|
||||||
|
}
|
||||||
|
|
||||||
|
// exec calls
|
||||||
|
// function itself
|
||||||
|
std::pair<std::string, int> ztd::exec(std::string const& bin, std::vector<char*> const& args)
|
||||||
|
{
|
||||||
|
std::string ret;
|
||||||
|
pid_t pid;
|
||||||
|
|
||||||
|
FILE *stream = eopen("r", &pid, bin.c_str(), args);
|
||||||
|
char* buff = NULL;
|
||||||
|
size_t buff_size = 0;
|
||||||
|
while (getline(&buff, &buff_size, stream) > 0)
|
||||||
|
{
|
||||||
|
ret += buff;
|
||||||
|
}
|
||||||
|
return std::make_pair(ret, WEXITSTATUS(eclose(stream, pid)));
|
||||||
|
}
|
||||||
|
// translate to char* call
|
||||||
|
std::pair<std::string, int> ztd::exec(std::string const& bin, std::vector<std::string> const& args)
|
||||||
|
{
|
||||||
|
std::vector<char*> rargs;
|
||||||
|
for(auto it: args)
|
||||||
|
rargs.push_back((char*) it.c_str());
|
||||||
|
return ztd::exec(bin, rargs);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue