1426 lines
42 KiB
C++
1426 lines
42 KiB
C++
|
#include "ace/Process.h"
|
||
|
|
||
|
#if !defined (__ACE_INLINE__)
|
||
|
#include "ace/Process.inl"
|
||
|
#endif /* __ACE_INLINE__ */
|
||
|
|
||
|
#include "ace/ARGV.h"
|
||
|
#include "ace/Auto_Ptr.h"
|
||
|
#include "ace/Signal.h"
|
||
|
#include "ace/SString.h"
|
||
|
#include "ace/Log_Category.h"
|
||
|
#include "ace/OS_NS_stdio.h"
|
||
|
#include "ace/OS_NS_stdlib.h"
|
||
|
#include "ace/OS_NS_sys_socket.h"
|
||
|
#include "ace/OS_NS_errno.h"
|
||
|
#include "ace/OS_NS_string.h"
|
||
|
#include "ace/OS_NS_unistd.h"
|
||
|
#include "ace/OS_NS_fcntl.h"
|
||
|
#include "ace/OS_Memory.h"
|
||
|
#include "ace/Countdown_Time.h"
|
||
|
#include "ace/Truncate.h"
|
||
|
#include "ace/Vector_T.h"
|
||
|
#include "ace/Tokenizer_T.h"
|
||
|
|
||
|
#if defined (ACE_VXWORKS) && defined (__RTP__)
|
||
|
# include <rtpLib.h>
|
||
|
# include <taskLib.h>
|
||
|
#endif
|
||
|
|
||
|
// This function acts as a signal handler for SIGCHLD. We don't really want
|
||
|
// to do anything with the signal - it's just needed to interrupt a sleep.
|
||
|
// See wait() for more info.
|
||
|
#if !defined (ACE_WIN32) && !defined(ACE_LACKS_UNIX_SIGNALS)
|
||
|
static void
|
||
|
sigchld_nop (int, siginfo_t *, ucontext_t *)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
#endif /* ACE_WIN32 */
|
||
|
|
||
|
|
||
|
ACE_BEGIN_VERSIONED_NAMESPACE_DECL
|
||
|
|
||
|
ACE_Process::ACE_Process (void)
|
||
|
:
|
||
|
#if !defined (ACE_WIN32)
|
||
|
child_id_ (ACE_INVALID_PID),
|
||
|
#endif /* !defined (ACE_WIN32) */
|
||
|
exit_code_ (0)
|
||
|
{
|
||
|
#if defined (ACE_WIN32)
|
||
|
ACE_OS::memset ((void *) &this->process_info_,
|
||
|
0,
|
||
|
sizeof this->process_info_);
|
||
|
#endif /* ACE_WIN32 */
|
||
|
}
|
||
|
|
||
|
ACE_Process::~ACE_Process (void)
|
||
|
{
|
||
|
#if defined (ACE_WIN32)
|
||
|
// Free resources allocated in kernel.
|
||
|
ACE_OS::close (this->process_info_.hThread);
|
||
|
ACE_OS::close (this->process_info_.hProcess);
|
||
|
#endif /* ACE_WIN32 */
|
||
|
// If any handles were duplicated for the child process and
|
||
|
// still not closed, get them now.
|
||
|
this->close_dup_handles ();
|
||
|
}
|
||
|
|
||
|
int
|
||
|
ACE_Process::prepare (ACE_Process_Options &)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
pid_t
|
||
|
ACE_Process::spawn (ACE_Process_Options &options)
|
||
|
{
|
||
|
if (this->prepare (options) < 0)
|
||
|
return ACE_INVALID_PID;
|
||
|
|
||
|
// Stash the passed/duped handle sets away in this object for later
|
||
|
// closing if needed or requested. At the same time, figure out which
|
||
|
// ones to include in command line options if that's needed below.
|
||
|
ACE_Handle_Set *set_p = 0;
|
||
|
if (options.dup_handles (this->dup_handles_))
|
||
|
set_p = &this->dup_handles_;
|
||
|
else if (options.passed_handles (this->handles_passed_))
|
||
|
set_p = &this->handles_passed_;
|
||
|
|
||
|
// If we are going to end up running a new program (i.e. Win32, or
|
||
|
// NO_EXEC option is set) then get any handles passed in the options,
|
||
|
// and tack them onto the command line with +H <handle> options,
|
||
|
// unless the command line runs out of space.
|
||
|
// Note that we're using the knowledge that all the options, argvs, etc.
|
||
|
// passed to the options are all sitting in the command_line_buf. Any
|
||
|
// call to get the argv then splits them out. So, regardless of the
|
||
|
// platform, tack them all onto the command line buf and take it
|
||
|
// from there.
|
||
|
if (set_p && !ACE_BIT_ENABLED (options.creation_flags (),
|
||
|
ACE_Process_Options::NO_EXEC))
|
||
|
{
|
||
|
size_t max_len = 0;
|
||
|
ACE_TCHAR *cmd_line_buf = options.command_line_buf (&max_len);
|
||
|
size_t curr_len = ACE_OS::strlen (cmd_line_buf);
|
||
|
ACE_Handle_Set_Iterator h_iter (*set_p);
|
||
|
// Because the length of the to-be-formatted +H option is not
|
||
|
// known, and we don't have a snprintf, guess at the space
|
||
|
// needed (20 chars), and use that as a limit.
|
||
|
for (ACE_HANDLE h = h_iter ();
|
||
|
h != ACE_INVALID_HANDLE && curr_len + 20 < max_len;
|
||
|
h = h_iter ())
|
||
|
{
|
||
|
#if defined (ACE_WIN32)
|
||
|
# if defined (ACE_WIN64)
|
||
|
// silence warnings coming from MinGW64 compilers
|
||
|
# if defined (__GNUC__)
|
||
|
# pragma GCC diagnostic push
|
||
|
# pragma GCC diagnostic ignored "-Wformat"
|
||
|
# pragma GCC diagnostic ignored "-Wformat-extra-args"
|
||
|
# endif /* __GNUC__ */
|
||
|
curr_len += ACE_OS::sprintf (&cmd_line_buf[curr_len],
|
||
|
ACE_TEXT (" +H %I64p"),
|
||
|
h);
|
||
|
# if defined (__GNUC__)
|
||
|
# pragma GCC diagnostic pop
|
||
|
# endif /* __GNUC__ */
|
||
|
# else
|
||
|
curr_len += ACE_OS::sprintf (&cmd_line_buf[curr_len],
|
||
|
ACE_TEXT (" +H %p"),
|
||
|
h);
|
||
|
# endif /* ACE_WIN64 */
|
||
|
#else
|
||
|
curr_len += ACE_OS::sprintf (&cmd_line_buf[curr_len],
|
||
|
ACE_TEXT (" +H %d"),
|
||
|
h);
|
||
|
#endif /* ACE_WIN32 */
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#if defined (ACE_HAS_WINCE)
|
||
|
// Note that WinCE does not have process name included in the command line as argv[0]
|
||
|
// like other OS environment. Therefore, it is user's whole responsibility to call
|
||
|
// 'ACE_Process_Options::process_name(const ACE_TCHAR *name)' to set the proper
|
||
|
// process name (the execution file name with path if needed).
|
||
|
BOOL fork_result =
|
||
|
ACE_TEXT_CreateProcess (options.process_name(),
|
||
|
options.command_line_buf(),
|
||
|
options.get_process_attributes(), // must be NULL in CE
|
||
|
options.get_thread_attributes(), // must be NULL in CE
|
||
|
options.handle_inheritance(), // must be false in CE
|
||
|
options.creation_flags(), // must be NULL in CE
|
||
|
options.env_buf(), // environment variables, must be NULL in CE
|
||
|
options.working_directory(), // must be NULL in CE
|
||
|
options.startup_info(), // must be NULL in CE
|
||
|
&this->process_info_);
|
||
|
|
||
|
if (fork_result)
|
||
|
{
|
||
|
parent (this->getpid ());
|
||
|
return this->getpid ();
|
||
|
}
|
||
|
return ACE_INVALID_PID;
|
||
|
|
||
|
#elif defined (ACE_WIN32)
|
||
|
void* env_buf = options.env_buf ();
|
||
|
DWORD flags = options.creation_flags ();
|
||
|
# if defined (ACE_HAS_WCHAR) && !defined (ACE_USES_WCHAR)
|
||
|
wchar_t* wenv_buf = 0;
|
||
|
if (options.use_unicode_environment ())
|
||
|
{
|
||
|
wenv_buf = this->convert_env_buffer (options.env_buf ());
|
||
|
env_buf = wenv_buf;
|
||
|
flags |= CREATE_UNICODE_ENVIRONMENT;
|
||
|
}
|
||
|
# endif
|
||
|
|
||
|
BOOL fork_result =
|
||
|
ACE_TEXT_CreateProcess (0,
|
||
|
options.command_line_buf (),
|
||
|
options.get_process_attributes (),
|
||
|
options.get_thread_attributes (),
|
||
|
options.handle_inheritance (),
|
||
|
flags,
|
||
|
env_buf, // environment variables
|
||
|
options.working_directory (),
|
||
|
options.startup_info (),
|
||
|
&this->process_info_);
|
||
|
|
||
|
# if defined (ACE_HAS_WCHAR) && !defined (ACE_USES_WCHAR)
|
||
|
if (options.use_unicode_environment ())
|
||
|
delete wenv_buf;
|
||
|
# endif
|
||
|
|
||
|
if (fork_result)
|
||
|
{
|
||
|
parent (this->getpid ());
|
||
|
return this->getpid ();
|
||
|
}
|
||
|
return ACE_INVALID_PID;
|
||
|
|
||
|
#elif defined(ACE_OPENVMS)
|
||
|
if (ACE_BIT_ENABLED (options.creation_flags (),
|
||
|
ACE_Process_Options::NO_EXEC))
|
||
|
ACE_NOTSUP_RETURN (ACE_INVALID_PID);
|
||
|
|
||
|
int saved_stdin = ACE_STDIN;
|
||
|
int saved_stdout = ACE_STDOUT;
|
||
|
int saved_stderr = ACE_STDERR;
|
||
|
// Save STD file descriptors and redirect
|
||
|
if (options.get_stdin () != ACE_INVALID_HANDLE) {
|
||
|
if ((saved_stdin = ACE_OS::dup (ACE_STDIN)) == -1 && errno != EBADF)
|
||
|
ACE_OS::exit (errno);
|
||
|
if (ACE_OS::dup2 (options.get_stdin (), ACE_STDIN) == -1)
|
||
|
ACE_OS::exit (errno);
|
||
|
}
|
||
|
if (options.get_stdout () != ACE_INVALID_HANDLE) {
|
||
|
if ((saved_stdout = ACE_OS::dup (ACE_STDOUT)) == -1 && errno != EBADF)
|
||
|
ACE_OS::exit (errno);
|
||
|
if (ACE_OS::dup2 (options.get_stdout (), ACE_STDOUT) == -1)
|
||
|
ACE_OS::exit (errno);
|
||
|
}
|
||
|
if (options.get_stderr () != ACE_INVALID_HANDLE) {
|
||
|
if ((saved_stderr = ACE_OS::dup (ACE_STDERR)) == -1 && errno != EBADF)
|
||
|
ACE_OS::exit (errno);
|
||
|
if (ACE_OS::dup2 (options.get_stderr (), ACE_STDERR) == -1)
|
||
|
ACE_OS::exit (errno);
|
||
|
}
|
||
|
|
||
|
if (options.working_directory () != 0)
|
||
|
ACE_NOTSUP_RETURN (ACE_INVALID_PID);
|
||
|
|
||
|
this->child_id_ = vfork();
|
||
|
if (this->child_id_ == 0) {
|
||
|
ACE_OS::execvp (options.process_name (),
|
||
|
options.command_line_argv ());
|
||
|
// something went wrong
|
||
|
this->child_id_ = ACE_INVALID_PID;
|
||
|
}
|
||
|
|
||
|
// restore STD file descriptors (if necessary)
|
||
|
if (options.get_stdin () != ACE_INVALID_HANDLE) {
|
||
|
if (saved_stdin == -1)
|
||
|
ACE_OS::close (ACE_STDIN);
|
||
|
else
|
||
|
ACE_OS::dup2 (saved_stdin, ACE_STDIN);
|
||
|
}
|
||
|
if (options.get_stdout () != ACE_INVALID_HANDLE) {
|
||
|
if (saved_stdout == -1)
|
||
|
ACE_OS::close (ACE_STDOUT);
|
||
|
else
|
||
|
ACE_OS::dup2 (saved_stdout, ACE_STDOUT);
|
||
|
}
|
||
|
if (options.get_stderr () != ACE_INVALID_HANDLE) {
|
||
|
if (saved_stderr == -1)
|
||
|
ACE_OS::close (ACE_STDERR);
|
||
|
else
|
||
|
ACE_OS::dup2 (saved_stderr, ACE_STDERR);
|
||
|
}
|
||
|
|
||
|
return this->child_id_;
|
||
|
#elif defined (ACE_VXWORKS) && defined (__RTP__)
|
||
|
if (ACE_BIT_ENABLED (options.creation_flags (),
|
||
|
ACE_Process_Options::NO_EXEC))
|
||
|
ACE_NOTSUP_RETURN (ACE_INVALID_PID);
|
||
|
|
||
|
if (options.working_directory () != 0)
|
||
|
ACE_NOTSUP_RETURN (ACE_INVALID_PID);
|
||
|
|
||
|
int saved_stdin = ACE_STDIN;
|
||
|
int saved_stdout = ACE_STDOUT;
|
||
|
int saved_stderr = ACE_STDERR;
|
||
|
// Save STD file descriptors and redirect
|
||
|
if (options.get_stdin () != ACE_INVALID_HANDLE) {
|
||
|
if ((saved_stdin = ACE_OS::dup (ACE_STDIN)) == -1 && errno != EBADF)
|
||
|
ACE_OS::exit (errno);
|
||
|
if (ACE_OS::dup2 (options.get_stdin (), ACE_STDIN) == -1)
|
||
|
ACE_OS::exit (errno);
|
||
|
}
|
||
|
if (options.get_stdout () != ACE_INVALID_HANDLE) {
|
||
|
if ((saved_stdout = ACE_OS::dup (ACE_STDOUT)) == -1 && errno != EBADF)
|
||
|
ACE_OS::exit (errno);
|
||
|
if (ACE_OS::dup2 (options.get_stdout (), ACE_STDOUT) == -1)
|
||
|
ACE_OS::exit (errno);
|
||
|
}
|
||
|
if (options.get_stderr () != ACE_INVALID_HANDLE) {
|
||
|
if ((saved_stderr = ACE_OS::dup (ACE_STDERR)) == -1 && errno != EBADF)
|
||
|
ACE_OS::exit (errno);
|
||
|
if (ACE_OS::dup2 (options.get_stderr (), ACE_STDERR) == -1)
|
||
|
ACE_OS::exit (errno);
|
||
|
}
|
||
|
|
||
|
// Wide-char builds need narrow-char strings for commandline and
|
||
|
// environment variables.
|
||
|
# if defined (ACE_USES_WCHAR)
|
||
|
wchar_t * const *wargv = options.command_line_argv ();
|
||
|
size_t vcount, i;
|
||
|
for (vcount = 0; wargv[vcount] != 0; ++vcount)
|
||
|
;
|
||
|
char **procargv = new char *[vcount + 1]; // Need 0 at the end
|
||
|
procargv[vcount] = 0;
|
||
|
for (i = 0; i < vcount; ++i)
|
||
|
procargv[i] = ACE_Wide_To_Ascii::convert (wargv[i]);
|
||
|
|
||
|
char **procenv = 0;
|
||
|
if (options.inherit_environment ())
|
||
|
{
|
||
|
wargv = options.env_argv ();
|
||
|
for (vcount = 0; wargv[vcount] != 0; ++vcount)
|
||
|
;
|
||
|
procenv = new char *[vcount + 1]; // Need 0 at the end
|
||
|
procenv[vcount] = 0;
|
||
|
for (i = 0; i < vcount; ++i)
|
||
|
procenv[i] = ACE_Wide_To_Ascii::convert (wargv[i]);
|
||
|
}
|
||
|
# else
|
||
|
const char **procargv = const_cast<const char**> (options.command_line_argv ());
|
||
|
const char **procenv = const_cast<const char**> (options.env_argv ());
|
||
|
# endif /* ACE_USES_WCHAR */
|
||
|
|
||
|
this->child_id_ = ::rtpSpawn (procargv[0],
|
||
|
procargv,
|
||
|
procenv,
|
||
|
200, // priority
|
||
|
0x10000, // uStackSize
|
||
|
0, // options
|
||
|
VX_FP_TASK); // taskOptions
|
||
|
int my_errno_ = errno;
|
||
|
if (this->child_id_ == ERROR) {
|
||
|
// something went wrong
|
||
|
this->child_id_ = ACE_INVALID_PID;
|
||
|
}
|
||
|
|
||
|
# if defined (ACE_USES_WCHAR)
|
||
|
if (procenv)
|
||
|
delete procenv;
|
||
|
# endif /* ACE_USES_WCHAR */
|
||
|
|
||
|
// restore STD file descriptors (if necessary)
|
||
|
if (options.get_stdin () != ACE_INVALID_HANDLE) {
|
||
|
if (saved_stdin == -1)
|
||
|
ACE_OS::close (ACE_STDIN);
|
||
|
else
|
||
|
ACE_OS::dup2 (saved_stdin, ACE_STDIN);
|
||
|
}
|
||
|
if (options.get_stdout () != ACE_INVALID_HANDLE) {
|
||
|
if (saved_stdout == -1)
|
||
|
ACE_OS::close (ACE_STDOUT);
|
||
|
else
|
||
|
ACE_OS::dup2 (saved_stdout, ACE_STDOUT);
|
||
|
}
|
||
|
if (options.get_stderr () != ACE_INVALID_HANDLE) {
|
||
|
if (saved_stderr == -1)
|
||
|
ACE_OS::close (ACE_STDERR);
|
||
|
else
|
||
|
ACE_OS::dup2 (saved_stderr, ACE_STDERR);
|
||
|
}
|
||
|
|
||
|
if (this->child_id_ == ACE_INVALID_PID)
|
||
|
{
|
||
|
errno = my_errno_;
|
||
|
}
|
||
|
|
||
|
return this->child_id_;
|
||
|
#else /* ACE_WIN32 */
|
||
|
// Fork the new process.
|
||
|
this->child_id_ = ACE::fork (options.process_name (),
|
||
|
options.avoid_zombies ());
|
||
|
|
||
|
if (this->child_id_ == 0)
|
||
|
{
|
||
|
# if !defined (ACE_LACKS_SETPGID)
|
||
|
// If we're the child and the options specified a non-default
|
||
|
// process group, try to set our pgid to it. This allows the
|
||
|
// <ACE_Process_Manager> to wait for processes by their
|
||
|
// process-group.
|
||
|
if (options.getgroup () != ACE_INVALID_PID
|
||
|
&& ACE_OS::setpgid (0,
|
||
|
options.getgroup ()) < 0)
|
||
|
{
|
||
|
#if !defined (ACE_HAS_THREADS)
|
||
|
// We can't emit this log message because ACELIB_ERROR(), etc.
|
||
|
// will invoke async signal unsafe functions, which results
|
||
|
// in undefined behavior in threaded programs.
|
||
|
ACELIB_ERROR ((LM_ERROR,
|
||
|
ACE_TEXT ("%p.\n"),
|
||
|
ACE_TEXT ("ACE_Process::spawn: setpgid failed.")));
|
||
|
#endif
|
||
|
}
|
||
|
# endif /* ACE_LACKS_SETPGID */
|
||
|
|
||
|
# if !defined (ACE_LACKS_SETREGID)
|
||
|
if (options.getrgid () != (uid_t) -1
|
||
|
|| options.getegid () != (uid_t) -1)
|
||
|
if (ACE_OS::setregid (options.getrgid (),
|
||
|
options.getegid ()) == -1)
|
||
|
{
|
||
|
#if !defined (ACE_HAS_THREADS)
|
||
|
// We can't emit this log message because ACELIB_ERROR(), etc.
|
||
|
// will invoke async signal unsafe functions, which results
|
||
|
// in undefined behavior in threaded programs.
|
||
|
ACELIB_ERROR ((LM_ERROR,
|
||
|
ACE_TEXT ("%p.\n"),
|
||
|
ACE_TEXT ("ACE_Process::spawn: setregid failed.")));
|
||
|
#endif
|
||
|
}
|
||
|
# endif /* ACE_LACKS_SETREGID */
|
||
|
|
||
|
# if !defined (ACE_LACKS_SETREUID)
|
||
|
// Set user and group id's.
|
||
|
if (options.getruid () != (uid_t) -1
|
||
|
|| options.geteuid () != (uid_t) -1)
|
||
|
if (ACE_OS::setreuid (options.getruid (),
|
||
|
options.geteuid ()) == -1)
|
||
|
{
|
||
|
#if !defined (ACE_HAS_THREADS)
|
||
|
// We can't emit this log message because ACELIB_ERROR(), etc.
|
||
|
// will invoke async signal unsafe functions, which results
|
||
|
// in undefined behavior in threaded programs.
|
||
|
ACELIB_ERROR ((LM_ERROR,
|
||
|
ACE_TEXT ("%p.\n"),
|
||
|
ACE_TEXT ("ACE_Process::spawn: setreuid failed.")));
|
||
|
#endif
|
||
|
}
|
||
|
# endif /* ACE_LACKS_SETREUID */
|
||
|
|
||
|
this->child (ACE_OS::getppid ());
|
||
|
}
|
||
|
else if (this->child_id_ != -1)
|
||
|
this->parent (this->child_id_);
|
||
|
|
||
|
// If we're not supposed to exec, return the process id.
|
||
|
if (ACE_BIT_ENABLED (options.creation_flags (),
|
||
|
ACE_Process_Options::NO_EXEC))
|
||
|
return this->child_id_;
|
||
|
|
||
|
switch (this->child_id_)
|
||
|
{
|
||
|
case -1:
|
||
|
// Error.
|
||
|
return ACE_INVALID_PID;
|
||
|
case 0:
|
||
|
// Child process...exec the
|
||
|
{
|
||
|
if (options.get_stdin () != ACE_INVALID_HANDLE
|
||
|
&& ACE_OS::dup2 (options.get_stdin (),
|
||
|
ACE_STDIN) == -1)
|
||
|
ACE_OS::exit (errno);
|
||
|
else if (options.get_stdout () != ACE_INVALID_HANDLE
|
||
|
&& ACE_OS::dup2 (options.get_stdout (),
|
||
|
ACE_STDOUT) == -1)
|
||
|
ACE_OS::exit (errno);
|
||
|
else if (options.get_stderr () != ACE_INVALID_HANDLE
|
||
|
&& ACE_OS::dup2 (options.get_stderr (),
|
||
|
ACE_STDERR) == -1)
|
||
|
ACE_OS::exit (errno);
|
||
|
|
||
|
// close down unneeded descriptors
|
||
|
ACE_OS::close (options.get_stdin ());
|
||
|
ACE_OS::close (options.get_stdout ());
|
||
|
ACE_OS::close (options.get_stderr ());
|
||
|
if (!options.handle_inheritance ())
|
||
|
{
|
||
|
// Set close-on-exec for all FDs except standard handles
|
||
|
for (int i = ACE::max_handles () - 1; i >= 0; i--)
|
||
|
{
|
||
|
if (i == ACE_STDIN || i == ACE_STDOUT || i == ACE_STDERR)
|
||
|
continue;
|
||
|
ACE_OS::fcntl (i, F_SETFD, FD_CLOEXEC);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// If we must, set the working directory for the child
|
||
|
// process.
|
||
|
if (options.working_directory () != 0)
|
||
|
ACE_OS::chdir (options.working_directory ());
|
||
|
// Should check for error here!
|
||
|
|
||
|
// Child process executes the command.
|
||
|
int result = 0;
|
||
|
|
||
|
// Wide-char builds not on Windows need narrow-char strings for
|
||
|
// exec() and environment variables. Don't need to worry about
|
||
|
// releasing any of the converted string memory since this
|
||
|
// process will either exec() or exit() shortly.
|
||
|
# if defined (ACE_USES_WCHAR)
|
||
|
ACE_Wide_To_Ascii n_procname (options.process_name ());
|
||
|
const char *procname = n_procname.char_rep ();
|
||
|
|
||
|
wchar_t * const *wargv = options.command_line_argv ();
|
||
|
size_t vcount, i;
|
||
|
for (vcount = 0; wargv[vcount] != 0; ++vcount)
|
||
|
;
|
||
|
char **procargv = new char *[vcount + 1]; // Need 0 at the end
|
||
|
procargv[vcount] = 0;
|
||
|
for (i = 0; i < vcount; ++i)
|
||
|
procargv[i] = ACE_Wide_To_Ascii::convert (wargv[i]);
|
||
|
|
||
|
wargv = options.env_argv ();
|
||
|
for (vcount = 0; wargv[vcount] != 0; ++vcount)
|
||
|
;
|
||
|
char **procenv = new char *[vcount + 1]; // Need 0 at the end
|
||
|
procenv[vcount] = 0;
|
||
|
for (i = 0; i < vcount; ++i)
|
||
|
procenv[i] = ACE_Wide_To_Ascii::convert (wargv[i]);
|
||
|
# else
|
||
|
const char *procname = options.process_name ();
|
||
|
char *const *procargv = options.command_line_argv ();
|
||
|
char *const *procenv = options.env_argv ();
|
||
|
# endif /* ACE_USES_WCHAR */
|
||
|
|
||
|
if (options.inherit_environment ())
|
||
|
{
|
||
|
// Add the new environment variables to the environment
|
||
|
// context of the context before doing an <execvp>.
|
||
|
for (size_t i = 0; procenv[i] != 0; i++)
|
||
|
if (ACE_OS::putenv (procenv[i]) != 0)
|
||
|
return ACE_INVALID_PID;
|
||
|
|
||
|
// Now the forked process has both inherited variables and
|
||
|
// the user's supplied variables.
|
||
|
result = ACE_OS::execvp (procname, procargv);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
result = ACE_OS::execve (procname, procargv, procenv);
|
||
|
}
|
||
|
if (result == -1)
|
||
|
{
|
||
|
// If the execv fails, this child needs to exit.
|
||
|
|
||
|
// Exit with the errno so that the calling process can
|
||
|
// catch this and figure out what went wrong.
|
||
|
ACE_OS::_exit (errno);
|
||
|
}
|
||
|
// ... otherwise, this is never reached.
|
||
|
return 0;
|
||
|
}
|
||
|
default:
|
||
|
// Server process. The fork succeeded.
|
||
|
return this->child_id_;
|
||
|
}
|
||
|
#endif /* ACE_WIN32 */
|
||
|
}
|
||
|
|
||
|
void
|
||
|
ACE_Process::parent (pid_t)
|
||
|
{
|
||
|
// nothing to do
|
||
|
}
|
||
|
|
||
|
void
|
||
|
ACE_Process::child (pid_t)
|
||
|
{
|
||
|
// nothing to do
|
||
|
}
|
||
|
|
||
|
void
|
||
|
ACE_Process::unmanage (void)
|
||
|
{
|
||
|
// nothing to do
|
||
|
}
|
||
|
|
||
|
int
|
||
|
ACE_Process::running (void) const
|
||
|
{
|
||
|
#if defined (ACE_WIN32)
|
||
|
DWORD code;
|
||
|
|
||
|
BOOL result = ::GetExitCodeProcess (this->gethandle (),
|
||
|
&code);
|
||
|
return result && code == STILL_ACTIVE;
|
||
|
#else
|
||
|
if (ACE_INVALID_PID == this->getpid ())
|
||
|
return 0;
|
||
|
else
|
||
|
return ACE_OS::kill (this->getpid (),
|
||
|
0) == 0
|
||
|
|| errno != ESRCH;
|
||
|
#endif /* ACE_WIN32 */
|
||
|
}
|
||
|
|
||
|
pid_t
|
||
|
ACE_Process::wait (const ACE_Time_Value &tv,
|
||
|
ACE_exitcode *status)
|
||
|
{
|
||
|
#if defined (ACE_WIN32)
|
||
|
// Don't try to get the process exit status if wait failed so we can
|
||
|
// keep the original error code intact.
|
||
|
switch (::WaitForSingleObject (process_info_.hProcess,
|
||
|
tv.msec ()))
|
||
|
{
|
||
|
case WAIT_OBJECT_0:
|
||
|
// The error status of <GetExitCodeProcess> is nonetheless not
|
||
|
// tested because we don't know how to return the value.
|
||
|
::GetExitCodeProcess (process_info_.hProcess,
|
||
|
&this->exit_code_);
|
||
|
if (status != 0)
|
||
|
*status = this->exit_code_;
|
||
|
return this->getpid ();
|
||
|
case WAIT_TIMEOUT:
|
||
|
errno = ETIME;
|
||
|
return 0;
|
||
|
default:
|
||
|
ACE_OS::set_errno_to_last_error ();
|
||
|
return -1;
|
||
|
}
|
||
|
#elif defined(ACE_LACKS_UNIX_SIGNALS)
|
||
|
if (tv == ACE_Time_Value::zero)
|
||
|
{
|
||
|
pid_t retv =
|
||
|
ACE_OS::waitpid (this->child_id_,
|
||
|
&this->exit_code_,
|
||
|
WNOHANG);
|
||
|
if (status != 0)
|
||
|
*status = this->exit_code_;
|
||
|
|
||
|
return retv;
|
||
|
}
|
||
|
|
||
|
if (tv == ACE_Time_Value::max_time)
|
||
|
# if defined (ACE_VXWORKS)
|
||
|
{
|
||
|
pid_t retv;
|
||
|
while ((retv = this->wait (status)) == ACE_INVALID_PID && errno == EINTR) ;
|
||
|
return retv;
|
||
|
}
|
||
|
# else
|
||
|
return this->wait (status);
|
||
|
# endif
|
||
|
|
||
|
pid_t pid = 0;
|
||
|
ACE_Time_Value sleeptm (1); // 1 msec
|
||
|
if (sleeptm > tv) // if sleeptime > waittime
|
||
|
sleeptm = tv;
|
||
|
ACE_Time_Value tmo (tv); // Need one we can change
|
||
|
for (ACE_Countdown_Time time_left (&tmo); tmo > ACE_Time_Value::zero ; time_left.update ())
|
||
|
{
|
||
|
pid = ACE_OS::waitpid (this->getpid (),
|
||
|
&this->exit_code_,
|
||
|
WNOHANG);
|
||
|
if (status != 0)
|
||
|
*status = this->exit_code_;
|
||
|
|
||
|
if (pid > 0 || pid == ACE_INVALID_PID)
|
||
|
break; // Got a child or an error - all done
|
||
|
|
||
|
// pid 0, nothing is ready yet, so wait.
|
||
|
// Do a (very) short sleep (only this thread sleeps).
|
||
|
ACE_OS::sleep (sleeptm);
|
||
|
}
|
||
|
|
||
|
return pid;
|
||
|
#else /* !ACE_WIN32 && !ACE_LACKS_UNIX_SIGNALS */
|
||
|
if (tv == ACE_Time_Value::zero)
|
||
|
{
|
||
|
pid_t retv =
|
||
|
ACE_OS::waitpid (this->child_id_,
|
||
|
&this->exit_code_,
|
||
|
WNOHANG);
|
||
|
if (status != 0)
|
||
|
*status = this->exit_code_;
|
||
|
|
||
|
return retv;
|
||
|
}
|
||
|
|
||
|
if (tv == ACE_Time_Value::max_time)
|
||
|
return this->wait (status);
|
||
|
|
||
|
// Need to wait but limited to specified time.
|
||
|
// Force generation of SIGCHLD, even though we don't want to
|
||
|
// catch it - just need it to interrupt the sleep below.
|
||
|
// If this object has a reactor set, assume it was given at
|
||
|
// open(), and there's already a SIGCHLD action set, so no
|
||
|
// action is needed here.
|
||
|
ACE_Sig_Action old_action;
|
||
|
ACE_Sig_Action do_sigchld ((ACE_SignalHandler)sigchld_nop);
|
||
|
do_sigchld.register_action (SIGCHLD, &old_action);
|
||
|
|
||
|
pid_t pid;
|
||
|
ACE_Time_Value tmo (tv); // Need one we can change
|
||
|
for (ACE_Countdown_Time time_left (&tmo); ; time_left.update ())
|
||
|
{
|
||
|
pid = ACE_OS::waitpid (this->getpid (),
|
||
|
&this->exit_code_,
|
||
|
WNOHANG);
|
||
|
if (status != 0)
|
||
|
*status = this->exit_code_;
|
||
|
|
||
|
if (pid > 0 || pid == ACE_INVALID_PID)
|
||
|
break; // Got a child or an error - all done
|
||
|
|
||
|
// pid 0, nothing is ready yet, so wait.
|
||
|
// Do a sleep (only this thread sleeps) til something
|
||
|
// happens. This relies on SIGCHLD interrupting the sleep.
|
||
|
// If SIGCHLD isn't delivered, we'll need to do something
|
||
|
// with sigaction to force it.
|
||
|
if (-1 == ACE_OS::sleep (tmo) && errno == EINTR)
|
||
|
continue;
|
||
|
// Timed out
|
||
|
pid = 0;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Restore the previous SIGCHLD action if it was changed.
|
||
|
old_action.register_action (SIGCHLD);
|
||
|
|
||
|
return pid;
|
||
|
#endif /* ACE_WIN32 */
|
||
|
}
|
||
|
|
||
|
void
|
||
|
ACE_Process::close_dup_handles (void)
|
||
|
{
|
||
|
if (this->dup_handles_.num_set () > 0)
|
||
|
{
|
||
|
ACE_Handle_Set_Iterator h_iter (this->dup_handles_);
|
||
|
for (ACE_HANDLE h = h_iter ();
|
||
|
h != ACE_INVALID_HANDLE;
|
||
|
h = h_iter ())
|
||
|
ACE_OS::closesocket (h);
|
||
|
this->dup_handles_.reset ();
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
ACE_Process::close_passed_handles (void)
|
||
|
{
|
||
|
if (this->handles_passed_.num_set () > 0)
|
||
|
{
|
||
|
ACE_Handle_Set_Iterator h_iter (this->handles_passed_);
|
||
|
for (ACE_HANDLE h = h_iter ();
|
||
|
h != ACE_INVALID_HANDLE;
|
||
|
h = h_iter ())
|
||
|
ACE_OS::closesocket (h);
|
||
|
this->handles_passed_.reset ();
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
#if defined (ACE_WIN32) && \
|
||
|
defined (ACE_HAS_WCHAR) && !defined (ACE_USES_WCHAR) && \
|
||
|
!defined (ACE_HAS_WINCE)
|
||
|
wchar_t*
|
||
|
ACE_Process::convert_env_buffer (const char* env) const
|
||
|
{
|
||
|
// Total starts out at 1 due to the final block nul terminator
|
||
|
size_t total = 1;
|
||
|
|
||
|
// Convert each individual character string to the equivalent wide
|
||
|
// character string.
|
||
|
ACE_Vector<wchar_t*> buffer;
|
||
|
size_t start = 0;
|
||
|
size_t i = 0;
|
||
|
while (true)
|
||
|
{
|
||
|
if (env[i] == '\0')
|
||
|
{
|
||
|
// Convert the char string to wchar_t
|
||
|
wchar_t* str = ACE_Ascii_To_Wide::convert (env + start);
|
||
|
|
||
|
// Add the length of the string plus the nul terminator
|
||
|
total += ACE_OS::strlen (str) + 1;
|
||
|
|
||
|
// Save it and set up for the next string
|
||
|
buffer.push_back (str);
|
||
|
start = ++i;
|
||
|
if (env[start] == '\0')
|
||
|
break;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
i += ACE_OS::strlen (env + i);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Copy each string into the buffer leaving a nul terminator between
|
||
|
// each string and adding a second nul terminator at the end
|
||
|
start = 0;
|
||
|
wchar_t* wenv = new wchar_t[total];
|
||
|
size_t length = buffer.size ();
|
||
|
for (i = 0; i < length; ++i)
|
||
|
{
|
||
|
ACE_OS::strcpy(wenv + start, buffer[i]);
|
||
|
start += ACE_OS::strlen (buffer[i]) + 1;
|
||
|
delete [] buffer[i];
|
||
|
}
|
||
|
wenv[start] = 0;
|
||
|
return wenv;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
ACE_Process_Options::ACE_Process_Options (bool inherit_environment,
|
||
|
size_t command_line_buf_len,
|
||
|
size_t env_buf_len,
|
||
|
size_t max_env_args,
|
||
|
size_t max_cmdline_args)
|
||
|
:
|
||
|
#if !defined (ACE_HAS_WINCE)
|
||
|
inherit_environment_ (inherit_environment),
|
||
|
#endif /* ACE_HAS_WINCE */
|
||
|
creation_flags_ (0),
|
||
|
avoid_zombies_ (0),
|
||
|
#if !defined (ACE_HAS_WINCE)
|
||
|
#if defined (ACE_WIN32)
|
||
|
environment_inherited_ (0),
|
||
|
process_attributes_ (0),
|
||
|
thread_attributes_ (0),
|
||
|
#else /* ACE_WIN32 */
|
||
|
stdin_ (ACE_INVALID_HANDLE),
|
||
|
stdout_ (ACE_INVALID_HANDLE),
|
||
|
stderr_ (ACE_INVALID_HANDLE),
|
||
|
ruid_ ((uid_t) -1),
|
||
|
euid_ ((uid_t) -1),
|
||
|
rgid_ ((uid_t) -1),
|
||
|
egid_ ((uid_t) -1),
|
||
|
#endif /* ACE_WIN32 */
|
||
|
handle_inheritance_ (true),
|
||
|
set_handles_called_ (0),
|
||
|
environment_buf_index_ (0),
|
||
|
environment_argv_index_ (0),
|
||
|
environment_buf_ (0),
|
||
|
environment_buf_len_ (env_buf_len),
|
||
|
max_environment_args_ (max_env_args),
|
||
|
max_environ_argv_index_ (max_env_args - 1),
|
||
|
#endif /* !ACE_HAS_WINCE */
|
||
|
command_line_argv_calculated_ (false),
|
||
|
command_line_buf_ (0),
|
||
|
command_line_copy_ (0),
|
||
|
command_line_buf_len_ (command_line_buf_len),
|
||
|
max_command_line_args_ (max_cmdline_args),
|
||
|
command_line_argv_ (0),
|
||
|
process_group_ (ACE_INVALID_PID),
|
||
|
use_unicode_environment_ (false)
|
||
|
{
|
||
|
ACE_NEW (command_line_buf_,
|
||
|
ACE_TCHAR[command_line_buf_len]);
|
||
|
command_line_buf_[0] = '\0';
|
||
|
process_name_[0] = '\0';
|
||
|
|
||
|
#if defined (ACE_HAS_WINCE)
|
||
|
ACE_UNUSED_ARG(inherit_environment);
|
||
|
ACE_UNUSED_ARG(env_buf_len);
|
||
|
ACE_UNUSED_ARG(max_env_args);
|
||
|
#endif
|
||
|
|
||
|
#if !defined (ACE_HAS_WINCE)
|
||
|
working_directory_[0] = '\0';
|
||
|
ACE_NEW (environment_buf_,
|
||
|
ACE_TCHAR[env_buf_len]);
|
||
|
ACE_NEW (environment_argv_,
|
||
|
ACE_TCHAR *[max_env_args]);
|
||
|
environment_buf_[0] = '\0';
|
||
|
environment_argv_[0] = 0;
|
||
|
#if defined (ACE_WIN32)
|
||
|
ACE_OS::memset ((void *) &this->startup_info_,
|
||
|
0,
|
||
|
sizeof this->startup_info_);
|
||
|
this->startup_info_.cb = sizeof this->startup_info_;
|
||
|
#endif /* ACE_WIN32 */
|
||
|
#endif /* !ACE_HAS_WINCE */
|
||
|
ACE_NEW (command_line_argv_,
|
||
|
ACE_TCHAR *[max_cmdline_args]);
|
||
|
}
|
||
|
|
||
|
#if !defined (ACE_HAS_WINCE)
|
||
|
#if defined (ACE_WIN32)
|
||
|
void
|
||
|
ACE_Process_Options::inherit_environment (void)
|
||
|
{
|
||
|
// Ensure only once execution.
|
||
|
if (environment_inherited_)
|
||
|
return;
|
||
|
environment_inherited_ = 1;
|
||
|
|
||
|
// Get the existing environment.
|
||
|
ACE_TCHAR *existing_environment = 0;
|
||
|
#if defined (ACE_HAS_WCHAR) && !defined (ACE_USES_WCHAR)
|
||
|
WCHAR *existing_wide_env = 0;
|
||
|
ACE_Vector<char> temp_narrow_env;
|
||
|
if (this->use_unicode_environment_)
|
||
|
{
|
||
|
existing_wide_env = ::GetEnvironmentStringsW ();
|
||
|
for (WCHAR *iter = existing_wide_env; *iter; ++iter)
|
||
|
{
|
||
|
ACE_Wide_To_Ascii wta (iter);
|
||
|
size_t len = ACE_OS::strlen (wta.char_rep ());
|
||
|
size_t idx = temp_narrow_env.size ();
|
||
|
temp_narrow_env.resize (idx + len + 1, 0);
|
||
|
ACE_OS::strncpy (&temp_narrow_env[idx], wta.char_rep (), len);
|
||
|
iter += len;
|
||
|
}
|
||
|
temp_narrow_env.push_back (0);
|
||
|
existing_environment = &temp_narrow_env[0];
|
||
|
}
|
||
|
else
|
||
|
#endif
|
||
|
existing_environment = ACE_OS::getenvstrings ();
|
||
|
|
||
|
size_t slot = 0;
|
||
|
|
||
|
while (existing_environment[slot] != '\0')
|
||
|
{
|
||
|
size_t len = ACE_OS::strlen (existing_environment + slot);
|
||
|
|
||
|
// Add the string to our env buffer.
|
||
|
if (this->setenv_i (existing_environment + slot, len) == -1)
|
||
|
{
|
||
|
ACELIB_ERROR ((LM_ERROR,
|
||
|
ACE_TEXT ("%p.\n"),
|
||
|
ACE_TEXT ("ACE_Process_Options::ACE_Process_Options")));
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Skip to the next word.
|
||
|
slot += len + 1;
|
||
|
}
|
||
|
|
||
|
#if defined (ACE_HAS_WCHAR) && !defined (ACE_USES_WCHAR)
|
||
|
if (this->use_unicode_environment_)
|
||
|
::FreeEnvironmentStringsW (existing_wide_env);
|
||
|
else
|
||
|
#endif
|
||
|
ACE_TEXT_FreeEnvironmentStrings (existing_environment);
|
||
|
}
|
||
|
|
||
|
#else /* defined ACE_WIN32 */
|
||
|
|
||
|
ACE_TCHAR * const *
|
||
|
ACE_Process_Options::env_argv (void)
|
||
|
{
|
||
|
return environment_argv_;
|
||
|
}
|
||
|
|
||
|
#endif /* ACE_WIN32 */
|
||
|
|
||
|
int
|
||
|
ACE_Process_Options::setenv (ACE_TCHAR *envp[])
|
||
|
{
|
||
|
int i = 0;
|
||
|
while (envp[i])
|
||
|
{
|
||
|
if (this->setenv_i (envp[i],
|
||
|
ACE_OS::strlen (envp[i])) == -1)
|
||
|
return -1;
|
||
|
i++;
|
||
|
}
|
||
|
|
||
|
#if defined (ACE_WIN32)
|
||
|
if (inherit_environment_)
|
||
|
this->inherit_environment ();
|
||
|
#endif /* ACE_WIN32 */
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int
|
||
|
ACE_Process_Options::setenv (const ACE_TCHAR *format, ...)
|
||
|
{
|
||
|
ACE_TCHAR stack_buf[DEFAULT_COMMAND_LINE_BUF_LEN];
|
||
|
|
||
|
int status;
|
||
|
// Start varargs.
|
||
|
va_list argp;
|
||
|
va_start (argp, format);
|
||
|
|
||
|
// Add the rest of the varargs.
|
||
|
// At the time of this writing, only one platform does not support
|
||
|
// vsnprintf (LynxOS). Should we get to the point where no platform
|
||
|
// sets ACE_LACKS_VSNPRINTF, this condition can be removed.
|
||
|
#if defined (ACE_LACKS_VSNPRINTF)
|
||
|
status = ACE_OS::vsprintf (stack_buf,
|
||
|
format,
|
||
|
argp);
|
||
|
#else
|
||
|
status = ACE_OS::vsnprintf (stack_buf,
|
||
|
DEFAULT_COMMAND_LINE_BUF_LEN,
|
||
|
format,
|
||
|
argp);
|
||
|
#endif /* ACE_LACKS_VSNPRINTF */
|
||
|
|
||
|
// End varargs.
|
||
|
va_end (argp);
|
||
|
|
||
|
if (status == -1)
|
||
|
return -1;
|
||
|
|
||
|
// Append the string to are environment buffer.
|
||
|
if (this->setenv_i (stack_buf,
|
||
|
ACE_OS::strlen (stack_buf)) == -1)
|
||
|
return -1;
|
||
|
|
||
|
#if defined (ACE_WIN32)
|
||
|
if (inherit_environment_)
|
||
|
this->inherit_environment ();
|
||
|
#endif /* ACE_WIN32 */
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int
|
||
|
ACE_Process_Options::setenv (const ACE_TCHAR *variable_name,
|
||
|
const ACE_TCHAR *format, ...)
|
||
|
{
|
||
|
// To address the potential buffer overflow,
|
||
|
// we now allocate the buffer on heap with a variable size.
|
||
|
size_t const buflen = ACE_OS::strlen (variable_name) + ACE_OS::strlen (format) + 2;
|
||
|
ACE_TCHAR *newformat = 0;
|
||
|
ACE_NEW_RETURN (newformat, ACE_TCHAR[buflen], -1);
|
||
|
ACE_Auto_Basic_Array_Ptr<ACE_TCHAR> safe_newformat (newformat);
|
||
|
|
||
|
# if !defined (ACE_WIN32) && defined (ACE_USES_WCHAR)
|
||
|
const ACE_TCHAR *fmt = ACE_TEXT ("%ls=%ls");
|
||
|
# else
|
||
|
const ACE_TCHAR *fmt = ACE_TEXT ("%s=%s");
|
||
|
# endif
|
||
|
|
||
|
// Add in the variable name.
|
||
|
ACE_OS::sprintf (safe_newformat.get (),
|
||
|
fmt,
|
||
|
variable_name,
|
||
|
format);
|
||
|
|
||
|
// Add the rest of the varargs.
|
||
|
size_t tmp_buflen = buflen;
|
||
|
if (DEFAULT_COMMAND_LINE_BUF_LEN > buflen)
|
||
|
{
|
||
|
tmp_buflen = DEFAULT_COMMAND_LINE_BUF_LEN;
|
||
|
}
|
||
|
int retval = 0;
|
||
|
|
||
|
ACE_TCHAR *stack_buf = 0;
|
||
|
ACE_NEW_RETURN (stack_buf, ACE_TCHAR[tmp_buflen], -1);
|
||
|
ACE_Auto_Basic_Array_Ptr<ACE_TCHAR> safe_stack_buf (stack_buf);
|
||
|
|
||
|
do
|
||
|
{
|
||
|
// Must restart varargs on each time through this loop,
|
||
|
va_list argp;
|
||
|
va_start (argp, format);
|
||
|
|
||
|
retval = ACE_OS::vsnprintf (safe_stack_buf.get (), tmp_buflen, safe_newformat.get (), argp);
|
||
|
|
||
|
// End varargs.
|
||
|
va_end (argp);
|
||
|
|
||
|
if (retval > ACE_Utils::truncate_cast<int> (tmp_buflen))
|
||
|
{
|
||
|
tmp_buflen *= 2;
|
||
|
ACE_NEW_RETURN (stack_buf, ACE_TCHAR[tmp_buflen], -1);
|
||
|
safe_stack_buf.reset (stack_buf);
|
||
|
}
|
||
|
else
|
||
|
break;
|
||
|
}
|
||
|
while (1);
|
||
|
|
||
|
if (retval == -1)
|
||
|
{
|
||
|
// In case that vsnprintf is not supported,
|
||
|
// e.g., LynxOS and VxWorks 5, we have to
|
||
|
// fall back to vsprintf.
|
||
|
if (errno == ENOTSUP)
|
||
|
{
|
||
|
// ALERT: Since we have to use vsprintf here, there is still a chance that
|
||
|
// the stack_buf overflows, i.e., the length of the resulting string
|
||
|
// can still possibly go beyond the allocated stack_buf.
|
||
|
va_list argp;
|
||
|
va_start (argp, format);
|
||
|
retval = ACE_OS::vsprintf (safe_stack_buf.get (), safe_newformat.get (), argp);
|
||
|
va_end (argp);
|
||
|
if (retval == -1)
|
||
|
// vsprintf is failed.
|
||
|
return -1;
|
||
|
}
|
||
|
else
|
||
|
// vsnprintf is failed.
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
// Append the string to our environment buffer.
|
||
|
if (this->setenv_i (safe_stack_buf.get (),
|
||
|
ACE_OS::strlen (safe_stack_buf.get ())) == -1)
|
||
|
return -1;
|
||
|
|
||
|
#if defined (ACE_WIN32)
|
||
|
if (inherit_environment_)
|
||
|
this->inherit_environment ();
|
||
|
#endif /* ACE_WIN32 */
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int
|
||
|
ACE_Process_Options::setenv_i (ACE_TCHAR *assignment,
|
||
|
size_t len)
|
||
|
{
|
||
|
// Add one for the null char.
|
||
|
++len;
|
||
|
|
||
|
// If environment larger than allocated buffer return. Also check to
|
||
|
// make sure we have enough room.
|
||
|
if (environment_argv_index_ == max_environ_argv_index_
|
||
|
|| (len + environment_buf_index_) >= environment_buf_len_)
|
||
|
return -1;
|
||
|
|
||
|
// Copy the new environment string.
|
||
|
ACE_OS::memcpy (environment_buf_ + environment_buf_index_,
|
||
|
assignment,
|
||
|
len * sizeof (ACE_TCHAR));
|
||
|
|
||
|
// Update the argv array.
|
||
|
environment_argv_[environment_argv_index_++] =
|
||
|
environment_buf_ + environment_buf_index_;
|
||
|
environment_argv_[environment_argv_index_] = 0;
|
||
|
|
||
|
// Update our index.
|
||
|
environment_buf_index_ += len;
|
||
|
|
||
|
// Make sure the buffer is null-terminated.
|
||
|
environment_buf_[environment_buf_index_] = '\0';
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int
|
||
|
ACE_Process_Options::set_handles (ACE_HANDLE std_in,
|
||
|
ACE_HANDLE std_out,
|
||
|
ACE_HANDLE std_err)
|
||
|
{
|
||
|
this->set_handles_called_ = 1;
|
||
|
#if defined (ACE_WIN32)
|
||
|
|
||
|
// Tell the new process to use our std handles.
|
||
|
this->startup_info_.dwFlags = STARTF_USESTDHANDLES;
|
||
|
|
||
|
if (std_in == ACE_INVALID_HANDLE)
|
||
|
std_in = ACE_STDIN;
|
||
|
if (std_out == ACE_INVALID_HANDLE)
|
||
|
std_out = ACE_STDOUT;
|
||
|
if (std_err == ACE_INVALID_HANDLE)
|
||
|
std_err = ACE_STDERR;
|
||
|
|
||
|
// STD handles may have value 0 (not ACE_INVALID_HANDLE) if there is no such
|
||
|
// handle in the process. This was observed to occur for stdin in console
|
||
|
// processes that were launched from services. In this case we need to make
|
||
|
// sure not to return -1 from setting std_in so that we can process std_out
|
||
|
// and std_err.
|
||
|
|
||
|
if (std_in)
|
||
|
{
|
||
|
if (!::DuplicateHandle (::GetCurrentProcess (),
|
||
|
std_in,
|
||
|
::GetCurrentProcess (),
|
||
|
&this->startup_info_.hStdInput,
|
||
|
0,
|
||
|
TRUE,
|
||
|
DUPLICATE_SAME_ACCESS))
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
if (std_out)
|
||
|
{
|
||
|
if (!::DuplicateHandle (::GetCurrentProcess (),
|
||
|
std_out,
|
||
|
::GetCurrentProcess (),
|
||
|
&this->startup_info_.hStdOutput,
|
||
|
0,
|
||
|
TRUE,
|
||
|
DUPLICATE_SAME_ACCESS))
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
if (std_err)
|
||
|
{
|
||
|
if (!::DuplicateHandle (::GetCurrentProcess (),
|
||
|
std_err,
|
||
|
::GetCurrentProcess (),
|
||
|
&this->startup_info_.hStdError,
|
||
|
0,
|
||
|
TRUE,
|
||
|
DUPLICATE_SAME_ACCESS))
|
||
|
return -1;
|
||
|
}
|
||
|
#else /* ACE_WIN32 */
|
||
|
this->stdin_ = ACE_OS::dup (std_in);
|
||
|
this->stdout_ = ACE_OS::dup (std_out);
|
||
|
this->stderr_ = ACE_OS::dup (std_err);
|
||
|
#endif /* ACE_WIN32 */
|
||
|
|
||
|
return 0; // Success.
|
||
|
}
|
||
|
|
||
|
|
||
|
void
|
||
|
ACE_Process_Options::release_handles ()
|
||
|
{
|
||
|
if (set_handles_called_)
|
||
|
{
|
||
|
#if defined (ACE_WIN32)
|
||
|
ACE_OS::close (startup_info_.hStdInput);
|
||
|
ACE_OS::close (startup_info_.hStdOutput);
|
||
|
ACE_OS::close (startup_info_.hStdError);
|
||
|
#else /* ACE_WIN32 */
|
||
|
ACE_OS::close (stdin_);
|
||
|
ACE_OS::close (stdout_);
|
||
|
ACE_OS::close (stderr_);
|
||
|
#endif /* ACE_WIN32 */
|
||
|
set_handles_called_ = 0;
|
||
|
}
|
||
|
}
|
||
|
#endif /* !ACE_HAS_WINCE */
|
||
|
|
||
|
|
||
|
ACE_Process_Options::~ACE_Process_Options (void)
|
||
|
{
|
||
|
#if !defined (ACE_HAS_WINCE)
|
||
|
release_handles();
|
||
|
delete [] environment_buf_;
|
||
|
delete [] environment_argv_;
|
||
|
#endif /* !ACE_HAS_WINCE */
|
||
|
delete [] command_line_buf_;
|
||
|
ACE::strdelete (command_line_copy_);
|
||
|
delete [] command_line_argv_;
|
||
|
}
|
||
|
|
||
|
int
|
||
|
ACE_Process_Options::command_line (const ACE_TCHAR *const argv[])
|
||
|
{
|
||
|
int i = 0;
|
||
|
|
||
|
if (argv[i])
|
||
|
{
|
||
|
ACE_OS::strcat (command_line_buf_, argv[i]);
|
||
|
|
||
|
while (argv[++i])
|
||
|
{
|
||
|
// Check to see if the next argument will overflow the
|
||
|
// command_line buffer.
|
||
|
size_t const cur_len =
|
||
|
ACE_OS::strlen (command_line_buf_)
|
||
|
+ ACE_OS::strlen (argv[i])
|
||
|
+ 2;
|
||
|
|
||
|
if (cur_len > command_line_buf_len_)
|
||
|
{
|
||
|
ACELIB_ERROR_RETURN ((LM_ERROR,
|
||
|
ACE_TEXT ("ACE_Process:command_line: ")
|
||
|
ACE_TEXT ("command line is ")
|
||
|
ACE_TEXT ("longer than %d\n"),
|
||
|
command_line_buf_len_),
|
||
|
1);
|
||
|
}
|
||
|
|
||
|
ACE_OS::strcat (command_line_buf_, ACE_TEXT (" "));
|
||
|
ACE_OS::strcat (command_line_buf_, argv[i]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
command_line_argv_calculated_ = false;
|
||
|
return 0; // Success.
|
||
|
}
|
||
|
|
||
|
int
|
||
|
ACE_Process_Options::command_line (const ACE_TCHAR *format, ...)
|
||
|
{
|
||
|
// Store all ... args in argp.
|
||
|
va_list argp;
|
||
|
va_start (argp, format);
|
||
|
|
||
|
if (command_line_buf_len_ < 1)
|
||
|
{
|
||
|
va_end (argp);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
#if !defined (ACE_LACKS_VSNPRINTF) || defined (ACE_HAS_TRIO)
|
||
|
// vsnprintf the format and args into command_line_buf__.
|
||
|
ACE_OS::vsnprintf (command_line_buf_,
|
||
|
command_line_buf_len_,
|
||
|
format,
|
||
|
argp);
|
||
|
#else
|
||
|
// sprintf the format and args into command_line_buf__.
|
||
|
ACE_OS::vsprintf (command_line_buf_,
|
||
|
format,
|
||
|
argp);
|
||
|
#endif
|
||
|
|
||
|
// Useless macro.
|
||
|
va_end (argp);
|
||
|
|
||
|
command_line_argv_calculated_ = false;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
#if defined (ACE_HAS_WCHAR) && !defined (ACE_HAS_WINCE)
|
||
|
/**
|
||
|
* @note Not available on Windows CE because it doesn't have a char version of
|
||
|
* vsprintf.
|
||
|
*/
|
||
|
int
|
||
|
ACE_Process_Options::command_line (const ACE_ANTI_TCHAR *format, ...)
|
||
|
{
|
||
|
ACE_ANTI_TCHAR *anti_clb = 0;
|
||
|
ACE_NEW_RETURN (anti_clb,
|
||
|
ACE_ANTI_TCHAR[this->command_line_buf_len_],
|
||
|
-1);
|
||
|
|
||
|
// Store all ... args in argp.
|
||
|
va_list argp;
|
||
|
va_start (argp, format);
|
||
|
|
||
|
// sprintf the format and args into command_line_buf_.
|
||
|
ACE_OS::vsprintf (anti_clb,
|
||
|
format,
|
||
|
argp);
|
||
|
|
||
|
// Useless macro.
|
||
|
va_end (argp);
|
||
|
|
||
|
ACE_OS::strcpy (this->command_line_buf_,
|
||
|
ACE_TEXT_ANTI_TO_TCHAR (anti_clb));
|
||
|
|
||
|
delete [] anti_clb;
|
||
|
|
||
|
command_line_argv_calculated_ = false;
|
||
|
return 0;
|
||
|
}
|
||
|
#endif /* ACE_HAS_WCHAR && !ACE_HAS_WINCE */
|
||
|
|
||
|
ACE_TCHAR *
|
||
|
ACE_Process_Options::env_buf (void)
|
||
|
{
|
||
|
#if !defined (ACE_HAS_WINCE)
|
||
|
if (environment_buf_[0] == '\0')
|
||
|
return 0;
|
||
|
else
|
||
|
return environment_buf_;
|
||
|
#else
|
||
|
return 0;
|
||
|
#endif /* !ACE_HAS_WINCE */
|
||
|
}
|
||
|
|
||
|
ACE_TCHAR * const *
|
||
|
ACE_Process_Options::command_line_argv (void)
|
||
|
{
|
||
|
if (!command_line_argv_calculated_)
|
||
|
{
|
||
|
command_line_argv_calculated_ = true;
|
||
|
|
||
|
// We need to free up any previous allocated memory first.
|
||
|
ACE::strdelete (command_line_copy_);
|
||
|
|
||
|
// We need to make a dynamically allocated copy here since
|
||
|
// ACE_Tokenizer modifies its arguments.
|
||
|
command_line_copy_ = ACE::strnew (command_line_buf_);
|
||
|
// This tokenizer will replace all spaces with end-of-string
|
||
|
// characters and will preserve text between "" and '' pairs.
|
||
|
ACE_Tokenizer parser (command_line_copy_);
|
||
|
parser.delimiter_replace (' ', '\0');
|
||
|
parser.preserve_designators ('\"', '\"'); // "
|
||
|
parser.preserve_designators ('\'', '\'');
|
||
|
|
||
|
unsigned int x = 0;
|
||
|
do
|
||
|
command_line_argv_[x] = parser.next ();
|
||
|
while (command_line_argv_[x] != 0
|
||
|
// subtract one for the ending zero.
|
||
|
&& ++x < max_command_line_args_ - 1);
|
||
|
|
||
|
command_line_argv_[x] = 0;
|
||
|
}
|
||
|
|
||
|
return command_line_argv_;
|
||
|
}
|
||
|
|
||
|
// Cause the specified handle to be passed to a child process
|
||
|
// when it's spawned.
|
||
|
int
|
||
|
ACE_Process_Options::pass_handle (ACE_HANDLE h)
|
||
|
{
|
||
|
#if defined (ACE_HAS_WINCE)
|
||
|
ACE_NOTSUP_RETURN (-1);
|
||
|
#else
|
||
|
this->handles_passed_.set_bit (h);
|
||
|
return 0;
|
||
|
#endif /* ACE_HAS_WINCE */
|
||
|
}
|
||
|
|
||
|
// Get a copy of the handles the ACE_Process_Options duplicated
|
||
|
// for the spawned process.
|
||
|
int
|
||
|
ACE_Process_Options::dup_handles (ACE_Handle_Set &set) const
|
||
|
{
|
||
|
if (this->dup_handles_.num_set () == 0)
|
||
|
return 0;
|
||
|
set.reset ();
|
||
|
set = this->dup_handles_;
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
// Get a copy of the handles passed to the spawned process. This
|
||
|
// will be the set of handles previously passed to @arg pass_handle().
|
||
|
int
|
||
|
ACE_Process_Options::passed_handles (ACE_Handle_Set &set) const
|
||
|
{
|
||
|
if (this->handles_passed_.num_set () == 0)
|
||
|
return 0;
|
||
|
set.reset ();
|
||
|
set = this->handles_passed_;
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
ACE_Managed_Process::~ACE_Managed_Process (void)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
void
|
||
|
ACE_Managed_Process::unmanage (void)
|
||
|
{
|
||
|
delete this;
|
||
|
}
|
||
|
|
||
|
ACE_END_VERSIONED_NAMESPACE_DECL
|