aboutsummaryrefslogtreecommitdiffstats
path: root/modules/entropy/unix_procs/unix_cmd.cpp
diff options
context:
space:
mode:
authorlloyd <[email protected]>2008-09-28 15:34:09 +0000
committerlloyd <[email protected]>2008-09-28 15:34:09 +0000
commitea32d18231b9c6c5c84b3754c4249170d3b4e4c0 (patch)
treecc179337d0594ed105768011722b9dbae105e07a /modules/entropy/unix_procs/unix_cmd.cpp
parentb841401e095cfc1aa0708689d7920eb95ece71af (diff)
This is the first checkin to net.randombit.botan.modularized, which
has the intent of modularizing Botan's source code, and making it much easier to add or remove various things at compile time. In this first checkin: Add support for nested directories in modules/ and move all the modules into grouped directories like entropy/ or compression/ Currently this is not ideal, it will _only_ find code in modules/*/*/modinfo.txt, while it would be much better to allow for arbitrary nestings under modules (find modules -name modinfo.txt) for more complicated setups. This 'new' (OMG I've found directories!) structure allows for a more free naming convention (no need for leading es_, ml_, etc to group names, though some keep it for lack of a more meaningful name being obvious to me right at the moment).
Diffstat (limited to 'modules/entropy/unix_procs/unix_cmd.cpp')
-rw-r--r--modules/entropy/unix_procs/unix_cmd.cpp240
1 files changed, 240 insertions, 0 deletions
diff --git a/modules/entropy/unix_procs/unix_cmd.cpp b/modules/entropy/unix_procs/unix_cmd.cpp
new file mode 100644
index 000000000..32829b91b
--- /dev/null
+++ b/modules/entropy/unix_procs/unix_cmd.cpp
@@ -0,0 +1,240 @@
+/*************************************************
+* Unix Command Execution Source File *
+* (C) 1999-2007 Jack Lloyd *
+*************************************************/
+
+#ifndef _XOPEN_SOURCE
+ #define _XOPEN_SOURCE 500
+#endif
+
+#ifndef _XOPEN_SOURCE_EXTENDED
+ #define _XOPEN_SOURCE_EXTENDED 1
+#endif
+
+#include <botan/unix_cmd.h>
+#include <botan/parsing.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+
+namespace Botan {
+
+namespace {
+
+/*************************************************
+* Attempt to execute the command *
+************************************************/
+void do_exec(const std::vector<std::string>& arg_list,
+ const std::vector<std::string>& paths)
+ {
+ const u32bit args = arg_list.size() - 1;
+
+ const char* arg1 = (args >= 1) ? arg_list[1].c_str() : 0;
+ const char* arg2 = (args >= 2) ? arg_list[2].c_str() : 0;
+ const char* arg3 = (args >= 3) ? arg_list[3].c_str() : 0;
+ const char* arg4 = (args >= 4) ? arg_list[4].c_str() : 0;
+
+ for(u32bit j = 0; j != paths.size(); j++)
+ {
+ const std::string full_path = paths[j] + "/" + arg_list[0];
+ const char* fsname = full_path.c_str();
+ ::execl(fsname, fsname, arg1, arg2, arg3, arg4, NULL);
+ }
+ }
+
+}
+
+/*************************************************
+* Local information about the pipe *
+*************************************************/
+struct pipe_wrapper
+ {
+ int fd;
+ pid_t pid;
+ pipe_wrapper() { fd = -1; pid = 0; }
+ };
+
+/*************************************************
+* Read from the pipe *
+*************************************************/
+u32bit DataSource_Command::read(byte buf[], u32bit length)
+ {
+ if(end_of_data())
+ return 0;
+
+ fd_set set;
+ FD_ZERO(&set);
+ FD_SET(pipe->fd, &set);
+
+ struct ::timeval tv;
+ tv.tv_sec = 0;
+ tv.tv_usec = MAX_BLOCK_USECS;
+
+ ssize_t got = 0;
+ if(::select(pipe->fd + 1, &set, 0, 0, &tv) == 1)
+ {
+ if(FD_ISSET(pipe->fd, &set))
+ got = ::read(pipe->fd, buf, length);
+ }
+
+ if(got <= 0)
+ {
+ shutdown_pipe();
+ return 0;
+ }
+
+ return static_cast<u32bit>(got);
+ }
+
+/*************************************************
+* Peek at the pipe contents *
+*************************************************/
+u32bit DataSource_Command::peek(byte[], u32bit, u32bit) const
+ {
+ if(end_of_data())
+ throw Invalid_State("DataSource_Command: Cannot peek when out of data");
+ throw Stream_IO_Error("Cannot peek/seek on a command pipe");
+ }
+
+/*************************************************
+* Check if we reached EOF *
+*************************************************/
+bool DataSource_Command::end_of_data() const
+ {
+ return (pipe) ? false : true;
+ }
+
+/*************************************************
+* Return the Unix file descriptor of the pipe *
+*************************************************/
+int DataSource_Command::fd() const
+ {
+ if(!pipe)
+ return -1;
+ return pipe->fd;
+ }
+
+/*************************************************
+* Return a human-readable ID for this stream *
+*************************************************/
+std::string DataSource_Command::id() const
+ {
+ return "Unix command: " + arg_list[0];
+ }
+
+/*************************************************
+* Create the pipe *
+*************************************************/
+void DataSource_Command::create_pipe(const std::vector<std::string>& paths)
+ {
+ bool found_something = false;
+ for(u32bit j = 0; j != paths.size(); j++)
+ {
+ const std::string full_path = paths[j] + "/" + arg_list[0];
+ if(::access(full_path.c_str(), X_OK) == 0)
+ {
+ found_something = true;
+ break;
+ }
+ }
+ if(!found_something)
+ return;
+
+ int pipe_fd[2];
+ if(::pipe(pipe_fd) != 0)
+ return;
+
+ pid_t pid = ::fork();
+
+ if(pid == -1)
+ {
+ ::close(pipe_fd[0]);
+ ::close(pipe_fd[1]);
+ }
+ else if(pid > 0)
+ {
+ pipe = new pipe_wrapper;
+ pipe->fd = pipe_fd[0];
+ pipe->pid = pid;
+ ::close(pipe_fd[1]);
+ }
+ else
+ {
+ if(dup2(pipe_fd[1], STDOUT_FILENO) == -1)
+ ::exit(127);
+ if(close(pipe_fd[0]) != 0 || close(pipe_fd[1]) != 0)
+ ::exit(127);
+ if(close(STDERR_FILENO) != 0)
+ ::exit(127);
+
+ do_exec(arg_list, paths);
+ ::exit(127);
+ }
+ }
+
+/*************************************************
+* Shutdown the pipe *
+*************************************************/
+void DataSource_Command::shutdown_pipe()
+ {
+ if(pipe)
+ {
+ pid_t reaped = waitpid(pipe->pid, 0, WNOHANG);
+
+ if(reaped == 0)
+ {
+ kill(pipe->pid, SIGTERM);
+
+ struct ::timeval tv;
+ tv.tv_sec = 0;
+ tv.tv_usec = KILL_WAIT;
+ select(0, 0, 0, 0, &tv);
+
+ reaped = ::waitpid(pipe->pid, 0, WNOHANG);
+
+ if(reaped == 0)
+ {
+ ::kill(pipe->pid, SIGKILL);
+ do
+ reaped = ::waitpid(pipe->pid, 0, 0);
+ while(reaped == -1);
+ }
+ }
+
+ ::close(pipe->fd);
+ delete pipe;
+ pipe = 0;
+ }
+ }
+
+/*************************************************
+* DataSource_Command Constructor *
+*************************************************/
+DataSource_Command::DataSource_Command(const std::string& prog_and_args,
+ const std::vector<std::string>& paths) :
+ MAX_BLOCK_USECS(100000), KILL_WAIT(10000)
+ {
+ arg_list = split_on(prog_and_args, ' ');
+
+ if(arg_list.size() == 0)
+ throw Invalid_Argument("DataSource_Command: No command given");
+ if(arg_list.size() > 5)
+ throw Invalid_Argument("DataSource_Command: Too many args");
+
+ pipe = 0;
+ create_pipe(paths);
+ }
+
+/*************************************************
+* DataSource_Command Destructor *
+*************************************************/
+DataSource_Command::~DataSource_Command()
+ {
+ if(!end_of_data())
+ shutdown_pipe();
+ }
+
+}