summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBernard Normier <bernard@zeroc.com>2003-12-27 20:36:41 +0000
committerBernard Normier <bernard@zeroc.com>2003-12-27 20:36:41 +0000
commit3f954aab0eab59e99bad75f9b1d98a7f7603a46b (patch)
tree9dfc1df4d61de79e8c453ab5ff789bd5fa516977
parentfixing all, minimal dependencies (diff)
downloadice-3f954aab0eab59e99bad75f9b1d98a7f7603a46b.tar.bz2
ice-3f954aab0eab59e99bad75f9b1d98a7f7603a46b.tar.xz
ice-3f954aab0eab59e99bad75f9b1d98a7f7603a46b.zip
Added new icepackadmin commands: signal, stdout, stderr
-rw-r--r--cpp/CHANGES16
-rw-r--r--cpp/doc/Properties.sgml33
-rw-r--r--cpp/slice/IcePack/Admin.ice40
-rw-r--r--cpp/slice/IcePack/Exception.ice10
-rw-r--r--cpp/src/Glacier/StarterI.cpp3
-rw-r--r--cpp/src/Ice/PropertiesI.cpp2
-rw-r--r--cpp/src/IcePack/Activator.ice14
-rw-r--r--cpp/src/IcePack/ActivatorI.cpp634
-rw-r--r--cpp/src/IcePack/ActivatorI.h16
-rw-r--r--cpp/src/IcePack/AdminI.cpp37
-rw-r--r--cpp/src/IcePack/AdminI.h2
-rw-r--r--cpp/src/IcePack/Grammar.y15
-rw-r--r--cpp/src/IcePack/Internal.ice14
-rw-r--r--cpp/src/IcePack/Parser.cpp51
-rw-r--r--cpp/src/IcePack/Parser.h2
-rw-r--r--cpp/src/IcePack/Scanner.l12
-rw-r--r--cpp/src/IcePack/ServerI.cpp13
-rw-r--r--cpp/src/IcePack/ServerI.h2
18 files changed, 797 insertions, 119 deletions
diff --git a/cpp/CHANGES b/cpp/CHANGES
index d23ba8b7293..cfb06eca07d 100644
--- a/cpp/CHANGES
+++ b/cpp/CHANGES
@@ -1,6 +1,22 @@
Changes since version 1.2.0
---------------------------
+- Three new icepackadmin commands:
+ - server signal NAME SIGNAL, to have the IcePackNode send a signal
+ to a server (Unix only)
+ - server stdout NAME MESSAGE to write MESSAGE on server's stdout
+ - server stderr NAME MESSAGE to write MESSAGE on servers'stderr
+
+- Two new IcePack.Node properties:
+ - IcePack.Node.Output=<path>
+ If set, the IcePack node will redirect the stdout and stderr
+ output of the started servers to files named <server>.out and
+ <server>.err in this directory. Otherwise, the started servers
+ share the stdout and stderr of the IcePack node.
+ - IcePack.Node.RedirectErrToOut=<num>
+ If <num> is set to a value larger than zero, the stderr of each
+ started server is redirected to the server's stdout.
+
- Eliminated Glacier's dependency on the crypt library. It now
uses an equivalent function from OpenSSL.
diff --git a/cpp/doc/Properties.sgml b/cpp/doc/Properties.sgml
index 39dba9d44da..755cd7e9ffb 100644
--- a/cpp/doc/Properties.sgml
+++ b/cpp/doc/Properties.sgml
@@ -1629,6 +1629,24 @@ each deployed server.
</section>
</section>
+<section><title>IcePack.Node.Output</title>
+<section><title>Synopsis</title>
+<synopsis>
+IcePack.Node.Output=<replaceable>path</replaceable>
+</synopsis>
+</section>
+<section>
+<title>Description</title>
+<para>
+Defines the path of the &IcePack; node output directory. If set, the
+node will redirect the stdout and stderr output of the started
+servers to files named <replaceable>server</replaceable>.out and
+<replaceable>server</replaceable>.err in this directory. Otherwise,
+the started servers share the stdout and stderr of the &IcePack; node.
+</para>
+</section>
+</section>
+
<section><title>IcePack.Node.PropertiesOverride</title>
<section><title>Synopsis</title>
<synopsis>
@@ -1647,6 +1665,21 @@ be separated by white space.
</section>
</section>
+<section><title>IcePack.Node.RedirectErrToOut</title>
+<section><title>Synopsis</title>
+<synopsis>
+IcePack.Node.RedirectErrToOut=<replaceable>num</replaceable>
+</synopsis>
+</section>
+<section>
+<title>Description</title>
+<para>
+If <replaceable>num</replaceable> is set to a value larger than zero,
+the stderr of each started server is redirected to the server's stdout.
+</para>
+</section>
+</section>
+
<section><title>IcePack.Node.WaitTime</title>
<section><title>Synopsis</title>
<synopsis>
diff --git a/cpp/slice/IcePack/Admin.ice b/cpp/slice/IcePack/Admin.ice
index 5c36ad10b3e..cbc975b56a8 100644
--- a/cpp/slice/IcePack/Admin.ice
+++ b/cpp/slice/IcePack/Admin.ice
@@ -420,6 +420,46 @@ interface Admin
void stopServer(string name)
throws ServerNotExistException, NodeUnreachableException;
+
+ /**
+ *
+ * Send signal to a server.
+ *
+ * @param name Must match the name of [ServerDescription::name].
+ * @param signal The signal, for example SIGTERM or 15.
+ *
+ * @throws ServerNotExistException Raised if the server is not
+ * found.
+ *
+ * @throws NodeUnreachableException Raised if the node could not be
+ * reached.
+ *
+ * @throws BadSignalException Raised if the signal is not recognized
+ * by the target server.
+ *
+ **/
+ void sendSignal(string name, string signal)
+ throws ServerNotExistException, NodeUnreachableException,
+ BadSignalException;
+
+ /**
+ *
+ * Write message on server stdout or stderr
+ *
+ * @param name Must match the name of [ServerDescription::name].
+ * @param message The message.
+ * @param fd 1 for stdout, 2 for stderr.
+ *
+ * @throws ServerNotExistException Raised if the server is not
+ * found.
+ *
+ * @throws NodeUnreachableException Raised if the node could not be
+ * reached.
+ *
+ **/
+ void writeMessage(string name, string message, int fd)
+ throws ServerNotExistException, NodeUnreachableException;
+
/**
*
* Get all the server names registered with &IcePack;.
diff --git a/cpp/slice/IcePack/Exception.ice b/cpp/slice/IcePack/Exception.ice
index 9689ad10050..a0377e274db 100644
--- a/cpp/slice/IcePack/Exception.ice
+++ b/cpp/slice/IcePack/Exception.ice
@@ -156,6 +156,16 @@ exception NodeUnreachableException
{
};
+/**
+ *
+ * This exception is raised if an unknown signal was sent to
+ * to a server.
+ *
+ **/
+exception BadSignalException
+{
+};
+
};
#endif
diff --git a/cpp/src/Glacier/StarterI.cpp b/cpp/src/Glacier/StarterI.cpp
index f48b49e4e5d..a90332caa71 100644
--- a/cpp/src/Glacier/StarterI.cpp
+++ b/cpp/src/Glacier/StarterI.cpp
@@ -603,11 +603,12 @@ Glacier::StarterI::startRouter(const string& userId, const string& password, Byt
// Send any errors to the parent process, using the write
// end of the pipe.
//
+ int err = errno;
char msg[500];
strcpy(msg, "can't execute `");
strcat(msg, argv[0]);
strcat(msg, "': ");
- strcat(msg, strerror(errno));
+ strcat(msg, strerror(err));
write(fds[1], msg, strlen(msg));
close(fds[1]);
diff --git a/cpp/src/Ice/PropertiesI.cpp b/cpp/src/Ice/PropertiesI.cpp
index f1538431e2d..aaf968258e7 100644
--- a/cpp/src/Ice/PropertiesI.cpp
+++ b/cpp/src/Ice/PropertiesI.cpp
@@ -165,6 +165,8 @@ static const string icePackProps[] =
"Node.AdapterId",
"Node.CollocateRegistry",
"Node.Data",
+ "Node.Output",
+ "Node.RedirectErrToOut",
"Node.Endpoints",
"Node.Name",
"Node.PrintServersReady",
diff --git a/cpp/src/IcePack/Activator.ice b/cpp/src/IcePack/Activator.ice
index 699751a0caa..312ad650303 100644
--- a/cpp/src/IcePack/Activator.ice
+++ b/cpp/src/IcePack/Activator.ice
@@ -48,6 +48,20 @@ local interface Activator
/**
*
+ * Send signal to server.
+ *
+ **/
+ void sendSignal(Server theServer, string signal);
+
+ /**
+ *
+ * Write message on the server stdout or stderr
+ *
+ **/
+ void writeMessage(Server theServer, string message, int fd);
+
+ /**
+ *
* Returns the server pid.
*
**/
diff --git a/cpp/src/IcePack/ActivatorI.cpp b/cpp/src/IcePack/ActivatorI.cpp
index adaf43ab328..517c0261a90 100644
--- a/cpp/src/IcePack/ActivatorI.cpp
+++ b/cpp/src/IcePack/ActivatorI.cpp
@@ -19,9 +19,11 @@
#include <IcePack/TraceLevels.h>
#include <sys/types.h>
+#include <sys/stat.h>
#include <signal.h>
#include <fcntl.h>
+
using namespace std;
using namespace Ice;
using namespace IcePack;
@@ -51,6 +53,192 @@ private:
}
+#define ICE_STRING(X) #X
+
+namespace
+{
+
+#ifndef _WIN32
+//
+// Helper function for async-signal safe error reporting
+//
+void
+reportChildError(int err, int fd, const char* cannot, const char* name)
+{
+ //
+ // Send any errors to the parent process, using the write
+ // end of the pipe.
+ //
+ char msg[500];
+ strcpy(msg, cannot);
+ strcat(msg, " `");
+ strcat(msg, name);
+ strcat(msg, "': ");
+ strcat(msg, strerror(err));
+ write(fd, msg, strlen(msg));
+ close(fd);
+ _exit(EXIT_FAILURE);
+}
+
+#endif
+
+#ifndef _WIN32
+string
+signalToString(int signal)
+{
+ switch(signal)
+ {
+ case SIGHUP:
+ {
+ return ICE_STRING(SIGHUP);
+ }
+ case SIGINT:
+ {
+ return ICE_STRING(SIGINT);
+ }
+ case SIGQUIT:
+ {
+ return ICE_STRING(SIGQUIT);
+ }
+ case SIGILL:
+ {
+ return ICE_STRING(SIGILL);
+ }
+ case SIGTRAP:
+ {
+ return ICE_STRING(SIGTRAP);
+ }
+ case SIGABRT:
+ {
+ return ICE_STRING(SIGABRT);
+ }
+ case SIGBUS:
+ {
+ return ICE_STRING(SIGBUS);
+ }
+ case SIGFPE:
+ {
+ return ICE_STRING(SIGFPE);
+ }
+ case SIGKILL:
+ {
+ return ICE_STRING(SIGKILL);
+ }
+ case SIGUSR1:
+ {
+ return ICE_STRING(SIGUSR1);
+ }
+ case SIGSEGV:
+ {
+ return ICE_STRING(SIGSEGV);
+ }
+ case SIGPIPE:
+ {
+ return ICE_STRING(SIGPIPE);
+ }
+ case SIGALRM:
+ {
+ return ICE_STRING(SIGALRM);
+ }
+ case SIGTERM:
+ {
+ return ICE_STRING(SIGTERM);
+ }
+ default:
+ {
+ ostringstream os;
+ os << "signal " << signal;
+ return os.str();
+ }
+ }
+#endif
+}
+
+int
+stringToSignal(const string& str)
+{
+#ifdef _WIN32
+ throw BadSignalException();
+#else
+
+ if(str == ICE_STRING(SIGHUP))
+ {
+ return SIGHUP;
+ }
+ else if(str == ICE_STRING(SIGINT))
+ {
+ return SIGINT;
+ }
+ else if(str == ICE_STRING(SIGQUIT))
+ {
+ return SIGQUIT;
+ }
+ else if(str == ICE_STRING(SIGILL))
+ {
+ return SIGILL;
+ }
+ else if(str == ICE_STRING(SIGTRAP))
+ {
+ return SIGTRAP;
+ }
+ else if(str == ICE_STRING(SIGABRT))
+ {
+ return SIGABRT;
+ }
+ else if(str == ICE_STRING(SIGBUS))
+ {
+ return SIGBUS;
+ }
+ else if(str == ICE_STRING(SIGFPE))
+ {
+ return SIGFPE;
+ }
+ else if(str == ICE_STRING(SIGKILL))
+ {
+ return SIGKILL;
+ }
+ else if(str == ICE_STRING(SIGUSR1))
+ {
+ return SIGUSR1;
+ }
+ else if(str == ICE_STRING(SIGSEGV))
+ {
+ return SIGSEGV;
+ }
+ else if(str == ICE_STRING(SIGUSR2))
+ {
+ return SIGUSR2;
+ }
+ else if(str == ICE_STRING(SIGPIPE))
+ {
+ return SIGPIPE;
+ }
+ else if(str == ICE_STRING(SIGALRM))
+ {
+ return SIGALRM;
+ }
+ else if(str == ICE_STRING(SIGTERM))
+ {
+ return SIGTERM;
+ }
+ else
+ {
+ if(str != "")
+ {
+ char* end;
+ long int signal = strtol(str.c_str(), &end, 10);
+ if(*end == '\0' && signal > 0 && signal < 64)
+ {
+ return static_cast<int>(signal);
+ }
+ }
+ throw BadSignalException();
+ }
+}
+#endif
+
+}
+
IcePack::ActivatorI::ActivatorI(const TraceLevelsPtr& traceLevels, const PropertiesPtr& properties) :
_traceLevels(traceLevels),
_properties(properties),
@@ -85,6 +273,9 @@ IcePack::ActivatorI::ActivatorI(const TraceLevelsPtr& traceLevels, const Propert
fcntl(_fdIntrRead, F_SETFL, flags);
#endif
+ _outputDir = _properties->getProperty("IcePack.Node.Output");
+ _redirectErrToOut = (_properties->getPropertyAsInt("IcePack.Node.RedirectErrToOut") > 0);
+
//
// Parse the properties override property.
//
@@ -342,9 +533,107 @@ IcePack::ActivatorI::activate(const ServerPtr& server)
env = envbuf.c_str();
}
+ Process process;
+
STARTUPINFO si;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
+ if(_outputDir.size() > 0)
+ {
+ string outFile = _outputDir + "/" + server->description.name + ".out";
+
+ SECURITY_ATTRIBUTES sec = { 0 };
+ sec.nLength = sizeof(sec);
+ sec.bInheritHandle = true;
+
+ process.outHandle = CreateFile(outFile.c_str(),
+ GENERIC_WRITE,
+ FILE_SHARE_READ,
+ &sec,
+ OPEN_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ if(process.outHandle == INVALID_HANDLE_VALUE)
+ {
+ SyscallException ex(__FILE__, __LINE__);
+ ex.error = getSystemErrno();
+ throw ex;
+ }
+ if(SetFilePointer(process.outHandle, 0, NULL, FILE_END)
+ == INVALID_SET_FILE_POINTER)
+ {
+ SyscallException ex(__FILE__, __LINE__);
+ ex.error = getSystemErrno();
+ throw ex;
+ }
+
+ if(_redirectErrToOut)
+ {
+ process.errHandle = process.outHandle;
+ }
+ else
+ {
+ string errFile = _outputDir + "/" + server->description.name + ".err";
+
+ process.errHandle = CreateFile(errFile.c_str(),
+ GENERIC_WRITE,
+ FILE_SHARE_READ,
+ &sec,
+ OPEN_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ if(process.errHandle == INVALID_HANDLE_VALUE)
+ {
+ SyscallException ex(__FILE__, __LINE__);
+ ex.error = getSystemErrno();
+ throw ex;
+ }
+ if(SetFilePointer(process.errHandle, 0, NULL, FILE_END)
+ == INVALID_SET_FILE_POINTER)
+ {
+ SyscallException ex(__FILE__, __LINE__);
+ ex.error = getSystemErrno();
+ throw ex;
+ }
+
+ }
+
+ si.hStdInput = GetStdHandle(STD_OUTPUT_HANDLE);
+ if(si.hStdInput == INVALID_HANDLE_VALUE)
+ {
+ SyscallException ex(__FILE__, __LINE__);
+ ex.error = getSystemErrno();
+ throw ex;
+ }
+ si.hStdOutput = process.outHandle;
+ si.hStdError = process.errHandle;
+ si.dwFlags = STARTF_USESTDHANDLES;
+ }
+ else
+ {
+ process.outHandle = GetStdHandle(STD_OUTPUT_HANDLE);
+ if(process.outHandle == INVALID_HANDLE_VALUE)
+ {
+ SyscallException ex(__FILE__, __LINE__);
+ ex.error = getSystemErrno();
+ throw ex;
+ }
+ if(_redirectErrToOut)
+ {
+ process.errHandle = process.outHandle;
+ }
+ else
+ {
+ process.errHandle = GetStdHandle(STD_ERROR_HANDLE);
+ if(process.errHandle == INVALID_HANDLE_VALUE)
+ {
+ SyscallException ex(__FILE__, __LINE__);
+ ex.error = getSystemErrno();
+ throw ex;
+ }
+ }
+ }
+
PROCESS_INFORMATION pi;
ZeroMemory(&pi, sizeof(pi));
@@ -353,7 +642,7 @@ IcePack::ActivatorI::activate(const ServerPtr& server)
cmdbuf, // Command line
NULL, // Process attributes
NULL, // Thread attributes
- FALSE, // Inherit handles
+ TRUE, // Inherit handles
CREATE_NEW_PROCESS_GROUP, // Process creation flags
(LPVOID)env, // Process environment
dir, // Current directory
@@ -376,7 +665,7 @@ IcePack::ActivatorI::activate(const ServerPtr& server)
//
CloseHandle(pi.hThread);
- Process process;
+
process.pid = pi.dwProcessId;
process.hnd = pi.hProcess;
process.server = server;
@@ -397,6 +686,84 @@ IcePack::ActivatorI::activate(const ServerPtr& server)
ex.error = getSystemErrno();
throw ex;
}
+
+ //
+ // Convert to standard argc/argv.
+ //
+ int argc = static_cast<int>(args.size());
+ char** argv = static_cast<char**>(malloc((argc + 1) * sizeof(char*)));
+ int i = 0;
+ for(StringSeq::const_iterator p = args.begin(); p != args.end(); ++p, ++i)
+ {
+ assert(i < argc);
+ argv[i] = strdup(p->c_str());
+ }
+ assert(i == argc);
+ argv[argc] = 0;
+
+ int envCount = server->description.envs.size();
+ char** envs = new char*[envCount];
+ i = 0;
+ for(StringSeq::const_iterator q = server->description.envs.begin(); q != server->description.envs.end(); ++q)
+ {
+ envs[i++] = strdup(q->c_str());
+ }
+
+ //
+ // stdout and stderr redirection
+ //
+ int flags = O_WRONLY | O_APPEND | O_CREAT;
+ mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
+
+ int outFd;;
+ string outFile;
+ int errFd;
+ string errFile;
+
+ if(_outputDir.size() == 0)
+ {
+ outFd = STDOUT_FILENO;
+ errFd = _redirectErrToOut ? outFd : STDERR_FILENO;
+ }
+ else
+ {
+ outFile = _outputDir + "/" + server->description.name + ".out";
+ outFd = open(outFile.c_str(), flags, mode);
+ if(outFd < 0)
+ {
+ SyscallException ex(__FILE__, __LINE__);
+ ex.error = getSystemErrno();
+ throw ex;
+ }
+
+ if(_redirectErrToOut)
+ {
+ errFile = outFile;
+ errFd = outFd;
+ }
+ else
+ {
+ errFile = _outputDir + "/" + server->description.name + ".err";
+ errFd = open(errFile.c_str(), flags, mode);
+
+ if(errFd < 0)
+ {
+ SyscallException ex(__FILE__, __LINE__);
+ ex.error = getSystemErrno();
+ throw ex;
+ }
+ }
+ }
+
+ const char* outFileCStr = outFile.c_str();
+ const char* errFileCStr = errFile.c_str();
+
+ //
+ // Current directory
+ //
+ const char* pwdCStr = pwd.c_str();
+
+
pid_t pid = fork();
if(pid == -1)
{
@@ -408,11 +775,9 @@ IcePack::ActivatorI::activate(const ServerPtr& server)
if(pid == 0) // Child process.
{
//
- // TODO: eliminate all non-async-signal-safe calls, in particular anything
- // that may allocate dynamic memory.
+ // Until exec, we can only use async-signal safe functions
//
-
#ifdef __linux
//
// Create a process group for this child, to be able to send
@@ -422,6 +787,22 @@ IcePack::ActivatorI::activate(const ServerPtr& server)
#endif
//
+ // stdout and stderr redirection
+ //
+ if(_outputDir.size() > 0)
+ {
+ if(dup2(outFd, STDOUT_FILENO) != STDOUT_FILENO)
+ {
+ reportChildError(errno, fds[1], "cannot associate stdout with opened file", outFileCStr);
+ }
+
+ if(dup2(errFd, STDERR_FILENO) != STDERR_FILENO)
+ {
+ reportChildError(errno, fds[1], "cannot associate stderr with opened file", errFileCStr);
+ }
+ }
+
+ //
// Close all file descriptors, except for standard input,
// standard output, standard error, and the write side
// of the newly created pipe.
@@ -435,115 +816,55 @@ IcePack::ActivatorI::activate(const ServerPtr& server)
}
}
- //
- // Convert to standard argc/argv.
- //
- int argc = static_cast<int>(args.size());
- char** argv = static_cast<char**>(malloc((argc + 1) * sizeof(char*)));
- int i = 0;
- for(StringSeq::const_iterator p = args.begin(); p != args.end(); ++p, ++i)
- {
- assert(i < argc);
- argv[i] = strdup(p->c_str());
- }
- assert(i == argc);
- argv[argc] = 0;
-
- for(StringSeq::const_iterator q = server->description.envs.begin(); q != server->description.envs.end(); ++q)
+ for(i = 0; i < envCount; i++)
{
- if(putenv(strdup(q->c_str())) != 0)
+ if(putenv(envs[i]) != 0)
{
- SyscallException ex(__FILE__, __LINE__);
- ex.error = getSystemErrno();
- ostringstream s;
- s << "can't set environment variable: " << *q << "':\n" << ex;
- write(fds[1], s.str().c_str(), s.str().length());
- close(fds[1]);
- _exit(EXIT_FAILURE);
+ reportChildError(errno, fds[1], "cannot set environment variable", envs[i]);
}
}
-
//
- // Redirect the standard error output to the write side of the
- // pipe.
+ // Each env is leaked on purpose ... see man putenv().
//
- // TODO: This doesn't work well if the server doesn't control
- // when and how the output is flushed. For example, we could
- // receive one character after the other over the pipe which
- // is problematic since we don't know when to log message. For
- // sure we don't want to log each character one after the
- // other. We want to log the message. One solution would be to
- // put the received information in a buffer and log it only
- // when we receive a '\n'.
- //
-
-// if(fds[1] != STDERR_FILENO)
-// {
-// if(dup2(fds[1], STDERR_FILENO) != STDERR_FILENO)
-// {
-// //
-// // Send any errors to the parent process, using the write
-// // end of the pipe.
-// //
-// SyscallException ex(__FILE__, __LINE__);
-// ex.error = getSystemErrno();
-// ostringstream s;
-// s << "can't redirect stderr to the pipe output";
-// write(fds[1], s.str().c_str(), s.str().length());
-// close(fds[1]);
-// _exit(EXIT_FAILURE);
-// }
-// }
+ delete[] envs;
//
// Change working directory.
//
- if(!pwd.empty())
+ if(strlen(pwdCStr) != 0)
{
- if(chdir(pwd.c_str()) == -1)
+ if(chdir(pwdCStr) == -1)
{
- //
- // Send any errors to the parent process, using the write
- // end of the pipe.
- //
- SyscallException ex(__FILE__, __LINE__);
- ex.error = getSystemErrno();
- ostringstream s;
- s << "can't change working directory to `" << pwd << "':\n" << ex;
- write(fds[1], s.str().c_str(), s.str().length());
- close(fds[1]);
- _exit(EXIT_FAILURE);
+ reportChildError(errno, fds[1], "cannot change working directory to", pwdCStr);
}
}
if(execvp(argv[0], argv) == -1)
{
- //
- // Send any errors to the parent process, using the write
- // end of the pipe.
- //
- SyscallException ex(__FILE__, __LINE__);
- ex.error = getSystemErrno();
- ostringstream s;
- s << "can't execute `" << path << "':\n" << ex;
- write(fds[1], s.str().c_str(), s.str().length());
- close(fds[1]);
- _exit(EXIT_FAILURE);
+ reportChildError(errno, fds[1], "cannot execute", argv[0]);
}
}
else // Parent process.
{
close(fds[1]);
+ for(i = 0; i < envCount; ++i)
+ {
+ free(envs[i]);
+ }
+ delete[] envs;
+
Process process;
process.pid = pid;
- process.fd = fds[0];
+ process.pipeFd = fds[0];
+ process.outFd = outFd;
+ process.errFd = errFd;
process.server = server;
_processes.push_back(process);
- int flags = fcntl(process.fd, F_GETFL);
+ int flags = fcntl(process.pipeFd, F_GETFL);
flags |= O_NONBLOCK;
- fcntl(process.fd, F_SETFL, flags);
+ fcntl(process.pipeFd, F_SETFL, flags);
setInterrupt();
@@ -561,6 +882,7 @@ IcePack::ActivatorI::activate(const ServerPtr& server)
void
IcePack::ActivatorI::deactivate(const ServerPtr& server)
{
+#ifdef _WIN32
Ice::Int pid = server->getPid();
if(pid == 0)
@@ -571,7 +893,6 @@ IcePack::ActivatorI::deactivate(const ServerPtr& server)
return;
}
-#ifdef _WIN32
//
// Generate a Ctrl+Break event on the child.
//
@@ -593,33 +914,15 @@ IcePack::ActivatorI::deactivate(const ServerPtr& server)
//
// Send a SIGTERM to the process.
//
-
-#ifdef __linux
- //
- // Use process groups on Linux instead of processes
- //
- int ret = ::killpg(static_cast<pid_t>(pid), SIGTERM);
-#else
- int ret = ::kill(static_cast<pid_t>(pid), SIGTERM);
-#endif
- if(ret != 0 && getSystemErrno() != ESRCH)
- {
- SyscallException ex(__FILE__, __LINE__);
- ex.error = getSystemErrno();
- throw ex;
- }
-
- if(_traceLevels->activator > 1)
- {
- Ice::Trace out(_traceLevels->logger, _traceLevels->activatorCat);
- out << "sent SIGTERM to server `" << server->description.name << "' (pid = " << pid << ")";
- }
+ sendSignal(server, SIGTERM);
+
#endif
}
void
IcePack::ActivatorI::kill(const ServerPtr& server)
{
+#ifdef _WIN32
Ice::Int pid = server->getPid();
if(pid == 0)
@@ -630,7 +933,6 @@ IcePack::ActivatorI::kill(const ServerPtr& server)
return;
}
-#ifdef _WIN32
HANDLE hnd = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
if(hnd == NULL)
{
@@ -655,15 +957,43 @@ IcePack::ActivatorI::kill(const ServerPtr& server)
Ice::Trace out(_traceLevels->logger, _traceLevels->activatorCat);
out << "terminating server `" << server->description.name << "' (pid = " << pid << ")";
}
+
#else
+ sendSignal(server, SIGKILL);
+#endif
+}
+
+
+void
+IcePack::ActivatorI::sendSignal(const ServerPtr& server, const string& signal)
+{
+ sendSignal(server, stringToSignal(signal));
+}
+void
+IcePack::ActivatorI::sendSignal(const ServerPtr& server, int signal)
+{
+#ifdef _WIN32
//
- // Send a SIGKILL to the process.
+ // TODO: Win32 implementation?
//
+ throw BadSignalException();
+
+#else
+ Ice::Int pid = server->getPid();
+
+ if(pid == 0)
+ {
+ //
+ // Server is already deactivated.
+ //
+ return;
+ }
+
#ifdef __linux
// Use process groups on Linux instead of processes
- int ret = ::killpg(static_cast<pid_t>(pid), SIGKILL);
+ int ret = ::killpg(static_cast<pid_t>(pid), signal);
#else
- int ret = ::kill(static_cast<pid_t>(pid), SIGKILL);
+ int ret = ::kill(static_cast<pid_t>(pid), signal);
#endif
if(ret != 0 && getSystemErrno() != ESRCH)
{
@@ -675,11 +1005,69 @@ IcePack::ActivatorI::kill(const ServerPtr& server)
if(_traceLevels->activator > 1)
{
Ice::Trace out(_traceLevels->logger, _traceLevels->activatorCat);
- out << "sent SIGKILL to server `" << server->description.name << "' (pid = " << pid << ")";
+ out << "sent " << signalToString(signal) << " to server `"
+ << server->description.name << "' (pid = " << pid << ")";
}
#endif
}
+void
+IcePack::ActivatorI::writeMessage(const ServerPtr& server, const string& message, Ice::Int fd)
+{
+ assert(fd == 1 || fd == 2);
+
+ string msg = message + "\n";
+
+#ifdef _WIN32
+ HANDLE handle = 0;
+#else
+ int actualFd = -1;
+#endif
+ {
+ IceUtil::Monitor< IceUtil::Mutex>::Lock sync(*this);
+
+ for(vector<Process>::iterator p = _processes.begin(); p != _processes.end(); ++p)
+ {
+ if(p->server == server)
+ {
+#ifdef _WIN32
+ handle = (fd == 1 ? p->outHandle : p->errHandle);
+#else
+ actualFd = (fd == 1 ? p->outFd : p->errFd);
+#endif
+ break; // for
+ }
+ }
+ }
+
+#ifdef _WIN32
+ if(handle != 0)
+ {
+ DWORD written = 0;
+ if(!WriteFile(handle, msg.c_str(), msg.size(), &written, NULL))
+ {
+ SyscallException ex(__FILE__, __LINE__);
+ ex.error = getSystemErrno();
+ throw ex;
+ }
+ assert(written == msg.size());
+ }
+#else
+ if(actualFd > 0)
+ {
+ ssize_t written = write(actualFd, msg.c_str(), msg.size());
+ if(written == -1)
+ {
+ SyscallException ex(__FILE__, __LINE__);
+ ex.error = getSystemErrno();
+ throw ex;
+ }
+ assert(written == static_cast<ssize_t>(msg.size()));
+ }
+#endif
+}
+
+
Ice::Int
IcePack::ActivatorI::getServerPid(const ServerPtr& server)
{
@@ -870,11 +1258,17 @@ IcePack::ActivatorI::terminationListener()
<< "' termination:\n" << ex;
}
+ CloseHandle(hnd);
+ CloseHandle(p->outHandle);
+ if(!_redirectErrToOut)
+ {
+ CloseHandle(p->errHandle);
+ }
_processes.erase(p);
break;
}
}
- CloseHandle(hnd);
+
}
if(_deactivating && _processes.empty())
@@ -895,7 +1289,7 @@ IcePack::ActivatorI::terminationListener()
for(vector<Process>::iterator p = _processes.begin(); p != _processes.end(); ++p)
{
- int fd = p->fd;
+ int fd = p->pipeFd;
FD_SET(fd, &fdSet);
if(maxFd < fd)
{
@@ -943,7 +1337,7 @@ IcePack::ActivatorI::terminationListener()
vector<Process>::iterator p = _processes.begin();
while(p != _processes.end())
{
- int fd = p->fd;
+ int fd = p->pipeFd;
if(!FD_ISSET(fd, &fdSet))
{
++p;
@@ -996,8 +1390,16 @@ IcePack::ActivatorI::terminationListener()
<< "' termination:\n" << ex;
}
+ if(p->errFd != p->outFd && p->errFd != STDERR_FILENO)
+ {
+ close(p->errFd);
+ }
+ if(p->outFd != STDOUT_FILENO)
+ {
+ close(p->outFd);
+ }
+ close(p->pipeFd);
p = _processes.erase(p);
- close(fd);
//
// We are deactivating and there's no more active processes. We can now
diff --git a/cpp/src/IcePack/ActivatorI.h b/cpp/src/IcePack/ActivatorI.h
index 78594176dfc..451eccd2bba 100644
--- a/cpp/src/IcePack/ActivatorI.h
+++ b/cpp/src/IcePack/ActivatorI.h
@@ -35,6 +35,9 @@ public:
virtual bool activate(const ::IcePack::ServerPtr&);
virtual void deactivate(const ::IcePack::ServerPtr&);
virtual void kill(const ::IcePack::ServerPtr&);
+ virtual void sendSignal(const ::IcePack::ServerPtr&, const std::string&);
+ virtual void writeMessage(const ::IcePack::ServerPtr&, const std::string&, Ice::Int);
+
virtual Ice::Int getServerPid(const ::IcePack::ServerPtr&);
virtual void start();
@@ -42,6 +45,8 @@ public:
virtual void shutdown();
virtual void destroy();
+
+ void sendSignal(const ::IcePack::ServerPtr&, int);
void runTerminationListener();
private:
@@ -57,9 +62,13 @@ private:
#ifdef _WIN32
DWORD pid;
HANDLE hnd;
+ HANDLE outHandle;
+ HANDLE errHandle;
#else
pid_t pid;
- int fd;
+ int pipeFd;
+ int outFd;
+ int errFd;
#endif
ServerPtr server;
};
@@ -77,7 +86,10 @@ private:
#endif
std::vector<std::string> _propertiesOverride;
-
+
+ std::string _outputDir;
+ bool _redirectErrToOut;
+
IceUtil::ThreadPtr _thread;
};
diff --git a/cpp/src/IcePack/AdminI.cpp b/cpp/src/IcePack/AdminI.cpp
index da27570a4ef..925bfcf36a5 100644
--- a/cpp/src/IcePack/AdminI.cpp
+++ b/cpp/src/IcePack/AdminI.cpp
@@ -168,6 +168,43 @@ IcePack::AdminI::stopServer(const string& name, const Current&)
}
}
+void
+IcePack::AdminI::sendSignal(const string& name, const string& signal, const Current&)
+{
+ ServerPrx server = _serverRegistry->findByName(name);
+ try
+ {
+ server->sendSignal(signal);
+ }
+ catch(const Ice::ObjectNotExistException&)
+ {
+ throw ServerNotExistException();
+ }
+ catch(const Ice::LocalException&)
+ {
+ throw NodeUnreachableException();
+ }
+}
+
+void
+IcePack::AdminI::writeMessage(const string& name, const string& message, Int fd, const Current&)
+{
+ ServerPrx server = _serverRegistry->findByName(name);
+ try
+ {
+ server->writeMessage(message, fd);
+ }
+ catch(const Ice::ObjectNotExistException&)
+ {
+ throw ServerNotExistException();
+ }
+ catch(const Ice::LocalException&)
+ {
+ throw NodeUnreachableException();
+ }
+}
+
+
StringSeq
IcePack::AdminI::getAllServerNames(const Current&) const
{
diff --git a/cpp/src/IcePack/AdminI.h b/cpp/src/IcePack/AdminI.h
index d3e92727015..43fce2d7e96 100644
--- a/cpp/src/IcePack/AdminI.h
+++ b/cpp/src/IcePack/AdminI.h
@@ -40,6 +40,8 @@ public:
virtual Ice::Int getServerPid(const ::std::string&, const Ice::Current&) const;
virtual bool startServer(const ::std::string&, const Ice::Current&);
virtual void stopServer(const ::std::string&, const Ice::Current&);
+ virtual void sendSignal(const ::std::string&, const ::std::string&, const Ice::Current&);
+ virtual void writeMessage(const ::std::string&, const ::std::string&, Ice::Int, const Ice::Current&);
virtual Ice::StringSeq getAllServerNames(const Ice::Current&) const;
virtual ServerActivation getServerActivation(const ::std::string&, const Ice::Current&) const;
virtual void setServerActivation(const ::std::string&, ServerActivation, const Ice::Current&);
diff --git a/cpp/src/IcePack/Grammar.y b/cpp/src/IcePack/Grammar.y
index 9586f6153aa..d3d88beffa6 100644
--- a/cpp/src/IcePack/Grammar.y
+++ b/cpp/src/IcePack/Grammar.y
@@ -53,6 +53,9 @@ yyerror(const char* s)
%token ICE_PACK_STRING
%token ICE_PACK_START
%token ICE_PACK_STOP
+%token ICE_PACK_SIGNAL
+%token ICE_PACK_STDOUT
+%token ICE_PACK_STDERR
%token ICE_PACK_DESCRIBE
%token ICE_PACK_STATE
%token ICE_PACK_PID
@@ -128,6 +131,18 @@ command
{
parser->stopServer($3);
}
+| ICE_PACK_SERVER ICE_PACK_SIGNAL strings ';'
+{
+ parser->signalServer($3);
+}
+| ICE_PACK_SERVER ICE_PACK_STDOUT strings ';'
+{
+ parser->writeMessage($3, 1);
+}
+| ICE_PACK_SERVER ICE_PACK_STDERR strings ';'
+{
+ parser->writeMessage($3, 2);
+}
| ICE_PACK_SERVER ICE_PACK_DESCRIBE strings ';'
{
parser->describeServer($3);
diff --git a/cpp/src/IcePack/Internal.ice b/cpp/src/IcePack/Internal.ice
index 2d4438f9f20..b16f06319f1 100644
--- a/cpp/src/IcePack/Internal.ice
+++ b/cpp/src/IcePack/Internal.ice
@@ -270,6 +270,20 @@ class Server
/**
*
+ * Send signal to the server
+ *
+ **/
+ void sendSignal(string signal) throws BadSignalException;
+
+ /**
+ *
+ * Write message on servers' stdout or stderr.
+ *
+ **/
+ void writeMessage(string message, int fd);
+
+ /**
+ *
* Destroy the server. This method destroys the server and
* eventually deactivates if it's still active.
*
diff --git a/cpp/src/IcePack/Parser.cpp b/cpp/src/IcePack/Parser.cpp
index 24d2ecc6172..dc057489274 100644
--- a/cpp/src/IcePack/Parser.cpp
+++ b/cpp/src/IcePack/Parser.cpp
@@ -72,6 +72,9 @@ IcePack::Parser::usage()
"server pid NAME Get server NAME pid.\n"
"server start NAME Start server NAME.\n"
"server stop NAME Stop server NAME.\n"
+ "server signal NAME SIGNAL Send SIGNAL (e.g. SIGTERM or 15) to server NAME\n"
+ "server stdout NAME MESSAGE Write MESSAGE on server NAME's stdout\n"
+ "server stderr NAME MESSAGE Write MESSAGE on server NAME's stderr\n"
"server activation NAME [on-demand | manual] \n"
" Set the server activation mode to on-demand or\n"
" manual activation"
@@ -327,6 +330,54 @@ IcePack::Parser::stopServer(const list<string>& args)
}
void
+IcePack::Parser::signalServer(const list<string>& args)
+{
+ if(args.size() != 2)
+ {
+ error("`server signal' requires exactly two arguments\n(`help' for more info)");
+ return;
+ }
+
+ try
+ {
+ list<string>::const_iterator p = args.begin();
+ string server = *p++;
+ _admin->sendSignal(server, *p);
+ }
+ catch(const Exception& ex)
+ {
+ ostringstream s;
+ s << ex;
+ error(s.str());
+ }
+}
+
+
+void
+IcePack::Parser::writeMessage(const list<string>& args, int fd)
+{
+ if(args.size() != 2)
+ {
+ error("`server stdout or server stderr' requires exactly two arguments\n(`help' for more info)");
+ return;
+ }
+
+ try
+ {
+ list<string>::const_iterator p = args.begin();
+ string server = *p++;
+ _admin->writeMessage(server, *p, fd);
+ }
+ catch(const Exception& ex)
+ {
+ ostringstream s;
+ s << ex;
+ error(s.str());
+ }
+}
+
+
+void
IcePack::Parser::removeServer(const list<string>& args)
{
if(args.size() != 1)
diff --git a/cpp/src/IcePack/Parser.h b/cpp/src/IcePack/Parser.h
index 0e78e2cbc34..0ac4d5859f8 100644
--- a/cpp/src/IcePack/Parser.h
+++ b/cpp/src/IcePack/Parser.h
@@ -82,6 +82,8 @@ public:
void addServer(const std::list<std::string>&);
void startServer(const std::list<std::string>&);
void stopServer(const std::list<std::string>&);
+ void signalServer(const std::list<std::string>&);
+ void writeMessage(const std::list<std::string>&, int fd);
void describeServer(const std::list<std::string>&);
void stateServer(const std::list<std::string>&);
void activationServer(const std::list<std::string>&);
diff --git a/cpp/src/IcePack/Scanner.l b/cpp/src/IcePack/Scanner.l
index 949a9725a20..60cbe6b0fcd 100644
--- a/cpp/src/IcePack/Scanner.l
+++ b/cpp/src/IcePack/Scanner.l
@@ -158,6 +158,18 @@ NL [\n]
return ICE_PACK_STOP;
}
+"signal" {
+ return ICE_PACK_SIGNAL;
+}
+
+"stdout" {
+ return ICE_PACK_STDOUT;
+}
+
+"stderr" {
+ return ICE_PACK_STDERR;
+}
+
"node" {
return ICE_PACK_NODE;
}
diff --git a/cpp/src/IcePack/ServerI.cpp b/cpp/src/IcePack/ServerI.cpp
index ec5261a686b..71c90c13028 100644
--- a/cpp/src/IcePack/ServerI.cpp
+++ b/cpp/src/IcePack/ServerI.cpp
@@ -157,6 +157,19 @@ IcePack::ServerI::stop(const Ice::Current& current)
}
void
+IcePack::ServerI::sendSignal(const string& signal, const Ice::Current& current)
+{
+ _activator->sendSignal(this, signal);
+}
+
+void
+IcePack::ServerI::writeMessage(const string& message, Ice::Int fd, const Ice::Current& current)
+{
+ _activator->writeMessage(this, message, fd);
+}
+
+
+void
IcePack::ServerI::destroy(const Ice::Current& current)
{
bool stop = false;
diff --git a/cpp/src/IcePack/ServerI.h b/cpp/src/IcePack/ServerI.h
index 4cece3a48e0..5e7e90fc058 100644
--- a/cpp/src/IcePack/ServerI.h
+++ b/cpp/src/IcePack/ServerI.h
@@ -42,6 +42,8 @@ public:
virtual bool start(ServerActivation, const ::Ice::Current&);
virtual void stop(const ::Ice::Current&);
+ virtual void sendSignal(const std::string&, const ::Ice::Current&);
+ virtual void writeMessage(const std::string&, Ice::Int, const ::Ice::Current&);
virtual void destroy(const ::Ice::Current&);
virtual void terminated(const ::Ice::Current&);