diff options
author | Bernard Normier <bernard@zeroc.com> | 2003-12-27 20:36:41 +0000 |
---|---|---|
committer | Bernard Normier <bernard@zeroc.com> | 2003-12-27 20:36:41 +0000 |
commit | 3f954aab0eab59e99bad75f9b1d98a7f7603a46b (patch) | |
tree | 9dfc1df4d61de79e8c453ab5ff789bd5fa516977 | |
parent | fixing all, minimal dependencies (diff) | |
download | ice-3f954aab0eab59e99bad75f9b1d98a7f7603a46b.tar.bz2 ice-3f954aab0eab59e99bad75f9b1d98a7f7603a46b.tar.xz ice-3f954aab0eab59e99bad75f9b1d98a7f7603a46b.zip |
Added new icepackadmin commands: signal, stdout, stderr
-rw-r--r-- | cpp/CHANGES | 16 | ||||
-rw-r--r-- | cpp/doc/Properties.sgml | 33 | ||||
-rw-r--r-- | cpp/slice/IcePack/Admin.ice | 40 | ||||
-rw-r--r-- | cpp/slice/IcePack/Exception.ice | 10 | ||||
-rw-r--r-- | cpp/src/Glacier/StarterI.cpp | 3 | ||||
-rw-r--r-- | cpp/src/Ice/PropertiesI.cpp | 2 | ||||
-rw-r--r-- | cpp/src/IcePack/Activator.ice | 14 | ||||
-rw-r--r-- | cpp/src/IcePack/ActivatorI.cpp | 634 | ||||
-rw-r--r-- | cpp/src/IcePack/ActivatorI.h | 16 | ||||
-rw-r--r-- | cpp/src/IcePack/AdminI.cpp | 37 | ||||
-rw-r--r-- | cpp/src/IcePack/AdminI.h | 2 | ||||
-rw-r--r-- | cpp/src/IcePack/Grammar.y | 15 | ||||
-rw-r--r-- | cpp/src/IcePack/Internal.ice | 14 | ||||
-rw-r--r-- | cpp/src/IcePack/Parser.cpp | 51 | ||||
-rw-r--r-- | cpp/src/IcePack/Parser.h | 2 | ||||
-rw-r--r-- | cpp/src/IcePack/Scanner.l | 12 | ||||
-rw-r--r-- | cpp/src/IcePack/ServerI.cpp | 13 | ||||
-rw-r--r-- | cpp/src/IcePack/ServerI.h | 2 |
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&); |