summaryrefslogtreecommitdiff
path: root/lib/server/LocalProcessStream.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/server/LocalProcessStream.cpp')
-rw-r--r--lib/server/LocalProcessStream.cpp101
1 files changed, 101 insertions, 0 deletions
diff --git a/lib/server/LocalProcessStream.cpp b/lib/server/LocalProcessStream.cpp
new file mode 100644
index 00000000..f2a97c56
--- /dev/null
+++ b/lib/server/LocalProcessStream.cpp
@@ -0,0 +1,101 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: LocalProcessStream.cpp
+// Purpose: Opens a process, and presents stdin/stdout as a stream.
+// Created: 12/3/04
+//
+// --------------------------------------------------------------------------
+
+#include "Box.h"
+
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "LocalProcessStream.h"
+#include "SocketStream.h"
+#include "autogen_ServerException.h"
+#include "Utils.h"
+
+#include "MemLeakFindOn.h"
+
+#define MAX_ARGUMENTS 64
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: LocalProcessStream(const char *, pid_t &)
+// Purpose: Run a new process, and return a stream giving access to it's
+// stdin and stdout. Returns the PID of the new process -- this
+// must be waited on at some point to avoid zombies.
+// Created: 12/3/04
+//
+// --------------------------------------------------------------------------
+std::auto_ptr<IOStream> LocalProcessStream(const char *CommandLine, pid_t &rPidOut)
+{
+ // Split up command
+ std::vector<std::string> command;
+ SplitString(std::string(CommandLine), ' ', command);
+ // Build arguments
+ char *args[MAX_ARGUMENTS + 4];
+ {
+ int a = 0;
+ std::vector<std::string>::const_iterator i(command.begin());
+ while(a < MAX_ARGUMENTS && i != command.end())
+ {
+ args[a++] = (char*)(*(i++)).c_str();
+ }
+ args[a] = NULL;
+ }
+
+ // Create a socket pair to communicate over.
+ int sv[2] = {-1,-1};
+ if(::socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, sv) != 0)
+ {
+ THROW_EXCEPTION(ServerException, SocketPairFailed)
+ }
+
+ std::auto_ptr<IOStream> stream(new SocketStream(sv[0]));
+
+ // Fork
+ pid_t pid = 0;
+ switch(pid = vfork())
+ {
+ case -1: // error
+ ::close(sv[0]);
+ ::close(sv[1]);
+ THROW_EXCEPTION(ServerException, ServerForkError)
+ break;
+
+ case 0: // child
+ // Close end of the socket not being used
+ ::close(sv[0]);
+ // Duplicate the file handles to stdin and stdout
+ if(sv[1] != 0) ::dup2(sv[1], 0);
+ if(sv[1] != 1) ::dup2(sv[1], 1);
+ // Close the now redundant socket
+ if(sv[1] != 0 && sv[1] != 1)
+ {
+ ::close(sv[1]);
+ }
+ // Execute command!
+ ::execv(args[0], args);
+ ::_exit(127); // report error
+ break;
+
+ default:
+ // just continue...
+ break;
+ }
+
+ // Close the file descriptor not being used
+ ::close(sv[1]);
+
+ // Return the stream object and PID
+ rPidOut = pid;
+ return stream;
+}
+
+
+
+